Pdfium 2079dce2ca47f3866f1dd5d51849c53362727f7b

Same as used by Chrome for Android 58.0.3029.83

Bug: 38203442
Test: CtsPrintTestCases:android.print.pdf.cts.PrintedPdfDocumentTest
      CtsPdfTestCases
Change-Id: Ib4c424ea09e914b73dffe724fdff6b6655849814
Merged-In: Ib8d903baaf733a96836e672b807386ca4a3bb783
diff --git a/.gn b/.gn
index fbcbf4b..ce52529 100644
--- a/.gn
+++ b/.gn
@@ -4,3 +4,12 @@
 
 buildconfig = "//build/config/BUILDCONFIG.gn"
 secondary_source = "//build/secondary/"
+
+default_args = {
+  v8_extra_library_files = []
+  v8_experimental_extra_library_files = []
+  v8_enable_inspector = false
+
+  # Turns on compiler optimizations in V8 in Debug build.
+  v8_optimized_debug = true
+}
diff --git a/AUTHORS b/AUTHORS
index 17a0c60..6c2a295 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -27,6 +27,7 @@
 Lucas Nihlen <luken@chromium.org>
 Matt Giuca <mgiuca@chromium.org>
 Michael Doppler <m.doppler@gmail.com>
+Miklos Vajna <vmiklos@vmiklos.hu>
 Nico Weber <thakis@chromium.org>
 Peter Kasting <pkasting@chromium.org>
 Raymes Khoury <raymes@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index 4a05c56..de7f21b 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -2,12 +2,12 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build_overrides/v8.gni")
 import("//testing/test.gni")
 import("pdfium.gni")
 
 config("pdfium_common_config") {
   cflags = []
+  ldflags = []
   include_dirs = [
     ".",
     "third_party/freetype/include",
@@ -33,16 +33,36 @@
 
   if (pdf_enable_xfa) {
     defines += [ "PDF_ENABLE_XFA" ]
+    if (pdf_enable_xfa_bmp) {
+      defines += [ "PDF_ENABLE_XFA_BMP" ]
+    }
+    if (pdf_enable_xfa_gif) {
+      defines += [ "PDF_ENABLE_XFA_GIF" ]
+    }
+    if (pdf_enable_xfa_png) {
+      defines += [ "PDF_ENABLE_XFA_PNG" ]
+    }
+    if (pdf_enable_xfa_tiff) {
+      defines += [ "PDF_ENABLE_XFA_TIFF" ]
+    }
   }
 
   if (pdf_use_win32_gdi) {
     defines += [ "PDFIUM_PRINT_TEXT_WITH_GDI" ]
   }
+
+  if (use_coverage && is_clang) {
+    cflags += [
+      "--coverage",
+      "-g",
+      "-O0",
+    ]
+    ldflags += [ "--coverage" ]
+  }
 }
 
 config("pdfium_core_config") {
   cflags = []
-  ldflags = []
   configs = [ ":pdfium_common_config" ]
   defines = [ "V8_DEPRECATION_WARNINGS" ]
   if (is_linux) {
@@ -56,14 +76,6 @@
   if (is_win) {
     cflags += [ "/wd4267" ]
   }
-  if (use_coverage && is_clang) {
-    cflags += [
-      "--coverage",
-      "-g",
-      "-O0",
-    ]
-    ldflags += [ "--coverage" ]
-  }
 }
 
 config("xfa_warnings") {
@@ -112,6 +124,8 @@
     "fpdfsdk/fpdfdoc.cpp",
     "fpdfsdk/fpdfeditimg.cpp",
     "fpdfsdk/fpdfeditpage.cpp",
+    "fpdfsdk/fpdfeditpath.cpp",
+    "fpdfsdk/fpdfedittext.cpp",
     "fpdfsdk/fpdfformfill.cpp",
     "fpdfsdk/fpdfppo.cpp",
     "fpdfsdk/fpdfsave.cpp",
@@ -685,16 +699,20 @@
 
   if (pdf_enable_xfa) {
     sources += [
+      "core/fxcodec/codec/ccodec_bmpmodule.cpp",
       "core/fxcodec/codec/ccodec_bmpmodule.h",
+      "core/fxcodec/codec/ccodec_gifmodule.cpp",
       "core/fxcodec/codec/ccodec_gifmodule.h",
+      "core/fxcodec/codec/ccodec_pngmodule.cpp",
       "core/fxcodec/codec/ccodec_pngmodule.h",
       "core/fxcodec/codec/ccodec_progressivedecoder.h",
+      "core/fxcodec/codec/ccodec_tiffmodule.cpp",
       "core/fxcodec/codec/ccodec_tiffmodule.h",
-      "core/fxcodec/codec/fx_codec_bmp.cpp",
-      "core/fxcodec/codec/fx_codec_gif.cpp",
-      "core/fxcodec/codec/fx_codec_png.cpp",
       "core/fxcodec/codec/fx_codec_progress.cpp",
-      "core/fxcodec/codec/fx_codec_tiff.cpp",
+      "core/fxcodec/codec/icodec_bmpmodule.h",
+      "core/fxcodec/codec/icodec_gifmodule.h",
+      "core/fxcodec/codec/icodec_pngmodule.h",
+      "core/fxcodec/codec/icodec_tiffmodule.h",
       "core/fxcodec/lbmp/fx_bmp.cpp",
       "core/fxcodec/lbmp/fx_bmp.h",
       "core/fxcodec/lgif/fx_gif.cpp",
@@ -964,6 +982,7 @@
     "fpdfsdk/pdfwindow/PWL_Utils.h",
     "fpdfsdk/pdfwindow/PWL_Wnd.cpp",
     "fpdfsdk/pdfwindow/PWL_Wnd.h",
+    "fpdfsdk/pdfwindow/cpwl_color.cpp",
     "fpdfsdk/pdfwindow/cpwl_color.h",
   ]
   configs += [ ":pdfium_core_config" ]
@@ -974,7 +993,7 @@
 
 static_library("javascript") {
   sources = [
-    "fpdfsdk/javascript/ijs_context.h",
+    "fpdfsdk/javascript/ijs_event_context.h",
     "fpdfsdk/javascript/ijs_runtime.h",
   ]
   configs += [ ":pdfium_core_config" ]
@@ -1009,8 +1028,8 @@
       "fpdfsdk/javascript/PublicMethods.h",
       "fpdfsdk/javascript/app.cpp",
       "fpdfsdk/javascript/app.h",
-      "fpdfsdk/javascript/cjs_context.cpp",
-      "fpdfsdk/javascript/cjs_context.h",
+      "fpdfsdk/javascript/cjs_event_context.cpp",
+      "fpdfsdk/javascript/cjs_event_context.h",
       "fpdfsdk/javascript/cjs_runtime.cpp",
       "fpdfsdk/javascript/cjs_runtime.h",
       "fpdfsdk/javascript/color.cpp",
@@ -1144,27 +1163,20 @@
       "xfa/fde/cfx_chariter.h",
       "xfa/fde/cfx_wordbreak.cpp",
       "xfa/fde/cfx_wordbreak.h",
-      "xfa/fde/css/cfde_cssaccelerator.cpp",
-      "xfa/fde/css/cfde_cssaccelerator.h",
       "xfa/fde/css/cfde_csscolorvalue.cpp",
       "xfa/fde/css/cfde_csscolorvalue.h",
       "xfa/fde/css/cfde_csscomputedstyle.cpp",
       "xfa/fde/css/cfde_csscomputedstyle.h",
+      "xfa/fde/css/cfde_csscustomproperty.cpp",
       "xfa/fde/css/cfde_csscustomproperty.h",
       "xfa/fde/css/cfde_cssdeclaration.cpp",
       "xfa/fde/css/cfde_cssdeclaration.h",
       "xfa/fde/css/cfde_cssenumvalue.cpp",
       "xfa/fde/css/cfde_cssenumvalue.h",
-      "xfa/fde/css/cfde_cssfontfacerule.cpp",
-      "xfa/fde/css/cfde_cssfontfacerule.h",
-      "xfa/fde/css/cfde_cssmediarule.cpp",
-      "xfa/fde/css/cfde_cssmediarule.h",
       "xfa/fde/css/cfde_cssnumbervalue.cpp",
       "xfa/fde/css/cfde_cssnumbervalue.h",
       "xfa/fde/css/cfde_csspropertyholder.cpp",
       "xfa/fde/css/cfde_csspropertyholder.h",
-      "xfa/fde/css/cfde_cssrule.cpp",
-      "xfa/fde/css/cfde_cssrule.h",
       "xfa/fde/css/cfde_cssrulecollection.cpp",
       "xfa/fde/css/cfde_cssrulecollection.h",
       "xfa/fde/css/cfde_cssselector.cpp",
@@ -1179,8 +1191,6 @@
       "xfa/fde/css/cfde_cssstylesheet.h",
       "xfa/fde/css/cfde_csssyntaxparser.cpp",
       "xfa/fde/css/cfde_csssyntaxparser.h",
-      "xfa/fde/css/cfde_csstagcache.cpp",
-      "xfa/fde/css/cfde_csstagcache.h",
       "xfa/fde/css/cfde_csstextbuf.cpp",
       "xfa/fde/css/cfde_csstextbuf.h",
       "xfa/fde/css/cfde_cssvalue.cpp",
@@ -1228,8 +1238,6 @@
       "xfa/fgas/layout/fgas_rtfbreak.h",
       "xfa/fgas/layout/fgas_textbreak.cpp",
       "xfa/fgas/layout/fgas_textbreak.h",
-      "xfa/fgas/layout/fgas_unicode.cpp",
-      "xfa/fgas/layout/fgas_unicode.h",
       "xfa/fgas/localization/fgas_datetime.cpp",
       "xfa/fgas/localization/fgas_datetime.h",
       "xfa/fgas/localization/fgas_locale.cpp",
@@ -1323,7 +1331,6 @@
       "xfa/fwl/cfwl_widgetproperties.h",
       "xfa/fwl/cfx_barcode.cpp",
       "xfa/fwl/cfx_barcode.h",
-      "xfa/fwl/fwl_error.h",
       "xfa/fwl/fwl_widgetdef.h",
       "xfa/fwl/fwl_widgethit.h",
       "xfa/fwl/ifwl_adaptertimermgr.h",
@@ -1710,16 +1717,12 @@
       "xfa/fxfa/xfa_ffwidgethandler.h",
       "xfa/fxfa/xfa_fontmgr.h",
       "xfa/fxfa/xfa_rendercontext.h",
-      "xfa/fxgraphics/cagg_graphics.cpp",
-      "xfa/fxgraphics/cagg_graphics.h",
       "xfa/fxgraphics/cfx_color.cpp",
       "xfa/fxgraphics/cfx_color.h",
       "xfa/fxgraphics/cfx_graphics.cpp",
       "xfa/fxgraphics/cfx_graphics.h",
       "xfa/fxgraphics/cfx_path.cpp",
       "xfa/fxgraphics/cfx_path.h",
-      "xfa/fxgraphics/cfx_path_generator.cpp",
-      "xfa/fxgraphics/cfx_path_generator.h",
       "xfa/fxgraphics/cfx_pattern.cpp",
       "xfa/fxgraphics/cfx_pattern.h",
       "xfa/fxgraphics/cfx_shading.cpp",
@@ -1740,6 +1743,7 @@
 test("pdfium_unittests") {
   sources = [
     "core/fdrm/crypto/fx_crypt_unittest.cpp",
+    "core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp",
     "core/fpdfapi/font/fpdf_font_cid_unittest.cpp",
     "core/fpdfapi/font/fpdf_font_unittest.cpp",
     "core/fpdfapi/page/cpdf_streamcontentparser_unittest.cpp",
@@ -1790,6 +1794,7 @@
       "xfa/fde/cfde_txtedtbuf_unittest.cpp",
       "xfa/fde/css/cfde_cssdeclaration_unittest.cpp",
       "xfa/fde/css/cfde_cssstylesheet_unittest.cpp",
+      "xfa/fde/css/cfde_cssvaluelistparser_unittest.cpp",
       "xfa/fde/xml/fde_xml_imp_unittest.cpp",
       "xfa/fxbarcode/pdf417/BC_PDF417HighLevelEncoder_unittest.cpp",
       "xfa/fxfa/app/cxfa_textparser_unittest.cpp",
diff --git a/DEPS b/DEPS
index a93bd2a..7ebf412 100644
--- a/DEPS
+++ b/DEPS
@@ -5,21 +5,21 @@
   'pdfium_git': 'https://pdfium.googlesource.com',
 
   'android_ndk_revision': '26d93ec07f3ce2ec2cdfeae1b21ee6f12ff868d8',
-  'build_revision': 'acf607f7d345915ea2ecca208bc516677d298463',
-  'buildtools_revision': '5fd66957f08bb752dca714a591c84587c9d70762',
+  'build_revision': 'dd795a26b9e43ff3a0d761bfd509c2fa67a3a7a1',
+  'buildtools_revision': 'cf493f8b1ae59611b19b000d7af922559b6ae92a',
   'catapult_revision': '86352b966b0245d6883e5f7df27687856978b6d7',
-  'clang_revision': '0a306690ccb471f75990b488b8b61cabbcca3011',
+  'clang_revision': '37d701b87a10a2bdee1a5c3523f754ebf64a7e66',
   'cygwin_revision': 'c89e446b273697fadf3a10ff1007a97c0b7de6df',
   'gen_library_loader_revision': '916d4acd8b2cde67a390737dfba90b3c37de23a1',
   'gmock_revision': '29763965ab52f24565299976b936d1265cb6a271',
   'gtest_revision': '8245545b6dc9c4703e6496d1efd19e975ad2b038',
   'icu_revision': '73e24736676b4b438270fda44e5b2c83b49fdd80',
   'instrumented_lib_revision': '45f5814b1543e41ea0be54c771e3840ea52cca4a',
-  'pdfium_tests_revision': '9d17ef47f310332ac64e78e636681d493482a409',
-  'skia_revision': 'f44703a87f532b3f593d91605d66d52c6bbc45c9',
+  'pdfium_tests_revision': 'd25a422ab03d6c3109370bc454c629575e969329',
+  'skia_revision': '90e3cd78991ef337dbd0023efb30ece864694308',
   'tools_memory_revision': '427f10475e1a8d72424c29d00bf689122b738e5d',
   'trace_event_revision': '06294c8a4a6f744ef284cd63cfe54dbf61eea290',
-  'v8_revision': '8e0dcfc4ac75c0bef9063bd5dec4dafaa3409b6d',
+  'v8_revision': '7a634798302b4ab1f1525a9a881629519c0c2a99',
 }
 
 deps = {
diff --git a/README.md b/README.md
index c5fc651..8e1fbcb 100644
--- a/README.md
+++ b/README.md
@@ -44,7 +44,6 @@
 If you want the IDE for debugging and editing, you will need to install
 it separately, but this is optional and not needed for building PDFium.
 
-
 ## Get the code
 
 The name of the top-level directory does not matter. In our examples, we use
@@ -105,7 +104,6 @@
 `ninja -C <directory>/pdfium_test` You can build the entire product (which
 includes a few unit tests) by: `ninja -C <directory>`.
 
-
 ## Running the sample program
 
 The pdfium\_test program supports reading, parsing, and rasterizing the pages of
diff --git a/build_overrides/build.gni b/build_overrides/build.gni
index 61d7814..af65788 100644
--- a/build_overrides/build.gni
+++ b/build_overrides/build.gni
@@ -12,12 +12,12 @@
 
 # Variable that can be used to support multiple build scenarios, like having
 # Chromium specific targets in a client project's GN file etc.
-build_with_chromium = true
+build_with_chromium = false
 
 # Support different NDK locations in non-Chromium builds.
 default_android_ndk_root = "//third_party/android_ndk"
 default_android_ndk_version = "r12b"
-default_android_ndk_major_version = "12"
+default_android_ndk_major_version = 12
 
 # PDFium builds don't support building java targets.
 enable_java_templates = false
@@ -51,8 +51,9 @@
 
 if (use_system_xcode == "") {
   if (target_os == "mac") {
-    _result =
-        exec_script("//build/mac/should_use_hermetic_xcode.py", [], "value")
+    _result = exec_script("//build/mac/should_use_hermetic_xcode.py",
+                          [ target_os ],
+                          "value")
     use_system_xcode = _result == 0
   }
   if (target_os == "ios") {
diff --git a/build_overrides/v8.gni b/build_overrides/v8.gni
deleted file mode 100644
index d9c21d4..0000000
--- a/build_overrides/v8.gni
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-if (is_android) {
-  import("//build/config/android/config.gni")
-}
-
-v8_use_external_startup_data = !is_ios
-
-# Turns on compiler optimizations in V8 in Debug build.
-v8_optimized_debug = true
-
-# V8 extras
-# Adding V8 extras files requires API owners review
-# Be sure to synchronize with build/common.gypi
-
-v8_extra_library_files = []
-v8_experimental_extra_library_files = []
-
-v8_enable_inspector_override = false
diff --git a/codereview.settings b/codereview.settings
index 5724235..77265c9 100644
--- a/codereview.settings
+++ b/codereview.settings
@@ -1,7 +1,8 @@
-# This file is used by gcl to get repository specific information.
-CODE_REVIEW_SERVER: codereview.chromium.org
+# This file is used by git cl to get repository specific information.
 CC_LIST: pdfium-reviews@googlegroups.com
+CODE_REVIEW_SERVER: codereview.chromium.org
+GERRIT_HOST: True
+PROJECT: pdfium
 STATUS: http://pdfium-status.appspot.com/status
 TRY_ON_UPLOAD: False
 VIEW_VC: https://pdfium.googlesource.com/pdfium/+/
-PROJECT: pdfium
diff --git a/core/fpdfapi/cpdf_pagerendercontext.cpp b/core/fpdfapi/cpdf_pagerendercontext.cpp
index 91ebc5e..39a881c 100644
--- a/core/fpdfapi/cpdf_pagerendercontext.cpp
+++ b/core/fpdfapi/cpdf_pagerendercontext.cpp
@@ -15,7 +15,4 @@
 
 CPDF_PageRenderContext::CPDF_PageRenderContext() {}
 
-CPDF_PageRenderContext::~CPDF_PageRenderContext() {
-  if (m_pOptions)
-    delete m_pOptions->m_pOCContext;
-}
+CPDF_PageRenderContext::~CPDF_PageRenderContext() {}
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
index a65d564..35595b3 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
@@ -6,13 +6,21 @@
 
 #include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h"
 
+#include <tuple>
+#include <utility>
+
+#include "core/fpdfapi/font/cpdf_font.h"
 #include "core/fpdfapi/page/cpdf_docpagedata.h"
 #include "core/fpdfapi/page/cpdf_image.h"
 #include "core/fpdfapi/page/cpdf_imageobject.h"
 #include "core/fpdfapi/page/cpdf_page.h"
+#include "core/fpdfapi/page/cpdf_path.h"
+#include "core/fpdfapi/page/cpdf_pathobject.h"
+#include "core/fpdfapi/page/cpdf_textobject.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fpdfapi/parser/cpdf_name.h"
+#include "core/fpdfapi/parser/cpdf_number.h"
 #include "core/fpdfapi/parser/cpdf_reference.h"
 #include "core/fpdfapi/parser/cpdf_stream.h"
 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
@@ -25,6 +33,19 @@
   return ar;
 }
 
+bool GetColor(const CPDF_Color* pColor, FX_FLOAT* rgb) {
+  int intRGB[3];
+  if (!pColor ||
+      pColor->GetColorSpace() != CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB) ||
+      !pColor->GetRGB(intRGB[0], intRGB[1], intRGB[2])) {
+    return false;
+  }
+  rgb[0] = intRGB[0] / 255.0f;
+  rgb[1] = intRGB[1] / 255.0f;
+  rgb[2] = intRGB[2] / 255.0f;
+  return true;
+}
+
 }  // namespace
 
 CPDF_PageContentGenerator::CPDF_PageContentGenerator(CPDF_Page* pPage)
@@ -40,9 +61,12 @@
 void CPDF_PageContentGenerator::GenerateContent() {
   CFX_ByteTextBuf buf;
   for (CPDF_PageObject* pPageObj : m_pageObjects) {
-    CPDF_ImageObject* pImageObject = pPageObj->AsImage();
-    if (pImageObject)
+    if (CPDF_ImageObject* pImageObject = pPageObj->AsImage())
       ProcessImage(&buf, pImageObject);
+    else if (CPDF_PathObject* pPathObj = pPageObj->AsPath())
+      ProcessPath(&buf, pPathObj);
+    else if (CPDF_TextObject* pTextObj = pPageObj->AsText())
+      ProcessText(&buf, pTextObj);
   }
   CPDF_Dictionary* pPageDict = m_pPage->m_pFormDict;
   CPDF_Object* pContent =
@@ -109,3 +133,144 @@
 
   *buf << "/" << PDF_NameEncode(name) << " Do Q\n";
 }
+
+// Processing path with operators from Tables 4.9 and 4.10 of PDF spec 1.7:
+// "re" appends a rectangle (here, used only if the whole path is a rectangle)
+// "m" moves current point to the given coordinates
+// "l" creates a line from current point to the new point
+// "c" adds a Bezier curve from current to last point, using the two other
+// points as the Bezier control points
+// Note: "l", "c" change the current point
+// "h" closes the subpath (appends a line from current to starting point)
+// Path painting operators: "S", "n", "B", "f", "B*", "f*", depending on
+// the filling mode and whether we want stroking the path or not.
+// "Q" restores the graphics state imposed by the ProcessGraphics method.
+void CPDF_PageContentGenerator::ProcessPath(CFX_ByteTextBuf* buf,
+                                            CPDF_PathObject* pPathObj) {
+  ProcessGraphics(buf, pPathObj);
+  auto& pPoints = pPathObj->m_Path.GetPoints();
+  if (pPathObj->m_Path.IsRect()) {
+    CFX_PointF diff = pPoints[2].m_Point - pPoints[0].m_Point;
+    *buf << pPoints[0].m_Point.x << " " << pPoints[0].m_Point.y << " " << diff.x
+         << " " << diff.y << " re";
+  } else {
+    for (size_t i = 0; i < pPoints.size(); i++) {
+      if (i > 0)
+        *buf << " ";
+      *buf << pPoints[i].m_Point.x << " " << pPoints[i].m_Point.y;
+      FXPT_TYPE pointType = pPoints[i].m_Type;
+      if (pointType == FXPT_TYPE::MoveTo) {
+        *buf << " m";
+      } else if (pointType == FXPT_TYPE::LineTo) {
+        *buf << " l";
+      } else if (pointType == FXPT_TYPE::BezierTo) {
+        if (i + 2 >= pPoints.size() ||
+            !pPoints[i].IsTypeAndOpen(FXPT_TYPE::BezierTo) ||
+            !pPoints[i + 1].IsTypeAndOpen(FXPT_TYPE::BezierTo) ||
+            pPoints[i + 2].m_Type != FXPT_TYPE::BezierTo) {
+          // If format is not supported, close the path and paint
+          *buf << " h";
+          break;
+        }
+        *buf << " " << pPoints[i + 1].m_Point.x << " "
+             << pPoints[i + 1].m_Point.y << " " << pPoints[i + 2].m_Point.x
+             << " " << pPoints[i + 2].m_Point.y << " c";
+        i += 2;
+      }
+      if (pPoints[i].m_CloseFigure)
+        *buf << " h";
+    }
+  }
+  if (pPathObj->m_FillType == 0)
+    *buf << (pPathObj->m_bStroke ? " S" : " n");
+  else if (pPathObj->m_FillType == FXFILL_WINDING)
+    *buf << (pPathObj->m_bStroke ? " B" : " f");
+  else if (pPathObj->m_FillType == FXFILL_ALTERNATE)
+    *buf << (pPathObj->m_bStroke ? " B*" : " f*");
+  *buf << " Q\n";
+}
+
+// This method supports color operators rg and RGB from Table 4.24 of PDF spec
+// 1.7. A color will not be set if the colorspace is not DefaultRGB or the RGB
+// values cannot be obtained. The method also adds an external graphics
+// dictionary, as described in Section 4.3.4.
+// "rg" sets the fill color, "RG" sets the stroke color (using DefaultRGB)
+// "w" sets the stroke line width.
+// "ca" sets the fill alpha, "CA" sets the stroke alpha.
+// "q" saves the graphics state, so that the settings can later be reversed
+void CPDF_PageContentGenerator::ProcessGraphics(CFX_ByteTextBuf* buf,
+                                                CPDF_PageObject* pPageObj) {
+  *buf << "q ";
+  FX_FLOAT fillColor[3];
+  if (GetColor(pPageObj->m_ColorState.GetFillColor(), fillColor)) {
+    *buf << fillColor[0] << " " << fillColor[1] << " " << fillColor[2]
+         << " rg ";
+  }
+  FX_FLOAT strokeColor[3];
+  if (GetColor(pPageObj->m_ColorState.GetStrokeColor(), strokeColor)) {
+    *buf << strokeColor[0] << " " << strokeColor[1] << " " << strokeColor[2]
+         << " RG ";
+  }
+  FX_FLOAT lineWidth = pPageObj->m_GraphState.GetLineWidth();
+  if (lineWidth != 1.0f)
+    *buf << lineWidth << " w ";
+
+  GraphicsData graphD;
+  graphD.fillAlpha = pPageObj->m_GeneralState.GetFillAlpha();
+  graphD.strokeAlpha = pPageObj->m_GeneralState.GetStrokeAlpha();
+  if (graphD.fillAlpha == 1.0f && graphD.strokeAlpha == 1.0f)
+    return;
+
+  CFX_ByteString name;
+  auto it = m_pPage->m_GraphicsMap.find(graphD);
+  if (it != m_pPage->m_GraphicsMap.end()) {
+    name = it->second;
+  } else {
+    auto gsDict = pdfium::MakeUnique<CPDF_Dictionary>();
+    gsDict->SetNewFor<CPDF_Number>("ca", graphD.fillAlpha);
+    gsDict->SetNewFor<CPDF_Number>("CA", graphD.strokeAlpha);
+    CPDF_Object* pDict = m_pDocument->AddIndirectObject(std::move(gsDict));
+    uint32_t dwObjNum = pDict->GetObjNum();
+    name = RealizeResource(dwObjNum, "ExtGState");
+    m_pPage->m_GraphicsMap[graphD] = name;
+  }
+  *buf << "/" << PDF_NameEncode(name) << " gs ";
+}
+
+// This method adds text to the buffer, BT begins the text object, ET ends it.
+// Tm sets the text matrix (allows positioning and transforming text).
+// Tf sets the font name (from Font in Resources) and font size.
+// Tj sets the actual text, <####...> is used when specifying charcodes.
+void CPDF_PageContentGenerator::ProcessText(CFX_ByteTextBuf* buf,
+                                            CPDF_TextObject* pTextObj) {
+  // TODO(npm): Add support for something other than standard type1 fonts.
+  *buf << "BT " << pTextObj->GetTextMatrix() << " Tm ";
+  CPDF_Font* pFont = pTextObj->GetFont();
+  if (!pFont)
+    pFont = CPDF_Font::GetStockFont(m_pDocument, "Helvetica");
+  FontData fontD;
+  fontD.baseFont = pFont->GetBaseFont();
+  auto it = m_pPage->m_FontsMap.find(fontD);
+  CFX_ByteString dictName;
+  if (it != m_pPage->m_FontsMap.end()) {
+    dictName = it->second;
+  } else {
+    auto fontDict = pdfium::MakeUnique<CPDF_Dictionary>();
+    fontDict->SetNewFor<CPDF_Name>("Type", "Font");
+    fontDict->SetNewFor<CPDF_Name>("Subtype", "Type1");
+    fontDict->SetNewFor<CPDF_Name>("BaseFont", fontD.baseFont);
+    CPDF_Object* pDict = m_pDocument->AddIndirectObject(std::move(fontDict));
+    uint32_t dwObjNum = pDict->GetObjNum();
+    dictName = RealizeResource(dwObjNum, "Font");
+    m_pPage->m_FontsMap[fontD] = dictName;
+  }
+  *buf << "/" << PDF_NameEncode(dictName) << " " << pTextObj->GetFontSize()
+       << " Tf ";
+  CFX_ByteString text;
+  for (uint32_t charcode : pTextObj->m_CharCodes) {
+    if (charcode == CPDF_Font::kInvalidCharCode)
+      continue;
+    pFont->AppendChar(text, charcode);
+  }
+  *buf << PDF_EncodeString(text, true) << " Tj ET\n";
+}
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h
index ac06dcb..73e7518 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h
@@ -16,6 +16,8 @@
 class CPDF_ImageObject;
 class CPDF_Page;
 class CPDF_PageObject;
+class CPDF_PathObject;
+class CPDF_TextObject;
 
 class CPDF_PageContentGenerator {
  public:
@@ -25,7 +27,12 @@
   void GenerateContent();
 
  private:
+  friend class CPDF_PageContentGeneratorTest;
+
+  void ProcessPath(CFX_ByteTextBuf* buf, CPDF_PathObject* pPathObj);
   void ProcessImage(CFX_ByteTextBuf* buf, CPDF_ImageObject* pImageObj);
+  void ProcessGraphics(CFX_ByteTextBuf* buf, CPDF_PageObject* pPageObj);
+  void ProcessText(CFX_ByteTextBuf* buf, CPDF_TextObject* pTextObj);
   CFX_ByteString RealizeResource(uint32_t dwResourceObjNum,
                                  const CFX_ByteString& bsType);
 
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
new file mode 100644
index 0000000..d8813ba
--- /dev/null
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
@@ -0,0 +1,178 @@
+// 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 "core/fpdfapi/edit/cpdf_pagecontentgenerator.h"
+
+#include "core/fpdfapi/cpdf_modulemgr.h"
+#include "core/fpdfapi/font/cpdf_font.h"
+#include "core/fpdfapi/page/cpdf_page.h"
+#include "core/fpdfapi/page/cpdf_pathobject.h"
+#include "core/fpdfapi/page/cpdf_textobject.h"
+#include "core/fpdfapi/parser/cpdf_document.h"
+#include "core/fpdfapi/parser/cpdf_parser.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/base/ptr_util.h"
+
+class CPDF_PageContentGeneratorTest : public testing::Test {
+ protected:
+  void SetUp() override { CPDF_ModuleMgr::Get()->InitPageModule(); }
+
+  void TearDown() override { CPDF_ModuleMgr::Destroy(); }
+
+  void TestProcessPath(CPDF_PageContentGenerator* pGen,
+                       CFX_ByteTextBuf* buf,
+                       CPDF_PathObject* pPathObj) {
+    pGen->ProcessPath(buf, pPathObj);
+  }
+
+  CPDF_Dictionary* TestGetResource(CPDF_PageContentGenerator* pGen,
+                                   const CFX_ByteString& type,
+                                   const CFX_ByteString& name) {
+    return pGen->m_pPage->m_pResources->GetDictFor(type)->GetDictFor(name);
+  }
+
+  void TestProcessText(CPDF_PageContentGenerator* pGen,
+                       CFX_ByteTextBuf* buf,
+                       CPDF_TextObject* pTextObj) {
+    pGen->ProcessText(buf, pTextObj);
+  }
+};
+
+TEST_F(CPDF_PageContentGeneratorTest, ProcessRect) {
+  auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
+  pPathObj->m_Path.AppendRect(10, 5, 13, 30);
+  pPathObj->m_FillType = FXFILL_ALTERNATE;
+  pPathObj->m_bStroke = true;
+
+  auto pTestPage = pdfium::MakeUnique<CPDF_Page>(nullptr, nullptr, false);
+  CPDF_PageContentGenerator generator(pTestPage.get());
+  CFX_ByteTextBuf buf;
+  TestProcessPath(&generator, &buf, pPathObj.get());
+  EXPECT_EQ("q 10 5 3 25 re B* Q\n", buf.MakeString());
+
+  pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
+  pPathObj->m_Path.AppendPoint(CFX_PointF(0, 0), FXPT_TYPE::MoveTo, false);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(5.2f, 0), FXPT_TYPE::LineTo, false);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(5.2f, 3.78f), FXPT_TYPE::LineTo,
+                               false);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(0, 3.78f), FXPT_TYPE::LineTo, true);
+  pPathObj->m_FillType = 0;
+  pPathObj->m_bStroke = false;
+  buf.Clear();
+
+  TestProcessPath(&generator, &buf, pPathObj.get());
+  EXPECT_EQ("q 0 0 5.2 3.78 re n Q\n", buf.MakeString());
+}
+
+TEST_F(CPDF_PageContentGeneratorTest, ProcessPath) {
+  auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
+  pPathObj->m_Path.AppendPoint(CFX_PointF(3.102f, 4.67f), FXPT_TYPE::MoveTo,
+                               false);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(5.45f, 0.29f), FXPT_TYPE::LineTo,
+                               false);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(4.24f, 3.15f), FXPT_TYPE::BezierTo,
+                               false);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(4.65f, 2.98f), FXPT_TYPE::BezierTo,
+                               false);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(3.456f, 0.24f), FXPT_TYPE::BezierTo,
+                               false);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(10.6f, 11.15f), FXPT_TYPE::LineTo,
+                               false);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(11, 12.5f), FXPT_TYPE::LineTo, false);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(11.46f, 12.67f), FXPT_TYPE::BezierTo,
+                               false);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(11.84f, 12.96f), FXPT_TYPE::BezierTo,
+                               false);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(12, 13.64f), FXPT_TYPE::BezierTo,
+                               true);
+  pPathObj->m_FillType = FXFILL_WINDING;
+  pPathObj->m_bStroke = false;
+
+  auto pTestPage = pdfium::MakeUnique<CPDF_Page>(nullptr, nullptr, false);
+  CPDF_PageContentGenerator generator(pTestPage.get());
+  CFX_ByteTextBuf buf;
+  TestProcessPath(&generator, &buf, pPathObj.get());
+  EXPECT_EQ(
+      "q 3.102 4.67 m 5.45 0.29 l 4.24 3.15 4.65 2.98 3.456 0.24 c 10.6 11.15 "
+      "l 11 12.5 l 11.46 12.67 11.84 12.96 12 13.64 c h f Q\n",
+      buf.MakeString());
+}
+
+TEST_F(CPDF_PageContentGeneratorTest, ProcessGraphics) {
+  auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
+  pPathObj->m_Path.AppendPoint(CFX_PointF(1, 2), FXPT_TYPE::MoveTo, false);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(3, 4), FXPT_TYPE::LineTo, false);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(5, 6), FXPT_TYPE::LineTo, true);
+  pPathObj->m_FillType = FXFILL_WINDING;
+  pPathObj->m_bStroke = true;
+
+  FX_FLOAT rgb[3] = {0.5f, 0.7f, 0.35f};
+  CPDF_ColorSpace* pCS = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB);
+  pPathObj->m_ColorState.SetFillColor(pCS, rgb, 3);
+
+  FX_FLOAT rgb2[3] = {1, 0.9f, 0};
+  pPathObj->m_ColorState.SetStrokeColor(pCS, rgb2, 3);
+  pPathObj->m_GeneralState.SetFillAlpha(0.5f);
+  pPathObj->m_GeneralState.SetStrokeAlpha(0.8f);
+
+  auto pDoc = pdfium::MakeUnique<CPDF_Document>(nullptr);
+  pDoc->CreateNewDoc();
+  CPDF_Dictionary* pPageDict = pDoc->CreateNewPage(0);
+  auto pTestPage = pdfium::MakeUnique<CPDF_Page>(pDoc.get(), pPageDict, false);
+  CPDF_PageContentGenerator generator(pTestPage.get());
+  CFX_ByteTextBuf buf;
+  TestProcessPath(&generator, &buf, pPathObj.get());
+  CFX_ByteString pathString = buf.MakeString();
+
+  // Color RGB values used are integers divided by 255.
+  EXPECT_EQ("q 0.501961 0.701961 0.34902 rg 1 0.901961 0 RG /",
+            pathString.Left(48));
+  EXPECT_EQ(" gs 1 2 m 3 4 l 5 6 l h B Q\n", pathString.Right(28));
+  ASSERT_TRUE(pathString.GetLength() > 76);
+  CPDF_Dictionary* externalGS = TestGetResource(
+      &generator, "ExtGState", pathString.Mid(48, pathString.GetLength() - 76));
+  ASSERT_TRUE(externalGS);
+  EXPECT_EQ(0.5f, externalGS->GetNumberFor("ca"));
+  EXPECT_EQ(0.8f, externalGS->GetNumberFor("CA"));
+
+  // Same path, now with a stroke.
+  pPathObj->m_GraphState.SetLineWidth(10.5f);
+  buf.Clear();
+  TestProcessPath(&generator, &buf, pPathObj.get());
+  CFX_ByteString pathString2 = buf.MakeString();
+  EXPECT_EQ("q 0.501961 0.701961 0.34902 rg 1 0.901961 0 RG 10.5 w /",
+            pathString2.Left(55));
+  EXPECT_EQ(" gs 1 2 m 3 4 l 5 6 l h B Q\n", pathString2.Right(28));
+
+  // Compare with the previous (should use same dictionary for gs)
+  EXPECT_EQ(pathString.GetLength() + 7, pathString2.GetLength());
+  EXPECT_EQ(pathString.Mid(48, pathString.GetLength() - 76),
+            pathString2.Mid(55, pathString2.GetLength() - 83));
+}
+
+TEST_F(CPDF_PageContentGeneratorTest, ProcessText) {
+  auto pDoc = pdfium::MakeUnique<CPDF_Document>(nullptr);
+  pDoc->CreateNewDoc();
+  CPDF_Dictionary* pPageDict = pDoc->CreateNewPage(0);
+  auto pTestPage = pdfium::MakeUnique<CPDF_Page>(pDoc.get(), pPageDict, false);
+  CPDF_PageContentGenerator generator(pTestPage.get());
+  auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>();
+  CPDF_Font* pFont = CPDF_Font::GetStockFont(pDoc.get(), "Times-Roman");
+  pTextObj->m_TextState.SetFont(pFont);
+  pTextObj->m_TextState.SetFontSize(10.0f);
+  pTextObj->Transform(CFX_Matrix(1, 0, 0, 1, 100, 100));
+  pTextObj->SetText("Hello World");
+  CFX_ByteTextBuf buf;
+  TestProcessText(&generator, &buf, pTextObj.get());
+  CFX_ByteString textString = buf.MakeString();
+  EXPECT_LT(61, textString.GetLength());
+  EXPECT_EQ("BT 1 0 0 1 100 100 Tm /", textString.Left(23));
+  EXPECT_EQ(" 10 Tf <48656C6C6F20576F726C64> Tj ET\n", textString.Right(38));
+  CPDF_Dictionary* fontDict = TestGetResource(
+      &generator, "Font", textString.Mid(23, textString.GetLength() - 61));
+  ASSERT_TRUE(fontDict);
+  EXPECT_EQ("Font", fontDict->GetStringFor("Type"));
+  EXPECT_EQ("Type1", fontDict->GetStringFor("Subtype"));
+  EXPECT_EQ("Times-Roman", fontDict->GetStringFor("BaseFont"));
+}
diff --git a/core/fpdfapi/font/cpdf_cidfont.cpp b/core/fpdfapi/font/cpdf_cidfont.cpp
index e96f824..6d01538 100644
--- a/core/fpdfapi/font/cpdf_cidfont.cpp
+++ b/core/fpdfapi/font/cpdf_cidfont.cpp
@@ -488,7 +488,7 @@
                         CIDTransformToFloat(pTransform[4]) * 1000,
                         CIDTransformToFloat(pTransform[5]) * 1000);
       CFX_FloatRect rect_f(rect);
-      rect_f.Transform(&matrix);
+      matrix.TransformRect(rect_f);
       rect = rect_f.GetOuterRect();
     }
   }
@@ -608,7 +608,7 @@
 #if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_
       return cid;
 #else
-      if (m_Flags & PDFFONT_SYMBOLIC)
+      if (m_Flags & FXFONT_SYMBOLIC)
         return cid;
 
       CFX_WideString uni_str = UnicodeFromCharCode(charcode);
diff --git a/core/fpdfapi/font/cpdf_font.cpp b/core/fpdfapi/font/cpdf_font.cpp
index 5563202..36d7d6a 100644
--- a/core/fpdfapi/font/cpdf_font.cpp
+++ b/core/fpdfapi/font/cpdf_font.cpp
@@ -161,7 +161,7 @@
 }
 
 void CPDF_Font::LoadFontDescriptor(CPDF_Dictionary* pFontDesc) {
-  m_Flags = pFontDesc->GetIntegerFor("Flags", PDFFONT_NONSYMBOLIC);
+  m_Flags = pFontDesc->GetIntegerFor("Flags", FXFONT_NONSYMBOLIC);
   int ItalicAngle = 0;
   bool bExistItalicAngle = false;
   if (pFontDesc->KeyExist("ItalicAngle")) {
@@ -169,7 +169,7 @@
     bExistItalicAngle = true;
   }
   if (ItalicAngle < 0) {
-    m_Flags |= PDFFONT_ITALIC;
+    m_Flags |= FXFONT_ITALIC;
     m_ItalicAngle = ItalicAngle;
   }
   bool bExistStemV = false;
@@ -188,16 +188,14 @@
     bExistDescent = true;
   }
   bool bExistCapHeight = false;
-  if (pFontDesc->KeyExist("CapHeight")) {
+  if (pFontDesc->KeyExist("CapHeight"))
     bExistCapHeight = true;
-  }
   if (bExistItalicAngle && bExistAscent && bExistCapHeight && bExistDescent &&
       bExistStemV) {
-    m_Flags |= PDFFONT_USEEXTERNATTR;
+    m_Flags |= FXFONT_USEEXTERNATTR;
   }
-  if (m_Descent > 10) {
+  if (m_Descent > 10)
     m_Descent = -m_Descent;
-  }
   CPDF_Array* pBBox = pFontDesc->GetArrayFor("FontBBox");
   if (pBBox) {
     m_FontBBox.left = pBBox->GetIntegerAt(0);
@@ -372,10 +370,9 @@
         iBaseEncoding == PDFFONT_ENCODING_ZAPFDINGBATS) {
       return;
     }
-    if ((m_Flags & PDFFONT_SYMBOLIC) && m_BaseFont == "Symbol") {
-      if (!bTrueType) {
+    if ((m_Flags & FXFONT_SYMBOLIC) && m_BaseFont == "Symbol") {
+      if (!bTrueType)
         iBaseEncoding = PDFFONT_ENCODING_ADOBE_SYMBOL;
-      }
       return;
     }
     CFX_ByteString bsEncoding = pEncoding->GetString();
diff --git a/core/fpdfapi/font/cpdf_font.h b/core/fpdfapi/font/cpdf_font.h
index 0a46f65..6025a82 100644
--- a/core/fpdfapi/font/cpdf_font.h
+++ b/core/fpdfapi/font/cpdf_font.h
@@ -14,17 +14,6 @@
 #include "core/fxcrt/fx_system.h"
 #include "core/fxge/fx_font.h"
 
-#define PDFFONT_FIXEDPITCH 1
-#define PDFFONT_SERIF 2
-#define PDFFONT_SYMBOLIC 4
-#define PDFFONT_SCRIPT 8
-#define PDFFONT_NONSYMBOLIC 32
-#define PDFFONT_ITALIC 64
-#define PDFFONT_ALLCAP 0x10000
-#define PDFFONT_SMALLCAP 0x20000
-#define PDFFONT_FORCEBOLD 0x40000
-#define PDFFONT_USEEXTERNATTR 0x80000
-
 class CFX_SubstFont;
 class CPDF_CIDFont;
 class CPDF_Dictionary;
diff --git a/core/fpdfapi/font/cpdf_simplefont.cpp b/core/fpdfapi/font/cpdf_simplefont.cpp
index ed98609..c414270 100644
--- a/core/fpdfapi/font/cpdf_simplefont.cpp
+++ b/core/fpdfapi/font/cpdf_simplefont.cpp
@@ -127,15 +127,13 @@
     }
   }
   if (m_pFontFile) {
-    if (m_BaseFont.GetLength() > 8 && m_BaseFont[7] == '+') {
+    if (m_BaseFont.GetLength() > 8 && m_BaseFont[7] == '+')
       m_BaseFont = m_BaseFont.Mid(8);
-    }
   } else {
     LoadSubstFont();
   }
-  if (!(m_Flags & PDFFONT_SYMBOLIC)) {
+  if (!(m_Flags & FXFONT_SYMBOLIC))
     m_BaseEncoding = PDFFONT_ENCODING_STANDARD;
-  }
   CPDF_Object* pEncoding = m_pFontDict->GetDirectObjectFor("Encoding");
   LoadPDFEncoding(pEncoding, m_BaseEncoding, &m_CharNames, !!m_pFontFile,
                   m_Font.IsTTFont());
@@ -144,7 +142,7 @@
   if (!m_Font.GetFace())
     return true;
 
-  if (m_Flags & PDFFONT_ALLCAP) {
+  if (m_Flags & FXFONT_ALLCAP) {
     unsigned char kLowercases[][2] = {{'a', 'z'}, {0xe0, 0xf6}, {0xf8, 0xfd}};
     for (size_t range = 0; range < FX_ArraySize(kLowercases); ++range) {
       const auto& lower = kLowercases[range];
@@ -166,21 +164,19 @@
 }
 
 void CPDF_SimpleFont::LoadSubstFont() {
-  if (!m_bUseFontWidth && !(m_Flags & PDFFONT_FIXEDPITCH)) {
+  if (!m_bUseFontWidth && !(m_Flags & FXFONT_FIXED_PITCH)) {
     int width = 0, i;
     for (i = 0; i < 256; i++) {
-      if (m_CharWidth[i] == 0 || m_CharWidth[i] == 0xffff) {
+      if (m_CharWidth[i] == 0 || m_CharWidth[i] == 0xffff)
         continue;
-      }
-      if (width == 0) {
+
+      if (width == 0)
         width = m_CharWidth[i];
-      } else if (width != m_CharWidth[i]) {
+      else if (width != m_CharWidth[i])
         break;
-      }
     }
-    if (i == 256 && width) {
-      m_Flags |= PDFFONT_FIXEDPITCH;
-    }
+    if (i == 256 && width)
+      m_Flags |= FXFONT_FIXED_PITCH;
   }
   pdfium::base::CheckedNumeric<int> safeStemV(m_StemV);
   if (m_StemV < 140)
diff --git a/core/fpdfapi/font/cpdf_truetypefont.cpp b/core/fpdfapi/font/cpdf_truetypefont.cpp
index a395e47..b8bee29 100644
--- a/core/fpdfapi/font/cpdf_truetypefont.cpp
+++ b/core/fpdfapi/font/cpdf_truetypefont.cpp
@@ -42,7 +42,7 @@
   if (m_pFontFile && m_Font.GetFace()->num_charmaps > 0 &&
       (baseEncoding == PDFFONT_ENCODING_MACROMAN ||
        baseEncoding == PDFFONT_ENCODING_WINANSI) &&
-      (m_Flags & PDFFONT_SYMBOLIC)) {
+      (m_Flags & FXFONT_SYMBOLIC)) {
     bool bSupportWin = false;
     bool bSupportMac = false;
     for (int i = 0; i < FXFT_Get_Face_CharmapCount(m_Font.GetFace()); i++) {
@@ -65,7 +65,7 @@
   if (((baseEncoding == PDFFONT_ENCODING_MACROMAN ||
         baseEncoding == PDFFONT_ENCODING_WINANSI) &&
        m_CharNames.empty()) ||
-      (m_Flags & PDFFONT_NONSYMBOLIC)) {
+      (m_Flags & FXFONT_NONSYMBOLIC)) {
     if (!FXFT_Has_Glyph_Names(m_Font.GetFace()) &&
         (!m_Font.GetFace()->num_charmaps || !m_Font.GetFace()->charmaps)) {
       int nStartChar = m_pFontDict->GetIntegerFor("FirstChar");
@@ -86,7 +86,7 @@
     bool bMacRoman = false;
     bool bMSSymbol = false;
     if (!bMSUnicode) {
-      if (m_Flags & PDFFONT_NONSYMBOLIC) {
+      if (m_Flags & FXFONT_NONSYMBOLIC) {
         bMacRoman = FT_UseTTCharmap(m_Font.GetFace(), 1, 0);
         bMSSymbol = !bMacRoman && FT_UseTTCharmap(m_Font.GetFace(), 3, 0);
       } else {
diff --git a/core/fpdfapi/font/cpdf_type1font.cpp b/core/fpdfapi/font/cpdf_type1font.cpp
index 9ef4510..1a37555 100644
--- a/core/fpdfapi/font/cpdf_type1font.cpp
+++ b/core/fpdfapi/font/cpdf_type1font.cpp
@@ -84,7 +84,7 @@
     if (pFontDesc && pFontDesc->KeyExist("Flags"))
       m_Flags = pFontDesc->GetIntegerFor("Flags");
     else
-      m_Flags = m_Base14Font >= 12 ? PDFFONT_SYMBOLIC : PDFFONT_NONSYMBOLIC;
+      m_Flags = m_Base14Font >= 12 ? FXFONT_SYMBOLIC : FXFONT_NONSYMBOLIC;
 
     if (m_Base14Font < 4) {
       for (int i = 0; i < 256; i++)
@@ -94,7 +94,7 @@
       m_BaseEncoding = PDFFONT_ENCODING_ADOBE_SYMBOL;
     else if (m_Base14Font == 13)
       m_BaseEncoding = PDFFONT_ENCODING_ZAPFDINGBATS;
-    else if (m_Flags & PDFFONT_NONSYMBOLIC)
+    else if (m_Flags & FXFONT_NONSYMBOLIC)
       m_BaseEncoding = PDFFONT_ENCODING_STANDARD;
   }
   return LoadCommon();
@@ -189,7 +189,7 @@
   FT_UseType1Charmap(m_Font.GetFace());
 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
   if (bCoreText) {
-    if (m_Flags & PDFFONT_SYMBOLIC) {
+    if (m_Flags & FXFONT_SYMBOLIC) {
       for (int charcode = 0; charcode < 256; charcode++) {
         const FX_CHAR* name =
             GetAdobeCharName(m_BaseEncoding, m_CharNames, charcode);
@@ -257,7 +257,7 @@
     return;
   }
 #endif  // _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
-  if (m_Flags & PDFFONT_SYMBOLIC) {
+  if (m_Flags & FXFONT_SYMBOLIC) {
     for (int charcode = 0; charcode < 256; charcode++) {
       const FX_CHAR* name =
           GetAdobeCharName(m_BaseEncoding, m_CharNames, charcode);
diff --git a/core/fpdfapi/font/cpdf_type3font.cpp b/core/fpdfapi/font/cpdf_type3font.cpp
index 9542945..f6cd6ec 100644
--- a/core/fpdfapi/font/cpdf_type3font.cpp
+++ b/core/fpdfapi/font/cpdf_type3font.cpp
@@ -121,7 +121,7 @@
   if (rcBBox.right <= rcBBox.left || rcBBox.bottom >= rcBBox.top)
     char_rect = pNewChar->m_pForm->CalcBoundingBox();
 
-  char_rect.Transform(&m_FontMatrix);
+  m_FontMatrix.TransformRect(char_rect);
   rcBBox.left = FXSYS_round(char_rect.left * 1000);
   rcBBox.right = FXSYS_round(char_rect.right * 1000);
   rcBBox.top = FXSYS_round(char_rect.top * 1000);
diff --git a/core/fpdfapi/font/fpdf_font_cid.cpp b/core/fpdfapi/font/fpdf_font_cid.cpp
index 386eec3..afb186d 100644
--- a/core/fpdfapi/font/fpdf_font_cid.cpp
+++ b/core/fpdfapi/font/fpdf_font_cid.cpp
@@ -18,6 +18,7 @@
 #include "core/fpdfapi/parser/cpdf_simple_parser.h"
 #include "core/fxcrt/fx_ext.h"
 #include "core/fxge/fx_freetype.h"
+#include "third_party/base/logging.h"
 #include "third_party/base/stl_util.h"
 
 namespace {
diff --git a/core/fpdfapi/font/ttgsubtable.cpp b/core/fpdfapi/font/ttgsubtable.cpp
index c037746..51e8e9c 100644
--- a/core/fpdfapi/font/ttgsubtable.cpp
+++ b/core/fpdfapi/font/ttgsubtable.cpp
@@ -7,6 +7,7 @@
 #include "core/fpdfapi/font/ttgsubtable.h"
 
 #include "core/fxge/fx_freetype.h"
+#include "third_party/base/ptr_util.h"
 #include "third_party/base/stl_util.h"
 
 CFX_GlyphMap::CFX_GlyphMap() {}
@@ -93,33 +94,29 @@
           (uint8_t)'t',
   };
   if (!m_bFeautureMapLoad) {
-    for (int i = 0; i < ScriptList.ScriptCount; i++) {
-      for (int j = 0; j < ScriptList.ScriptRecord[i].Script.LangSysCount; ++j) {
-        const auto& record = ScriptList.ScriptRecord[i].Script.LangSysRecord[j];
-        for (int k = 0; k < record.LangSys.FeatureCount; ++k) {
-          uint32_t index = record.LangSys.FeatureIndex[k];
-          if (FeatureList.FeatureRecord[index].FeatureTag == tag[0] ||
-              FeatureList.FeatureRecord[index].FeatureTag == tag[1]) {
-            if (!pdfium::ContainsKey(m_featureMap, index)) {
-              m_featureMap[index] = index;
-            }
+    for (const auto& script : ScriptList.ScriptRecords) {
+      for (const auto& record : script.Script.LangSysRecords) {
+        for (const auto& index : record.LangSys.FeatureIndices) {
+          if (FeatureList.FeatureRecords[index].FeatureTag == tag[0] ||
+              FeatureList.FeatureRecords[index].FeatureTag == tag[1]) {
+            m_featureSet.insert(index);
           }
         }
       }
     }
-    if (m_featureMap.empty()) {
-      for (int i = 0; i < FeatureList.FeatureCount; i++) {
-        if (FeatureList.FeatureRecord[i].FeatureTag == tag[0] ||
-            FeatureList.FeatureRecord[i].FeatureTag == tag[1]) {
-          m_featureMap[i] = i;
-        }
+    if (m_featureSet.empty()) {
+      int i = 0;
+      for (const auto& feature : FeatureList.FeatureRecords) {
+        if (feature.FeatureTag == tag[0] || feature.FeatureTag == tag[1])
+          m_featureSet.insert(i);
+        ++i;
       }
     }
     m_bFeautureMapLoad = true;
   }
-  for (const auto& pair : m_featureMap) {
+  for (const auto& item : m_featureSet) {
     if (GetVerticalGlyphSub(glyphnum, vglyphnum,
-                            &FeatureList.FeatureRecord[pair.second].Feature)) {
+                            &FeatureList.FeatureRecords[item].Feature)) {
       return true;
     }
   }
@@ -128,17 +125,14 @@
 
 bool CFX_CTTGSUBTable::GetVerticalGlyphSub(uint32_t glyphnum,
                                            uint32_t* vglyphnum,
-                                           TFeature* Feature) const {
-  for (int i = 0; i < Feature->LookupCount; i++) {
-    int index = Feature->LookupListIndex[i];
-    if (index < 0 || LookupList.LookupCount < index) {
+                                           TFeature* Feature) {
+  for (int index : Feature->LookupListIndices) {
+    if (index < 0 || index >= pdfium::CollectionSize<int>(LookupList.Lookups))
       continue;
-    }
-    if (LookupList.Lookup[index].LookupType == 1) {
-      if (GetVerticalGlyphSub2(glyphnum, vglyphnum,
-                               &LookupList.Lookup[index])) {
-        return true;
-      }
+
+    if (LookupList.Lookups[index].LookupType == 1 &&
+        GetVerticalGlyphSub2(glyphnum, vglyphnum, &LookupList.Lookups[index])) {
+      return true;
     }
   }
   return false;
@@ -146,11 +140,11 @@
 
 bool CFX_CTTGSUBTable::GetVerticalGlyphSub2(uint32_t glyphnum,
                                             uint32_t* vglyphnum,
-                                            TLookup* Lookup) const {
-  for (int i = 0; i < Lookup->SubTableCount; i++) {
-    switch (Lookup->SubTable[i]->SubstFormat) {
+                                            TLookup* Lookup) {
+  for (const auto& subTable : Lookup->SubTables) {
+    switch (subTable->SubstFormat) {
       case 1: {
-        TSingleSubstFormat1* tbl1 = (TSingleSubstFormat1*)Lookup->SubTable[i];
+        auto tbl1 = static_cast<TSingleSubstFormat1*>(subTable.get());
         if (GetCoverageIndex(tbl1->Coverage.get(), glyphnum) >= 0) {
           *vglyphnum = glyphnum + tbl1->DeltaGlyphID;
           return true;
@@ -158,11 +152,11 @@
         break;
       }
       case 2: {
-        TSingleSubstFormat2* tbl2 = (TSingleSubstFormat2*)Lookup->SubTable[i];
-        int index = -1;
-        index = GetCoverageIndex(tbl2->Coverage.get(), glyphnum);
-        if (0 <= index && index < tbl2->GlyphCount) {
-          *vglyphnum = tbl2->Substitute[index];
+        auto tbl2 = static_cast<TSingleSubstFormat2*>(subTable.get());
+        int index = GetCoverageIndex(tbl2->Coverage.get(), glyphnum);
+        if (index >= 0 &&
+            index < pdfium::CollectionSize<int>(tbl2->Substitutes)) {
+          *vglyphnum = tbl2->Substitutes[index];
           return true;
         }
         break;
@@ -174,29 +168,28 @@
 
 int CFX_CTTGSUBTable::GetCoverageIndex(TCoverageFormatBase* Coverage,
                                        uint32_t g) const {
-  int i = 0;
-  if (!Coverage) {
+  if (!Coverage)
     return -1;
-  }
+
   switch (Coverage->CoverageFormat) {
     case 1: {
+      int i = 0;
       TCoverageFormat1* c1 = (TCoverageFormat1*)Coverage;
-      for (i = 0; i < c1->GlyphCount; i++) {
-        if ((uint32_t)c1->GlyphArray[i] == g) {
+      for (const auto& glyph : c1->GlyphArray) {
+        if (static_cast<uint32_t>(glyph) == g)
           return i;
-        }
+        ++i;
       }
       return -1;
     }
     case 2: {
       TCoverageFormat2* c2 = (TCoverageFormat2*)Coverage;
-      for (i = 0; i < c2->RangeCount; i++) {
-        uint32_t s = c2->RangeRecord[i].Start;
-        uint32_t e = c2->RangeRecord[i].End;
-        uint32_t si = c2->RangeRecord[i].StartCoverageIndex;
-        if (s <= g && g <= e) {
+      for (const auto& rangeRec : c2->RangeRecords) {
+        uint32_t s = rangeRec.Start;
+        uint32_t e = rangeRec.End;
+        uint32_t si = rangeRec.StartCoverageIndex;
+        if (s <= g && g <= e)
           return si + g - s;
-        }
       }
       return -1;
     }
@@ -244,33 +237,21 @@
 }
 
 void CFX_CTTGSUBTable::ParseScriptList(FT_Bytes raw, TScriptList* rec) {
-  int i;
   FT_Bytes sp = raw;
-  rec->ScriptCount = GetUInt16(sp);
-  if (rec->ScriptCount <= 0) {
-    return;
-  }
-  rec->ScriptRecord.reset(new TScriptRecord[rec->ScriptCount]);
-  for (i = 0; i < rec->ScriptCount; i++) {
-    rec->ScriptRecord[i].ScriptTag = GetUInt32(sp);
-    uint16_t offset = GetUInt16(sp);
-    ParseScript(&raw[offset], &rec->ScriptRecord[i].Script);
+  rec->ScriptRecords = std::vector<TScriptRecord>(GetUInt16(sp));
+  for (auto& scriptRec : rec->ScriptRecords) {
+    scriptRec.ScriptTag = GetUInt32(sp);
+    ParseScript(&raw[GetUInt16(sp)], &scriptRec.Script);
   }
 }
 
 void CFX_CTTGSUBTable::ParseScript(FT_Bytes raw, TScript* rec) {
-  int i;
   FT_Bytes sp = raw;
   rec->DefaultLangSys = GetUInt16(sp);
-  rec->LangSysCount = GetUInt16(sp);
-  if (rec->LangSysCount <= 0) {
-    return;
-  }
-  rec->LangSysRecord.reset(new TLangSysRecord[rec->LangSysCount]);
-  for (i = 0; i < rec->LangSysCount; i++) {
-    rec->LangSysRecord[i].LangSysTag = GetUInt32(sp);
-    uint16_t offset = GetUInt16(sp);
-    ParseLangSys(&raw[offset], &rec->LangSysRecord[i].LangSys);
+  rec->LangSysRecords = std::vector<TLangSysRecord>(GetUInt16(sp));
+  for (auto& sysRecord : rec->LangSysRecords) {
+    sysRecord.LangSysTag = GetUInt32(sp);
+    ParseLangSys(&raw[GetUInt16(sp)], &sysRecord.LangSys);
   }
 }
 
@@ -278,81 +259,45 @@
   FT_Bytes sp = raw;
   rec->LookupOrder = GetUInt16(sp);
   rec->ReqFeatureIndex = GetUInt16(sp);
-  rec->FeatureCount = GetUInt16(sp);
-  if (rec->FeatureCount <= 0) {
-    return;
-  }
-  rec->FeatureIndex.reset(new uint16_t[rec->FeatureCount]);
-  FXSYS_memset(rec->FeatureIndex.get(), 0,
-               sizeof(uint16_t) * rec->FeatureCount);
-  for (int i = 0; i < rec->FeatureCount; ++i) {
-    rec->FeatureIndex[i] = GetUInt16(sp);
-  }
+  rec->FeatureIndices = std::vector<uint16_t>(GetUInt16(sp));
+  for (auto& element : rec->FeatureIndices)
+    element = GetUInt16(sp);
 }
 
 void CFX_CTTGSUBTable::ParseFeatureList(FT_Bytes raw, TFeatureList* rec) {
-  int i;
   FT_Bytes sp = raw;
-  rec->FeatureCount = GetUInt16(sp);
-  if (rec->FeatureCount <= 0) {
-    return;
-  }
-  rec->FeatureRecord.reset(new TFeatureRecord[rec->FeatureCount]);
-  for (i = 0; i < rec->FeatureCount; i++) {
-    rec->FeatureRecord[i].FeatureTag = GetUInt32(sp);
-    uint16_t offset = GetUInt16(sp);
-    ParseFeature(&raw[offset], &rec->FeatureRecord[i].Feature);
+  rec->FeatureRecords = std::vector<TFeatureRecord>(GetUInt16(sp));
+  for (auto& featureRec : rec->FeatureRecords) {
+    featureRec.FeatureTag = GetUInt32(sp);
+    ParseFeature(&raw[GetUInt16(sp)], &featureRec.Feature);
   }
 }
 
 void CFX_CTTGSUBTable::ParseFeature(FT_Bytes raw, TFeature* rec) {
-  int i;
   FT_Bytes sp = raw;
   rec->FeatureParams = GetUInt16(sp);
-  rec->LookupCount = GetUInt16(sp);
-  if (rec->LookupCount <= 0) {
-    return;
-  }
-  rec->LookupListIndex.reset(new uint16_t[rec->LookupCount]);
-  for (i = 0; i < rec->LookupCount; i++) {
-    rec->LookupListIndex[i] = GetUInt16(sp);
-  }
+  rec->LookupListIndices = std::vector<uint16_t>(GetUInt16(sp));
+  for (auto& listIndex : rec->LookupListIndices)
+    listIndex = GetUInt16(sp);
 }
 
 void CFX_CTTGSUBTable::ParseLookupList(FT_Bytes raw, TLookupList* rec) {
-  int i;
   FT_Bytes sp = raw;
-  rec->LookupCount = GetUInt16(sp);
-  if (rec->LookupCount <= 0) {
-    return;
-  }
-  rec->Lookup.reset(new TLookup[rec->LookupCount]);
-  for (i = 0; i < rec->LookupCount; i++) {
-    uint16_t offset = GetUInt16(sp);
-    ParseLookup(&raw[offset], &rec->Lookup[i]);
-  }
+  rec->Lookups = std::vector<TLookup>(GetUInt16(sp));
+  for (auto& lookup : rec->Lookups)
+    ParseLookup(&raw[GetUInt16(sp)], &lookup);
 }
 
 void CFX_CTTGSUBTable::ParseLookup(FT_Bytes raw, TLookup* rec) {
-  int i;
   FT_Bytes sp = raw;
   rec->LookupType = GetUInt16(sp);
   rec->LookupFlag = GetUInt16(sp);
-  rec->SubTableCount = GetUInt16(sp);
-  if (rec->SubTableCount <= 0) {
+  rec->SubTables = std::vector<std::unique_ptr<TSubTableBase>>(GetUInt16(sp));
+  if (rec->LookupType != 1)
     return;
-  }
-  rec->SubTable.reset(new TSubTableBase*[rec->SubTableCount]);
-  for (i = 0; i < rec->SubTableCount; i++) {
-    rec->SubTable[i] = nullptr;
-  }
-  if (rec->LookupType != 1) {
-    return;
-  }
-  for (i = 0; i < rec->SubTableCount; i++) {
-    uint16_t offset = GetUInt16(sp);
-    ParseSingleSubst(&raw[offset], &rec->SubTable[i]);
-  }
+
+  for (auto& subTable : rec->SubTables)
+    ParseSingleSubst(&raw[GetUInt16(sp)], &subTable);
 }
 
 CFX_CTTGSUBTable::TCoverageFormatBase* CFX_CTTGSUBTable::ParseCoverage(
@@ -372,47 +317,39 @@
 
 void CFX_CTTGSUBTable::ParseCoverageFormat1(FT_Bytes raw,
                                             TCoverageFormat1* rec) {
-  int i;
   FT_Bytes sp = raw;
-  GetUInt16(sp);
-  rec->GlyphCount = GetUInt16(sp);
-  if (rec->GlyphCount <= 0) {
-    return;
-  }
-  rec->GlyphArray.reset(new uint16_t[rec->GlyphCount]);
-  for (i = 0; i < rec->GlyphCount; i++) {
-    rec->GlyphArray[i] = GetUInt16(sp);
-  }
+  (void)GetUInt16(sp);
+  rec->GlyphArray = std::vector<uint16_t>(GetUInt16(sp));
+  for (auto& glyph : rec->GlyphArray)
+    glyph = GetUInt16(sp);
 }
 
 void CFX_CTTGSUBTable::ParseCoverageFormat2(FT_Bytes raw,
                                             TCoverageFormat2* rec) {
-  int i;
   FT_Bytes sp = raw;
-  GetUInt16(sp);
-  rec->RangeCount = GetUInt16(sp);
-  if (rec->RangeCount <= 0) {
-    return;
-  }
-  rec->RangeRecord.reset(new TRangeRecord[rec->RangeCount]);
-  for (i = 0; i < rec->RangeCount; i++) {
-    rec->RangeRecord[i].Start = GetUInt16(sp);
-    rec->RangeRecord[i].End = GetUInt16(sp);
-    rec->RangeRecord[i].StartCoverageIndex = GetUInt16(sp);
+  (void)GetUInt16(sp);
+  rec->RangeRecords = std::vector<TRangeRecord>(GetUInt16(sp));
+  for (auto& rangeRec : rec->RangeRecords) {
+    rangeRec.Start = GetUInt16(sp);
+    rangeRec.End = GetUInt16(sp);
+    rangeRec.StartCoverageIndex = GetUInt16(sp);
   }
 }
 
-void CFX_CTTGSUBTable::ParseSingleSubst(FT_Bytes raw, TSubTableBase** rec) {
+void CFX_CTTGSUBTable::ParseSingleSubst(FT_Bytes raw,
+                                        std::unique_ptr<TSubTableBase>* rec) {
   FT_Bytes sp = raw;
   uint16_t Format = GetUInt16(sp);
   switch (Format) {
     case 1:
-      *rec = new TSingleSubstFormat1();
-      ParseSingleSubstFormat1(raw, (TSingleSubstFormat1*)*rec);
+      *rec = pdfium::MakeUnique<TSingleSubstFormat1>();
+      ParseSingleSubstFormat1(raw,
+                              static_cast<TSingleSubstFormat1*>(rec->get()));
       break;
     case 2:
-      *rec = new TSingleSubstFormat2();
-      ParseSingleSubstFormat2(raw, (TSingleSubstFormat2*)*rec);
+      *rec = pdfium::MakeUnique<TSingleSubstFormat2>();
+      ParseSingleSubstFormat2(raw,
+                              static_cast<TSingleSubstFormat2*>(rec->get()));
       break;
   }
 }
@@ -428,23 +365,17 @@
 
 void CFX_CTTGSUBTable::ParseSingleSubstFormat2(FT_Bytes raw,
                                                TSingleSubstFormat2* rec) {
-  int i;
   FT_Bytes sp = raw;
-  GetUInt16(sp);
+  (void)GetUInt16(sp);
   uint16_t offset = GetUInt16(sp);
   rec->Coverage.reset(ParseCoverage(&raw[offset]));
-  rec->GlyphCount = GetUInt16(sp);
-  if (rec->GlyphCount <= 0) {
-    return;
-  }
-  rec->Substitute.reset(new uint16_t[rec->GlyphCount]);
-  for (i = 0; i < rec->GlyphCount; i++) {
-    rec->Substitute[i] = GetUInt16(sp);
-  }
+  rec->Substitutes = std::vector<uint16_t>(GetUInt16(sp));
+  for (auto& substitute : rec->Substitutes)
+    substitute = GetUInt16(sp);
 }
 
 CFX_CTTGSUBTable::TCoverageFormat1::TCoverageFormat1()
-    : TCoverageFormatBase(1), GlyphCount(0) {}
+    : TCoverageFormatBase(1) {}
 
 CFX_CTTGSUBTable::TCoverageFormat1::~TCoverageFormat1() {}
 
@@ -452,7 +383,7 @@
     : Start(0), End(0), StartCoverageIndex(0) {}
 
 CFX_CTTGSUBTable::TCoverageFormat2::TCoverageFormat2()
-    : TCoverageFormatBase(2), RangeCount(0) {}
+    : TCoverageFormatBase(2) {}
 
 CFX_CTTGSUBTable::TCoverageFormat2::~TCoverageFormat2() {}
 
@@ -462,41 +393,34 @@
 CFX_CTTGSUBTable::TSingleSubstFormat1::~TSingleSubstFormat1() {}
 
 CFX_CTTGSUBTable::TSingleSubstFormat2::TSingleSubstFormat2()
-    : TSubTableBase(2), GlyphCount(0) {}
+    : TSubTableBase(2) {}
 
 CFX_CTTGSUBTable::TSingleSubstFormat2::~TSingleSubstFormat2() {}
 
-CFX_CTTGSUBTable::TLookup::TLookup()
-    : LookupType(0), LookupFlag(0), SubTableCount(0) {}
+CFX_CTTGSUBTable::TLookup::TLookup() : LookupType(0), LookupFlag(0) {}
 
-CFX_CTTGSUBTable::TLookup::~TLookup() {
-  if (SubTable) {
-    for (int i = 0; i < SubTableCount; ++i)
-      delete SubTable[i];
-  }
-}
+CFX_CTTGSUBTable::TLookup::~TLookup() {}
 
-CFX_CTTGSUBTable::TScript::TScript() : DefaultLangSys(0), LangSysCount(0) {}
+CFX_CTTGSUBTable::TScript::TScript() : DefaultLangSys(0) {}
 
 CFX_CTTGSUBTable::TScript::~TScript() {}
 
-CFX_CTTGSUBTable::TScriptList::TScriptList() : ScriptCount(0) {}
+CFX_CTTGSUBTable::TScriptList::TScriptList() {}
 
 CFX_CTTGSUBTable::TScriptList::~TScriptList() {}
 
-CFX_CTTGSUBTable::TFeature::TFeature() : FeatureParams(0), LookupCount(0) {}
+CFX_CTTGSUBTable::TFeature::TFeature() : FeatureParams(0) {}
 
 CFX_CTTGSUBTable::TFeature::~TFeature() {}
 
-CFX_CTTGSUBTable::TFeatureList::TFeatureList() : FeatureCount(0) {}
+CFX_CTTGSUBTable::TFeatureList::TFeatureList() {}
 
 CFX_CTTGSUBTable::TFeatureList::~TFeatureList() {}
 
-CFX_CTTGSUBTable::TLookupList::TLookupList() : LookupCount(0) {}
+CFX_CTTGSUBTable::TLookupList::TLookupList() {}
 
 CFX_CTTGSUBTable::TLookupList::~TLookupList() {}
 
-CFX_CTTGSUBTable::TLangSys::TLangSys()
-    : LookupOrder(0), ReqFeatureIndex(0), FeatureCount(0) {}
+CFX_CTTGSUBTable::TLangSys::TLangSys() : LookupOrder(0), ReqFeatureIndex(0) {}
 
 CFX_CTTGSUBTable::TLangSys::~TLangSys() {}
diff --git a/core/fpdfapi/font/ttgsubtable.h b/core/fpdfapi/font/ttgsubtable.h
index e0e4bbb..f927269 100644
--- a/core/fpdfapi/font/ttgsubtable.h
+++ b/core/fpdfapi/font/ttgsubtable.h
@@ -9,8 +9,9 @@
 
 #include <stdint.h>
 
-#include <map>
 #include <memory>
+#include <set>
+#include <vector>
 
 #include "core/fxcrt/fx_basic.h"
 #include "core/fxge/fx_font.h"
@@ -45,19 +46,20 @@
     uint16_t FeatureList;
     uint16_t LookupList;
   };
+
   struct TLangSys {
     TLangSys();
     ~TLangSys();
 
     uint16_t LookupOrder;
     uint16_t ReqFeatureIndex;
-    uint16_t FeatureCount;
-    std::unique_ptr<uint16_t[]> FeatureIndex;
+    std::vector<uint16_t> FeatureIndices;
 
    private:
-    TLangSys(const TLangSys&);
-    TLangSys& operator=(const TLangSys&);
+    TLangSys(const TLangSys&) = delete;
+    TLangSys& operator=(const TLangSys&) = delete;
   };
+
   struct TLangSysRecord {
     TLangSysRecord() : LangSysTag(0) {}
 
@@ -65,21 +67,22 @@
     TLangSys LangSys;
 
    private:
-    TLangSysRecord(const TLangSysRecord&);
-    TLangSysRecord& operator=(const TLangSysRecord&);
+    TLangSysRecord(const TLangSysRecord&) = delete;
+    TLangSysRecord& operator=(const TLangSysRecord&) = delete;
   };
+
   struct TScript {
     TScript();
     ~TScript();
 
     uint16_t DefaultLangSys;
-    uint16_t LangSysCount;
-    std::unique_ptr<TLangSysRecord[]> LangSysRecord;
+    std::vector<TLangSysRecord> LangSysRecords;
 
    private:
-    TScript(const TScript&);
-    TScript& operator=(const TScript&);
+    TScript(const TScript&) = delete;
+    TScript& operator=(const TScript&) = delete;
   };
+
   struct TScriptRecord {
     TScriptRecord() : ScriptTag(0) {}
 
@@ -87,32 +90,33 @@
     TScript Script;
 
    private:
-    TScriptRecord(const TScriptRecord&);
-    TScriptRecord& operator=(const TScriptRecord&);
+    TScriptRecord(const TScriptRecord&) = delete;
+    TScriptRecord& operator=(const TScriptRecord&) = delete;
   };
+
   struct TScriptList {
     TScriptList();
     ~TScriptList();
 
-    uint16_t ScriptCount;
-    std::unique_ptr<TScriptRecord[]> ScriptRecord;
+    std::vector<TScriptRecord> ScriptRecords;
 
    private:
-    TScriptList(const TScriptList&);
-    TScriptList& operator=(const TScriptList&);
+    TScriptList(const TScriptList&) = delete;
+    TScriptList& operator=(const TScriptList&) = delete;
   };
+
   struct TFeature {
     TFeature();
     ~TFeature();
 
     uint16_t FeatureParams;
-    int LookupCount;
-    std::unique_ptr<uint16_t[]> LookupListIndex;
+    std::vector<uint16_t> LookupListIndices;
 
    private:
-    TFeature(const TFeature&);
-    TFeature& operator=(const TFeature&);
+    TFeature(const TFeature&) = delete;
+    TFeature& operator=(const TFeature&) = delete;
   };
+
   struct TFeatureRecord {
     TFeatureRecord() : FeatureTag(0) {}
 
@@ -120,20 +124,21 @@
     TFeature Feature;
 
    private:
-    TFeatureRecord(const TFeatureRecord&);
-    TFeatureRecord& operator=(const TFeatureRecord&);
+    TFeatureRecord(const TFeatureRecord&) = delete;
+    TFeatureRecord& operator=(const TFeatureRecord&) = delete;
   };
+
   struct TFeatureList {
     TFeatureList();
     ~TFeatureList();
 
-    int FeatureCount;
-    std::unique_ptr<TFeatureRecord[]> FeatureRecord;
+    std::vector<TFeatureRecord> FeatureRecords;
 
    private:
-    TFeatureList(const TFeatureList&);
-    TFeatureList& operator=(const TFeatureList&);
+    TFeatureList(const TFeatureList&) = delete;
+    TFeatureList& operator=(const TFeatureList&) = delete;
   };
+
   enum TLookupFlag {
     LOOKUPFLAG_RightToLeft = 0x0001,
     LOOKUPFLAG_IgnoreBaseGlyphs = 0x0002,
@@ -142,6 +147,7 @@
     LOOKUPFLAG_Reserved = 0x00F0,
     LOOKUPFLAG_MarkAttachmentType = 0xFF00,
   };
+
   struct TCoverageFormatBase {
     TCoverageFormatBase() : CoverageFormat(0) {}
     explicit TCoverageFormatBase(uint16_t format) : CoverageFormat(format) {}
@@ -154,17 +160,18 @@
     TCoverageFormatBase(const TCoverageFormatBase&);
     TCoverageFormatBase& operator=(const TCoverageFormatBase&);
   };
+
   struct TCoverageFormat1 : public TCoverageFormatBase {
     TCoverageFormat1();
     ~TCoverageFormat1() override;
 
-    uint16_t GlyphCount;
-    std::unique_ptr<uint16_t[]> GlyphArray;
+    std::vector<uint16_t> GlyphArray;
 
    private:
-    TCoverageFormat1(const TCoverageFormat1&);
-    TCoverageFormat1& operator=(const TCoverageFormat1&);
+    TCoverageFormat1(const TCoverageFormat1&) = delete;
+    TCoverageFormat1& operator=(const TCoverageFormat1&) = delete;
   };
+
   struct TRangeRecord {
     TRangeRecord();
 
@@ -177,19 +184,20 @@
     uint16_t StartCoverageIndex;
 
    private:
-    TRangeRecord(const TRangeRecord&);
+    TRangeRecord(const TRangeRecord&) = delete;
   };
+
   struct TCoverageFormat2 : public TCoverageFormatBase {
     TCoverageFormat2();
     ~TCoverageFormat2() override;
 
-    uint16_t RangeCount;
-    std::unique_ptr<TRangeRecord[]> RangeRecord;
+    std::vector<TRangeRecord> RangeRecords;
 
    private:
-    TCoverageFormat2(const TCoverageFormat2&);
-    TCoverageFormat2& operator=(const TCoverageFormat2&);
+    TCoverageFormat2(const TCoverageFormat2&) = delete;
+    TCoverageFormat2& operator=(const TCoverageFormat2&) = delete;
   };
+
   struct TDevice {
     TDevice() : StartSize(0), EndSize(0), DeltaFormat(0) {}
 
@@ -198,9 +206,10 @@
     uint16_t DeltaFormat;
 
    private:
-    TDevice(const TDevice&);
-    TDevice& operator=(const TDevice&);
+    TDevice(const TDevice&) = delete;
+    TDevice& operator=(const TDevice&) = delete;
   };
+
   struct TSubTableBase {
     TSubTableBase() : SubstFormat(0) {}
     explicit TSubTableBase(uint16_t format) : SubstFormat(format) {}
@@ -209,9 +218,10 @@
     uint16_t SubstFormat;
 
    private:
-    TSubTableBase(const TSubTableBase&);
-    TSubTableBase& operator=(const TSubTableBase&);
+    TSubTableBase(const TSubTableBase&) = delete;
+    TSubTableBase& operator=(const TSubTableBase&) = delete;
   };
+
   struct TSingleSubstFormat1 : public TSubTableBase {
     TSingleSubstFormat1();
     ~TSingleSubstFormat1() override;
@@ -220,44 +230,44 @@
     int16_t DeltaGlyphID;
 
    private:
-    TSingleSubstFormat1(const TSingleSubstFormat1&);
-    TSingleSubstFormat1& operator=(const TSingleSubstFormat1&);
+    TSingleSubstFormat1(const TSingleSubstFormat1&) = delete;
+    TSingleSubstFormat1& operator=(const TSingleSubstFormat1&) = delete;
   };
+
   struct TSingleSubstFormat2 : public TSubTableBase {
     TSingleSubstFormat2();
     ~TSingleSubstFormat2() override;
 
     std::unique_ptr<TCoverageFormatBase> Coverage;
-    uint16_t GlyphCount;
-    std::unique_ptr<uint16_t[]> Substitute;
+    std::vector<uint16_t> Substitutes;
 
    private:
-    TSingleSubstFormat2(const TSingleSubstFormat2&);
-    TSingleSubstFormat2& operator=(const TSingleSubstFormat2&);
+    TSingleSubstFormat2(const TSingleSubstFormat2&) = delete;
+    TSingleSubstFormat2& operator=(const TSingleSubstFormat2&) = delete;
   };
+
   struct TLookup {
     TLookup();
     ~TLookup();
 
     uint16_t LookupType;
     uint16_t LookupFlag;
-    uint16_t SubTableCount;
-    std::unique_ptr<TSubTableBase* []> SubTable;
+    std::vector<std::unique_ptr<TSubTableBase>> SubTables;
 
    private:
-    TLookup(const TLookup&);
-    TLookup& operator=(const TLookup&);
+    TLookup(const TLookup&) = delete;
+    TLookup& operator=(const TLookup&) = delete;
   };
+
   struct TLookupList {
     TLookupList();
     ~TLookupList();
 
-    int LookupCount;
-    std::unique_ptr<TLookup[]> Lookup;
+    std::vector<TLookup> Lookups;
 
    private:
-    TLookupList(const TLookupList&);
-    TLookupList& operator=(const TLookupList&);
+    TLookupList(const TLookupList&) = delete;
+    TLookupList& operator=(const TLookupList&) = delete;
   };
 
   bool Parse(FT_Bytes scriptlist, FT_Bytes featurelist, FT_Bytes lookuplist);
@@ -271,16 +281,16 @@
   TCoverageFormatBase* ParseCoverage(FT_Bytes raw);
   void ParseCoverageFormat1(FT_Bytes raw, TCoverageFormat1* rec);
   void ParseCoverageFormat2(FT_Bytes raw, TCoverageFormat2* rec);
-  void ParseSingleSubst(FT_Bytes raw, TSubTableBase** rec);
+  void ParseSingleSubst(FT_Bytes raw, std::unique_ptr<TSubTableBase>* rec);
   void ParseSingleSubstFormat1(FT_Bytes raw, TSingleSubstFormat1* rec);
   void ParseSingleSubstFormat2(FT_Bytes raw, TSingleSubstFormat2* rec);
 
   bool GetVerticalGlyphSub(uint32_t glyphnum,
                            uint32_t* vglyphnum,
-                           TFeature* Feature) const;
+                           TFeature* Feature);
   bool GetVerticalGlyphSub2(uint32_t glyphnum,
                             uint32_t* vglyphnum,
-                            TLookup* Lookup) const;
+                            TLookup* Lookup);
   int GetCoverageIndex(TCoverageFormatBase* Coverage, uint32_t g) const;
 
   uint8_t GetUInt8(FT_Bytes& p) const;
@@ -289,7 +299,7 @@
   int32_t GetInt32(FT_Bytes& p) const;
   uint32_t GetUInt32(FT_Bytes& p) const;
 
-  std::map<uint32_t, uint32_t> m_featureMap;
+  std::set<uint32_t> m_featureSet;
   bool m_bFeautureMapLoad;
   bool loaded;
   tt_gsub_header header;
diff --git a/core/fpdfapi/page/cpdf_allstates.cpp b/core/fpdfapi/page/cpdf_allstates.cpp
index 94bc7b4..282a47f 100644
--- a/core/fpdfapi/page/cpdf_allstates.cpp
+++ b/core/fpdfapi/page/cpdf_allstates.cpp
@@ -23,12 +23,8 @@
 
 }  // namespace
 
-CPDF_AllStates::CPDF_AllStates() {
-  m_TextX = m_TextY = m_TextLineX = m_TextLineY = 0;
-  m_TextLeading = 0;
-  m_TextRise = 0;
-  m_TextHorzScale = 1.0f;
-}
+CPDF_AllStates::CPDF_AllStates()
+    : m_TextLeading(0), m_TextRise(0), m_TextHorzScale(1.0f) {}
 
 CPDF_AllStates::~CPDF_AllStates() {}
 
@@ -37,10 +33,8 @@
   m_TextMatrix = src.m_TextMatrix;
   m_ParentMatrix = src.m_ParentMatrix;
   m_CTM = src.m_CTM;
-  m_TextX = src.m_TextX;
-  m_TextY = src.m_TextY;
-  m_TextLineX = src.m_TextLineX;
-  m_TextLineY = src.m_TextLineY;
+  m_TextPos = src.m_TextPos;
+  m_TextLinePos = src.m_TextLinePos;
   m_TextLeading = src.m_TextLeading;
   m_TextRise = src.m_TextRise;
   m_TextHorzScale = src.m_TextHorzScale;
diff --git a/core/fpdfapi/page/cpdf_allstates.h b/core/fpdfapi/page/cpdf_allstates.h
index 1aa680a..dad1b85 100644
--- a/core/fpdfapi/page/cpdf_allstates.h
+++ b/core/fpdfapi/page/cpdf_allstates.h
@@ -27,10 +27,8 @@
   CFX_Matrix m_TextMatrix;
   CFX_Matrix m_CTM;
   CFX_Matrix m_ParentMatrix;
-  FX_FLOAT m_TextX;
-  FX_FLOAT m_TextY;
-  FX_FLOAT m_TextLineX;
-  FX_FLOAT m_TextLineY;
+  CFX_PointF m_TextPos;
+  CFX_PointF m_TextLinePos;
   FX_FLOAT m_TextLeading;
   FX_FLOAT m_TextRise;
   FX_FLOAT m_TextHorzScale;
diff --git a/core/fpdfapi/page/cpdf_clippath.cpp b/core/fpdfapi/page/cpdf_clippath.cpp
index cfcd9a1..714b56b 100644
--- a/core/fpdfapi/page/cpdf_clippath.cpp
+++ b/core/fpdfapi/page/cpdf_clippath.cpp
@@ -84,8 +84,9 @@
   if (!pData->m_PathAndTypeList.empty() && bAutoMerge) {
     const CPDF_Path& old_path = pData->m_PathAndTypeList.back().first;
     if (old_path.IsRect()) {
-      CFX_FloatRect old_rect(old_path.GetPointX(0), old_path.GetPointY(0),
-                             old_path.GetPointX(2), old_path.GetPointY(2));
+      CFX_PointF point0 = old_path.GetPoint(0);
+      CFX_PointF point2 = old_path.GetPoint(2);
+      CFX_FloatRect old_rect(point0.x, point0.y, point2.x, point2.y);
       CFX_FloatRect new_rect = path.GetBoundingBox();
       if (old_rect.Contains(new_rect))
         pData->m_PathAndTypeList.pop_back();
diff --git a/core/fpdfapi/page/cpdf_contentparser.cpp b/core/fpdfapi/page/cpdf_contentparser.cpp
index 1e0fe62..7ceb509 100644
--- a/core/fpdfapi/page/cpdf_contentparser.cpp
+++ b/core/fpdfapi/page/cpdf_contentparser.cpp
@@ -90,10 +90,12 @@
     ClipPath.Transform(&form_matrix);
     if (pParentMatrix)
       ClipPath.Transform(pParentMatrix);
-    form_bbox.Transform(&form_matrix);
+
+    form_matrix.TransformRect(form_bbox);
     if (pParentMatrix)
-      form_bbox.Transform(pParentMatrix);
+      pParentMatrix->TransformRect(form_bbox);
   }
+
   CPDF_Dictionary* pResources = pForm->m_pFormDict->GetDictFor("Resources");
   m_pParser = pdfium::MakeUnique<CPDF_StreamContentParser>(
       pForm->m_pDocument, pForm->m_pPageResources, pForm->m_pResources,
@@ -201,8 +203,10 @@
         CPDF_Path ClipPath = pObj->m_ClipPath.GetPath(0);
         if (!ClipPath.IsRect() || pObj->IsShading())
           continue;
-        CFX_FloatRect old_rect(ClipPath.GetPointX(0), ClipPath.GetPointY(0),
-                               ClipPath.GetPointX(2), ClipPath.GetPointY(2));
+
+        CFX_PointF point0 = ClipPath.GetPoint(0);
+        CFX_PointF point2 = ClipPath.GetPoint(2);
+        CFX_FloatRect old_rect(point0.x, point0.y, point2.x, point2.y);
         CFX_FloatRect obj_rect(pObj->m_Left, pObj->m_Bottom, pObj->m_Right,
                                pObj->m_Top);
         if (old_rect.Contains(obj_rect))
diff --git a/core/fpdfapi/page/cpdf_formobject.cpp b/core/fpdfapi/page/cpdf_formobject.cpp
index dc596e5..5642a5d 100644
--- a/core/fpdfapi/page/cpdf_formobject.cpp
+++ b/core/fpdfapi/page/cpdf_formobject.cpp
@@ -35,7 +35,7 @@
 
 void CPDF_FormObject::CalcBoundingBox() {
   CFX_FloatRect form_rect = m_pForm->CalcBoundingBox();
-  form_rect.Transform(&m_FormMatrix);
+  m_FormMatrix.TransformRect(form_rect);
   m_Left = form_rect.left;
   m_Bottom = form_rect.bottom;
   m_Right = form_rect.right;
diff --git a/core/fpdfapi/page/cpdf_imageobject.cpp b/core/fpdfapi/page/cpdf_imageobject.cpp
index bb91820..01d2df7 100644
--- a/core/fpdfapi/page/cpdf_imageobject.cpp
+++ b/core/fpdfapi/page/cpdf_imageobject.cpp
@@ -41,8 +41,10 @@
 }
 
 void CPDF_ImageObject::CalcBoundingBox() {
-  m_Left = m_Bottom = 0;
-  m_Right = m_Top = 1.0f;
+  m_Left = 0;
+  m_Bottom = 0;
+  m_Right = 1.0f;
+  m_Top = 1.0f;
   m_Matrix.TransformRect(m_Left, m_Right, m_Top, m_Bottom);
 }
 
diff --git a/core/fpdfapi/page/cpdf_meshstream.cpp b/core/fpdfapi/page/cpdf_meshstream.cpp
index 8bc2a85..24ef9b2 100644
--- a/core/fpdfapi/page/cpdf_meshstream.cpp
+++ b/core/fpdfapi/page/cpdf_meshstream.cpp
@@ -83,6 +83,12 @@
 
 }  // namespace
 
+CPDF_MeshVertex::CPDF_MeshVertex() = default;
+
+CPDF_MeshVertex::CPDF_MeshVertex(const CPDF_MeshVertex&) = default;
+
+CPDF_MeshVertex::~CPDF_MeshVertex() = default;
+
 CPDF_MeshStream::CPDF_MeshStream(
     ShadingType type,
     const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
@@ -148,37 +154,59 @@
   return true;
 }
 
-uint32_t CPDF_MeshStream::GetFlag() {
+bool CPDF_MeshStream::CanReadFlag() const {
+  return m_BitStream.BitsRemaining() >= m_nFlagBits;
+}
+
+bool CPDF_MeshStream::CanReadCoords() const {
+  return m_BitStream.BitsRemaining() / 2 >= m_nCoordBits;
+}
+
+bool CPDF_MeshStream::CanReadColor() const {
+  return m_BitStream.BitsRemaining() / m_nComponentBits >= m_nComponents;
+}
+
+uint32_t CPDF_MeshStream::ReadFlag() {
   ASSERT(ShouldCheckBitsPerFlag(m_type));
   return m_BitStream.GetBits(m_nFlagBits) & 0x03;
 }
 
-void CPDF_MeshStream::GetCoords(FX_FLOAT& x, FX_FLOAT& y) {
+CFX_PointF CPDF_MeshStream::ReadCoords() {
   ASSERT(ShouldCheckBPC(m_type));
+
+  CFX_PointF pos;
   if (m_nCoordBits == 32) {
-    x = m_xmin + (FX_FLOAT)(m_BitStream.GetBits(m_nCoordBits) *
-                            (m_xmax - m_xmin) / (double)m_CoordMax);
-    y = m_ymin + (FX_FLOAT)(m_BitStream.GetBits(m_nCoordBits) *
-                            (m_ymax - m_ymin) / (double)m_CoordMax);
+    pos.x = m_xmin +
+            m_BitStream.GetBits(m_nCoordBits) * (m_xmax - m_xmin) /
+                static_cast<double>(m_CoordMax);
+    pos.y = m_ymin +
+            m_BitStream.GetBits(m_nCoordBits) * (m_ymax - m_ymin) /
+                static_cast<double>(m_CoordMax);
   } else {
-    x = m_xmin +
-        m_BitStream.GetBits(m_nCoordBits) * (m_xmax - m_xmin) / m_CoordMax;
-    y = m_ymin +
-        m_BitStream.GetBits(m_nCoordBits) * (m_ymax - m_ymin) / m_CoordMax;
+    pos.x = m_xmin +
+            m_BitStream.GetBits(m_nCoordBits) * (m_xmax - m_xmin) / m_CoordMax;
+    pos.y = m_ymin +
+            m_BitStream.GetBits(m_nCoordBits) * (m_ymax - m_ymin) / m_CoordMax;
   }
+  return pos;
 }
 
-void CPDF_MeshStream::GetColor(FX_FLOAT& r, FX_FLOAT& g, FX_FLOAT& b) {
+std::tuple<FX_FLOAT, FX_FLOAT, FX_FLOAT> CPDF_MeshStream::ReadColor() {
   ASSERT(ShouldCheckBPC(m_type));
+
   FX_FLOAT color_value[kMaxComponents];
   for (uint32_t i = 0; i < m_nComponents; ++i) {
     color_value[i] = m_ColorMin[i] +
                      m_BitStream.GetBits(m_nComponentBits) *
                          (m_ColorMax[i] - m_ColorMin[i]) / m_ComponentMax;
   }
+
+  FX_FLOAT r;
+  FX_FLOAT g;
+  FX_FLOAT b;
   if (m_funcs.empty()) {
     m_pCS->GetRGB(color_value, r, g, b);
-    return;
+    return std::tuple<FX_FLOAT, FX_FLOAT, FX_FLOAT>(r, g, b);
   }
 
   FX_FLOAT result[kMaxComponents];
@@ -188,29 +216,41 @@
     if (func && func->CountOutputs() <= kMaxComponents)
       func->Call(color_value, 1, result, nResults);
   }
+
   m_pCS->GetRGB(result, r, g, b);
+  return std::tuple<FX_FLOAT, FX_FLOAT, FX_FLOAT>(r, g, b);
 }
 
-uint32_t CPDF_MeshStream::GetVertex(CPDF_MeshVertex& vertex,
-                                    CFX_Matrix* pObject2Bitmap) {
-  uint32_t flag = GetFlag();
-  GetCoords(vertex.x, vertex.y);
-  pObject2Bitmap->Transform(vertex.x, vertex.y);
-  GetColor(vertex.r, vertex.g, vertex.b);
+bool CPDF_MeshStream::ReadVertex(const CFX_Matrix& pObject2Bitmap,
+                                 CPDF_MeshVertex* vertex,
+                                 uint32_t* flag) {
+  if (!CanReadFlag())
+    return false;
+  *flag = ReadFlag();
+
+  if (!CanReadCoords())
+    return false;
+  vertex->position = pObject2Bitmap.Transform(ReadCoords());
+
+  if (!CanReadColor())
+    return false;
+  std::tie(vertex->r, vertex->g, vertex->b) = ReadColor();
   m_BitStream.ByteAlign();
-  return flag;
+  return true;
 }
 
-bool CPDF_MeshStream::GetVertexRow(CPDF_MeshVertex* vertex,
-                                   int count,
-                                   CFX_Matrix* pObject2Bitmap) {
+bool CPDF_MeshStream::ReadVertexRow(const CFX_Matrix& pObject2Bitmap,
+                                    int count,
+                                    CPDF_MeshVertex* vertex) {
   for (int i = 0; i < count; i++) {
-    if (m_BitStream.IsEOF())
+    if (m_BitStream.IsEOF() || !CanReadCoords())
       return false;
 
-    GetCoords(vertex[i].x, vertex[i].y);
-    pObject2Bitmap->Transform(vertex[i].x, vertex[i].y);
-    GetColor(vertex[i].r, vertex[i].g, vertex[i].b);
+    vertex[i].position = pObject2Bitmap.Transform(ReadCoords());
+    if (!CanReadColor())
+      return false;
+
+    std::tie(vertex[i].r, vertex[i].g, vertex[i].b) = ReadColor();
     m_BitStream.ByteAlign();
   }
   return true;
diff --git a/core/fpdfapi/page/cpdf_meshstream.h b/core/fpdfapi/page/cpdf_meshstream.h
index 21a6c2f..d40de4a 100644
--- a/core/fpdfapi/page/cpdf_meshstream.h
+++ b/core/fpdfapi/page/cpdf_meshstream.h
@@ -8,6 +8,7 @@
 #define CORE_FPDFAPI_PAGE_CPDF_MESHSTREAM_H_
 
 #include <memory>
+#include <tuple>
 #include <vector>
 
 #include "core/fpdfapi/page/cpdf_shadingpattern.h"
@@ -15,9 +16,13 @@
 #include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_system.h"
 
-struct CPDF_MeshVertex {
-  FX_FLOAT x;
-  FX_FLOAT y;
+class CPDF_MeshVertex {
+ public:
+  CPDF_MeshVertex();
+  CPDF_MeshVertex(const CPDF_MeshVertex&);
+  ~CPDF_MeshVertex();
+
+  CFX_PointF position;
   FX_FLOAT r;
   FX_FLOAT g;
   FX_FLOAT b;
@@ -37,14 +42,20 @@
 
   bool Load();
 
-  uint32_t GetFlag();
-  void GetCoords(FX_FLOAT& x, FX_FLOAT& y);
-  void GetColor(FX_FLOAT& r, FX_FLOAT& g, FX_FLOAT& b);
+  bool CanReadFlag() const;
+  bool CanReadCoords() const;
+  bool CanReadColor() const;
 
-  uint32_t GetVertex(CPDF_MeshVertex& vertex, CFX_Matrix* pObject2Bitmap);
-  bool GetVertexRow(CPDF_MeshVertex* vertex,
-                    int count,
-                    CFX_Matrix* pObject2Bitmap);
+  uint32_t ReadFlag();
+  CFX_PointF ReadCoords();
+  std::tuple<FX_FLOAT, FX_FLOAT, FX_FLOAT> ReadColor();
+
+  bool ReadVertex(const CFX_Matrix& pObject2Bitmap,
+                  CPDF_MeshVertex* vertex,
+                  uint32_t* flag);
+  bool ReadVertexRow(const CFX_Matrix& pObject2Bitmap,
+                     int count,
+                     CPDF_MeshVertex* vertex);
 
   CFX_BitStream* BitStream() { return &m_BitStream; }
   uint32_t ComponentBits() const { return m_nComponentBits; }
diff --git a/core/fpdfapi/page/cpdf_page.cpp b/core/fpdfapi/page/cpdf_page.cpp
index f9c0283..46123ab 100644
--- a/core/fpdfapi/page/cpdf_page.cpp
+++ b/core/fpdfapi/page/cpdf_page.cpp
@@ -66,16 +66,17 @@
 
   switch (rotate) {
     case 0:
-      m_PageMatrix.Set(1.0f, 0, 0, 1.0f, -m_BBox.left, -m_BBox.bottom);
+      m_PageMatrix = CFX_Matrix(1.0f, 0, 0, 1.0f, -m_BBox.left, -m_BBox.bottom);
       break;
     case 1:
-      m_PageMatrix.Set(0, -1.0f, 1.0f, 0, -m_BBox.bottom, m_BBox.right);
+      m_PageMatrix =
+          CFX_Matrix(0, -1.0f, 1.0f, 0, -m_BBox.bottom, m_BBox.right);
       break;
     case 2:
-      m_PageMatrix.Set(-1.0f, 0, 0, -1.0f, m_BBox.right, m_BBox.top);
+      m_PageMatrix = CFX_Matrix(-1.0f, 0, 0, -1.0f, m_BBox.right, m_BBox.top);
       break;
     case 3:
-      m_PageMatrix.Set(0, 1.0f, -1.0f, 0, m_BBox.top, -m_BBox.left);
+      m_PageMatrix = CFX_Matrix(0, 1.0f, -1.0f, 0, m_BBox.top, -m_BBox.left);
       break;
   }
 
@@ -119,16 +120,14 @@
   return nullptr;
 }
 
-void CPDF_Page::GetDisplayMatrix(CFX_Matrix& matrix,
-                                 int xPos,
-                                 int yPos,
-                                 int xSize,
-                                 int ySize,
-                                 int iRotate) const {
-  if (m_PageWidth == 0 || m_PageHeight == 0) {
-    return;
-  }
-  CFX_Matrix display_matrix;
+CFX_Matrix CPDF_Page::GetDisplayMatrix(int xPos,
+                                       int yPos,
+                                       int xSize,
+                                       int ySize,
+                                       int iRotate) const {
+  if (m_PageWidth == 0 || m_PageHeight == 0)
+    return CFX_Matrix();
+
   float x0 = 0;
   float y0 = 0;
   float x1 = 0;
@@ -170,9 +169,19 @@
       y2 = yPos;
       break;
   }
-  display_matrix.Set((x2 - x0) / m_PageWidth, (y2 - y0) / m_PageWidth,
-                     (x1 - x0) / m_PageHeight, (y1 - y0) / m_PageHeight, x0,
-                     y0);
-  matrix = m_PageMatrix;
-  matrix.Concat(display_matrix);
+  CFX_Matrix matrix = m_PageMatrix;
+  matrix.Concat(CFX_Matrix((x2 - x0) / m_PageWidth, (y2 - y0) / m_PageWidth,
+                           (x1 - x0) / m_PageHeight, (y1 - y0) / m_PageHeight,
+                           x0, y0));
+  return matrix;
+}
+
+bool GraphicsData::operator<(const GraphicsData& other) const {
+  if (fillAlpha != other.fillAlpha)
+    return fillAlpha < other.fillAlpha;
+  return strokeAlpha < other.strokeAlpha;
+}
+
+bool FontData::operator<(const FontData& other) const {
+  return baseFont < other.baseFont;
 }
diff --git a/core/fpdfapi/page/cpdf_page.h b/core/fpdfapi/page/cpdf_page.h
index 3812d28..9e30356 100644
--- a/core/fpdfapi/page/cpdf_page.h
+++ b/core/fpdfapi/page/cpdf_page.h
@@ -7,6 +7,7 @@
 #ifndef CORE_FPDFAPI_PAGE_CPDF_PAGE_H_
 #define CORE_FPDFAPI_PAGE_CPDF_PAGE_H_
 
+#include <map>
 #include <memory>
 
 #include "core/fpdfapi/page/cpdf_pageobjectholder.h"
@@ -20,6 +21,19 @@
 class CPDF_PageRenderCache;
 class CPDF_PageRenderContext;
 
+// These structs are used to keep track of resources that have already been
+// generated in the page.
+struct GraphicsData {
+  FX_FLOAT fillAlpha;
+  FX_FLOAT strokeAlpha;
+  bool operator<(const GraphicsData& other) const;
+};
+
+struct FontData {
+  CFX_ByteString baseFont;
+  bool operator<(const FontData& other) const;
+};
+
 class CPDF_Page : public CPDF_PageObjectHolder {
  public:
   class View {};  // Caller implements as desired, empty here due to layering.
@@ -31,12 +45,11 @@
 
   void ParseContent();
 
-  void GetDisplayMatrix(CFX_Matrix& matrix,
-                        int xPos,
-                        int yPos,
-                        int xSize,
-                        int ySize,
-                        int iRotate) const;
+  CFX_Matrix GetDisplayMatrix(int xPos,
+                              int yPos,
+                              int xSize,
+                              int ySize,
+                              int iRotate) const;
 
   FX_FLOAT GetPageWidth() const { return m_PageWidth; }
   FX_FLOAT GetPageHeight() const { return m_PageHeight; }
@@ -53,6 +66,9 @@
   View* GetView() const { return m_pView; }
   void SetView(View* pView) { m_pView = pView; }
 
+  std::map<GraphicsData, CFX_ByteString> m_GraphicsMap;
+  std::map<FontData, CFX_ByteString> m_FontsMap;
+
  protected:
   void StartParse();
 
diff --git a/core/fpdfapi/page/cpdf_pageobject.h b/core/fpdfapi/page/cpdf_pageobject.h
index ffc59f4..d2b84a5 100644
--- a/core/fpdfapi/page/cpdf_pageobject.h
+++ b/core/fpdfapi/page/cpdf_pageobject.h
@@ -51,6 +51,10 @@
 
   void TransformClipPath(CFX_Matrix& matrix);
   void TransformGeneralState(CFX_Matrix& matrix);
+
+  CFX_FloatRect GetRect() const {
+    return CFX_FloatRect(m_Left, m_Bottom, m_Right, m_Top);
+  }
   FX_RECT GetBBox(const CFX_Matrix* pMatrix) const;
 
   FX_FLOAT m_Left;
diff --git a/core/fpdfapi/page/cpdf_path.cpp b/core/fpdfapi/page/cpdf_path.cpp
index 2bfda75..ddc6bbd 100644
--- a/core/fpdfapi/page/cpdf_path.cpp
+++ b/core/fpdfapi/page/cpdf_path.cpp
@@ -12,32 +12,16 @@
 
 CPDF_Path::~CPDF_Path() {}
 
-int CPDF_Path::GetPointCount() const {
-  return m_Ref.GetObject()->GetPointCount();
-}
-
-void CPDF_Path::SetPointCount(int count) {
-  m_Ref.GetPrivateCopy()->SetPointCount(count);
-}
-
-const FX_PATHPOINT* CPDF_Path::GetPoints() const {
+const std::vector<FX_PATHPOINT>& CPDF_Path::GetPoints() const {
   return m_Ref.GetObject()->GetPoints();
 }
 
-FX_PATHPOINT* CPDF_Path::GetMutablePoints() {
-  return m_Ref.GetPrivateCopy()->GetPoints();
+void CPDF_Path::ClosePath() {
+  m_Ref.GetPrivateCopy()->ClosePath();
 }
 
-int CPDF_Path::GetFlag(int index) const {
-  return m_Ref.GetObject()->GetFlag(index);
-}
-
-FX_FLOAT CPDF_Path::GetPointX(int index) const {
-  return m_Ref.GetObject()->GetPointX(index);
-}
-
-FX_FLOAT CPDF_Path::GetPointY(int index) const {
-  return m_Ref.GetObject()->GetPointY(index);
+CFX_PointF CPDF_Path::GetPoint(int index) const {
+  return m_Ref.GetObject()->GetPoint(index);
 }
 
 CFX_FloatRect CPDF_Path::GetBoundingBox() const {
@@ -71,3 +55,11 @@
                            FX_FLOAT top) {
   m_Ref.GetPrivateCopy()->AppendRect(left, bottom, right, top);
 }
+
+void CPDF_Path::AppendPoint(const CFX_PointF& point,
+                            FXPT_TYPE type,
+                            bool close) {
+  CFX_PathData data;
+  data.AppendPoint(point, type, close);
+  Append(&data, nullptr);
+}
diff --git a/core/fpdfapi/page/cpdf_path.h b/core/fpdfapi/page/cpdf_path.h
index 407905e..b0c5a68 100644
--- a/core/fpdfapi/page/cpdf_path.h
+++ b/core/fpdfapi/page/cpdf_path.h
@@ -7,6 +7,8 @@
 #ifndef CORE_FPDFAPI_PAGE_CPDF_PATH_H_
 #define CORE_FPDFAPI_PAGE_CPDF_PATH_H_
 
+#include <vector>
+
 #include "core/fxcrt/cfx_shared_copy_on_write.h"
 #include "core/fxcrt/fx_system.h"
 #include "core/fxge/cfx_fxgedevice.h"
@@ -22,14 +24,10 @@
   void Emplace() { m_Ref.Emplace(); }
   explicit operator bool() const { return !!m_Ref; }
 
-  int GetPointCount() const;
-  void SetPointCount(int count);
-  const FX_PATHPOINT* GetPoints() const;
-  FX_PATHPOINT* GetMutablePoints();
+  const std::vector<FX_PATHPOINT>& GetPoints() const;
+  void ClosePath();
 
-  int GetFlag(int index) const;
-  FX_FLOAT GetPointX(int index) const;
-  FX_FLOAT GetPointY(int index) const;
+  CFX_PointF GetPoint(int index) const;
   CFX_FloatRect GetBoundingBox() const;
   CFX_FloatRect GetBoundingBox(FX_FLOAT line_width, FX_FLOAT miter_limit) const;
 
@@ -39,6 +37,7 @@
   void Append(const CPDF_Path& other, const CFX_Matrix* pMatrix);
   void Append(const CFX_PathData* pData, const CFX_Matrix* pMatrix);
   void AppendRect(FX_FLOAT left, FX_FLOAT bottom, FX_FLOAT right, FX_FLOAT top);
+  void AppendPoint(const CFX_PointF& point, FXPT_TYPE type, bool close);
 
   // TODO(tsepez): Remove when all access thru this class.
   const CFX_PathData* GetObject() const { return m_Ref.GetObject(); }
diff --git a/core/fpdfapi/page/cpdf_pathobject.cpp b/core/fpdfapi/page/cpdf_pathobject.cpp
index 27c4535..b5bb893 100644
--- a/core/fpdfapi/page/cpdf_pathobject.cpp
+++ b/core/fpdfapi/page/cpdf_pathobject.cpp
@@ -41,7 +41,8 @@
   } else {
     rect = m_Path.GetBoundingBox();
   }
-  rect.Transform(&m_Matrix);
+  m_Matrix.TransformRect(rect);
+
   if (width == 0 && m_bStroke) {
     rect.left += -0.5f;
     rect.right += 0.5f;
diff --git a/core/fpdfapi/page/cpdf_psengine.h b/core/fpdfapi/page/cpdf_psengine.h
index 9bdaa67..659ca82 100644
--- a/core/fpdfapi/page/cpdf_psengine.h
+++ b/core/fpdfapi/page/cpdf_psengine.h
@@ -88,7 +88,6 @@
   bool DoOperator(PDF_PSOP op);
   void Reset() { m_StackCount = 0; }
   void Push(FX_FLOAT value);
-  void Push(int value) { Push((FX_FLOAT)value); }
   FX_FLOAT Pop();
   uint32_t GetStackSize() const { return m_StackCount; }
 
diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.cpp b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
index 141442b..6211b6a 100644
--- a/core/fpdfapi/page/cpdf_streamcontentparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
@@ -98,8 +98,11 @@
 
   while (!stream.BitStream()->IsEOF()) {
     uint32_t flag = 0;
-    if (type != kLatticeFormGouraudTriangleMeshShading)
-      flag = stream.GetFlag();
+    if (type != kLatticeFormGouraudTriangleMeshShading) {
+      if (!stream.CanReadFlag())
+        break;
+      flag = stream.ReadFlag();
+    }
 
     if (!bGouraud && flag) {
       point_count -= 4;
@@ -107,13 +110,13 @@
     }
 
     for (int i = 0; i < point_count; i++) {
-      FX_FLOAT x;
-      FX_FLOAT y;
-      stream.GetCoords(x, y);
+      if (!stream.CanReadCoords())
+        break;
+      CFX_PointF origin = stream.ReadCoords();
       if (bStarted) {
-        rect.UpdateRect(x, y);
+        rect.UpdateRect(origin.x, origin.y);
       } else {
-        rect.InitRect(x, y);
+        rect.InitRect(origin.x, origin.y);
         bStarted = true;
       }
     }
@@ -127,7 +130,7 @@
     if (bGouraud)
       stream.BitStream()->ByteAlign();
   }
-  rect.Transform(&matrix);
+  matrix.TransformRect(rect);
   return rect;
 }
 
@@ -265,6 +268,8 @@
       m_pPathPoints(nullptr),
       m_PathPointCount(0),
       m_PathAllocSize(0),
+      m_PathStartX(0.0f),
+      m_PathStartY(0.0f),
       m_PathCurrentX(0.0f),
       m_PathCurrentY(0.0f),
       m_PathClipType(0),
@@ -316,18 +321,17 @@
   return index;
 }
 
-void CPDF_StreamContentParser::AddNameParam(const FX_CHAR* name, int len) {
-  CFX_ByteStringC bsName(name, len);
+void CPDF_StreamContentParser::AddNameParam(const CFX_ByteStringC& bsName) {
   ContentParam& param = m_ParamBuf[GetNextParamPos()];
-  if (len > 32) {
+  if (bsName.GetLength() > 32) {
     param.m_Type = ContentParam::OBJECT;
     param.m_pObject = pdfium::MakeUnique<CPDF_Name>(
         m_pDocument->GetByteStringPool(), PDF_NameDecode(bsName));
   } else {
     param.m_Type = ContentParam::NAME;
     if (bsName.Find('#') == -1) {
-      FXSYS_memcpy(param.m_Name.m_Buffer, name, len);
-      param.m_Name.m_Len = len;
+      FXSYS_memcpy(param.m_Name.m_Buffer, bsName.raw_str(), bsName.GetLength());
+      param.m_Name.m_Len = bsName.GetLength();
     } else {
       CFX_ByteString str = PDF_NameDecode(bsName);
       FXSYS_memcpy(param.m_Name.m_Buffer, str.c_str(), str.GetLength());
@@ -336,11 +340,10 @@
   }
 }
 
-void CPDF_StreamContentParser::AddNumberParam(const FX_CHAR* str, int len) {
+void CPDF_StreamContentParser::AddNumberParam(const CFX_ByteStringC& str) {
   ContentParam& param = m_ParamBuf[GetNextParamPos()];
   param.m_Type = ContentParam::NUMBER;
-  param.m_Number.m_bInteger =
-      FX_atonum(CFX_ByteStringC(str, len), &param.m_Number.m_Integer);
+  param.m_Number.m_bInteger = FX_atonum(str, &param.m_Number.m_Integer);
 }
 
 void CPDF_StreamContentParser::AddObjectParam(
@@ -570,21 +573,10 @@
   });
 }
 
-void CPDF_StreamContentParser::OnOperator(const FX_CHAR* op) {
-  int i = 0;
-  uint32_t opid = 0;
-  while (i < 4 && op[i]) {
-    opid = (opid << 8) + op[i];
-    i++;
-  }
-  while (i < 4) {
-    opid <<= 8;
-    i++;
-  }
-
+void CPDF_StreamContentParser::OnOperator(const CFX_ByteStringC& op) {
   static const OpCodes s_OpCodes = InitializeOpCodes();
 
-  auto it = s_OpCodes.find(opid);
+  auto it = s_OpCodes.find(op.GetID());
   if (it != s_OpCodes.end())
     (this->*it->second)();
 }
@@ -599,7 +591,7 @@
 }
 
 void CPDF_StreamContentParser::Handle_CloseEOFillStrokePath() {
-  AddPathPoint(m_PathStartX, m_PathStartY, FXPT_LINETO | FXPT_CLOSEFIGURE);
+  AddPathPoint(m_PathStartX, m_PathStartY, FXPT_TYPE::LineTo, true);
   AddPathObject(FXFILL_ALTERNATE, true);
 }
 
@@ -632,9 +624,7 @@
   while (1) {
     CPDF_StreamParser::SyntaxType type = m_pSyntax->ParseNextElement();
     if (type == CPDF_StreamParser::Keyword) {
-      CFX_ByteString bsKeyword(m_pSyntax->GetWordBuf(),
-                               m_pSyntax->GetWordSize());
-      if (bsKeyword != "ID") {
+      if (m_pSyntax->GetWord() != "ID") {
         m_pSyntax->SetPos(savePos);
         return;
       }
@@ -642,9 +632,8 @@
     if (type != CPDF_StreamParser::Name) {
       break;
     }
-    CFX_ByteString key((const FX_CHAR*)m_pSyntax->GetWordBuf() + 1,
-                       m_pSyntax->GetWordSize() - 1);
-    auto pObj = m_pSyntax->ReadNextObject(false, 0);
+    CFX_ByteString key(m_pSyntax->GetWord().Mid(1));
+    auto pObj = m_pSyntax->ReadNextObject(false, false, 0);
     if (!key.IsEmpty()) {
       uint32_t dwObjNum = pObj ? pObj->GetObjNum() : 0;
       if (dwObjNum)
@@ -677,8 +666,7 @@
     if (type != CPDF_StreamParser::Keyword) {
       continue;
     }
-    if (m_pSyntax->GetWordSize() == 2 && m_pSyntax->GetWordBuf()[0] == 'E' &&
-        m_pSyntax->GetWordBuf()[1] == 'I') {
+    if (m_pSyntax->GetWord() == "EI") {
       break;
     }
   }
@@ -690,18 +678,16 @@
 }
 
 void CPDF_StreamContentParser::Handle_BeginText() {
-  m_pCurStates->m_TextMatrix.Set(1.0f, 0, 0, 1.0f, 0, 0);
+  m_pCurStates->m_TextMatrix = CFX_Matrix();
   OnChangeTextMatrix();
-  m_pCurStates->m_TextX = 0;
-  m_pCurStates->m_TextY = 0;
-  m_pCurStates->m_TextLineX = 0;
-  m_pCurStates->m_TextLineY = 0;
+  m_pCurStates->m_TextPos = CFX_PointF();
+  m_pCurStates->m_TextLinePos = CFX_PointF();
 }
 
 void CPDF_StreamContentParser::Handle_CurveTo_123() {
-  AddPathPoint(GetNumber(5), GetNumber(4), FXPT_BEZIERTO);
-  AddPathPoint(GetNumber(3), GetNumber(2), FXPT_BEZIERTO);
-  AddPathPoint(GetNumber(1), GetNumber(0), FXPT_BEZIERTO);
+  AddPathPoint(GetNumber(5), GetNumber(4), FXPT_TYPE::BezierTo, false);
+  AddPathPoint(GetNumber(3), GetNumber(2), FXPT_TYPE::BezierTo, false);
+  AddPathPoint(GetNumber(1), GetNumber(0), FXPT_TYPE::BezierTo, false);
 }
 
 void CPDF_StreamContentParser::Handle_ConcatMatrix() {
@@ -904,9 +890,9 @@
     return;
   }
   if (m_PathStartX != m_PathCurrentX || m_PathStartY != m_PathCurrentY) {
-    AddPathPoint(m_PathStartX, m_PathStartY, FXPT_LINETO | FXPT_CLOSEFIGURE);
-  } else if (m_pPathPoints[m_PathPointCount - 1].m_Flag != FXPT_MOVETO) {
-    m_pPathPoints[m_PathPointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
+    AddPathPoint(m_PathStartX, m_PathStartY, FXPT_TYPE::LineTo, true);
+  } else if (m_pPathPoints[m_PathPointCount - 1].m_Type != FXPT_TYPE::MoveTo) {
+    m_pPathPoints[m_PathPointCount - 1].m_CloseFigure = true;
   }
 }
 
@@ -954,14 +940,14 @@
   if (m_ParamCount != 2)
     return;
 
-  AddPathPoint(GetNumber(1), GetNumber(0), FXPT_LINETO);
+  AddPathPoint(GetNumber(1), GetNumber(0), FXPT_TYPE::LineTo, false);
 }
 
 void CPDF_StreamContentParser::Handle_MoveTo() {
   if (m_ParamCount != 2)
     return;
 
-  AddPathPoint(GetNumber(1), GetNumber(0), FXPT_MOVETO);
+  AddPathPoint(GetNumber(1), GetNumber(0), FXPT_TYPE::MoveTo, false);
   ParsePathObject();
 }
 
@@ -999,11 +985,11 @@
                                            FX_FLOAT y,
                                            FX_FLOAT w,
                                            FX_FLOAT h) {
-  AddPathPoint(x, y, FXPT_MOVETO);
-  AddPathPoint(x + w, y, FXPT_LINETO);
-  AddPathPoint(x + w, y + h, FXPT_LINETO);
-  AddPathPoint(x, y + h, FXPT_LINETO);
-  AddPathPoint(x, y, FXPT_LINETO | FXPT_CLOSEFIGURE);
+  AddPathPoint(x, y, FXPT_TYPE::MoveTo, false);
+  AddPathPoint(x + w, y, FXPT_TYPE::LineTo, false);
+  AddPathPoint(x + w, y + h, FXPT_TYPE::LineTo, false);
+  AddPathPoint(x, y + h, FXPT_TYPE::LineTo, false);
+  AddPathPoint(x, y, FXPT_TYPE::LineTo, true);
 }
 
 void CPDF_StreamContentParser::Handle_SetRGBColor_Fill() {
@@ -1153,10 +1139,8 @@
 }
 
 void CPDF_StreamContentParser::Handle_MoveTextPoint() {
-  m_pCurStates->m_TextLineX += GetNumber(1);
-  m_pCurStates->m_TextLineY += GetNumber(0);
-  m_pCurStates->m_TextX = m_pCurStates->m_TextLineX;
-  m_pCurStates->m_TextY = m_pCurStates->m_TextLineY;
+  m_pCurStates->m_TextLinePos += CFX_PointF(GetNumber(1), GetNumber(0));
+  m_pCurStates->m_TextPos = m_pCurStates->m_TextLinePos;
 }
 
 void CPDF_StreamContentParser::Handle_MoveTextPoint_SetLeading() {
@@ -1246,16 +1230,6 @@
                                   m_pCurStates->m_ParentMatrix);
 }
 
-void CPDF_StreamContentParser::ConvertTextSpace(FX_FLOAT& x, FX_FLOAT& y) {
-  m_pCurStates->m_TextMatrix.Transform(x, y, x, y);
-  ConvertUserSpace(x, y);
-}
-
-void CPDF_StreamContentParser::ConvertUserSpace(FX_FLOAT& x, FX_FLOAT& y) {
-  m_pCurStates->m_CTM.Transform(x, y, x, y);
-  m_mtContentToUser.Transform(x, y, x, y);
-}
-
 void CPDF_StreamContentParser::AddTextObject(CFX_ByteString* pStrs,
                                              FX_FLOAT fInitKerning,
                                              FX_FLOAT* pKerning,
@@ -1266,12 +1240,12 @@
   }
   if (fInitKerning != 0) {
     if (!pFont->IsVertWriting()) {
-      m_pCurStates->m_TextX -=
+      m_pCurStates->m_TextPos.x -=
           (fInitKerning * m_pCurStates->m_TextState.GetFontSize() *
            m_pCurStates->m_TextHorzScale) /
           1000;
     } else {
-      m_pCurStates->m_TextY -=
+      m_pCurStates->m_TextPos.y -=
           (fInitKerning * m_pCurStates->m_TextState.GetFontSize()) / 1000;
     }
   }
@@ -1293,15 +1267,13 @@
       pCTM[3] = m_pCurStates->m_CTM.d;
     }
     pText->SetSegments(pStrs, pKerning, nsegs);
-    pText->m_PosX = m_pCurStates->m_TextX;
-    pText->m_PosY = m_pCurStates->m_TextY + m_pCurStates->m_TextRise;
-    ConvertTextSpace(pText->m_PosX, pText->m_PosY);
-    FX_FLOAT x_advance;
-    FX_FLOAT y_advance;
-    pText->CalcPositionData(&x_advance, &y_advance,
-                            m_pCurStates->m_TextHorzScale);
-    m_pCurStates->m_TextX += x_advance;
-    m_pCurStates->m_TextY += y_advance;
+    pText->m_Pos = m_mtContentToUser.Transform(
+        m_pCurStates->m_CTM.Transform(m_pCurStates->m_TextMatrix.Transform(
+            CFX_PointF(m_pCurStates->m_TextPos.x,
+                       m_pCurStates->m_TextPos.y + m_pCurStates->m_TextRise))));
+
+    m_pCurStates->m_TextPos +=
+        pText->CalcPositionData(m_pCurStates->m_TextHorzScale);
     if (TextRenderingModeIsClipMode(text_mode)) {
       m_ClipTextList.push_back(
           std::unique_ptr<CPDF_TextObject>(pText->Clone()));
@@ -1310,12 +1282,12 @@
   }
   if (pKerning && pKerning[nsegs - 1] != 0) {
     if (!pFont->IsVertWriting()) {
-      m_pCurStates->m_TextX -=
+      m_pCurStates->m_TextPos.x -=
           (pKerning[nsegs - 1] * m_pCurStates->m_TextState.GetFontSize() *
            m_pCurStates->m_TextHorzScale) /
           1000;
     } else {
-      m_pCurStates->m_TextY -=
+      m_pCurStates->m_TextPos.y -=
           (pKerning[nsegs - 1] * m_pCurStates->m_TextState.GetFontSize()) /
           1000;
     }
@@ -1343,7 +1315,7 @@
   }
   if (nsegs == 0) {
     for (size_t i = 0; i < n; i++) {
-      m_pCurStates->m_TextX -=
+      m_pCurStates->m_TextPos.x -=
           (pArray->GetNumberAt(i) * m_pCurStates->m_TextState.GetFontSize() *
            m_pCurStates->m_TextHorzScale) /
           1000;
@@ -1382,13 +1354,12 @@
 }
 
 void CPDF_StreamContentParser::Handle_SetTextMatrix() {
-  m_pCurStates->m_TextMatrix.Set(GetNumber(5), GetNumber(4), GetNumber(3),
-                                 GetNumber(2), GetNumber(1), GetNumber(0));
+  m_pCurStates->m_TextMatrix =
+      CFX_Matrix(GetNumber(5), GetNumber(4), GetNumber(3), GetNumber(2),
+                 GetNumber(1), GetNumber(0));
   OnChangeTextMatrix();
-  m_pCurStates->m_TextX = 0;
-  m_pCurStates->m_TextY = 0;
-  m_pCurStates->m_TextLineX = 0;
-  m_pCurStates->m_TextLineY = 0;
+  m_pCurStates->m_TextPos = CFX_PointF();
+  m_pCurStates->m_TextLinePos = CFX_PointF();
 }
 
 void CPDF_StreamContentParser::OnChangeTextMatrix() {
@@ -1427,15 +1398,14 @@
 }
 
 void CPDF_StreamContentParser::Handle_MoveToNextLine() {
-  m_pCurStates->m_TextLineY -= m_pCurStates->m_TextLeading;
-  m_pCurStates->m_TextX = m_pCurStates->m_TextLineX;
-  m_pCurStates->m_TextY = m_pCurStates->m_TextLineY;
+  m_pCurStates->m_TextLinePos.y -= m_pCurStates->m_TextLeading;
+  m_pCurStates->m_TextPos = m_pCurStates->m_TextLinePos;
 }
 
 void CPDF_StreamContentParser::Handle_CurveTo_23() {
-  AddPathPoint(m_PathCurrentX, m_PathCurrentY, FXPT_BEZIERTO);
-  AddPathPoint(GetNumber(3), GetNumber(2), FXPT_BEZIERTO);
-  AddPathPoint(GetNumber(1), GetNumber(0), FXPT_BEZIERTO);
+  AddPathPoint(m_PathCurrentX, m_PathCurrentY, FXPT_TYPE::BezierTo, false);
+  AddPathPoint(GetNumber(3), GetNumber(2), FXPT_TYPE::BezierTo, false);
+  AddPathPoint(GetNumber(1), GetNumber(0), FXPT_TYPE::BezierTo, false);
 }
 
 void CPDF_StreamContentParser::Handle_SetLineWidth() {
@@ -1451,9 +1421,9 @@
 }
 
 void CPDF_StreamContentParser::Handle_CurveTo_13() {
-  AddPathPoint(GetNumber(3), GetNumber(2), FXPT_BEZIERTO);
-  AddPathPoint(GetNumber(1), GetNumber(0), FXPT_BEZIERTO);
-  AddPathPoint(GetNumber(1), GetNumber(0), FXPT_BEZIERTO);
+  AddPathPoint(GetNumber(3), GetNumber(2), FXPT_TYPE::BezierTo, false);
+  AddPathPoint(GetNumber(1), GetNumber(0), FXPT_TYPE::BezierTo, false);
+  AddPathPoint(GetNumber(1), GetNumber(0), FXPT_TYPE::BezierTo, false);
 }
 
 void CPDF_StreamContentParser::Handle_NextLineShowText() {
@@ -1469,16 +1439,18 @@
 
 void CPDF_StreamContentParser::Handle_Invalid() {}
 
-void CPDF_StreamContentParser::AddPathPoint(FX_FLOAT x, FX_FLOAT y, int flag) {
+void CPDF_StreamContentParser::AddPathPoint(FX_FLOAT x,
+                                            FX_FLOAT y,
+                                            FXPT_TYPE type,
+                                            bool close) {
   m_PathCurrentX = x;
   m_PathCurrentY = y;
-  if (flag == FXPT_MOVETO) {
+  if (type == FXPT_TYPE::MoveTo && !close) {
     m_PathStartX = x;
     m_PathStartY = y;
     if (m_PathPointCount &&
-        m_pPathPoints[m_PathPointCount - 1].m_Flag == FXPT_MOVETO) {
-      m_pPathPoints[m_PathPointCount - 1].m_PointX = x;
-      m_pPathPoints[m_PathPointCount - 1].m_PointY = y;
+        m_pPathPoints[m_PathPointCount - 1].IsTypeAndOpen(FXPT_TYPE::MoveTo)) {
+      m_pPathPoints[m_PathPointCount - 1].m_Point = CFX_PointF(x, y);
       return;
     }
   } else if (m_PathPointCount == 0) {
@@ -1496,9 +1468,9 @@
     m_pPathPoints = pNewPoints;
     m_PathAllocSize = newsize;
   }
-  m_pPathPoints[m_PathPointCount - 1].m_Flag = flag;
-  m_pPathPoints[m_PathPointCount - 1].m_PointX = x;
-  m_pPathPoints[m_PathPointCount - 1].m_PointY = y;
+  m_pPathPoints[m_PathPointCount - 1].m_Type = type;
+  m_pPathPoints[m_PathPointCount - 1].m_CloseFigure = close;
+  m_pPathPoints[m_PathPointCount - 1].m_Point = CFX_PointF(x, y);
 }
 
 void CPDF_StreamContentParser::AddPathObject(int FillType, bool bStroke) {
@@ -1515,13 +1487,16 @@
     return;
   }
   if (PathPointCount &&
-      m_pPathPoints[PathPointCount - 1].m_Flag == FXPT_MOVETO) {
+      m_pPathPoints[PathPointCount - 1].IsTypeAndOpen(FXPT_TYPE::MoveTo)) {
     PathPointCount--;
   }
+
   CPDF_Path Path;
-  Path.SetPointCount(PathPointCount);
-  FXSYS_memcpy(Path.GetMutablePoints(), m_pPathPoints,
-               sizeof(FX_PATHPOINT) * PathPointCount);
+  for (int i = 0; i < PathPointCount; i++) {
+    FX_PATHPOINT& point = m_pPathPoints[i];
+    Path.AppendPoint(point.m_Point, point.m_Type, point.m_CloseFigure);
+  }
+
   CFX_Matrix matrix = m_pCurStates->m_CTM;
   matrix.Concat(m_mtContentToUser);
   if (bStroke || FillType) {
@@ -1561,15 +1536,14 @@
       case CPDF_StreamParser::EndOfData:
         return m_pSyntax->GetPos();
       case CPDF_StreamParser::Keyword:
-        OnOperator((char*)syntax.GetWordBuf());
+        OnOperator(syntax.GetWord());
         ClearAllParams();
         break;
       case CPDF_StreamParser::Number:
-        AddNumberParam((char*)syntax.GetWordBuf(), syntax.GetWordSize());
+        AddNumberParam(syntax.GetWord());
         break;
       case CPDF_StreamParser::Name:
-        AddNameParam((const FX_CHAR*)syntax.GetWordBuf() + 1,
-                     syntax.GetWordSize() - 1);
+        AddNameParam(syntax.GetWord().Mid(1));
         break;
       default:
         AddObjectParam(syntax.GetObject());
@@ -1589,33 +1563,35 @@
       case CPDF_StreamParser::EndOfData:
         return;
       case CPDF_StreamParser::Keyword: {
-        int len = m_pSyntax->GetWordSize();
+        CFX_ByteStringC strc = m_pSyntax->GetWord();
+        int len = strc.GetLength();
         if (len == 1) {
-          switch (m_pSyntax->GetWordBuf()[0]) {
+          switch (strc[0]) {
             case kPathOperatorSubpath:
-              AddPathPoint(params[0], params[1], FXPT_MOVETO);
+              AddPathPoint(params[0], params[1], FXPT_TYPE::MoveTo, false);
               nParams = 0;
               break;
             case kPathOperatorLine:
-              AddPathPoint(params[0], params[1], FXPT_LINETO);
+              AddPathPoint(params[0], params[1], FXPT_TYPE::LineTo, false);
               nParams = 0;
               break;
             case kPathOperatorCubicBezier1:
-              AddPathPoint(params[0], params[1], FXPT_BEZIERTO);
-              AddPathPoint(params[2], params[3], FXPT_BEZIERTO);
-              AddPathPoint(params[4], params[5], FXPT_BEZIERTO);
+              AddPathPoint(params[0], params[1], FXPT_TYPE::BezierTo, false);
+              AddPathPoint(params[2], params[3], FXPT_TYPE::BezierTo, false);
+              AddPathPoint(params[4], params[5], FXPT_TYPE::BezierTo, false);
               nParams = 0;
               break;
             case kPathOperatorCubicBezier2:
-              AddPathPoint(m_PathCurrentX, m_PathCurrentY, FXPT_BEZIERTO);
-              AddPathPoint(params[0], params[1], FXPT_BEZIERTO);
-              AddPathPoint(params[2], params[3], FXPT_BEZIERTO);
+              AddPathPoint(m_PathCurrentX, m_PathCurrentY, FXPT_TYPE::BezierTo,
+                           false);
+              AddPathPoint(params[0], params[1], FXPT_TYPE::BezierTo, false);
+              AddPathPoint(params[2], params[3], FXPT_TYPE::BezierTo, false);
               nParams = 0;
               break;
             case kPathOperatorCubicBezier3:
-              AddPathPoint(params[0], params[1], FXPT_BEZIERTO);
-              AddPathPoint(params[2], params[3], FXPT_BEZIERTO);
-              AddPathPoint(params[2], params[3], FXPT_BEZIERTO);
+              AddPathPoint(params[0], params[1], FXPT_TYPE::BezierTo, false);
+              AddPathPoint(params[2], params[3], FXPT_TYPE::BezierTo, false);
+              AddPathPoint(params[2], params[3], FXPT_TYPE::BezierTo, false);
               nParams = 0;
               break;
             case kPathOperatorClosePath:
@@ -1627,8 +1603,8 @@
               break;
           }
         } else if (len == 2) {
-          if (m_pSyntax->GetWordBuf()[0] == kPathOperatorRectangle[0] &&
-              m_pSyntax->GetWordBuf()[1] == kPathOperatorRectangle[1]) {
+          if (strc[0] == kPathOperatorRectangle[0] &&
+              strc[1] == kPathOperatorRectangle[1]) {
             AddPathRect(params[0], params[1], params[2], params[3]);
             nParams = 0;
           } else {
@@ -1647,9 +1623,7 @@
           break;
 
         int value;
-        bool bInteger = FX_atonum(
-            CFX_ByteStringC(m_pSyntax->GetWordBuf(), m_pSyntax->GetWordSize()),
-            &value);
+        bool bInteger = FX_atonum(m_pSyntax->GetWord(), &value);
         params[nParams++] = bInteger ? (FX_FLOAT)value : *(FX_FLOAT*)&value;
         break;
       }
diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.h b/core/fpdfapi/page/cpdf_streamcontentparser.h
index 6429b02..cd41990 100644
--- a/core/fpdfapi/page/cpdf_streamcontentparser.h
+++ b/core/fpdfapi/page/cpdf_streamcontentparser.h
@@ -77,26 +77,24 @@
       std::unordered_map<uint32_t, void (CPDF_StreamContentParser::*)()>;
   static OpCodes InitializeOpCodes();
 
-  void AddNumberParam(const FX_CHAR* str, int len);
+  void AddNameParam(const CFX_ByteStringC& str);
+  void AddNumberParam(const CFX_ByteStringC& str);
   void AddObjectParam(std::unique_ptr<CPDF_Object> pObj);
-  void AddNameParam(const FX_CHAR* name, int size);
   int GetNextParamPos();
   void ClearAllParams();
   CPDF_Object* GetObject(uint32_t index);
   CFX_ByteString GetString(uint32_t index);
   FX_FLOAT GetNumber(uint32_t index);
   int GetInteger(uint32_t index) { return (int32_t)(GetNumber(index)); }
-  void OnOperator(const FX_CHAR* op);
+  void OnOperator(const CFX_ByteStringC& op);
   void AddTextObject(CFX_ByteString* pText,
                      FX_FLOAT fInitKerning,
                      FX_FLOAT* pKerning,
                      int count);
 
-  void ConvertUserSpace(FX_FLOAT& x, FX_FLOAT& y);
-  void ConvertTextSpace(FX_FLOAT& x, FX_FLOAT& y);
   void OnChangeTextMatrix();
   void ParsePathObject();
-  void AddPathPoint(FX_FLOAT x, FX_FLOAT y, int flag);
+  void AddPathPoint(FX_FLOAT x, FX_FLOAT y, FXPT_TYPE type, bool close);
   void AddPathRect(FX_FLOAT x, FX_FLOAT y, FX_FLOAT w, FX_FLOAT h);
   void AddPathObject(int FillType, bool bStroke);
   CPDF_ImageObject* AddImage(std::unique_ptr<CPDF_Stream> pStream);
diff --git a/core/fpdfapi/page/cpdf_streamparser.cpp b/core/fpdfapi/page/cpdf_streamparser.cpp
index e26de60..294d72c 100644
--- a/core/fpdfapi/page/cpdf_streamparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamparser.cpp
@@ -29,7 +29,7 @@
 
 namespace {
 
-const uint32_t kMaxNestedArrayLevel = 512;
+const uint32_t kMaxNestedParsingLevel = 512;
 const uint32_t kMaxWordBuffer = 256;
 const FX_STRSIZE kMaxStringLength = 32767;
 
@@ -209,8 +209,7 @@
         dwStreamSize += m_Pos - dwPrevPos;
         continue;
       }
-      if (GetWordSize() == 2 && GetWordBuf()[0] == 'E' &&
-          GetWordBuf()[1] == 'I') {
+      if (GetWord() == "EI") {
         m_Pos = dwPrevPos;
         break;
       }
@@ -256,7 +255,7 @@
 
   if (PDFCharIsDelimiter(ch) && ch != '/') {
     m_Pos--;
-    m_pLastObj = ReadNextObject(false, 0);
+    m_pLastObj = ReadNextObject(false, false, 0);
     return Others;
   }
 
@@ -306,10 +305,12 @@
 
 std::unique_ptr<CPDF_Object> CPDF_StreamParser::ReadNextObject(
     bool bAllowNestedArray,
-    uint32_t dwInArrayLevel) {
+    bool bInArray,
+    uint32_t dwRecursionLevel) {
   bool bIsNumber;
+  // Must get the next word before returning to avoid infinite loops.
   GetNextWord(bIsNumber);
-  if (!m_WordSize)
+  if (!m_WordSize || dwRecursionLevel > kMaxNestedParsingLevel)
     return nullptr;
 
   if (bIsNumber) {
@@ -345,7 +346,8 @@
 
       CFX_ByteString key =
           PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1));
-      std::unique_ptr<CPDF_Object> pObj = ReadNextObject(true, 0);
+      std::unique_ptr<CPDF_Object> pObj =
+          ReadNextObject(true, bInArray, dwRecursionLevel + 1);
       if (!pObj)
         return nullptr;
 
@@ -356,15 +358,13 @@
   }
 
   if (first_char == '[') {
-    if ((!bAllowNestedArray && dwInArrayLevel) ||
-        dwInArrayLevel > kMaxNestedArrayLevel) {
+    if ((!bAllowNestedArray && bInArray))
       return nullptr;
-    }
 
     auto pArray = pdfium::MakeUnique<CPDF_Array>();
     while (1) {
       std::unique_ptr<CPDF_Object> pObj =
-          ReadNextObject(bAllowNestedArray, dwInArrayLevel + 1);
+          ReadNextObject(bAllowNestedArray, true, dwRecursionLevel + 1);
       if (pObj) {
         pArray->Add(std::move(pObj));
         continue;
diff --git a/core/fpdfapi/page/cpdf_streamparser.h b/core/fpdfapi/page/cpdf_streamparser.h
index ce01dd0..fdc418c 100644
--- a/core/fpdfapi/page/cpdf_streamparser.h
+++ b/core/fpdfapi/page/cpdf_streamparser.h
@@ -28,13 +28,15 @@
   ~CPDF_StreamParser();
 
   SyntaxType ParseNextElement();
-  const uint8_t* GetWordBuf() const { return m_WordBuffer; }
-  uint32_t GetWordSize() const { return m_WordSize; }
+  CFX_ByteStringC GetWord() const {
+    return CFX_ByteStringC(m_WordBuffer, m_WordSize);
+  }
   uint32_t GetPos() const { return m_Pos; }
   void SetPos(uint32_t pos) { m_Pos = pos; }
   std::unique_ptr<CPDF_Object> GetObject() { return std::move(m_pLastObj); }
   std::unique_ptr<CPDF_Object> ReadNextObject(bool bAllowNestedArray,
-                                              uint32_t dwInArrayLevel);
+                                              bool bInArray,
+                                              uint32_t dwRecursionLevel);
   std::unique_ptr<CPDF_Stream> ReadInlineStream(
       CPDF_Document* pDoc,
       std::unique_ptr<CPDF_Dictionary> pDict,
diff --git a/core/fpdfapi/page/cpdf_textobject.cpp b/core/fpdfapi/page/cpdf_textobject.cpp
index 0979fcf..da69de8 100644
--- a/core/fpdfapi/page/cpdf_textobject.cpp
+++ b/core/fpdfapi/page/cpdf_textobject.cpp
@@ -6,126 +6,97 @@
 
 #include "core/fpdfapi/page/cpdf_textobject.h"
 
+#include <algorithm>
+
 #include "core/fpdfapi/font/cpdf_cidfont.h"
 #include "core/fpdfapi/font/cpdf_font.h"
 #include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
 
-CPDF_TextObject::CPDF_TextObject()
-    : m_PosX(0),
-      m_PosY(0),
-      m_nChars(0),
-      m_pCharCodes(nullptr),
-      m_pCharPos(nullptr) {}
+CPDF_TextObjectItem::CPDF_TextObjectItem() : m_CharCode(0) {}
 
-CPDF_TextObject::~CPDF_TextObject() {
-  if (m_nChars > 1) {
-    FX_Free(m_pCharCodes);
-  }
-  FX_Free(m_pCharPos);
-}
+CPDF_TextObjectItem::~CPDF_TextObjectItem() = default;
+
+CPDF_TextObject::CPDF_TextObject() {}
+
+CPDF_TextObject::~CPDF_TextObject() {}
 
 int CPDF_TextObject::CountItems() const {
-  return m_nChars;
+  return pdfium::CollectionSize<int>(m_CharCodes);
 }
 
 void CPDF_TextObject::GetItemInfo(int index, CPDF_TextObjectItem* pInfo) const {
-  pInfo->m_CharCode =
-      m_nChars == 1 ? (uint32_t)(uintptr_t)m_pCharCodes : m_pCharCodes[index];
-  pInfo->m_OriginX = index ? m_pCharPos[index - 1] : 0;
-  pInfo->m_OriginY = 0;
-  if (pInfo->m_CharCode == CPDF_Font::kInvalidCharCode) {
+  pInfo->m_CharCode = m_CharCodes[index];
+  pInfo->m_Origin = CFX_PointF(index ? m_CharPos[index - 1] : 0, 0);
+  if (pInfo->m_CharCode == CPDF_Font::kInvalidCharCode)
     return;
-  }
+
   CPDF_Font* pFont = m_TextState.GetFont();
-  if (!pFont->IsCIDFont()) {
+  if (!pFont->IsCIDFont())
     return;
-  }
-  if (!pFont->AsCIDFont()->IsVertWriting()) {
+  if (!pFont->AsCIDFont()->IsVertWriting())
     return;
-  }
+
   uint16_t CID = pFont->AsCIDFont()->CIDFromCharCode(pInfo->m_CharCode);
-  pInfo->m_OriginY = pInfo->m_OriginX;
-  pInfo->m_OriginX = 0;
-  short vx, vy;
+  pInfo->m_Origin = CFX_PointF(0, pInfo->m_Origin.x);
+
+  short vx;
+  short vy;
   pFont->AsCIDFont()->GetVertOrigin(CID, vx, vy);
+
   FX_FLOAT fontsize = m_TextState.GetFontSize();
-  pInfo->m_OriginX -= fontsize * vx / 1000;
-  pInfo->m_OriginY -= fontsize * vy / 1000;
+  pInfo->m_Origin.x -= fontsize * vx / 1000;
+  pInfo->m_Origin.y -= fontsize * vy / 1000;
 }
 
 int CPDF_TextObject::CountChars() const {
-  if (m_nChars == 1) {
-    return 1;
-  }
   int count = 0;
-  for (int i = 0; i < m_nChars; ++i)
-    if (m_pCharCodes[i] != CPDF_Font::kInvalidCharCode) {
-      ++count;
-    }
+  for (uint32_t charcode : m_CharCodes) {
+    if (charcode != CPDF_Font::kInvalidCharCode)
+      count++;
+  }
   return count;
 }
 
 void CPDF_TextObject::GetCharInfo(int index,
-                                  uint32_t& charcode,
-                                  FX_FLOAT& kerning) const {
-  if (m_nChars == 1) {
-    charcode = (uint32_t)(uintptr_t)m_pCharCodes;
-    kerning = 0;
-    return;
-  }
+                                  uint32_t* charcode,
+                                  FX_FLOAT* kerning) const {
   int count = 0;
-  for (int i = 0; i < m_nChars; ++i) {
-    if (m_pCharCodes[i] != CPDF_Font::kInvalidCharCode) {
-      if (count == index) {
-        charcode = m_pCharCodes[i];
-        if (i == m_nChars - 1 ||
-            m_pCharCodes[i + 1] != CPDF_Font::kInvalidCharCode) {
-          kerning = 0;
-        } else {
-          kerning = m_pCharPos[i];
-        }
-        return;
-      }
-      ++count;
+  for (size_t i = 0; i < m_CharCodes.size(); ++i) {
+    if (m_CharCodes[i] == CPDF_Font::kInvalidCharCode)
+      continue;
+    if (count++ != index)
+      continue;
+    *charcode = m_CharCodes[i];
+    if (i == m_CharCodes.size() - 1 ||
+        m_CharCodes[i + 1] != CPDF_Font::kInvalidCharCode) {
+      *kerning = 0;
+    } else {
+      *kerning = m_CharPos[i];
     }
+    return;
   }
 }
 
 void CPDF_TextObject::GetCharInfo(int index, CPDF_TextObjectItem* pInfo) const {
-  if (m_nChars == 1) {
-    GetItemInfo(0, pInfo);
-    return;
-  }
   int count = 0;
-  for (int i = 0; i < m_nChars; ++i) {
-    uint32_t charcode = m_pCharCodes[i];
-    if (charcode == CPDF_Font::kInvalidCharCode) {
+  for (int i = 0; i < pdfium::CollectionSize<int>(m_CharCodes); ++i) {
+    uint32_t charcode = m_CharCodes[i];
+    if (charcode == CPDF_Font::kInvalidCharCode)
       continue;
-    }
-    if (count == index) {
-      GetItemInfo(i, pInfo);
-      break;
-    }
-    ++count;
+    if (count++ != index)
+      continue;
+    GetItemInfo(i, pInfo);
+    break;
   }
 }
 
 std::unique_ptr<CPDF_TextObject> CPDF_TextObject::Clone() const {
   auto obj = pdfium::MakeUnique<CPDF_TextObject>();
   obj->CopyData(this);
-
-  obj->m_nChars = m_nChars;
-  if (m_nChars > 1) {
-    obj->m_pCharCodes = FX_Alloc(uint32_t, m_nChars);
-    FXSYS_memcpy(obj->m_pCharCodes, m_pCharCodes, m_nChars * sizeof(uint32_t));
-    obj->m_pCharPos = FX_Alloc(FX_FLOAT, m_nChars - 1);
-    FXSYS_memcpy(obj->m_pCharPos, m_pCharPos,
-                 (m_nChars - 1) * sizeof(FX_FLOAT));
-  } else {
-    obj->m_pCharCodes = m_pCharCodes;
-  }
-  obj->m_PosX = m_PosX;
-  obj->m_PosY = m_PosY;
+  obj->m_CharCodes = m_CharCodes;
+  obj->m_CharPos = m_CharPos;
+  obj->m_Pos = m_Pos;
   return obj;
 }
 
@@ -134,18 +105,16 @@
 }
 
 void CPDF_TextObject::Transform(const CFX_Matrix& matrix) {
-  CFX_Matrix text_matrix;
-  GetTextMatrix(&text_matrix);
+  CFX_Matrix text_matrix = GetTextMatrix();
   text_matrix.Concat(matrix);
 
   FX_FLOAT* pTextMatrix = m_TextState.GetMutableMatrix();
-  pTextMatrix[0] = text_matrix.GetA();
-  pTextMatrix[1] = text_matrix.GetC();
-  pTextMatrix[2] = text_matrix.GetB();
-  pTextMatrix[3] = text_matrix.GetD();
-  m_PosX = text_matrix.GetE();
-  m_PosY = text_matrix.GetF();
-  CalcPositionData(nullptr, nullptr, 0);
+  pTextMatrix[0] = text_matrix.a;
+  pTextMatrix[1] = text_matrix.c;
+  pTextMatrix[2] = text_matrix.b;
+  pTextMatrix[3] = text_matrix.d;
+  m_Pos = CFX_PointF(text_matrix.e, text_matrix.f);
+  CalcPositionData(0);
 }
 
 bool CPDF_TextObject::IsText() const {
@@ -160,47 +129,35 @@
   return this;
 }
 
-void CPDF_TextObject::GetTextMatrix(CFX_Matrix* pMatrix) const {
+CFX_Matrix CPDF_TextObject::GetTextMatrix() const {
   const FX_FLOAT* pTextMatrix = m_TextState.GetMatrix();
-  pMatrix->Set(pTextMatrix[0], pTextMatrix[2], pTextMatrix[1], pTextMatrix[3],
-               m_PosX, m_PosY);
+  return CFX_Matrix(pTextMatrix[0], pTextMatrix[2], pTextMatrix[1],
+                    pTextMatrix[3], m_Pos.x, m_Pos.y);
 }
 
 void CPDF_TextObject::SetSegments(const CFX_ByteString* pStrs,
-                                  FX_FLOAT* pKerning,
+                                  const FX_FLOAT* pKerning,
                                   int nsegs) {
-  if (m_nChars > 1) {
-    FX_Free(m_pCharCodes);
-    m_pCharCodes = nullptr;
-  }
-  FX_Free(m_pCharPos);
-  m_pCharPos = nullptr;
+  m_CharCodes.clear();
+  m_CharPos.clear();
   CPDF_Font* pFont = m_TextState.GetFont();
-  m_nChars = 0;
+  int nChars = 0;
+  for (int i = 0; i < nsegs; ++i)
+    nChars += pFont->CountChar(pStrs[i].c_str(), pStrs[i].GetLength());
+  nChars += nsegs - 1;
+  m_CharCodes.resize(nChars);
+  m_CharPos.resize(nChars - 1);
+  int index = 0;
   for (int i = 0; i < nsegs; ++i) {
-    m_nChars += pFont->CountChar(pStrs[i].c_str(), pStrs[i].GetLength());
-  }
-  m_nChars += nsegs - 1;
-  if (m_nChars > 1) {
-    m_pCharCodes = FX_Alloc(uint32_t, m_nChars);
-    m_pCharPos = FX_Alloc(FX_FLOAT, m_nChars - 1);
-    int index = 0;
-    for (int i = 0; i < nsegs; ++i) {
-      const FX_CHAR* segment = pStrs[i].c_str();
-      int len = pStrs[i].GetLength();
-      int offset = 0;
-      while (offset < len) {
-        m_pCharCodes[index++] = pFont->GetNextChar(segment, len, offset);
-      }
-      if (i != nsegs - 1) {
-        m_pCharPos[index - 1] = pKerning[i];
-        m_pCharCodes[index++] = CPDF_Font::kInvalidCharCode;
-      }
-    }
-  } else {
+    const FX_CHAR* segment = pStrs[i].c_str();
+    int len = pStrs[i].GetLength();
     int offset = 0;
-    m_pCharCodes = (uint32_t*)(uintptr_t)pFont->GetNextChar(
-        pStrs[0].c_str(), pStrs[0].GetLength(), offset);
+    while (offset < len)
+      m_CharCodes[index++] = pFont->GetNextChar(segment, len, offset);
+    if (i != nsegs - 1) {
+      m_CharPos[index - 1] = pKerning[i];
+      m_CharCodes[index++] = CPDF_Font::kInvalidCharCode;
+    }
   }
 }
 
@@ -214,9 +171,8 @@
   CPDF_Font* pFont = m_TextState.GetFont();
   bool bVertWriting = false;
   CPDF_CIDFont* pCIDFont = pFont->AsCIDFont();
-  if (pCIDFont) {
+  if (pCIDFont)
     bVertWriting = pCIDFont->IsVertWriting();
-  }
   if (!bVertWriting)
     return pFont->GetCharWidthF(charcode) * fontsize;
 
@@ -224,14 +180,6 @@
   return pCIDFont->GetVertWidth(CID) * fontsize;
 }
 
-FX_FLOAT CPDF_TextObject::GetPosX() const {
-  return m_PosX;
-}
-
-FX_FLOAT CPDF_TextObject::GetPosY() const {
-  return m_PosY;
-}
-
 CPDF_Font* CPDF_TextObject::GetFont() const {
   return m_TextState.GetFont();
 }
@@ -240,9 +188,7 @@
   return m_TextState.GetFontSize();
 }
 
-void CPDF_TextObject::CalcPositionData(FX_FLOAT* pTextAdvanceX,
-                                       FX_FLOAT* pTextAdvanceY,
-                                       FX_FLOAT horz_scale) {
+CFX_PointF CPDF_TextObject::CalcPositionData(FX_FLOAT horz_scale) {
   FX_FLOAT curpos = 0;
   FX_FLOAT min_x = 10000 * 1.0f;
   FX_FLOAT max_x = -10000 * 1.0f;
@@ -251,49 +197,31 @@
   CPDF_Font* pFont = m_TextState.GetFont();
   bool bVertWriting = false;
   CPDF_CIDFont* pCIDFont = pFont->AsCIDFont();
-  if (pCIDFont) {
+  if (pCIDFont)
     bVertWriting = pCIDFont->IsVertWriting();
-  }
+
   FX_FLOAT fontsize = m_TextState.GetFontSize();
-  for (int i = 0; i < m_nChars; ++i) {
-    uint32_t charcode =
-        m_nChars == 1 ? (uint32_t)(uintptr_t)m_pCharCodes : m_pCharCodes[i];
+  for (int i = 0; i < pdfium::CollectionSize<int>(m_CharCodes); ++i) {
+    uint32_t charcode = m_CharCodes[i];
     if (i > 0) {
       if (charcode == CPDF_Font::kInvalidCharCode) {
-        curpos -= (m_pCharPos[i - 1] * fontsize) / 1000;
+        curpos -= (m_CharPos[i - 1] * fontsize) / 1000;
         continue;
       }
-      m_pCharPos[i - 1] = curpos;
+      m_CharPos[i - 1] = curpos;
     }
+
     FX_RECT char_rect = pFont->GetCharBBox(charcode);
     FX_FLOAT charwidth;
     if (!bVertWriting) {
-      if (min_y > char_rect.top) {
-        min_y = (FX_FLOAT)char_rect.top;
-      }
-      if (max_y < char_rect.top) {
-        max_y = (FX_FLOAT)char_rect.top;
-      }
-      if (min_y > char_rect.bottom) {
-        min_y = (FX_FLOAT)char_rect.bottom;
-      }
-      if (max_y < char_rect.bottom) {
-        max_y = (FX_FLOAT)char_rect.bottom;
-      }
+      min_y = std::min(min_y, static_cast<FX_FLOAT>(
+                                  std::min(char_rect.top, char_rect.bottom)));
+      max_y = std::max(max_y, static_cast<FX_FLOAT>(
+                                  std::max(char_rect.top, char_rect.bottom)));
       FX_FLOAT char_left = curpos + char_rect.left * fontsize / 1000;
       FX_FLOAT char_right = curpos + char_rect.right * fontsize / 1000;
-      if (min_x > char_left) {
-        min_x = char_left;
-      }
-      if (max_x < char_left) {
-        max_x = char_left;
-      }
-      if (min_x > char_right) {
-        min_x = char_right;
-      }
-      if (max_x < char_right) {
-        max_x = char_right;
-      }
+      min_x = std::min(min_x, std::min(char_left, char_right));
+      max_x = std::max(max_x, std::max(char_left, char_right));
       charwidth = pFont->GetCharWidthF(charcode) * fontsize / 1000;
     } else {
       uint16_t CID = pCIDFont->CIDFromCharCode(charcode);
@@ -304,80 +232,57 @@
       char_rect.right -= vx;
       char_rect.top -= vy;
       char_rect.bottom -= vy;
-      if (min_x > char_rect.left) {
-        min_x = (FX_FLOAT)char_rect.left;
-      }
-      if (max_x < char_rect.left) {
-        max_x = (FX_FLOAT)char_rect.left;
-      }
-      if (min_x > char_rect.right) {
-        min_x = (FX_FLOAT)char_rect.right;
-      }
-      if (max_x < char_rect.right) {
-        max_x = (FX_FLOAT)char_rect.right;
-      }
+      min_x = std::min(min_x, static_cast<FX_FLOAT>(
+                                  std::min(char_rect.left, char_rect.right)));
+      max_x = std::max(max_x, static_cast<FX_FLOAT>(
+                                  std::max(char_rect.left, char_rect.right)));
       FX_FLOAT char_top = curpos + char_rect.top * fontsize / 1000;
       FX_FLOAT char_bottom = curpos + char_rect.bottom * fontsize / 1000;
-      if (min_y > char_top) {
-        min_y = char_top;
-      }
-      if (max_y < char_top) {
-        max_y = char_top;
-      }
-      if (min_y > char_bottom) {
-        min_y = char_bottom;
-      }
-      if (max_y < char_bottom) {
-        max_y = char_bottom;
-      }
+      min_y = std::min(min_y, std::min(char_top, char_bottom));
+      max_y = std::max(max_y, std::max(char_top, char_bottom));
       charwidth = pCIDFont->GetVertWidth(CID) * fontsize / 1000;
     }
     curpos += charwidth;
-    if (charcode == ' ' && (!pCIDFont || pCIDFont->GetCharSize(32) == 1)) {
+    if (charcode == ' ' && (!pCIDFont || pCIDFont->GetCharSize(' ') == 1))
       curpos += m_TextState.GetWordSpace();
-    }
+
     curpos += m_TextState.GetCharSpace();
   }
+
+  CFX_PointF ret;
   if (bVertWriting) {
-    if (pTextAdvanceX) {
-      *pTextAdvanceX = 0;
-    }
-    if (pTextAdvanceY) {
-      *pTextAdvanceY = curpos;
-    }
+    ret.y = curpos;
     min_x = min_x * fontsize / 1000;
     max_x = max_x * fontsize / 1000;
   } else {
-    if (pTextAdvanceX) {
-      *pTextAdvanceX = curpos * horz_scale;
-    }
-    if (pTextAdvanceY) {
-      *pTextAdvanceY = 0;
-    }
+    ret.x = curpos * horz_scale;
     min_y = min_y * fontsize / 1000;
     max_y = max_y * fontsize / 1000;
   }
-  CFX_Matrix matrix;
-  GetTextMatrix(&matrix);
+
   m_Left = min_x;
   m_Right = max_x;
   m_Bottom = min_y;
   m_Top = max_y;
-  matrix.TransformRect(m_Left, m_Right, m_Top, m_Bottom);
-  if (TextRenderingModeIsStrokeMode(m_TextState.GetTextMode())) {
-    FX_FLOAT half_width = m_GraphState.GetLineWidth() / 2;
-    m_Left -= half_width;
-    m_Right += half_width;
-    m_Top += half_width;
-    m_Bottom -= half_width;
-  }
+  GetTextMatrix().TransformRect(m_Left, m_Right, m_Top, m_Bottom);
+
+  if (!TextRenderingModeIsStrokeMode(m_TextState.GetTextMode()))
+    return ret;
+
+  FX_FLOAT half_width = m_GraphState.GetLineWidth() / 2;
+  m_Left -= half_width;
+  m_Right += half_width;
+  m_Top += half_width;
+  m_Bottom -= half_width;
+
+  return ret;
 }
 
 void CPDF_TextObject::SetPosition(FX_FLOAT x, FX_FLOAT y) {
-  FX_FLOAT dx = x - m_PosX;
-  FX_FLOAT dy = y - m_PosY;
-  m_PosX = x;
-  m_PosY = y;
+  FX_FLOAT dx = x - m_Pos.x;
+  FX_FLOAT dy = y - m_Pos.y;
+  m_Pos.x = x;
+  m_Pos.y = y;
   m_Left += dx;
   m_Right += dx;
   m_Top += dy;
@@ -385,5 +290,5 @@
 }
 
 void CPDF_TextObject::RecalcPositionData() {
-  CalcPositionData(nullptr, nullptr, 1);
+  CalcPositionData(1);
 }
diff --git a/core/fpdfapi/page/cpdf_textobject.h b/core/fpdfapi/page/cpdf_textobject.h
index b520e3e..59da718 100644
--- a/core/fpdfapi/page/cpdf_textobject.h
+++ b/core/fpdfapi/page/cpdf_textobject.h
@@ -8,15 +8,19 @@
 #define CORE_FPDFAPI_PAGE_CPDF_TEXTOBJECT_H_
 
 #include <memory>
+#include <vector>
 
 #include "core/fpdfapi/page/cpdf_pageobject.h"
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
 
-struct CPDF_TextObjectItem {
+class CPDF_TextObjectItem {
+ public:
+  CPDF_TextObjectItem();
+  ~CPDF_TextObjectItem();
+
   uint32_t m_CharCode;
-  FX_FLOAT m_OriginX;
-  FX_FLOAT m_OriginY;
+  CFX_PointF m_Origin;
 };
 
 class CPDF_TextObject : public CPDF_PageObject {
@@ -35,12 +39,11 @@
   int CountItems() const;
   void GetItemInfo(int index, CPDF_TextObjectItem* pInfo) const;
   int CountChars() const;
-  void GetCharInfo(int index, uint32_t& charcode, FX_FLOAT& kerning) const;
+  void GetCharInfo(int index, uint32_t* charcode, FX_FLOAT* kerning) const;
   void GetCharInfo(int index, CPDF_TextObjectItem* pInfo) const;
   FX_FLOAT GetCharWidth(uint32_t charcode) const;
-  FX_FLOAT GetPosX() const;
-  FX_FLOAT GetPosY() const;
-  void GetTextMatrix(CFX_Matrix* pMatrix) const;
+  CFX_PointF GetPos() const { return m_Pos; }
+  CFX_Matrix GetTextMatrix() const;
   CPDF_Font* GetFont() const;
   FX_FLOAT GetFontSize() const;
 
@@ -49,22 +52,21 @@
 
   void RecalcPositionData();
 
- protected:
+ private:
   friend class CPDF_RenderStatus;
   friend class CPDF_StreamContentParser;
   friend class CPDF_TextRenderer;
+  friend class CPDF_PageContentGenerator;
 
-  void SetSegments(const CFX_ByteString* pStrs, FX_FLOAT* pKerning, int nSegs);
+  void SetSegments(const CFX_ByteString* pStrs,
+                   const FX_FLOAT* pKerning,
+                   int nSegs);
 
-  void CalcPositionData(FX_FLOAT* pTextAdvanceX,
-                        FX_FLOAT* pTextAdvanceY,
-                        FX_FLOAT horz_scale);
+  CFX_PointF CalcPositionData(FX_FLOAT horz_scale);
 
-  FX_FLOAT m_PosX;
-  FX_FLOAT m_PosY;
-  int m_nChars;
-  uint32_t* m_pCharCodes;
-  FX_FLOAT* m_pCharPos;
+  CFX_PointF m_Pos;
+  std::vector<uint32_t> m_CharCodes;
+  std::vector<FX_FLOAT> m_CharPos;
 };
 
 #endif  // CORE_FPDFAPI_PAGE_CPDF_TEXTOBJECT_H_
diff --git a/core/fpdfapi/page/fpdf_page_func.cpp b/core/fpdfapi/page/fpdf_page_func.cpp
index 672bfc0..916641f 100644
--- a/core/fpdfapi/page/fpdf_page_func.cpp
+++ b/core/fpdfapi/page/fpdf_page_func.cpp
@@ -410,12 +410,15 @@
       break;
     case PSOP_BITSHIFT: {
       int shift = (int)Pop();
-      int i = (int)Pop();
+      result = (int)Pop();
       if (shift > 0) {
-        Push(i << shift);
+        result <<= shift;
       } else {
-        Push(i >> -shift);
+        // Avoids unsafe negation of INT_MIN.
+        FX_SAFE_INT32 safe_shift = shift;
+        result >>= (-safe_shift).ValueOrDefault(0);
       }
+      Push(result.ValueOrDefault(0));
       break;
     }
     case PSOP_TRUE:
@@ -574,10 +577,9 @@
   if (!pSampleData)
     return false;
 
-  for (uint32_t j = 0; j < m_nOutputs; j++) {
+  for (uint32_t j = 0; j < m_nOutputs; j++, bitpos += m_nBitsPerSample) {
     uint32_t sample =
-        GetBits32(pSampleData, bitpos.ValueOrDie() + j * m_nBitsPerSample,
-                  m_nBitsPerSample);
+        GetBits32(pSampleData, bitpos.ValueOrDie(), m_nBitsPerSample);
     FX_FLOAT encoded = (FX_FLOAT)sample;
     for (uint32_t i = 0; i < m_nInputs; i++) {
       if (index[i] == m_EncodeInfo[i].sizes - 1) {
diff --git a/core/fpdfapi/parser/cpdf_array.cpp b/core/fpdfapi/parser/cpdf_array.cpp
index 64010e1..05a9370 100644
--- a/core/fpdfapi/parser/cpdf_array.cpp
+++ b/core/fpdfapi/parser/cpdf_array.cpp
@@ -78,11 +78,10 @@
 CFX_Matrix CPDF_Array::GetMatrix() {
   CFX_Matrix matrix;
   if (!IsArray() || m_Objects.size() != 6)
-    return matrix;
+    return CFX_Matrix();
 
-  matrix.Set(GetNumberAt(0), GetNumberAt(1), GetNumberAt(2), GetNumberAt(3),
-             GetNumberAt(4), GetNumberAt(5));
-  return matrix;
+  return CFX_Matrix(GetNumberAt(0), GetNumberAt(1), GetNumberAt(2),
+                    GetNumberAt(3), GetNumberAt(4), GetNumberAt(5));
 }
 
 CPDF_Object* CPDF_Array::GetObjectAt(size_t i) const {
diff --git a/core/fpdfapi/parser/cpdf_data_avail.cpp b/core/fpdfapi/parser/cpdf_data_avail.cpp
index 4205ed2..64eaf2a 100644
--- a/core/fpdfapi/parser/cpdf_data_avail.cpp
+++ b/core/fpdfapi/parser/cpdf_data_avail.cpp
@@ -46,6 +46,7 @@
   }
   m_dwCurrentOffset = 0;
   m_dwXRefOffset = 0;
+  m_dwTrailerOffset = 0;
   m_bufferOffset = 0;
   m_bufferSize = 0;
   m_PagesObjNum = 0;
@@ -1123,13 +1124,8 @@
     return false;
   }
 
-  if (!pPages) {
-    if (m_docStatus == PDF_DATAAVAIL_ERROR) {
-      m_docStatus = PDF_DATAAVAIL_ERROR;
-      return false;
-    }
+  if (!pPages)
     return false;
-  }
 
   CPDF_Array* pArray = pPages->AsArray();
   if (!pArray) {
@@ -1160,11 +1156,8 @@
     return false;
   }
 
-  if (!pPage) {
-    if (m_docStatus == PDF_DATAAVAIL_ERROR)
-      m_docStatus = PDF_DATAAVAIL_ERROR;
+  if (!pPage)
     return false;
-  }
 
   if (pPage->IsArray()) {
     pPageNode->m_dwPageNo = dwPageNo;
diff --git a/core/fpdfapi/parser/cpdf_document.cpp b/core/fpdfapi/parser/cpdf_document.cpp
index e425cfc..21eb61a 100644
--- a/core/fpdfapi/parser/cpdf_document.cpp
+++ b/core/fpdfapi/parser/cpdf_document.cpp
@@ -279,19 +279,19 @@
                    bool symbolic) {
   int flags = 0;
   if (bold)
-    flags |= PDFFONT_FORCEBOLD;
+    flags |= FXFONT_BOLD;
   if (italic)
-    flags |= PDFFONT_ITALIC;
+    flags |= FXFONT_ITALIC;
   if (fixedPitch)
-    flags |= PDFFONT_FIXEDPITCH;
+    flags |= FXFONT_FIXED_PITCH;
   if (serif)
-    flags |= PDFFONT_SERIF;
+    flags |= FXFONT_SERIF;
   if (script)
-    flags |= PDFFONT_SCRIPT;
+    flags |= FXFONT_SCRIPT;
   if (symbolic)
-    flags |= PDFFONT_SYMBOLIC;
+    flags |= FXFONT_SYMBOLIC;
   else
-    flags |= PDFFONT_NONSYMBOLIC;
+    flags |= FXFONT_NONSYMBOLIC;
   return flags;
 }
 
diff --git a/core/fpdfapi/parser/cpdf_hint_tables.cpp b/core/fpdfapi/parser/cpdf_hint_tables.cpp
index 5c0f2a7..e000188 100644
--- a/core/fpdfapi/parser/cpdf_hint_tables.cpp
+++ b/core/fpdfapi/parser/cpdf_hint_tables.cpp
@@ -257,7 +257,7 @@
   bit_offset *= 8;
   if (!bit_offset.IsValid() || hStream->GetPos() > bit_offset.ValueOrDie())
     return false;
-  hStream->SkipBits(bit_offset.ValueOrDie() - hStream->GetPos());
+  hStream->SkipBits((bit_offset - hStream->GetPos()).ValueOrDie());
 
   const uint32_t kHeaderSize = 192;
   if (hStream->BitsRemaining() < kHeaderSize)
diff --git a/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp b/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp
index efb9f84..3037d0b 100644
--- a/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp
+++ b/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp
@@ -11,6 +11,7 @@
 
 #include "core/fpdfapi/parser/cpdf_object.h"
 #include "core/fpdfapi/parser/cpdf_parser.h"
+#include "third_party/base/logging.h"
 
 CPDF_IndirectObjectHolder::CPDF_IndirectObjectHolder()
     : m_LastObjNum(0),
@@ -55,7 +56,9 @@
   CHECK(!pObj->m_ObjNum);
   CPDF_Object* pUnowned = pObj.get();
   pObj->m_ObjNum = ++m_LastObjNum;
-  m_IndirectObjs[m_LastObjNum].release();  // TODO(tsepez): stop this leak.
+  if (m_IndirectObjs[m_LastObjNum])
+    m_OrphanObjs.push_back(std::move(m_IndirectObjs[m_LastObjNum]));
+
   m_IndirectObjs[m_LastObjNum] = std::move(pObj);
   return pUnowned;
 }
diff --git a/core/fpdfapi/parser/cpdf_indirect_object_holder.h b/core/fpdfapi/parser/cpdf_indirect_object_holder.h
index 1b174d8..b6d33a3 100644
--- a/core/fpdfapi/parser/cpdf_indirect_object_holder.h
+++ b/core/fpdfapi/parser/cpdf_indirect_object_holder.h
@@ -11,6 +11,7 @@
 #include <memory>
 #include <type_traits>
 #include <utility>
+#include <vector>
 
 #include "core/fpdfapi/parser/cpdf_object.h"
 #include "core/fxcrt/cfx_string_pool_template.h"
@@ -70,6 +71,7 @@
  private:
   uint32_t m_LastObjNum;
   std::map<uint32_t, std::unique_ptr<CPDF_Object>> m_IndirectObjs;
+  std::vector<std::unique_ptr<CPDF_Object>> m_OrphanObjs;
   CFX_WeakPtr<CFX_ByteStringPool> m_pByteStringPool;
 };
 
diff --git a/core/fpdfapi/parser/cpdf_object_unittest.cpp b/core/fpdfapi/parser/cpdf_object_unittest.cpp
index 4977c99..927b106 100644
--- a/core/fpdfapi/parser/cpdf_object_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_object_unittest.cpp
@@ -397,12 +397,12 @@
     for (size_t j = 0; j < 6; ++j)
       arr->AddNew<CPDF_Number>(elems[i][j]);
     CFX_Matrix arr_matrix = arr->GetMatrix();
-    EXPECT_EQ(matrix.GetA(), arr_matrix.GetA());
-    EXPECT_EQ(matrix.GetB(), arr_matrix.GetB());
-    EXPECT_EQ(matrix.GetC(), arr_matrix.GetC());
-    EXPECT_EQ(matrix.GetD(), arr_matrix.GetD());
-    EXPECT_EQ(matrix.GetE(), arr_matrix.GetE());
-    EXPECT_EQ(matrix.GetF(), arr_matrix.GetF());
+    EXPECT_EQ(matrix.a, arr_matrix.a);
+    EXPECT_EQ(matrix.b, arr_matrix.b);
+    EXPECT_EQ(matrix.c, arr_matrix.c);
+    EXPECT_EQ(matrix.d, arr_matrix.d);
+    EXPECT_EQ(matrix.e, arr_matrix.e);
+    EXPECT_EQ(matrix.f, arr_matrix.f);
   }
 }
 
diff --git a/core/fpdfapi/parser/cpdf_stream.cpp b/core/fpdfapi/parser/cpdf_stream.cpp
index e186bc1..d62b456 100644
--- a/core/fpdfapi/parser/cpdf_stream.cpp
+++ b/core/fpdfapi/parser/cpdf_stream.cpp
@@ -113,7 +113,7 @@
 bool CPDF_Stream::ReadRawData(FX_FILESIZE offset,
                               uint8_t* buf,
                               uint32_t size) const {
-  if (m_bMemoryBased && m_pFile)
+  if (!m_bMemoryBased && m_pFile)
     return m_pFile->ReadBlock(buf, offset, size);
 
   if (m_pDataBuf)
diff --git a/core/fpdfapi/parser/fpdf_parser_decode.cpp b/core/fpdfapi/parser/fpdf_parser_decode.cpp
index 884b5c5..480e2c1 100644
--- a/core/fpdfapi/parser/fpdf_parser_decode.cpp
+++ b/core/fpdfapi/parser/fpdf_parser_decode.cpp
@@ -500,7 +500,7 @@
   dest_buf2[1] = 0xff;
   dest_buf2 += 2;
   for (int j = 0; j < len; j++) {
-    *dest_buf2++ = pString[i] >> 8;
+    *dest_buf2++ = pString[j] >> 8;
     *dest_buf2++ = (uint8_t)pString[j];
   }
   result.ReleaseBuffer(encLen);
diff --git a/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp b/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
index 83860f9..30d30a4 100644
--- a/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
+++ b/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
@@ -76,3 +76,36 @@
     FX_Free(result);
   }
 }
+
+TEST(fpdf_parser_decode, EncodeText) {
+  struct EncodeTestData {
+    const FX_WCHAR* input;
+    const FX_CHAR* expected_output;
+    FX_STRSIZE expected_length;
+  } test_data[] = {
+      // Empty src string.
+      {L"", "", 0},
+      // ASCII text.
+      {L"the quick\tfox", "the quick\tfox", 13},
+      // Unicode text.
+      {L"\x0330\x0331", "\xFE\xFF\x03\x30\x03\x31", 6},
+      // More Unicode text.
+      {L"\x7F51\x9875\x0020\x56FE\x7247\x0020"
+       L"\x8D44\x8BAF\x66F4\x591A\x0020\x00BB",
+       "\xFE\xFF\x7F\x51\x98\x75\x00\x20\x56\xFE\x72\x47\x00"
+       "\x20\x8D\x44\x8B\xAF\x66\xF4\x59\x1A\x00\x20\x00\xBB",
+       26},
+  };
+
+  for (size_t i = 0; i < FX_ArraySize(test_data); ++i) {
+    const auto& test_case = test_data[i];
+    CFX_ByteString output = PDF_EncodeText(test_case.input);
+    ASSERT_EQ(test_case.expected_length, output.GetLength()) << "for case "
+                                                             << i;
+    const FX_CHAR* str_ptr = output.c_str();
+    for (FX_STRSIZE j = 0; j < test_case.expected_length; ++j) {
+      EXPECT_EQ(test_case.expected_output[j], str_ptr[j]) << "for case " << i
+                                                          << " char " << j;
+    }
+  }
+}
diff --git a/core/fpdfapi/render/cpdf_charposlist.cpp b/core/fpdfapi/render/cpdf_charposlist.cpp
index 4857b93..639bdcf 100644
--- a/core/fpdfapi/render/cpdf_charposlist.cpp
+++ b/core/fpdfapi/render/cpdf_charposlist.cpp
@@ -8,35 +8,36 @@
 
 #include "core/fpdfapi/font/cpdf_cidfont.h"
 #include "core/fpdfapi/font/cpdf_font.h"
+#include "third_party/base/stl_util.h"
 
 CPDF_CharPosList::CPDF_CharPosList() {
   m_pCharPos = nullptr;
+  m_nChars = 0;
 }
 
 CPDF_CharPosList::~CPDF_CharPosList() {
   FX_Free(m_pCharPos);
 }
 
-void CPDF_CharPosList::Load(int nChars,
-                            uint32_t* pCharCodes,
-                            FX_FLOAT* pCharPos,
+void CPDF_CharPosList::Load(const std::vector<uint32_t>& charCodes,
+                            const std::vector<FX_FLOAT>& charPos,
                             CPDF_Font* pFont,
                             FX_FLOAT FontSize) {
+  int nChars = pdfium::CollectionSize<int>(charCodes);
   m_pCharPos = FX_Alloc(FXTEXT_CHARPOS, nChars);
   m_nChars = 0;
   CPDF_CIDFont* pCIDFont = pFont->AsCIDFont();
   bool bVertWriting = pCIDFont && pCIDFont->IsVertWriting();
   for (int iChar = 0; iChar < nChars; iChar++) {
-    uint32_t CharCode =
-        nChars == 1 ? (uint32_t)(uintptr_t)pCharCodes : pCharCodes[iChar];
-    if (CharCode == (uint32_t)-1) {
+    uint32_t CharCode = charCodes[iChar];
+    if (CharCode == static_cast<uint32_t>(-1))
       continue;
-    }
+
     bool bVert = false;
     FXTEXT_CHARPOS& charpos = m_pCharPos[m_nChars++];
-    if (pCIDFont) {
+    if (pCIDFont)
       charpos.m_bFontStyle = true;
-    }
+
     charpos.m_GlyphIndex = pFont->GlyphFromCharCode(CharCode, &bVert);
     if (charpos.m_GlyphIndex != static_cast<uint32_t>(-1)) {
       charpos.m_FallbackFontPosition = -1;
@@ -46,39 +47,41 @@
       charpos.m_GlyphIndex = pFont->FallbackGlyphFromCharcode(
           charpos.m_FallbackFontPosition, CharCode);
     }
+
 // TODO(npm): Figure out how this affects m_ExtGID
 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
     charpos.m_ExtGID = pFont->GlyphFromCharCodeExt(CharCode);
 #endif
-    if (!pFont->IsEmbedded() && !pFont->IsCIDFont()) {
+    if (!pFont->IsEmbedded() && !pFont->IsCIDFont())
       charpos.m_FontCharWidth = pFont->GetCharWidthF(CharCode);
-    } else {
+    else
       charpos.m_FontCharWidth = 0;
-    }
-    charpos.m_OriginX = iChar ? pCharPos[iChar - 1] : 0;
-    charpos.m_OriginY = 0;
+
+    charpos.m_Origin = CFX_PointF(iChar ? charPos[iChar - 1] : 0, 0);
     charpos.m_bGlyphAdjust = false;
-    if (!pCIDFont) {
+    if (!pCIDFont)
       continue;
-    }
+
     uint16_t CID = pCIDFont->CIDFromCharCode(CharCode);
     if (bVertWriting) {
-      charpos.m_OriginY = charpos.m_OriginX;
-      charpos.m_OriginX = 0;
-      short vx, vy;
+      charpos.m_Origin = CFX_PointF(0, charpos.m_Origin.x);
+
+      short vx;
+      short vy;
       pCIDFont->GetVertOrigin(CID, vx, vy);
-      charpos.m_OriginX -= FontSize * vx / 1000;
-      charpos.m_OriginY -= FontSize * vy / 1000;
+      charpos.m_Origin.x -= FontSize * vx / 1000;
+      charpos.m_Origin.y -= FontSize * vy / 1000;
     }
+
     const uint8_t* pTransform = pCIDFont->GetCIDTransform(CID);
     if (pTransform && !bVert) {
       charpos.m_AdjustMatrix[0] = pCIDFont->CIDTransformToFloat(pTransform[0]);
       charpos.m_AdjustMatrix[2] = pCIDFont->CIDTransformToFloat(pTransform[2]);
       charpos.m_AdjustMatrix[1] = pCIDFont->CIDTransformToFloat(pTransform[1]);
       charpos.m_AdjustMatrix[3] = pCIDFont->CIDTransformToFloat(pTransform[3]);
-      charpos.m_OriginX +=
+      charpos.m_Origin.x +=
           pCIDFont->CIDTransformToFloat(pTransform[4]) * FontSize;
-      charpos.m_OriginY +=
+      charpos.m_Origin.y +=
           pCIDFont->CIDTransformToFloat(pTransform[5]) * FontSize;
       charpos.m_bGlyphAdjust = true;
     }
diff --git a/core/fpdfapi/render/cpdf_charposlist.h b/core/fpdfapi/render/cpdf_charposlist.h
index 9fa3c2c..2f5a44d 100644
--- a/core/fpdfapi/render/cpdf_charposlist.h
+++ b/core/fpdfapi/render/cpdf_charposlist.h
@@ -7,6 +7,8 @@
 #ifndef CORE_FPDFAPI_RENDER_CPDF_CHARPOSLIST_H_
 #define CORE_FPDFAPI_RENDER_CPDF_CHARPOSLIST_H_
 
+#include <vector>
+
 #include "core/fxcrt/fx_system.h"
 #include "core/fxge/cfx_renderdevice.h"
 
@@ -16,9 +18,8 @@
  public:
   CPDF_CharPosList();
   ~CPDF_CharPosList();
-  void Load(int nChars,
-            uint32_t* pCharCodes,
-            FX_FLOAT* pCharPos,
+  void Load(const std::vector<uint32_t>& charCodes,
+            const std::vector<FX_FLOAT>& charPos,
             CPDF_Font* pFont,
             FX_FLOAT font_size);
   FXTEXT_CHARPOS* m_pCharPos;
diff --git a/core/fpdfapi/render/cpdf_devicebuffer.cpp b/core/fpdfapi/render/cpdf_devicebuffer.cpp
index edc9180..dec1343 100644
--- a/core/fpdfapi/render/cpdf_devicebuffer.cpp
+++ b/core/fpdfapi/render/cpdf_devicebuffer.cpp
@@ -28,7 +28,7 @@
   m_pContext = pContext;
   m_Rect = *pRect;
   m_pObject = pObj;
-  m_Matrix.TranslateI(-pRect->left, -pRect->top);
+  m_Matrix.Translate(-pRect->left, -pRect->top);
 #if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_
   int horz_size = pDevice->GetDeviceCaps(FXDC_HORZ_SIZE);
   int vert_size = pDevice->GetDeviceCaps(FXDC_VERT_SIZE);
@@ -44,11 +44,11 @@
   }
 #endif
   CFX_Matrix ctm = m_pDevice->GetCTM();
-  FX_FLOAT fScaleX = FXSYS_fabs(ctm.a);
-  FX_FLOAT fScaleY = FXSYS_fabs(ctm.d);
-  m_Matrix.Concat(fScaleX, 0, 0, fScaleY, 0, 0);
+  m_Matrix.Concat(CFX_Matrix(FXSYS_fabs(ctm.a), 0, 0, FXSYS_fabs(ctm.d), 0, 0));
+
   CFX_FloatRect rect(*pRect);
   m_Matrix.TransformRect(rect);
+
   FX_RECT bitmap_rect = rect.GetOuterRect();
   m_pBitmap = pdfium::MakeUnique<CFX_DIBitmap>();
   m_pBitmap->Create(bitmap_rect.Width(), bitmap_rect.Height(), FXDIB_Argb);
diff --git a/core/fpdfapi/render/cpdf_imagerenderer.cpp b/core/fpdfapi/render/cpdf_imagerenderer.cpp
index ad713d0..358d13e 100644
--- a/core/fpdfapi/render/cpdf_imagerenderer.cpp
+++ b/core/fpdfapi/render/cpdf_imagerenderer.cpp
@@ -239,7 +239,7 @@
 
 CFX_Matrix CPDF_ImageRenderer::GetDrawMatrix(const FX_RECT& rect) const {
   CFX_Matrix new_matrix = m_ImageMatrix;
-  new_matrix.TranslateI(-rect.left, -rect.top);
+  new_matrix.Translate(-rect.left, -rect.top);
   return new_matrix;
 }
 
diff --git a/core/fpdfapi/render/cpdf_renderoptions.cpp b/core/fpdfapi/render/cpdf_renderoptions.cpp
index ea11d7f..717e036 100644
--- a/core/fpdfapi/render/cpdf_renderoptions.cpp
+++ b/core/fpdfapi/render/cpdf_renderoptions.cpp
@@ -11,7 +11,6 @@
       m_Flags(RENDER_CLEARTYPE),
       m_Interpolation(0),
       m_AddFlags(0),
-      m_pOCContext(nullptr),
       m_dwLimitCacheSize(1024 * 1024 * 100),
       m_HalftoneLimit(-1),
       m_bDrawAnnots(false) {}
@@ -23,10 +22,12 @@
       m_Flags(rhs.m_Flags),
       m_Interpolation(rhs.m_Interpolation),
       m_AddFlags(rhs.m_AddFlags),
-      m_pOCContext(rhs.m_pOCContext),
       m_dwLimitCacheSize(rhs.m_dwLimitCacheSize),
       m_HalftoneLimit(rhs.m_HalftoneLimit),
-      m_bDrawAnnots(rhs.m_bDrawAnnots) {}
+      m_bDrawAnnots(rhs.m_bDrawAnnots),
+      m_pOCContext(rhs.m_pOCContext) {}
+
+CPDF_RenderOptions::~CPDF_RenderOptions() {}
 
 FX_ARGB CPDF_RenderOptions::TranslateColor(FX_ARGB argb) const {
   if (m_ColorMode == RENDER_COLOR_NORMAL)
diff --git a/core/fpdfapi/render/cpdf_renderoptions.h b/core/fpdfapi/render/cpdf_renderoptions.h
index 95651d9..b934941 100644
--- a/core/fpdfapi/render/cpdf_renderoptions.h
+++ b/core/fpdfapi/render/cpdf_renderoptions.h
@@ -7,11 +7,11 @@
 #ifndef CORE_FPDFAPI_RENDER_CPDF_RENDEROPTIONS_H_
 #define CORE_FPDFAPI_RENDER_CPDF_RENDEROPTIONS_H_
 
+#include "core/fpdfdoc/cpdf_occontext.h"
+#include "core/fxcrt/cfx_retain_ptr.h"
 #include "core/fxcrt/fx_system.h"
 #include "core/fxge/fx_dib.h"
 
-class CPDF_OCContext;
-
 #define RENDER_COLOR_NORMAL 0
 #define RENDER_COLOR_GRAY 1
 #define RENDER_COLOR_TWOCOLOR 2
@@ -37,6 +37,8 @@
  public:
   CPDF_RenderOptions();
   CPDF_RenderOptions(const CPDF_RenderOptions& rhs);
+  ~CPDF_RenderOptions();
+
   FX_ARGB TranslateColor(FX_ARGB argb) const;
 
   int m_ColorMode;
@@ -45,10 +47,10 @@
   uint32_t m_Flags;
   int m_Interpolation;
   uint32_t m_AddFlags;
-  CPDF_OCContext* m_pOCContext;
   uint32_t m_dwLimitCacheSize;
   int m_HalftoneLimit;
   bool m_bDrawAnnots;
+  CFX_RetainPtr<CPDF_OCContext> m_pOCContext;
 };
 
 #endif  // CORE_FPDFAPI_RENDER_CPDF_RENDEROPTIONS_H_
diff --git a/core/fpdfapi/render/cpdf_renderstatus.cpp b/core/fpdfapi/render/cpdf_renderstatus.cpp
index 35d0616..9022212 100644
--- a/core/fpdfapi/render/cpdf_renderstatus.cpp
+++ b/core/fpdfapi/render/cpdf_renderstatus.cpp
@@ -159,10 +159,11 @@
   for (int row = 0; row < height; row++) {
     uint32_t* dib_buf = (uint32_t*)(pBitmap->GetBuffer() + row * pitch);
     for (int column = 0; column < width; column++) {
-      FX_FLOAT x = (FX_FLOAT)column, y = (FX_FLOAT)row;
-      matrix.Transform(x, y);
-      FX_FLOAT scale = (((x - start_x) * x_span) + ((y - start_y) * y_span)) /
-                       axis_len_square;
+      CFX_PointF pos = matrix.Transform(CFX_PointF(
+          static_cast<FX_FLOAT>(column), static_cast<FX_FLOAT>(row)));
+      FX_FLOAT scale =
+          (((pos.x - start_x) * x_span) + ((pos.y - start_y) * y_span)) /
+          axis_len_square;
       int index = (int32_t)(scale * (SHADING_STEPS - 1));
       if (index < 0) {
         if (!bStartExtend)
@@ -252,13 +253,14 @@
   for (int row = 0; row < height; row++) {
     uint32_t* dib_buf = (uint32_t*)(pBitmap->GetBuffer() + row * pitch);
     for (int column = 0; column < width; column++) {
-      FX_FLOAT x = (FX_FLOAT)column, y = (FX_FLOAT)row;
-      matrix.Transform(x, y);
-      FX_FLOAT b = -2 * (((x - start_x) * (end_x - start_x)) +
-                         ((y - start_y) * (end_y - start_y)) +
+      CFX_PointF pos = matrix.Transform(CFX_PointF(
+          static_cast<FX_FLOAT>(column), static_cast<FX_FLOAT>(row)));
+      FX_FLOAT b = -2 * (((pos.x - start_x) * (end_x - start_x)) +
+                         ((pos.y - start_y) * (end_y - start_y)) +
                          (start_r * (end_r - start_r)));
-      FX_FLOAT c = ((x - start_x) * (x - start_x)) +
-                   ((y - start_y) * (y - start_y)) - (start_r * start_r);
+      FX_FLOAT c = ((pos.x - start_x) * (pos.x - start_x)) +
+                   ((pos.y - start_y) * (pos.y - start_y)) -
+                   (start_r * start_r);
       FX_FLOAT s;
       if (a == 0) {
         s = -c / b;
@@ -327,8 +329,10 @@
     ymax = pDomain->GetNumberAt(3);
   }
   CFX_Matrix mtDomain2Target = pDict->GetMatrixFor("Matrix");
-  CFX_Matrix matrix, reverse_matrix;
+  CFX_Matrix matrix;
   matrix.SetReverse(*pObject2Bitmap);
+
+  CFX_Matrix reverse_matrix;
   reverse_matrix.SetReverse(mtDomain2Target);
   matrix.Concat(reverse_matrix);
   int width = pBitmap->GetWidth();
@@ -342,15 +346,13 @@
   for (int row = 0; row < height; row++) {
     uint32_t* dib_buf = (uint32_t*)(pBitmap->GetBuffer() + row * pitch);
     for (int column = 0; column < width; column++) {
-      FX_FLOAT x = (FX_FLOAT)column, y = (FX_FLOAT)row;
-      matrix.Transform(x, y);
-      if (x < xmin || x > xmax || y < ymin || y > ymax) {
+      CFX_PointF pos = matrix.Transform(CFX_PointF(
+          static_cast<FX_FLOAT>(column), static_cast<FX_FLOAT>(row)));
+      if (pos.x < xmin || pos.x > xmax || pos.y < ymin || pos.y > ymax)
         continue;
-      }
-      FX_FLOAT input[2];
+
+      FX_FLOAT input[] = {pos.x, pos.y};
       int offset = 0;
-      input[0] = x;
-      input[1] = y;
       for (const auto& func : funcs) {
         if (func) {
           int nresults;
@@ -358,7 +360,10 @@
             offset += nresults;
         }
       }
-      FX_FLOAT R = 0.0f, G = 0.0f, B = 0.0f;
+
+      FX_FLOAT R = 0.0f;
+      FX_FLOAT G = 0.0f;
+      FX_FLOAT B = 0.0f;
       pCS->GetRGB(pResults, R, G, B);
       dib_buf[column] = FXARGB_TODIB(FXARGB_MAKE(
           alpha, (int32_t)(R * 255), (int32_t)(G * 255), (int32_t)(B * 255)));
@@ -367,67 +372,65 @@
 }
 
 bool GetScanlineIntersect(int y,
-                          FX_FLOAT x1,
-                          FX_FLOAT y1,
-                          FX_FLOAT x2,
-                          FX_FLOAT y2,
+                          const CFX_PointF& first,
+                          const CFX_PointF& second,
                           FX_FLOAT* x) {
-  if (y1 == y2)
+  if (first.y == second.y)
     return false;
 
-  if (y1 < y2) {
-    if (y < y1 || y > y2)
+  if (first.y < second.y) {
+    if (y < first.y || y > second.y)
       return false;
-  } else {
-    if (y < y2 || y > y1)
-      return false;
+  } else if (y < second.y || y > first.y) {
+    return false;
   }
-  *x = x1 + ((x2 - x1) * (y - y1) / (y2 - y1));
+  *x = first.x + ((second.x - first.x) * (y - first.y) / (second.y - first.y));
   return true;
 }
 
 void DrawGouraud(CFX_DIBitmap* pBitmap,
                  int alpha,
                  CPDF_MeshVertex triangle[3]) {
-  FX_FLOAT min_y = triangle[0].y, max_y = triangle[0].y;
+  FX_FLOAT min_y = triangle[0].position.y;
+  FX_FLOAT max_y = triangle[0].position.y;
   for (int i = 1; i < 3; i++) {
-    if (min_y > triangle[i].y) {
-      min_y = triangle[i].y;
-    }
-    if (max_y < triangle[i].y) {
-      max_y = triangle[i].y;
-    }
+    min_y = std::min(min_y, triangle[i].position.y);
+    max_y = std::max(max_y, triangle[i].position.y);
   }
-  if (min_y == max_y) {
+  if (min_y == max_y)
     return;
-  }
-  int min_yi = (int)FXSYS_floor(min_y), max_yi = (int)FXSYS_ceil(max_y);
-  if (min_yi < 0) {
-    min_yi = 0;
-  }
-  if (max_yi >= pBitmap->GetHeight()) {
+
+  int min_yi = std::max(static_cast<int>(FXSYS_floor(min_y)), 0);
+  int max_yi = static_cast<int>(FXSYS_ceil(max_y));
+
+  if (max_yi >= pBitmap->GetHeight())
     max_yi = pBitmap->GetHeight() - 1;
-  }
+
   for (int y = min_yi; y <= max_yi; y++) {
     int nIntersects = 0;
-    FX_FLOAT inter_x[3], r[3], g[3], b[3];
+    FX_FLOAT inter_x[3];
+    FX_FLOAT r[3];
+    FX_FLOAT g[3];
+    FX_FLOAT b[3];
     for (int i = 0; i < 3; i++) {
       CPDF_MeshVertex& vertex1 = triangle[i];
       CPDF_MeshVertex& vertex2 = triangle[(i + 1) % 3];
-      bool bIntersect = GetScanlineIntersect(y, vertex1.x, vertex1.y, vertex2.x,
-                                             vertex2.y, &inter_x[nIntersects]);
+      CFX_PointF& position1 = vertex1.position;
+      CFX_PointF& position2 = vertex2.position;
+      bool bIntersect =
+          GetScanlineIntersect(y, position1, position2, &inter_x[nIntersects]);
       if (!bIntersect)
         continue;
 
-      FX_FLOAT y_dist = (y - vertex1.y) / (vertex2.y - vertex1.y);
+      FX_FLOAT y_dist = (y - position1.y) / (position2.y - position1.y);
       r[nIntersects] = vertex1.r + ((vertex2.r - vertex1.r) * y_dist);
       g[nIntersects] = vertex1.g + ((vertex2.g - vertex1.g) * y_dist);
       b[nIntersects] = vertex1.b + ((vertex2.b - vertex1.b) * y_dist);
       nIntersects++;
     }
-    if (nIntersects != 2) {
+    if (nIntersects != 2)
       continue;
-    }
+
     int min_x, max_x, start_index, end_index;
     if (inter_x[0] < inter_x[1]) {
       min_x = (int)FXSYS_floor(inter_x[0]);
@@ -440,13 +443,12 @@
       start_index = 1;
       end_index = 0;
     }
-    int start_x = min_x, end_x = max_x;
-    if (start_x < 0) {
-      start_x = 0;
-    }
-    if (end_x > pBitmap->GetWidth()) {
+
+    int start_x = std::max(min_x, 0);
+    int end_x = max_x;
+    if (end_x > pBitmap->GetWidth())
       end_x = pBitmap->GetWidth();
-    }
+
     uint8_t* dib_buf =
         pBitmap->GetBuffer() + y * pBitmap->GetPitch() + start_x * 4;
     FX_FLOAT r_unit = (r[end_index] - r[start_index]) / (max_x - min_x);
@@ -486,16 +488,21 @@
 
   while (!stream.BitStream()->IsEOF()) {
     CPDF_MeshVertex vertex;
-    uint32_t flag = stream.GetVertex(vertex, pObject2Bitmap);
+    uint32_t flag;
+    if (!stream.ReadVertex(*pObject2Bitmap, &vertex, &flag))
+      return;
+
     if (flag == 0) {
       triangle[0] = vertex;
       for (int j = 1; j < 3; j++) {
-        stream.GetVertex(triangle[j], pObject2Bitmap);
+        uint32_t tflag;
+        if (!stream.ReadVertex(*pObject2Bitmap, &triangle[j], &tflag))
+          return;
       }
     } else {
-      if (flag == 1) {
+      if (flag == 1)
         triangle[0] = triangle[1];
-      }
+
       triangle[1] = triangle[2];
       triangle[2] = vertex;
     }
@@ -523,14 +530,14 @@
 
   std::unique_ptr<CPDF_MeshVertex, FxFreeDeleter> vertex(
       FX_Alloc2D(CPDF_MeshVertex, row_verts, 2));
-  if (!stream.GetVertexRow(vertex.get(), row_verts, pObject2Bitmap))
+  if (!stream.ReadVertexRow(*pObject2Bitmap, row_verts, vertex.get()))
     return;
 
   int last_index = 0;
   while (1) {
     CPDF_MeshVertex* last_row = vertex.get() + last_index * row_verts;
     CPDF_MeshVertex* this_row = vertex.get() + (1 - last_index) * row_verts;
-    if (!stream.GetVertexRow(this_row, row_verts, pObject2Bitmap))
+    if (!stream.ReadVertexRow(*pObject2Bitmap, row_verts, this_row))
       return;
 
     CPDF_MeshVertex triangle[3];
@@ -611,18 +618,21 @@
     x.FromPoints(x0, x1, x2, x3);
     y.FromPoints(y0, y1, y2, y3);
   }
+
   Coon_Bezier first_half() {
     Coon_Bezier result;
     result.x = x.first_half();
     result.y = y.first_half();
     return result;
   }
+
   Coon_Bezier second_half() {
     Coon_Bezier result;
     result.x = x.second_half();
     result.y = y.second_half();
     return result;
   }
+
   void BezierInterpol(Coon_Bezier& C1,
                       Coon_Bezier& C2,
                       Coon_Bezier& D1,
@@ -630,30 +640,31 @@
     x.BezierInterpol(C1.x, C2.x, D1.x, D2.x);
     y.BezierInterpol(C1.y, C2.y, D1.y, D2.y);
   }
-  void GetPoints(FX_PATHPOINT* pPoints) {
+
+  void GetPoints(std::vector<FX_PATHPOINT>& pPoints, size_t start_idx) {
     float p[4];
     int i;
     x.GetPoints(p);
-    for (i = 0; i < 4; i++) {
-      pPoints[i].m_PointX = p[i];
-    }
+    for (i = 0; i < 4; i++)
+      pPoints[start_idx + i].m_Point.x = p[i];
+
     y.GetPoints(p);
-    for (i = 0; i < 4; i++) {
-      pPoints[i].m_PointY = p[i];
-    }
+    for (i = 0; i < 4; i++)
+      pPoints[start_idx + i].m_Point.y = p[i];
   }
-  void GetPointsReverse(FX_PATHPOINT* pPoints) {
+
+  void GetPointsReverse(std::vector<FX_PATHPOINT>& pPoints, size_t start_idx) {
     float p[4];
     int i;
     x.GetPointsReverse(p);
-    for (i = 0; i < 4; i++) {
-      pPoints[i].m_PointX = p[i];
-    }
+    for (i = 0; i < 4; i++)
+      pPoints[i + start_idx].m_Point.x = p[i];
+
     y.GetPointsReverse(p);
-    for (i = 0; i < 4; i++) {
-      pPoints[i].m_PointY = p[i];
-    }
+    for (i = 0; i < 4; i++)
+      pPoints[i + start_idx].m_Point.y = p[i];
   }
+
   float Distance() { return x.Distance() + y.Distance(); }
 };
 
@@ -693,6 +704,7 @@
   }
 };
 
+#define COONCOLOR_THRESHOLD 4
 struct CPDF_PatchDrawer {
   Coon_Color patch_colors[4];
   int max_delta;
@@ -728,15 +740,15 @@
       d_top = div_colors[1].Distance(div_colors[2]);
       d_right = div_colors[2].Distance(div_colors[3]);
     }
-#define COONCOLOR_THRESHOLD 4
+
     if (bSmall ||
         (d_bottom < COONCOLOR_THRESHOLD && d_left < COONCOLOR_THRESHOLD &&
          d_top < COONCOLOR_THRESHOLD && d_right < COONCOLOR_THRESHOLD)) {
-      FX_PATHPOINT* pPoints = path.GetPoints();
-      C1.GetPoints(pPoints);
-      D2.GetPoints(pPoints + 3);
-      C2.GetPointsReverse(pPoints + 6);
-      D1.GetPointsReverse(pPoints + 9);
+      std::vector<FX_PATHPOINT>& pPoints = path.GetPoints();
+      C1.GetPoints(pPoints, 0);
+      D2.GetPoints(pPoints, 3);
+      C2.GetPointsReverse(pPoints, 6);
+      D1.GetPointsReverse(pPoints, 9);
       int fillFlags = FXFILL_WINDING | FXFILL_FULLCOVER;
       if (fill_mode & RENDER_NOPATHSMOOTH) {
         fillFlags |= FXFILL_NOPATHSMOOTH;
@@ -814,15 +826,18 @@
   patch.alpha = alpha;
   patch.pDevice = &device;
   patch.fill_mode = fill_mode;
-  patch.path.SetPointCount(13);
-  FX_PATHPOINT* pPoints = patch.path.GetPoints();
-  pPoints[0].m_Flag = FXPT_MOVETO;
-  for (int i = 1; i < 13; i++)
-    pPoints[i].m_Flag = FXPT_BEZIERTO;
+
+  for (int i = 0; i < 13; i++) {
+    patch.path.AppendPoint(
+        CFX_PointF(), i == 0 ? FXPT_TYPE::MoveTo : FXPT_TYPE::BezierTo, false);
+  }
+
   CFX_PointF coords[16];
   int point_count = type == kTensorProductPatchMeshShading ? 16 : 12;
   while (!stream.BitStream()->IsEOF()) {
-    uint32_t flag = stream.GetFlag();
+    if (!stream.CanReadFlag())
+      break;
+    uint32_t flag = stream.ReadFlag();
     int iStartPoint = 0, iStartColor = 0, i = 0;
     if (flag) {
       iStartPoint = 4;
@@ -838,12 +853,20 @@
       FXSYS_memcpy(patch.patch_colors, tempColors, sizeof(Coon_Color) * 2);
     }
     for (i = iStartPoint; i < point_count; i++) {
-      stream.GetCoords(coords[i].x, coords[i].y);
-      pObject2Bitmap->Transform(coords[i].x, coords[i].y);
+      if (!stream.CanReadCoords())
+        break;
+      coords[i] = pObject2Bitmap->Transform(stream.ReadCoords());
     }
+
     for (i = iStartColor; i < 4; i++) {
-      FX_FLOAT r = 0.0f, g = 0.0f, b = 0.0f;
-      stream.GetColor(r, g, b);
+      if (!stream.CanReadColor())
+        break;
+
+      FX_FLOAT r;
+      FX_FLOAT g;
+      FX_FLOAT b;
+      std::tie(r, g, b) = stream.ReadColor();
+
       patch.patch_colors[i].comp[0] = (int32_t)(r * 255);
       patch.patch_colors[i].comp[1] = (int32_t)(g * 255);
       patch.patch_colors[i].comp[2] = (int32_t)(b * 255);
@@ -888,6 +911,7 @@
   CFX_FloatRect bitmap_rect(0.0f, 0.0f, (FX_FLOAT)width, (FX_FLOAT)height);
   CFX_Matrix mtAdjust;
   mtAdjust.MatchRect(bitmap_rect, cell_bbox);
+
   CFX_Matrix mtPattern2Bitmap = *pObject2Device;
   mtPattern2Bitmap.Concat(mtAdjust);
   CPDF_RenderOptions options;
@@ -1360,7 +1384,7 @@
     if (!pPathData)
       continue;
 
-    if (pPathData->GetPointCount() == 0) {
+    if (pPathData->GetPoints().empty()) {
       CFX_PathData EmptyPath;
       EmptyPath.AppendRect(-1, -1, 0, 0);
       int fill_mode = FXFILL_WINDING;
@@ -1525,7 +1549,7 @@
   CFX_DIBitmap* bitmap = bitmap_device.GetBitmap();
   bitmap->Clear(0);
   CFX_Matrix new_matrix = *pObj2Device;
-  new_matrix.TranslateI(-rect.left, -rect.top);
+  new_matrix.Translate(-rect.left, -rect.top);
   new_matrix.Scale(scaleX, scaleY);
   std::unique_ptr<CFX_DIBitmap> pTextMask;
   if (bTextClip) {
@@ -1538,16 +1562,15 @@
     text_device.Attach(pTextMask.get(), false, nullptr, false);
     for (uint32_t i = 0; i < pPageObj->m_ClipPath.GetTextCount(); i++) {
       CPDF_TextObject* textobj = pPageObj->m_ClipPath.GetText(i);
-      if (!textobj) {
+      if (!textobj)
         break;
-      }
-      CFX_Matrix text_matrix;
-      textobj->GetTextMatrix(&text_matrix);
+
+      CFX_Matrix text_matrix = textobj->GetTextMatrix();
       CPDF_TextRenderer::DrawTextPath(
-          &text_device, textobj->m_nChars, textobj->m_pCharCodes,
-          textobj->m_pCharPos, textobj->m_TextState.GetFont(),
-          textobj->m_TextState.GetFontSize(), &text_matrix, &new_matrix,
-          textobj->m_GraphState.GetObject(), (FX_ARGB)-1, 0, nullptr, 0);
+          &text_device, textobj->m_CharCodes, textobj->m_CharPos,
+          textobj->m_TextState.GetFont(), textobj->m_TextState.GetFontSize(),
+          &text_matrix, &new_matrix, textobj->m_GraphState.GetObject(),
+          (FX_ARGB)-1, 0, nullptr, 0);
     }
   }
   CPDF_RenderStatus bitmap_render;
@@ -1628,7 +1651,7 @@
   }
 
   CFX_Matrix FinalMatrix = m_DeviceMatrix;
-  FinalMatrix.TranslateI(-left, -top);
+  FinalMatrix.Translate(-left, -top);
   FinalMatrix.Scale(scaleX, scaleY);
   pBackdrop->Clear(pBackdrop->HasAlpha() ? 0 : 0xffffffff);
   CFX_FxgeDevice device;
@@ -1666,7 +1689,7 @@
 bool CPDF_RenderStatus::ProcessText(CPDF_TextObject* textobj,
                                     const CFX_Matrix* pObj2Device,
                                     CFX_PathData* pClippingPath) {
-  if (textobj->m_nChars == 0)
+  if (textobj->m_CharCodes.empty())
     return true;
 
   const TextRenderingMode text_render_mode = textobj->m_TextState.GetTextMode();
@@ -1726,8 +1749,7 @@
       fill_argb = GetFillArgb(textobj);
     }
   }
-  CFX_Matrix text_matrix;
-  textobj->GetTextMatrix(&text_matrix);
+  CFX_Matrix text_matrix = textobj->GetTextMatrix();
   if (!IsAvailableMatrix(text_matrix))
     return true;
 
@@ -1760,15 +1782,14 @@
     if (m_Options.m_Flags & RENDER_NOTEXTSMOOTH)
       flag |= FXFILL_NOPATHSMOOTH;
     return CPDF_TextRenderer::DrawTextPath(
-        m_pDevice, textobj->m_nChars, textobj->m_pCharCodes,
-        textobj->m_pCharPos, pFont, font_size, &text_matrix, pDeviceMatrix,
-        textobj->m_GraphState.GetObject(), fill_argb, stroke_argb,
-        pClippingPath, flag);
+        m_pDevice, textobj->m_CharCodes, textobj->m_CharPos, pFont, font_size,
+        &text_matrix, pDeviceMatrix, textobj->m_GraphState.GetObject(),
+        fill_argb, stroke_argb, pClippingPath, flag);
   }
   text_matrix.Concat(*pObj2Device);
-  return CPDF_TextRenderer::DrawNormalText(
-      m_pDevice, textobj->m_nChars, textobj->m_pCharCodes, textobj->m_pCharPos,
-      pFont, font_size, &text_matrix, fill_argb, &m_Options);
+  return CPDF_TextRenderer::DrawNormalText(m_pDevice, textobj->m_CharCodes,
+                                           textobj->m_CharPos, pFont, font_size,
+                                           &text_matrix, fill_argb, &m_Options);
 }
 
 CPDF_Type3Cache* CPDF_RenderStatus::GetCachedType3(CPDF_Type3Font* pFont) {
@@ -1789,8 +1810,7 @@
   CFX_Matrix dCTM = m_pDevice->GetCTM();
   FX_FLOAT sa = FXSYS_fabs(dCTM.a);
   FX_FLOAT sd = FXSYS_fabs(dCTM.d);
-  CFX_Matrix text_matrix;
-  textobj->GetTextMatrix(&text_matrix);
+  CFX_Matrix text_matrix = textobj->GetTextMatrix();
   CFX_Matrix char_matrix = pType3Font->GetFontMatrix();
   FX_FLOAT font_size = textobj->m_TextState.GetFontSize();
   char_matrix.Scale(font_size, font_size);
@@ -1799,18 +1819,15 @@
   int device_class = m_pDevice->GetDeviceClass();
   std::vector<FXTEXT_GLYPHPOS> glyphs;
   if (device_class == FXDC_DISPLAY)
-    glyphs.resize(textobj->m_nChars);
+    glyphs.resize(textobj->m_CharCodes.size());
   else if (fill_alpha < 255)
     return false;
 
   CPDF_RefType3Cache refTypeCache(pType3Font);
-  uint32_t* pChars = textobj->m_pCharCodes;
-  if (textobj->m_nChars == 1)
-    pChars = (uint32_t*)(&textobj->m_pCharCodes);
-
-  for (int iChar = 0; iChar < textobj->m_nChars; iChar++) {
-    uint32_t charcode = pChars[iChar];
-    if (charcode == (uint32_t)-1)
+  for (int iChar = 0; iChar < pdfium::CollectionSize<int>(textobj->m_CharCodes);
+       iChar++) {
+    uint32_t charcode = textobj->m_CharCodes[iChar];
+    if (charcode == static_cast<uint32_t>(-1))
       continue;
 
     CPDF_Type3Char* pType3Char = pType3Font->LoadChar(charcode);
@@ -1818,7 +1835,7 @@
       continue;
 
     CFX_Matrix matrix = char_matrix;
-    matrix.e += iChar ? textobj->m_pCharPos[iChar - 1] : 0;
+    matrix.e += iChar ? textobj->m_CharPos[iChar - 1] : 0;
     matrix.Concat(text_matrix);
     matrix.Concat(*pObj2Device);
     if (!pType3Char->LoadBitmap(m_pContext)) {
@@ -1829,8 +1846,8 @@
             continue;
 
           m_pDevice->SetBitMask(&glyph.m_pGlyph->m_Bitmap,
-                                glyph.m_OriginX + glyph.m_pGlyph->m_Left,
-                                glyph.m_OriginY - glyph.m_pGlyph->m_Top,
+                                glyph.m_Origin.x + glyph.m_pGlyph->m_Left,
+                                glyph.m_Origin.y - glyph.m_pGlyph->m_Top,
                                 fill_argb);
         }
         glyphs.clear();
@@ -1857,7 +1874,8 @@
         m_pDevice->RestoreState(false);
       } else {
         CFX_FloatRect rect_f = pType3Char->m_pForm->CalcBoundingBox();
-        rect_f.Transform(&matrix);
+        matrix.TransformRect(rect_f);
+
         FX_RECT rect = rect_f.GetOuterRect();
         CFX_FxgeDevice bitmap_device;
         if (!bitmap_device.Create((int)(rect.Width() * sa),
@@ -1873,7 +1891,7 @@
                           pFormResource, false, pType3Char, fill_argb);
         status.m_Type3FontCache = m_Type3FontCache;
         status.m_Type3FontCache.push_back(pType3Font);
-        matrix.TranslateI(-rect.left, -rect.top);
+        matrix.Translate(-rect.left, -rect.top);
         matrix.Scale(sa, sd);
         status.RenderObjectList(pType3Char->m_pForm.get(), &matrix);
         m_pDevice->SetDIBits(bitmap_device.GetBitmap(), rect.left, rect.top);
@@ -1887,15 +1905,13 @@
         if (!pBitmap)
           continue;
 
-        int origin_x = FXSYS_round(matrix.e);
-        int origin_y = FXSYS_round(matrix.f);
+        CFX_Point origin(FXSYS_round(matrix.e), FXSYS_round(matrix.f));
         if (glyphs.empty()) {
-          m_pDevice->SetBitMask(&pBitmap->m_Bitmap, origin_x + pBitmap->m_Left,
-                                origin_y - pBitmap->m_Top, fill_argb);
+          m_pDevice->SetBitMask(&pBitmap->m_Bitmap, origin.x + pBitmap->m_Left,
+                                origin.y - pBitmap->m_Top, fill_argb);
         } else {
           glyphs[iChar].m_pGlyph = pBitmap;
-          glyphs[iChar].m_OriginX = origin_x;
-          glyphs[iChar].m_OriginY = origin_y;
+          glyphs[iChar].m_Origin = origin;
         }
       } else {
         CFX_Matrix image_matrix = pType3Char->m_ImageMatrix;
@@ -1925,14 +1941,14 @@
     if (!glyph.m_pGlyph)
       continue;
 
-    pdfium::base::CheckedNumeric<int> left = glyph.m_OriginX;
+    pdfium::base::CheckedNumeric<int> left = glyph.m_Origin.x;
     left += glyph.m_pGlyph->m_Left;
     left -= rect.left;
     left *= sa;
     if (!left.IsValid())
       continue;
 
-    pdfium::base::CheckedNumeric<int> top = glyph.m_OriginY;
+    pdfium::base::CheckedNumeric<int> top = glyph.m_Origin.y;
     top -= glyph.m_pGlyph->m_Top;
     top -= rect.top;
     top *= sd;
@@ -1974,8 +1990,7 @@
     return;
   }
   CPDF_CharPosList CharPosList;
-  CharPosList.Load(textobj->m_nChars, textobj->m_pCharCodes,
-                   textobj->m_pCharPos, pFont, font_size);
+  CharPosList.Load(textobj->m_CharCodes, textobj->m_CharPos, pFont, font_size);
   for (uint32_t i = 0; i < CharPosList.m_nChars; i++) {
     FXTEXT_CHARPOS& charpos = CharPosList.m_pCharPos[i];
     auto font =
@@ -1984,18 +1999,21 @@
             : pFont->m_FontFallbacks[charpos.m_FallbackFontPosition].get();
     const CFX_PathData* pPath =
         font->LoadGlyphPath(charpos.m_GlyphIndex, charpos.m_FontCharWidth);
-    if (!pPath) {
+    if (!pPath)
       continue;
-    }
+
     CPDF_PathObject path;
     path.m_GraphState = textobj->m_GraphState;
     path.m_ColorState = textobj->m_ColorState;
+
     CFX_Matrix matrix;
-    if (charpos.m_bGlyphAdjust)
-      matrix.Set(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
-                 charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
-    matrix.Concat(font_size, 0, 0, font_size, charpos.m_OriginX,
-                  charpos.m_OriginY);
+    if (charpos.m_bGlyphAdjust) {
+      matrix = CFX_Matrix(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
+                          charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3],
+                          0, 0);
+    }
+    matrix.Concat(CFX_Matrix(font_size, 0, 0, font_size, charpos.m_Origin.x,
+                             charpos.m_Origin.y));
     path.m_Path.Append(pPath, &matrix);
     path.m_Matrix = *pTextMatrix;
     path.m_bStroke = bStroke;
@@ -2032,7 +2050,7 @@
   }
   if (pDict->KeyExist("BBox")) {
     CFX_FloatRect rect = pDict->GetRectFor("BBox");
-    rect.Transform(pMatrix);
+    pMatrix->TransformRect(rect);
     clip_rect.Intersect(rect.GetOuterRect());
   }
   if (m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SHADING &&
@@ -2198,8 +2216,9 @@
   int min_col, max_col, min_row, max_row;
   CFX_Matrix mtDevice2Pattern;
   mtDevice2Pattern.SetReverse(mtPattern2Device);
+
   CFX_FloatRect clip_box_p(clip_box);
-  clip_box_p.Transform(&mtDevice2Pattern);
+  mtDevice2Pattern.TransformRect(clip_box_p);
 
   min_col = (int)FXSYS_ceil((clip_box_p.left - pPattern->bbox().right) /
                             pPattern->x_step());
@@ -2222,13 +2241,11 @@
 
     for (int col = min_col; col <= max_col; col++)
       for (int row = min_row; row <= max_row; row++) {
-        FX_FLOAT orig_x, orig_y;
-        orig_x = col * pPattern->x_step();
-        orig_y = row * pPattern->y_step();
-        mtPattern2Device.Transform(orig_x, orig_y);
+        CFX_PointF original = mtPattern2Device.Transform(
+            CFX_PointF(col * pPattern->x_step(), row * pPattern->y_step()));
         CFX_Matrix matrix = *pObj2Device;
-        matrix.Translate(orig_x - mtPattern2Device.e,
-                         orig_y - mtPattern2Device.f);
+        matrix.Translate(original.x - mtPattern2Device.e,
+                         original.y - mtPattern2Device.f);
         m_pDevice->SaveState();
         CPDF_RenderStatus status;
         status.Initialize(m_pContext, m_pDevice, nullptr, nullptr, this,
@@ -2298,14 +2315,13 @@
         start_x = FXSYS_round(mtPattern2Device.e) + col * width - clip_box.left;
         start_y = FXSYS_round(mtPattern2Device.f) + row * height - clip_box.top;
       } else {
-        FX_FLOAT orig_x = col * pPattern->x_step();
-        FX_FLOAT orig_y = row * pPattern->y_step();
-        mtPattern2Device.Transform(orig_x, orig_y);
+        CFX_PointF original = mtPattern2Device.Transform(
+            CFX_PointF(col * pPattern->x_step(), row * pPattern->y_step()));
 
         pdfium::base::CheckedNumeric<int> safeStartX =
-            FXSYS_round(orig_x + left_offset);
+            FXSYS_round(original.x + left_offset);
         pdfium::base::CheckedNumeric<int> safeStartY =
-            FXSYS_round(orig_y + top_offset);
+            FXSYS_round(original.y + top_offset);
 
         safeStartX -= clip_box.left;
         safeStartY -= clip_box.top;
@@ -2516,7 +2532,7 @@
     pFunc = CPDF_Function::Load(pFuncObj);
 
   CFX_Matrix matrix = *pMatrix;
-  matrix.TranslateI(-pClipRect->left, -pClipRect->top);
+  matrix.Translate(-pClipRect->left, -pClipRect->top);
 
   CPDF_Form form(m_pContext->GetDocument(), m_pContext->GetPageResources(),
                  pGroup);
diff --git a/core/fpdfapi/render/cpdf_scaledrenderbuffer.cpp b/core/fpdfapi/render/cpdf_scaledrenderbuffer.cpp
index bcc03ba..de60e73 100644
--- a/core/fpdfapi/render/cpdf_scaledrenderbuffer.cpp
+++ b/core/fpdfapi/render/cpdf_scaledrenderbuffer.cpp
@@ -31,7 +31,7 @@
   m_pContext = pContext;
   m_Rect = pRect;
   m_pObject = pObj;
-  m_Matrix.TranslateI(-pRect.left, -pRect.top);
+  m_Matrix.Translate(-pRect.left, -pRect.top);
   int horz_size = pDevice->GetDeviceCaps(FXDC_HORZ_SIZE);
   int vert_size = pDevice->GetDeviceCaps(FXDC_VERT_SIZE);
   if (horz_size && vert_size && max_dpi) {
diff --git a/core/fpdfapi/render/cpdf_textrenderer.cpp b/core/fpdfapi/render/cpdf_textrenderer.cpp
index 9cb8ce9..95af863 100644
--- a/core/fpdfapi/render/cpdf_textrenderer.cpp
+++ b/core/fpdfapi/render/cpdf_textrenderer.cpp
@@ -6,7 +6,7 @@
 
 #include "core/fpdfapi/render/cpdf_textrenderer.h"
 
-#include <vector>
+#include <algorithm>
 
 #include "core/fpdfapi/font/cpdf_font.h"
 #include "core/fpdfapi/render/cpdf_charposlist.h"
@@ -17,9 +17,8 @@
 
 // static
 bool CPDF_TextRenderer::DrawTextPath(CFX_RenderDevice* pDevice,
-                                     int nChars,
-                                     uint32_t* pCharCodes,
-                                     FX_FLOAT* pCharPos,
+                                     const std::vector<uint32_t>& charCodes,
+                                     const std::vector<FX_FLOAT>& charPos,
                                      CPDF_Font* pFont,
                                      FX_FLOAT font_size,
                                      const CFX_Matrix* pText2User,
@@ -30,7 +29,7 @@
                                      CFX_PathData* pClippingPath,
                                      int nFlag) {
   CPDF_CharPosList CharPosList;
-  CharPosList.Load(nChars, pCharCodes, pCharPos, pFont, font_size);
+  CharPosList.Load(charCodes, charPos, pFont, font_size);
   if (CharPosList.m_nChars == 0)
     return true;
 
@@ -73,7 +72,6 @@
                                        const CFX_Matrix* pMatrix,
                                        const CFX_ByteString& str,
                                        FX_ARGB fill_argb,
-                                       FX_ARGB stroke_argb,
                                        const CFX_GraphStateData* pGraphState,
                                        const CPDF_RenderOptions* pOptions) {
   if (pFont->IsType3Font())
@@ -84,26 +82,16 @@
     return;
 
   int offset = 0;
-  uint32_t* pCharCodes;
-  FX_FLOAT* pCharPos;
   std::vector<uint32_t> codes;
   std::vector<FX_FLOAT> positions;
-  if (nChars == 1) {
-    pCharCodes = reinterpret_cast<uint32_t*>(
-        pFont->GetNextChar(str.c_str(), str.GetLength(), offset));
-    pCharPos = nullptr;
-  } else {
-    codes.resize(nChars);
-    positions.resize(nChars - 1);
-    FX_FLOAT cur_pos = 0;
-    for (int i = 0; i < nChars; i++) {
-      codes[i] = pFont->GetNextChar(str.c_str(), str.GetLength(), offset);
-      if (i)
-        positions[i - 1] = cur_pos;
-      cur_pos += pFont->GetCharWidthF(codes[i]) * font_size / 1000;
-    }
-    pCharCodes = codes.data();
-    pCharPos = positions.data();
+  codes.resize(nChars);
+  positions.resize(nChars - 1);
+  FX_FLOAT cur_pos = 0;
+  for (int i = 0; i < nChars; i++) {
+    codes[i] = pFont->GetNextChar(str.c_str(), str.GetLength(), offset);
+    if (i)
+      positions[i - 1] = cur_pos;
+    cur_pos += pFont->GetCharWidthF(codes[i]) * font_size / 1000;
   }
   CFX_Matrix matrix;
   if (pMatrix)
@@ -112,28 +100,21 @@
   matrix.e = origin_x;
   matrix.f = origin_y;
 
-  if (stroke_argb == 0) {
-    DrawNormalText(pDevice, nChars, pCharCodes, pCharPos, pFont, font_size,
-                   &matrix, fill_argb, pOptions);
-  } else {
-    DrawTextPath(pDevice, nChars, pCharCodes, pCharPos, pFont, font_size,
-                 &matrix, nullptr, pGraphState, fill_argb, stroke_argb, nullptr,
-                 0);
-  }
+  DrawNormalText(pDevice, codes, positions, pFont, font_size, &matrix,
+                 fill_argb, pOptions);
 }
 
 // static
 bool CPDF_TextRenderer::DrawNormalText(CFX_RenderDevice* pDevice,
-                                       int nChars,
-                                       uint32_t* pCharCodes,
-                                       FX_FLOAT* pCharPos,
+                                       const std::vector<uint32_t>& charCodes,
+                                       const std::vector<FX_FLOAT>& charPos,
                                        CPDF_Font* pFont,
                                        FX_FLOAT font_size,
                                        const CFX_Matrix* pText2Device,
                                        FX_ARGB fill_argb,
                                        const CPDF_RenderOptions* pOptions) {
   CPDF_CharPosList CharPosList;
-  CharPosList.Load(nChars, pCharCodes, pCharPos, pFont, font_size);
+  CharPosList.Load(charCodes, charPos, pFont, font_size);
   if (CharPosList.m_nChars == 0)
     return true;
   int FXGE_flags = 0;
diff --git a/core/fpdfapi/render/cpdf_textrenderer.h b/core/fpdfapi/render/cpdf_textrenderer.h
index 82cc2cf..54e9d1b 100644
--- a/core/fpdfapi/render/cpdf_textrenderer.h
+++ b/core/fpdfapi/render/cpdf_textrenderer.h
@@ -7,6 +7,8 @@
 #ifndef CORE_FPDFAPI_RENDER_CPDF_TEXTRENDERER_H_
 #define CORE_FPDFAPI_RENDER_CPDF_TEXTRENDERER_H_
 
+#include <vector>
+
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
@@ -28,14 +30,12 @@
                              const CFX_Matrix* matrix,
                              const CFX_ByteString& str,
                              FX_ARGB fill_argb,
-                             FX_ARGB stroke_argb,
                              const CFX_GraphStateData* pGraphState,
                              const CPDF_RenderOptions* pOptions);
 
   static bool DrawTextPath(CFX_RenderDevice* pDevice,
-                           int nChars,
-                           uint32_t* pCharCodes,
-                           FX_FLOAT* pCharPos,
+                           const std::vector<uint32_t>& charCodes,
+                           const std::vector<FX_FLOAT>& charPos,
                            CPDF_Font* pFont,
                            FX_FLOAT font_size,
                            const CFX_Matrix* pText2User,
@@ -47,9 +47,8 @@
                            int nFlag);
 
   static bool DrawNormalText(CFX_RenderDevice* pDevice,
-                             int nChars,
-                             uint32_t* pCharCodes,
-                             FX_FLOAT* pCharPos,
+                             const std::vector<uint32_t>& charCodes,
+                             const std::vector<FX_FLOAT>& charPos,
                              CPDF_Font* pFont,
                              FX_FLOAT font_size,
                              const CFX_Matrix* pText2Device,
diff --git a/core/fpdfapi/render/cpdf_type3cache.cpp b/core/fpdfapi/render/cpdf_type3cache.cpp
index b27fdf5..63cc780 100644
--- a/core/fpdfapi/render/cpdf_type3cache.cpp
+++ b/core/fpdfapi/render/cpdf_type3cache.cpp
@@ -122,10 +122,10 @@
     return nullptr;
 
   CFX_DIBitmap* pBitmap = pChar->m_pBitmap.get();
-  CFX_Matrix image_matrix, text_matrix;
-  image_matrix = pChar->m_ImageMatrix;
-  text_matrix.Set(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d, 0, 0);
+  CFX_Matrix image_matrix = pChar->m_ImageMatrix;
+  CFX_Matrix text_matrix(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d, 0, 0);
   image_matrix.Concat(text_matrix);
+
   std::unique_ptr<CFX_DIBitmap> pResBitmap;
   int left = 0;
   int top = 0;
diff --git a/core/fpdfdoc/cpdf_annot.cpp b/core/fpdfdoc/cpdf_annot.cpp
index 38e5b5f..89c4785 100644
--- a/core/fpdfdoc/cpdf_annot.cpp
+++ b/core/fpdfdoc/cpdf_annot.cpp
@@ -500,8 +500,8 @@
   path.AppendRect(rect.left + width, rect.bottom + width, rect.right - width,
                   rect.top - width);
   int fill_type = 0;
-  if (pOptions && (pOptions->m_Flags & RENDER_NOPATHSMOOTH)) {
+  if (pOptions && (pOptions->m_Flags & RENDER_NOPATHSMOOTH))
     fill_type |= FXFILL_NOPATHSMOOTH;
-  }
+
   pDevice->DrawPath(&path, pUser2Device, &graph_state, argb, argb, fill_type);
 }
diff --git a/core/fpdfdoc/cpdf_annotlist.cpp b/core/fpdfdoc/cpdf_annotlist.cpp
index 1ad6ab2..ed1b60c 100644
--- a/core/fpdfdoc/cpdf_annotlist.cpp
+++ b/core/fpdfdoc/cpdf_annotlist.cpp
@@ -126,7 +126,7 @@
       continue;
 
     if (pOptions) {
-      CPDF_OCContext* pOCContext = pOptions->m_pOCContext;
+      CFX_RetainPtr<CPDF_OCContext> pOCContext = pOptions->m_pOCContext;
       CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict();
       if (pOCContext && pAnnotDict &&
           !pOCContext->CheckOCGVisible(pAnnotDict->GetDictFor("OC"))) {
@@ -136,12 +136,12 @@
     CFX_FloatRect annot_rect_f = pAnnot->GetRect();
     CFX_Matrix matrix = *pMatrix;
     if (clip_rect) {
-      annot_rect_f.Transform(&matrix);
+      matrix.TransformRect(annot_rect_f);
+
       FX_RECT annot_rect = annot_rect_f.GetOuterRect();
       annot_rect.Intersect(*clip_rect);
-      if (annot_rect.IsEmpty()) {
+      if (annot_rect.IsEmpty())
         continue;
-      }
     }
     if (pContext) {
       pAnnot->DrawInContext(pPage, pContext, &matrix, CPDF_Annot::Normal);
diff --git a/core/fpdfdoc/cpdf_defaultappearance.cpp b/core/fpdfdoc/cpdf_defaultappearance.cpp
index daf9341..1976765 100644
--- a/core/fpdfdoc/cpdf_defaultappearance.cpp
+++ b/core/fpdfdoc/cpdf_defaultappearance.cpp
@@ -209,16 +209,15 @@
 }
 
 CFX_Matrix CPDF_DefaultAppearance::GetTextMatrix() {
-  CFX_Matrix tm;
   if (m_csDA.IsEmpty())
-    return tm;
+    return CFX_Matrix();
 
   CPDF_SimpleParser syntax(m_csDA.AsStringC());
-  if (syntax.FindTagParamFromStart("Tm", 6)) {
-    FX_FLOAT f[6];
-    for (int i = 0; i < 6; i++)
-      f[i] = FX_atof(syntax.GetWord());
-    tm.Set(f[0], f[1], f[2], f[3], f[4], f[5]);
-  }
-  return tm;
+  if (!syntax.FindTagParamFromStart("Tm", 6))
+    return CFX_Matrix();
+
+  FX_FLOAT f[6];
+  for (int i = 0; i < 6; i++)
+    f[i] = FX_atof(syntax.GetWord());
+  return CFX_Matrix(f);
 }
diff --git a/core/fpdfdoc/cpdf_filespec.cpp b/core/fpdfdoc/cpdf_filespec.cpp
index d6a66f7..ce6f9a2 100644
--- a/core/fpdfdoc/cpdf_filespec.cpp
+++ b/core/fpdfdoc/cpdf_filespec.cpp
@@ -143,7 +143,7 @@
   }
   return ChangeSlashToPDF(filepath.c_str());
 #elif _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
-  if (filepath.Left(sizeof("Mac") - 1) == FX_WSTRC(L"Mac")) {
+  if (filepath.Left(sizeof("Mac") - 1) == L"Mac") {
     CFX_WideString result;
     result = '/';
     result += ChangeSlashToPDF(filepath.c_str());
diff --git a/core/fpdfdoc/cpdf_formfield.cpp b/core/fpdfdoc/cpdf_formfield.cpp
index b344327..b4aa90e 100644
--- a/core/fpdfdoc/cpdf_formfield.cpp
+++ b/core/fpdfdoc/cpdf_formfield.cpp
@@ -31,10 +31,6 @@
 
 const int kFormComboEdit = 0x100;
 
-const int kFormFieldReadOnly = 0x01;
-const int kFormFieldRequired = 0x02;
-const int kFormFieldNoExport = 0x04;
-
 const int kFormRadioNoToggleOff = 0x100;
 const int kFormRadioUnison = 0x200;
 
@@ -108,12 +104,12 @@
                        ? FPDF_GetFieldAttr(m_pDict, "Ff")->GetInteger()
                        : 0;
   m_Flags = 0;
-  if (flags & 1)
-    m_Flags |= kFormFieldReadOnly;
-  if (flags & 2)
-    m_Flags |= kFormFieldRequired;
-  if (flags & 4)
-    m_Flags |= kFormFieldNoExport;
+  if (flags & FORMFLAG_READONLY)
+    m_Flags |= FORMFLAG_READONLY;
+  if (flags & FORMFLAG_REQUIRED)
+    m_Flags |= FORMFLAG_REQUIRED;
+  if (flags & FORMFLAG_NOEXPORT)
+    m_Flags |= FORMFLAG_NOEXPORT;
 
   if (type_name == "Btn") {
     if (flags & 0x8000) {
diff --git a/core/fpdfdoc/cpdf_formfield.h b/core/fpdfdoc/cpdf_formfield.h
index 9a1ddc4..42608b1 100644
--- a/core/fpdfdoc/cpdf_formfield.h
+++ b/core/fpdfdoc/cpdf_formfield.h
@@ -25,6 +25,10 @@
 #define FIELDTYPE_TEXTFIELD 6
 #define FIELDTYPE_SIGNATURE 7
 
+#define FORMFLAG_READONLY 0x01
+#define FORMFLAG_REQUIRED 0x02
+#define FORMFLAG_NOEXPORT 0x04
+
 class CPDF_Dictionary;
 class CPDF_Font;
 class CPDF_FormControl;
diff --git a/core/fpdfdoc/cpdf_interform.cpp b/core/fpdfdoc/cpdf_interform.cpp
index 6cffea6..d9f0db9 100644
--- a/core/fpdfdoc/cpdf_interform.cpp
+++ b/core/fpdfdoc/cpdf_interform.cpp
@@ -900,8 +900,8 @@
 }
 
 CPDF_FormControl* CPDF_InterForm::GetControlAtPoint(CPDF_Page* pPage,
-                                                    FX_FLOAT pdf_x,
-                                                    FX_FLOAT pdf_y,
+                                                    const CFX_PointF& point,
+
                                                     int* z_order) const {
   CPDF_Array* pAnnotList = pPage->m_pFormDict->GetArrayFor("Annots");
   if (!pAnnotList)
@@ -918,8 +918,7 @@
       continue;
 
     CPDF_FormControl* pControl = it->second.get();
-    CFX_FloatRect rect = pControl->GetRect();
-    if (!rect.Contains(pdf_x, pdf_y))
+    if (!pControl->GetRect().Contains(point))
       continue;
 
     if (z_order)
@@ -1157,7 +1156,7 @@
   return pControl;
 }
 
-CPDF_FormField* CPDF_InterForm::CheckRequiredFields(
+bool CPDF_InterForm::CheckRequiredFields(
     const std::vector<CPDF_FormField*>* fields,
     bool bIncludeOrExclude) const {
   size_t nCount = m_pFieldTree->m_Root.CountFields();
@@ -1173,7 +1172,7 @@
     }
     uint32_t dwFlags = pField->GetFieldFlags();
     // TODO(thestig): Look up these magic numbers and add constants for them.
-    if (dwFlags & 0x04)
+    if (dwFlags & FORMFLAG_NOEXPORT)
       continue;
 
     bool bFind = true;
@@ -1181,11 +1180,13 @@
       bFind = pdfium::ContainsValue(*fields, pField);
     if (bIncludeOrExclude == bFind) {
       CPDF_Dictionary* pFieldDict = pField->m_pDict;
-      if ((dwFlags & 0x02) != 0 && pFieldDict->GetStringFor("V").IsEmpty())
-        return pField;
+      if ((dwFlags & FORMFLAG_REQUIRED) != 0 &&
+          pFieldDict->GetStringFor("V").IsEmpty()) {
+        return false;
+      }
     }
   }
-  return nullptr;
+  return true;
 }
 
 std::unique_ptr<CFDF_Document> CPDF_InterForm::ExportToFDF(
diff --git a/core/fpdfdoc/cpdf_interform.h b/core/fpdfdoc/cpdf_interform.h
index b846973..cbaaa7b 100644
--- a/core/fpdfdoc/cpdf_interform.h
+++ b/core/fpdfdoc/cpdf_interform.h
@@ -55,8 +55,7 @@
   CPDF_FormField* GetFieldByDict(CPDF_Dictionary* pFieldDict) const;
 
   CPDF_FormControl* GetControlAtPoint(CPDF_Page* pPage,
-                                      FX_FLOAT pdf_x,
-                                      FX_FLOAT pdf_y,
+                                      const CFX_PointF& point,
                                       int* z_order) const;
   CPDF_FormControl* GetControlByDict(const CPDF_Dictionary* pWidgetDict) const;
 
@@ -69,9 +68,8 @@
   CPDF_DefaultAppearance GetDefaultAppearance() const;
   int GetFormAlignment() const;
 
-  CPDF_FormField* CheckRequiredFields(
-      const std::vector<CPDF_FormField*>* fields,
-      bool bIncludeOrExclude) const;
+  bool CheckRequiredFields(const std::vector<CPDF_FormField*>* fields,
+                           bool bIncludeOrExclude) const;
 
   std::unique_ptr<CFDF_Document> ExportToFDF(const CFX_WideStringC& pdf_path,
                                              bool bSimpleFileSpec) const;
diff --git a/core/fpdfdoc/cpdf_linklist.cpp b/core/fpdfdoc/cpdf_linklist.cpp
index 2d8f7e2..0620dbf 100644
--- a/core/fpdfdoc/cpdf_linklist.cpp
+++ b/core/fpdfdoc/cpdf_linklist.cpp
@@ -30,8 +30,7 @@
 }
 
 CPDF_Link CPDF_LinkList::GetLinkAtPoint(CPDF_Page* pPage,
-                                        FX_FLOAT pdf_x,
-                                        FX_FLOAT pdf_y,
+                                        const CFX_PointF& point,
                                         int* z_order) {
   const std::vector<CPDF_Dictionary*>* pPageLinkList = GetPageLinks(pPage);
   if (!pPageLinkList)
@@ -44,8 +43,7 @@
       continue;
 
     CPDF_Link link(pAnnot);
-    CFX_FloatRect rect = link.GetRect();
-    if (!rect.Contains(pdf_x, pdf_y))
+    if (!link.GetRect().Contains(point))
       continue;
 
     if (z_order)
diff --git a/core/fpdfdoc/cpdf_linklist.h b/core/fpdfdoc/cpdf_linklist.h
index 21d69fd..129790f 100644
--- a/core/fpdfdoc/cpdf_linklist.h
+++ b/core/fpdfdoc/cpdf_linklist.h
@@ -22,8 +22,7 @@
   ~CPDF_LinkList();
 
   CPDF_Link GetLinkAtPoint(CPDF_Page* pPage,
-                           FX_FLOAT pdf_x,
-                           FX_FLOAT pdf_y,
+                           const CFX_PointF& point,
                            int* z_order);
 
  private:
diff --git a/core/fpdfdoc/cpdf_metadata.cpp b/core/fpdfdoc/cpdf_metadata.cpp
index bdb70c0..5e3acbe 100644
--- a/core/fpdfdoc/cpdf_metadata.cpp
+++ b/core/fpdfdoc/cpdf_metadata.cpp
@@ -22,7 +22,7 @@
 
   CPDF_StreamAcc acc;
   acc.LoadAllData(pStream, false);
-  m_pXmlElement.reset(CXML_Element::Parse(acc.GetData(), acc.GetSize()));
+  m_pXmlElement = CXML_Element::Parse(acc.GetData(), acc.GetSize());
 }
 
 CPDF_Metadata::~CPDF_Metadata() {}
diff --git a/core/fpdfdoc/cpdf_occontext.h b/core/fpdfdoc/cpdf_occontext.h
index 49bbd76..ecdcfae 100644
--- a/core/fpdfdoc/cpdf_occontext.h
+++ b/core/fpdfdoc/cpdf_occontext.h
@@ -9,6 +9,7 @@
 
 #include <unordered_map>
 
+#include "core/fxcrt/cfx_retain_ptr.h"
 #include "core/fxcrt/fx_string.h"
 
 class CPDF_Array;
@@ -16,17 +17,20 @@
 class CPDF_Document;
 class CPDF_PageObject;
 
-class CPDF_OCContext {
+class CPDF_OCContext : public CFX_Retainable {
  public:
-  enum UsageType { View = 0, Design, Print, Export };
+  template <typename T, typename... Args>
+  friend CFX_RetainPtr<T> pdfium::MakeRetain(Args&&... args);
 
-  CPDF_OCContext(CPDF_Document* pDoc, UsageType eUsageType);
-  ~CPDF_OCContext();
+  enum UsageType { View = 0, Design, Print, Export };
 
   bool CheckOCGVisible(const CPDF_Dictionary* pOCGDict);
   bool CheckObjectVisible(const CPDF_PageObject* pObj);
 
  private:
+  CPDF_OCContext(CPDF_Document* pDoc, UsageType eUsageType);
+  ~CPDF_OCContext() override;
+
   bool LoadOCGStateFromConfig(const CFX_ByteString& csConfig,
                               const CPDF_Dictionary* pOCGDict) const;
   bool LoadOCGState(const CPDF_Dictionary* pOCGDict) const;
diff --git a/core/fpdfdoc/cpdf_variabletext.cpp b/core/fpdfdoc/cpdf_variabletext.cpp
index 1313516..94b3425 100644
--- a/core/fpdfdoc/cpdf_variabletext.cpp
+++ b/core/fpdfdoc/cpdf_variabletext.cpp
@@ -172,8 +172,8 @@
         word.nCharset = pWord->nCharset;
         word.fWidth = m_pVT->GetWordWidth(*pWord);
         word.ptWord = m_pVT->InToOut(
-            CFX_FloatPoint(pWord->fWordX + pSection->m_SecInfo.rcSection.left,
-                           pWord->fWordY + pSection->m_SecInfo.rcSection.top));
+            CFX_PointF(pWord->fWordX + pSection->m_SecInfo.rcSection.left,
+                       pWord->fWordY + pSection->m_SecInfo.rcSection.top));
         word.fAscent = m_pVT->GetWordAscent(*pWord);
         word.fDescent = m_pVT->GetWordDescent(*pWord);
         if (pWord->pWordProps)
@@ -205,7 +205,7 @@
   line.lineplace = CPVT_WordPlace(m_CurPos.nSecIndex, m_CurPos.nLineIndex, -1);
   if (CSection* pSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex)) {
     if (CLine* pLine = pSection->m_LineArray.GetAt(m_CurPos.nLineIndex)) {
-      line.ptLine = m_pVT->InToOut(CFX_FloatPoint(
+      line.ptLine = m_pVT->InToOut(CFX_PointF(
           pLine->m_LineInfo.fLineX + pSection->m_SecInfo.rcSection.left,
           pLine->m_LineInfo.fLineY + pSection->m_SecInfo.rcSection.top));
       line.fLineWidth = pLine->m_LineInfo.fLineWidth;
@@ -548,8 +548,8 @@
 }
 
 CPVT_WordPlace CPDF_VariableText::SearchWordPlace(
-    const CFX_FloatPoint& point) const {
-  CFX_FloatPoint pt = OutToIn(point);
+    const CFX_PointF& point) const {
+  CFX_PointF pt = OutToIn(point);
   CPVT_WordPlace place = GetBeginWordPlace();
   int32_t nLeft = 0;
   int32_t nRight = m_SectionArray.GetSize() - 1;
@@ -574,8 +574,8 @@
         continue;
       } else {
         place = pSection->SearchWordPlace(
-            CFX_FloatPoint(pt.x - pSection->m_SecInfo.rcSection.left,
-                           pt.y - pSection->m_SecInfo.rcSection.top));
+            CFX_PointF(pt.x - pSection->m_SecInfo.rcSection.left,
+                       pt.y - pSection->m_SecInfo.rcSection.top));
         place.nSecIndex = nMid;
         return place;
       }
@@ -592,10 +592,10 @@
 
 CPVT_WordPlace CPDF_VariableText::GetUpWordPlace(
     const CPVT_WordPlace& place,
-    const CFX_FloatPoint& point) const {
+    const CFX_PointF& point) const {
   if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) {
     CPVT_WordPlace temp = place;
-    CFX_FloatPoint pt = OutToIn(point);
+    CFX_PointF pt = OutToIn(point);
     if (temp.nLineIndex-- > 0) {
       return pSection->SearchWordPlace(
           pt.x - pSection->m_SecInfo.rcSection.left, temp);
@@ -613,10 +613,10 @@
 
 CPVT_WordPlace CPDF_VariableText::GetDownWordPlace(
     const CPVT_WordPlace& place,
-    const CFX_FloatPoint& point) const {
+    const CFX_PointF& point) const {
   if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) {
     CPVT_WordPlace temp = place;
-    CFX_FloatPoint pt = OutToIn(point);
+    CFX_PointF pt = OutToIn(point);
     if (temp.nLineIndex++ < pSection->m_LineArray.GetSize() - 1) {
       return pSection->SearchWordPlace(
           pt.x - pSection->m_SecInfo.rcSection.left, temp);
@@ -1010,10 +1010,10 @@
   for (int32_t s = 0, sz = m_SectionArray.GetSize(); s < sz; s++) {
     if (CSection* pSection = m_SectionArray.GetAt(s)) {
       CFX_SizeF size = pSection->GetSectionSize(fFontSize);
-      szTotal.x = std::max(size.x, szTotal.x);
-      szTotal.y += size.y;
-      if (IsFloatBigger(szTotal.x, GetPlateWidth()) ||
-          IsFloatBigger(szTotal.y, GetPlateHeight())) {
+      szTotal.width = std::max(size.width, szTotal.width);
+      szTotal.height += size.height;
+      if (IsFloatBigger(szTotal.width, GetPlateWidth()) ||
+          IsFloatBigger(szTotal.height, GetPlateHeight())) {
         return true;
       }
     }
@@ -1109,34 +1109,32 @@
   return CFX_SizeF(GetPlateWidth(), GetPlateHeight());
 }
 
-CFX_FloatPoint CPDF_VariableText::GetBTPoint() const {
-  return CFX_FloatPoint(m_rcPlate.left, m_rcPlate.top);
+CFX_PointF CPDF_VariableText::GetBTPoint() const {
+  return CFX_PointF(m_rcPlate.left, m_rcPlate.top);
 }
 
-CFX_FloatPoint CPDF_VariableText::GetETPoint() const {
-  return CFX_FloatPoint(m_rcPlate.right, m_rcPlate.bottom);
+CFX_PointF CPDF_VariableText::GetETPoint() const {
+  return CFX_PointF(m_rcPlate.right, m_rcPlate.bottom);
 }
 
-CFX_FloatPoint CPDF_VariableText::InToOut(const CFX_FloatPoint& point) const {
-  return CFX_FloatPoint(point.x + GetBTPoint().x, GetBTPoint().y - point.y);
+CFX_PointF CPDF_VariableText::InToOut(const CFX_PointF& point) const {
+  return CFX_PointF(point.x + GetBTPoint().x, GetBTPoint().y - point.y);
 }
 
-CFX_FloatPoint CPDF_VariableText::OutToIn(const CFX_FloatPoint& point) const {
-  return CFX_FloatPoint(point.x - GetBTPoint().x, GetBTPoint().y - point.y);
+CFX_PointF CPDF_VariableText::OutToIn(const CFX_PointF& point) const {
+  return CFX_PointF(point.x - GetBTPoint().x, GetBTPoint().y - point.y);
 }
 
 CFX_FloatRect CPDF_VariableText::InToOut(const CPVT_FloatRect& rect) const {
-  CFX_FloatPoint ptLeftTop = InToOut(CFX_FloatPoint(rect.left, rect.top));
-  CFX_FloatPoint ptRightBottom =
-      InToOut(CFX_FloatPoint(rect.right, rect.bottom));
+  CFX_PointF ptLeftTop = InToOut(CFX_PointF(rect.left, rect.top));
+  CFX_PointF ptRightBottom = InToOut(CFX_PointF(rect.right, rect.bottom));
   return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x,
                        ptLeftTop.y);
 }
 
 CPVT_FloatRect CPDF_VariableText::OutToIn(const CFX_FloatRect& rect) const {
-  CFX_FloatPoint ptLeftTop = OutToIn(CFX_FloatPoint(rect.left, rect.top));
-  CFX_FloatPoint ptRightBottom =
-      OutToIn(CFX_FloatPoint(rect.right, rect.bottom));
+  CFX_PointF ptLeftTop = OutToIn(CFX_PointF(rect.left, rect.top));
+  CFX_PointF ptRightBottom = OutToIn(CFX_PointF(rect.right, rect.bottom));
   return CPVT_FloatRect(ptLeftTop.x, ptLeftTop.y, ptRightBottom.x,
                         ptRightBottom.y);
 }
diff --git a/core/fpdfdoc/cpdf_variabletext.h b/core/fpdfdoc/cpdf_variabletext.h
index 5983a29..8e7c0c9 100644
--- a/core/fpdfdoc/cpdf_variabletext.h
+++ b/core/fpdfdoc/cpdf_variabletext.h
@@ -20,13 +20,13 @@
 #include "core/fxcrt/fx_system.h"
 #include "core/fxge/fx_font.h"
 
+class CPVT_Word;
 class CSection;
 class IPVT_FontMap;
-
 struct CPVT_SecProps;
 struct CPVT_Section;
 struct CPVT_SectionInfo;
-struct CPVT_Word;
+
 struct CPVT_WordInfo;
 struct CPVT_WordProps;
 
@@ -132,11 +132,11 @@
   CPVT_WordPlace GetEndWordPlace() const;
   CPVT_WordPlace GetPrevWordPlace(const CPVT_WordPlace& place) const;
   CPVT_WordPlace GetNextWordPlace(const CPVT_WordPlace& place) const;
-  CPVT_WordPlace SearchWordPlace(const CFX_FloatPoint& point) const;
+  CPVT_WordPlace SearchWordPlace(const CFX_PointF& point) const;
   CPVT_WordPlace GetUpWordPlace(const CPVT_WordPlace& place,
-                                const CFX_FloatPoint& point) const;
+                                const CFX_PointF& point) const;
   CPVT_WordPlace GetDownWordPlace(const CPVT_WordPlace& place,
-                                  const CFX_FloatPoint& point) const;
+                                  const CFX_PointF& point) const;
   CPVT_WordPlace GetLineBeginPlace(const CPVT_WordPlace& place) const;
   CPVT_WordPlace GetLineEndPlace(const CPVT_WordPlace& place) const;
   CPVT_WordPlace GetSectionBeginPlace(const CPVT_WordPlace& place) const;
@@ -152,11 +152,11 @@
   FX_FLOAT GetPlateWidth() const { return m_rcPlate.right - m_rcPlate.left; }
   FX_FLOAT GetPlateHeight() const { return m_rcPlate.top - m_rcPlate.bottom; }
   CFX_SizeF GetPlateSize() const;
-  CFX_FloatPoint GetBTPoint() const;
-  CFX_FloatPoint GetETPoint() const;
+  CFX_PointF GetBTPoint() const;
+  CFX_PointF GetETPoint() const;
 
-  CFX_FloatPoint InToOut(const CFX_FloatPoint& point) const;
-  CFX_FloatPoint OutToIn(const CFX_FloatPoint& point) const;
+  CFX_PointF InToOut(const CFX_PointF& point) const;
+  CFX_PointF OutToIn(const CFX_PointF& point) const;
   CFX_FloatRect InToOut(const CPVT_FloatRect& rect) const;
   CPVT_FloatRect OutToIn(const CFX_FloatRect& rect) const;
 
diff --git a/core/fpdfdoc/cpvt_generateap.cpp b/core/fpdfdoc/cpvt_generateap.cpp
index 4bb244f..1551515 100644
--- a/core/fpdfdoc/cpvt_generateap.cpp
+++ b/core/fpdfdoc/cpvt_generateap.cpp
@@ -246,10 +246,10 @@
       vt.SetText(swValue);
       vt.RearrangeAll();
       CFX_FloatRect rcContent = vt.GetContentRect();
-      CFX_FloatPoint ptOffset;
+      CFX_PointF ptOffset;
       if (!bMultiLine) {
         ptOffset =
-            CFX_FloatPoint(0.0f, (rcContent.Height() - rcBody.Height()) / 2.0f);
+            CFX_PointF(0.0f, (rcContent.Height() - rcBody.Height()) / 2.0f);
       }
       CFX_ByteString sBody = CPVT_GenerateAP::GenerateEditAP(
           &map, vt.GetIterator(), ptOffset, !bCharArray, subWord);
@@ -296,8 +296,8 @@
       vt.SetText(swValue);
       vt.RearrangeAll();
       CFX_FloatRect rcContent = vt.GetContentRect();
-      CFX_FloatPoint ptOffset =
-          CFX_FloatPoint(0.0f, (rcContent.Height() - rcEdit.Height()) / 2.0f);
+      CFX_PointF ptOffset =
+          CFX_PointF(0.0f, (rcContent.Height() - rcEdit.Height()) / 2.0f);
       CFX_ByteString sEdit = CPVT_GenerateAP::GenerateEditAP(
           &map, vt.GetIterator(), ptOffset, true, 0);
       if (sEdit.GetLength() > 0) {
@@ -328,9 +328,8 @@
         if (sButtonBorder.GetLength() > 0)
           sAppStream << "q\n" << sButtonBorder << "Q\n";
 
-        CFX_FloatPoint ptCenter =
-            CFX_FloatPoint((rcButton.left + rcButton.right) / 2,
-                           (rcButton.top + rcButton.bottom) / 2);
+        CFX_PointF ptCenter = CFX_PointF((rcButton.left + rcButton.right) / 2,
+                                         (rcButton.top + rcButton.bottom) / 2);
         if (IsFloatBigger(rcButton.Width(), 6) &&
             IsFloatBigger(rcButton.Height(), 6)) {
           sAppStream << "q\n"
@@ -402,7 +401,7 @@
                            CPVT_Color(CPVT_Color::kGray, 1),
                            PaintOperation::FILL)
                     << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(),
-                                                       CFX_FloatPoint(0.0f, fy),
+                                                       CFX_PointF(0.0f, fy),
                                                        true, 0)
                     << "ET\n";
             } else {
@@ -410,7 +409,7 @@
                     << CPVT_GenerateAP::GenerateColorAP(crText,
                                                         PaintOperation::FILL)
                     << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(),
-                                                       CFX_FloatPoint(0.0f, fy),
+                                                       CFX_PointF(0.0f, fy),
                                                        true, 0)
                     << "ET\n";
             }
@@ -529,7 +528,7 @@
   vt.Initialize();
   vt.SetText(swValue);
   vt.RearrangeAll();
-  CFX_FloatPoint ptOffset(3.0f, -3.0f);
+  CFX_PointF ptOffset(3.0f, -3.0f);
   CFX_ByteString sContent = CPVT_GenerateAP::GenerateEditAP(
       &map, vt.GetIterator(), ptOffset, false, 0);
 
@@ -1102,14 +1101,14 @@
 CFX_ByteString CPVT_GenerateAP::GenerateEditAP(
     IPVT_FontMap* pFontMap,
     CPDF_VariableText::Iterator* pIterator,
-    const CFX_FloatPoint& ptOffset,
+    const CFX_PointF& ptOffset,
     bool bContinuous,
     uint16_t SubWord) {
   CFX_ByteTextBuf sEditStream;
   CFX_ByteTextBuf sLineStream;
   CFX_ByteTextBuf sWords;
-  CFX_FloatPoint ptOld;
-  CFX_FloatPoint ptNew;
+  CFX_PointF ptOld;
+  CFX_PointF ptNew;
   int32_t nCurFontIndex = -1;
   CPVT_WordPlace oldplace;
 
@@ -1126,13 +1125,13 @@
         }
         CPVT_Word word;
         if (pIterator->GetWord(word)) {
-          ptNew = CFX_FloatPoint(word.ptWord.x + ptOffset.x,
-                                 word.ptWord.y + ptOffset.y);
+          ptNew = CFX_PointF(word.ptWord.x + ptOffset.x,
+                             word.ptWord.y + ptOffset.y);
         } else {
           CPVT_Line line;
           pIterator->GetLine(line);
-          ptNew = CFX_FloatPoint(line.ptLine.x + ptOffset.x,
-                                 line.ptLine.y + ptOffset.y);
+          ptNew = CFX_PointF(line.ptLine.x + ptOffset.x,
+                             line.ptLine.y + ptOffset.y);
         }
         if (ptNew != ptOld) {
           sLineStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
@@ -1157,8 +1156,8 @@
     } else {
       CPVT_Word word;
       if (pIterator->GetWord(word)) {
-        ptNew = CFX_FloatPoint(word.ptWord.x + ptOffset.x,
-                               word.ptWord.y + ptOffset.y);
+        ptNew =
+            CFX_PointF(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y);
         if (ptNew != ptOld) {
           sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
                       << " Td\n";
diff --git a/core/fpdfdoc/cpvt_generateap.h b/core/fpdfdoc/cpvt_generateap.h
index 16c939f..62a8453 100644
--- a/core/fpdfdoc/cpvt_generateap.h
+++ b/core/fpdfdoc/cpvt_generateap.h
@@ -48,7 +48,7 @@
                                   CPDF_Dictionary* pAnnotDict);
   static CFX_ByteString GenerateEditAP(IPVT_FontMap* pFontMap,
                                        CPDF_VariableText::Iterator* pIterator,
-                                       const CFX_FloatPoint& ptOffset,
+                                       const CFX_PointF& ptOffset,
                                        bool bContinuous,
                                        uint16_t SubWord);
   static CFX_ByteString GenerateBorderAP(const CFX_FloatRect& rect,
diff --git a/core/fpdfdoc/cpvt_line.h b/core/fpdfdoc/cpvt_line.h
index 25ae34a..47c3e84 100644
--- a/core/fpdfdoc/cpvt_line.h
+++ b/core/fpdfdoc/cpvt_line.h
@@ -11,15 +11,19 @@
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_system.h"
 
-struct CPVT_Line {
-  CPVT_Line() : fLineWidth(0.0f), fLineAscent(0.0f), fLineDescent(0.0f) {}
+class CPVT_Line {
+ public:
+  CPVT_Line();
 
   CPVT_WordPlace lineplace;
   CPVT_WordPlace lineEnd;
-  CFX_FloatPoint ptLine;
+  CFX_PointF ptLine;
   FX_FLOAT fLineWidth;
   FX_FLOAT fLineAscent;
   FX_FLOAT fLineDescent;
 };
 
+inline CPVT_Line::CPVT_Line()
+    : fLineWidth(0.0f), fLineAscent(0.0f), fLineDescent(0.0f) {}
+
 #endif  // CORE_FPDFDOC_CPVT_LINE_H_
diff --git a/core/fpdfdoc/cpvt_lineinfo.h b/core/fpdfdoc/cpvt_lineinfo.h
index 2ebc51c..8fb10de 100644
--- a/core/fpdfdoc/cpvt_lineinfo.h
+++ b/core/fpdfdoc/cpvt_lineinfo.h
@@ -9,16 +9,9 @@
 
 #include "core/fxcrt/fx_system.h"
 
-struct CPVT_LineInfo {
-  CPVT_LineInfo()
-      : nTotalWord(0),
-        nBeginWordIndex(-1),
-        nEndWordIndex(-1),
-        fLineX(0.0f),
-        fLineY(0.0f),
-        fLineWidth(0.0f),
-        fLineAscent(0.0f),
-        fLineDescent(0.0f) {}
+class CPVT_LineInfo {
+ public:
+  CPVT_LineInfo();
 
   int32_t nTotalWord;
   int32_t nBeginWordIndex;
@@ -30,4 +23,14 @@
   FX_FLOAT fLineDescent;
 };
 
+inline CPVT_LineInfo::CPVT_LineInfo()
+    : nTotalWord(0),
+      nBeginWordIndex(-1),
+      nEndWordIndex(-1),
+      fLineX(0.0f),
+      fLineY(0.0f),
+      fLineWidth(0.0f),
+      fLineAscent(0.0f),
+      fLineDescent(0.0f) {}
+
 #endif  // CORE_FPDFDOC_CPVT_LINEINFO_H_
diff --git a/core/fpdfdoc/cpvt_word.h b/core/fpdfdoc/cpvt_word.h
index 92a4ce1..540f041 100644
--- a/core/fpdfdoc/cpvt_word.h
+++ b/core/fpdfdoc/cpvt_word.h
@@ -11,13 +11,14 @@
 #include "core/fpdfdoc/cpvt_wordprops.h"
 #include "core/fxcrt/fx_system.h"
 
-struct CPVT_Word {
+class CPVT_Word {
+ public:
   CPVT_Word();
 
   uint16_t Word;
   int32_t nCharset;
   CPVT_WordPlace WordPlace;
-  CFX_FloatPoint ptWord;
+  CFX_PointF ptWord;
   FX_FLOAT fAscent;
   FX_FLOAT fDescent;
   FX_FLOAT fWidth;
diff --git a/core/fpdfdoc/csection.cpp b/core/fpdfdoc/csection.cpp
index 4964504..490ef1b 100644
--- a/core/fpdfdoc/csection.cpp
+++ b/core/fpdfdoc/csection.cpp
@@ -146,7 +146,7 @@
   }
 }
 
-CPVT_WordPlace CSection::SearchWordPlace(const CFX_FloatPoint& point) const {
+CPVT_WordPlace CSection::SearchWordPlace(const CFX_PointF& point) const {
   ASSERT(m_pVT);
   CPVT_WordPlace place = GetBeginWordPlace();
   bool bUp = true;
diff --git a/core/fpdfdoc/csection.h b/core/fpdfdoc/csection.h
index 706f5b6..a2ac43b 100644
--- a/core/fpdfdoc/csection.h
+++ b/core/fpdfdoc/csection.h
@@ -14,8 +14,7 @@
 #include "core/fxcrt/fx_system.h"
 
 class CPDF_VariableText;
-
-struct CPVT_LineInfo;
+class CPVT_LineInfo;
 struct CPVT_WordLine;
 struct CPVT_WordPlace;
 
@@ -40,7 +39,7 @@
   CPVT_WordPlace GetPrevWordPlace(const CPVT_WordPlace& place) const;
   CPVT_WordPlace GetNextWordPlace(const CPVT_WordPlace& place) const;
   void UpdateWordPlace(CPVT_WordPlace& place) const;
-  CPVT_WordPlace SearchWordPlace(const CFX_FloatPoint& point) const;
+  CPVT_WordPlace SearchWordPlace(const CFX_PointF& point) const;
   CPVT_WordPlace SearchWordPlace(FX_FLOAT fx,
                                  const CPVT_WordPlace& lineplace) const;
   CPVT_WordPlace SearchWordPlace(FX_FLOAT fx,
diff --git a/core/fpdfdoc/doc_tagged.cpp b/core/fpdfdoc/doc_tagged.cpp
index 39feaee..af5cf85 100644
--- a/core/fpdfdoc/doc_tagged.cpp
+++ b/core/fpdfdoc/doc_tagged.cpp
@@ -32,6 +32,17 @@
 
 }  // namespace
 
+CPDF_StructKid::CPDF_StructKid()
+    : m_Type(Invalid),
+      m_pDict(nullptr),
+      m_PageObjNum(0),
+      m_RefObjNum(0),
+      m_ContentId(0) {}
+
+CPDF_StructKid::CPDF_StructKid(const CPDF_StructKid& that) = default;
+
+CPDF_StructKid::~CPDF_StructKid() {}
+
 // static
 std::unique_ptr<IPDF_StructTree> IPDF_StructTree::LoadPage(
     const CPDF_Document* pDoc,
@@ -39,27 +50,27 @@
   if (!IsTagged(pDoc))
     return nullptr;
 
-  auto pTree = pdfium::MakeUnique<CPDF_StructTreeImpl>(pDoc);
+  auto pTree = pdfium::MakeUnique<CPDF_StructTree>(pDoc);
   pTree->LoadPageTree(pPageDict);
   return std::move(pTree);
 }
 
-CPDF_StructTreeImpl::CPDF_StructTreeImpl(const CPDF_Document* pDoc)
+CPDF_StructTree::CPDF_StructTree(const CPDF_Document* pDoc)
     : m_pTreeRoot(pDoc->GetRoot()->GetDictFor("StructTreeRoot")),
       m_pRoleMap(m_pTreeRoot ? m_pTreeRoot->GetDictFor("RoleMap") : nullptr),
       m_pPage(nullptr) {}
 
-CPDF_StructTreeImpl::~CPDF_StructTreeImpl() {}
+CPDF_StructTree::~CPDF_StructTree() {}
 
-int CPDF_StructTreeImpl::CountTopElements() const {
+int CPDF_StructTree::CountTopElements() const {
   return pdfium::CollectionSize<int>(m_Kids);
 }
 
-IPDF_StructElement* CPDF_StructTreeImpl::GetTopElement(int i) const {
+IPDF_StructElement* CPDF_StructTree::GetTopElement(int i) const {
   return m_Kids[i].Get();
 }
 
-void CPDF_StructTreeImpl::LoadPageTree(const CPDF_Dictionary* pPageDict) {
+void CPDF_StructTree::LoadPageTree(const CPDF_Dictionary* pPageDict) {
   m_pPage = pPageDict;
   if (!m_pTreeRoot)
     return;
@@ -91,54 +102,50 @@
   if (!pParentArray)
     return;
 
-  std::map<CPDF_Dictionary*, CPDF_StructElementImpl*> element_map;
+  std::map<CPDF_Dictionary*, CFX_RetainPtr<CPDF_StructElement>> element_map;
   for (size_t i = 0; i < pParentArray->GetCount(); i++) {
     if (CPDF_Dictionary* pParent = pParentArray->GetDictAt(i))
-      AddPageNode(pParent, element_map);
+      AddPageNode(pParent, &element_map);
   }
 }
 
-CPDF_StructElementImpl* CPDF_StructTreeImpl::AddPageNode(
+CFX_RetainPtr<CPDF_StructElement> CPDF_StructTree::AddPageNode(
     CPDF_Dictionary* pDict,
-    std::map<CPDF_Dictionary*, CPDF_StructElementImpl*>& map,
+    std::map<CPDF_Dictionary*, CFX_RetainPtr<CPDF_StructElement>>* map,
     int nLevel) {
   if (nLevel > nMaxRecursion)
     return nullptr;
 
-  auto it = map.find(pDict);
-  if (it != map.end())
+  auto it = map->find(pDict);
+  if (it != map->end())
     return it->second;
 
-  CPDF_StructElementImpl* pElement =
-      new CPDF_StructElementImpl(this, nullptr, pDict);
-  map[pDict] = pElement;
+  auto pElement = pdfium::MakeRetain<CPDF_StructElement>(this, nullptr, pDict);
+  (*map)[pDict] = pElement;
   CPDF_Dictionary* pParent = pDict->GetDictFor("P");
   if (!pParent || pParent->GetStringFor("Type") == "StructTreeRoot") {
-    if (!AddTopLevelNode(pDict, pElement)) {
-      pElement->Release();
-      map.erase(pDict);
-    }
-  } else {
-    CPDF_StructElementImpl* pParentElement =
-        AddPageNode(pParent, map, nLevel + 1);
-    bool bSave = false;
-    for (CPDF_StructKid& kid : pParentElement->m_Kids) {
-      if (kid.m_Type != CPDF_StructKid::Element)
-        continue;
-      if (kid.m_Element.m_pDict != pDict)
-        continue;
-      kid.m_Element.m_pElement = pElement->Retain();
+    if (!AddTopLevelNode(pDict, pElement))
+      map->erase(pDict);
+    return pElement;
+  }
+
+  CFX_RetainPtr<CPDF_StructElement> pParentElement =
+      AddPageNode(pParent, map, nLevel + 1);
+  bool bSave = false;
+  for (CPDF_StructKid& kid : *pParentElement->GetKids()) {
+    if (kid.m_Type == CPDF_StructKid::Element && kid.m_pDict == pDict) {
+      kid.m_pElement = pElement;
       bSave = true;
     }
-    if (!bSave) {
-      pElement->Release();
-      map.erase(pDict);
-    }
   }
+  if (!bSave)
+    map->erase(pDict);
   return pElement;
 }
-bool CPDF_StructTreeImpl::AddTopLevelNode(CPDF_Dictionary* pDict,
-                                          CPDF_StructElementImpl* pElement) {
+
+bool CPDF_StructTree::AddTopLevelNode(
+    CPDF_Dictionary* pDict,
+    const CFX_RetainPtr<CPDF_StructElement>& pElement) {
   CPDF_Object* pObj = m_pTreeRoot->GetDirectObjectFor("K");
   if (!pObj)
     return false;
@@ -146,14 +153,14 @@
   if (pObj->IsDictionary()) {
     if (pObj->GetObjNum() != pDict->GetObjNum())
       return false;
-    m_Kids[0].Reset(pElement);
+    m_Kids[0] = pElement;
   }
   if (CPDF_Array* pTopKids = pObj->AsArray()) {
     bool bSave = false;
     for (size_t i = 0; i < pTopKids->GetCount(); i++) {
       CPDF_Reference* pKidRef = ToReference(pTopKids->GetObjectAt(i));
       if (pKidRef && pKidRef->GetRefObjNum() == pDict->GetObjNum()) {
-        m_Kids[i].Reset(pElement);
+        m_Kids[i] = pElement;
         bSave = true;
       }
     }
@@ -163,11 +170,10 @@
   return true;
 }
 
-CPDF_StructElementImpl::CPDF_StructElementImpl(CPDF_StructTreeImpl* pTree,
-                                               CPDF_StructElementImpl* pParent,
-                                               CPDF_Dictionary* pDict)
-    : m_RefCount(0),
-      m_pTree(pTree),
+CPDF_StructElement::CPDF_StructElement(CPDF_StructTree* pTree,
+                                       CPDF_StructElement* pParent,
+                                       CPDF_Dictionary* pDict)
+    : m_pTree(pTree),
       m_pParent(pParent),
       m_pDict(pDict),
       m_Type(pDict->GetStringFor("S")) {
@@ -179,47 +185,36 @@
   LoadKids(pDict);
 }
 
-IPDF_StructTree* CPDF_StructElementImpl::GetTree() const {
+IPDF_StructTree* CPDF_StructElement::GetTree() const {
   return m_pTree;
 }
 
-const CFX_ByteString& CPDF_StructElementImpl::GetType() const {
+const CFX_ByteString& CPDF_StructElement::GetType() const {
   return m_Type;
 }
 
-IPDF_StructElement* CPDF_StructElementImpl::GetParent() const {
+IPDF_StructElement* CPDF_StructElement::GetParent() const {
   return m_pParent;
 }
 
-CPDF_Dictionary* CPDF_StructElementImpl::GetDict() const {
+CPDF_Dictionary* CPDF_StructElement::GetDict() const {
   return m_pDict;
 }
 
-int CPDF_StructElementImpl::CountKids() const {
+int CPDF_StructElement::CountKids() const {
   return pdfium::CollectionSize<int>(m_Kids);
 }
 
-const CPDF_StructKid& CPDF_StructElementImpl::GetKid(int index) const {
-  return m_Kids[index];
+IPDF_StructElement* CPDF_StructElement::GetKidIfElement(int index) const {
+  if (m_Kids[index].m_Type != CPDF_StructKid::Element)
+    return nullptr;
+
+  return m_Kids[index].m_pElement.Get();
 }
 
-CPDF_StructElementImpl::~CPDF_StructElementImpl() {
-  for (CPDF_StructKid& kid : m_Kids) {
-    if (kid.m_Type == CPDF_StructKid::Element && kid.m_Element.m_pElement)
-      static_cast<CPDF_StructElementImpl*>(kid.m_Element.m_pElement)->Release();
-  }
-}
+CPDF_StructElement::~CPDF_StructElement() {}
 
-CPDF_StructElementImpl* CPDF_StructElementImpl::Retain() {
-  m_RefCount++;
-  return this;
-}
-void CPDF_StructElementImpl::Release() {
-  if (--m_RefCount < 1) {
-    delete this;
-  }
-}
-void CPDF_StructElementImpl::LoadKids(CPDF_Dictionary* pDict) {
+void CPDF_StructElement::LoadKids(CPDF_Dictionary* pDict) {
   CPDF_Object* pObj = pDict->GetObjectFor("Pg");
   uint32_t PageObjNum = 0;
   if (CPDF_Reference* pRef = ToReference(pObj))
@@ -241,9 +236,9 @@
     LoadKid(PageObjNum, pKids, &m_Kids[0]);
   }
 }
-void CPDF_StructElementImpl::LoadKid(uint32_t PageObjNum,
-                                     CPDF_Object* pKidObj,
-                                     CPDF_StructKid* pKid) {
+void CPDF_StructElement::LoadKid(uint32_t PageObjNum,
+                                 CPDF_Object* pKidObj,
+                                 CPDF_StructKid* pKid) {
   pKid->m_Type = CPDF_StructKid::Invalid;
   if (!pKidObj)
     return;
@@ -253,8 +248,8 @@
       return;
     }
     pKid->m_Type = CPDF_StructKid::PageContent;
-    pKid->m_PageContent.m_ContentId = pKidObj->GetInteger();
-    pKid->m_PageContent.m_PageObjNum = PageObjNum;
+    pKid->m_ContentId = pKidObj->GetInteger();
+    pKid->m_PageObjNum = PageObjNum;
     return;
   }
 
@@ -271,32 +266,26 @@
       return;
     }
     pKid->m_Type = CPDF_StructKid::StreamContent;
-    if (CPDF_Reference* pRef = ToReference(pKidDict->GetObjectFor("Stm"))) {
-      pKid->m_StreamContent.m_RefObjNum = pRef->GetRefObjNum();
-    } else {
-      pKid->m_StreamContent.m_RefObjNum = 0;
-    }
-    pKid->m_StreamContent.m_PageObjNum = PageObjNum;
-    pKid->m_StreamContent.m_ContentId = pKidDict->GetIntegerFor("MCID");
+    CPDF_Reference* pRef = ToReference(pKidDict->GetObjectFor("Stm"));
+    pKid->m_RefObjNum = pRef ? pRef->GetRefObjNum() : 0;
+    pKid->m_PageObjNum = PageObjNum;
+    pKid->m_ContentId = pKidDict->GetIntegerFor("MCID");
   } else if (type == "OBJR") {
     if (m_pTree->m_pPage && m_pTree->m_pPage->GetObjNum() != PageObjNum) {
       return;
     }
     pKid->m_Type = CPDF_StructKid::Object;
-    if (CPDF_Reference* pObj = ToReference(pKidDict->GetObjectFor("Obj"))) {
-      pKid->m_Object.m_RefObjNum = pObj->GetRefObjNum();
-    } else {
-      pKid->m_Object.m_RefObjNum = 0;
-    }
-    pKid->m_Object.m_PageObjNum = PageObjNum;
+    CPDF_Reference* pObj = ToReference(pKidDict->GetObjectFor("Obj"));
+    pKid->m_RefObjNum = pObj ? pObj->GetRefObjNum() : 0;
+    pKid->m_PageObjNum = PageObjNum;
   } else {
     pKid->m_Type = CPDF_StructKid::Element;
-    pKid->m_Element.m_pDict = pKidDict;
+    pKid->m_pDict = pKidDict;
     if (!m_pTree->m_pPage) {
-      pKid->m_Element.m_pElement =
-          new CPDF_StructElementImpl(m_pTree, this, pKidDict);
+      pKid->m_pElement =
+          pdfium::MakeRetain<CPDF_StructElement>(m_pTree, this, pKidDict);
     } else {
-      pKid->m_Element.m_pElement = nullptr;
+      pKid->m_pElement = nullptr;
     }
   }
 }
@@ -325,10 +314,10 @@
     return pDict;
   return nullptr;
 }
-CPDF_Object* CPDF_StructElementImpl::GetAttr(const CFX_ByteStringC& owner,
-                                             const CFX_ByteStringC& name,
-                                             bool bInheritable,
-                                             FX_FLOAT fLevel) {
+CPDF_Object* CPDF_StructElement::GetAttr(const CFX_ByteStringC& owner,
+                                         const CFX_ByteStringC& name,
+                                         bool bInheritable,
+                                         FX_FLOAT fLevel) {
   if (fLevel > nMaxRecursion) {
     return nullptr;
   }
@@ -375,10 +364,10 @@
     return pClassDict->GetDirectObjectFor(CFX_ByteString(name));
   return nullptr;
 }
-CPDF_Object* CPDF_StructElementImpl::GetAttr(const CFX_ByteStringC& owner,
-                                             const CFX_ByteStringC& name,
-                                             bool bInheritable,
-                                             int subindex) {
+CPDF_Object* CPDF_StructElement::GetAttr(const CFX_ByteStringC& owner,
+                                         const CFX_ByteStringC& name,
+                                         bool bInheritable,
+                                         int subindex) {
   CPDF_Object* pAttr = GetAttr(owner, name, bInheritable);
   CPDF_Array* pArray = ToArray(pAttr);
   if (!pArray || subindex == -1)
@@ -388,23 +377,22 @@
     return pAttr;
   return pArray->GetDirectObjectAt(subindex);
 }
-CFX_ByteString CPDF_StructElementImpl::GetName(
-    const CFX_ByteStringC& owner,
-    const CFX_ByteStringC& name,
-    const CFX_ByteStringC& default_value,
-    bool bInheritable,
-    int subindex) {
+CFX_ByteString CPDF_StructElement::GetName(const CFX_ByteStringC& owner,
+                                           const CFX_ByteStringC& name,
+                                           const CFX_ByteStringC& default_value,
+                                           bool bInheritable,
+                                           int subindex) {
   CPDF_Object* pAttr = GetAttr(owner, name, bInheritable, subindex);
   if (ToName(pAttr))
     return pAttr->GetString();
   return CFX_ByteString(default_value);
 }
 
-FX_ARGB CPDF_StructElementImpl::GetColor(const CFX_ByteStringC& owner,
-                                         const CFX_ByteStringC& name,
-                                         FX_ARGB default_value,
-                                         bool bInheritable,
-                                         int subindex) {
+FX_ARGB CPDF_StructElement::GetColor(const CFX_ByteStringC& owner,
+                                     const CFX_ByteStringC& name,
+                                     FX_ARGB default_value,
+                                     bool bInheritable,
+                                     int subindex) {
   CPDF_Array* pArray = ToArray(GetAttr(owner, name, bInheritable, subindex));
   if (!pArray)
     return default_value;
@@ -412,19 +400,19 @@
          ((int)(pArray->GetNumberAt(1) * 255) << 8) |
          (int)(pArray->GetNumberAt(2) * 255);
 }
-FX_FLOAT CPDF_StructElementImpl::GetNumber(const CFX_ByteStringC& owner,
-                                           const CFX_ByteStringC& name,
-                                           FX_FLOAT default_value,
-                                           bool bInheritable,
-                                           int subindex) {
+FX_FLOAT CPDF_StructElement::GetNumber(const CFX_ByteStringC& owner,
+                                       const CFX_ByteStringC& name,
+                                       FX_FLOAT default_value,
+                                       bool bInheritable,
+                                       int subindex) {
   CPDF_Object* pAttr = GetAttr(owner, name, bInheritable, subindex);
   return ToNumber(pAttr) ? pAttr->GetNumber() : default_value;
 }
-int CPDF_StructElementImpl::GetInteger(const CFX_ByteStringC& owner,
-                                       const CFX_ByteStringC& name,
-                                       int default_value,
-                                       bool bInheritable,
-                                       int subindex) {
+int CPDF_StructElement::GetInteger(const CFX_ByteStringC& owner,
+                                   const CFX_ByteStringC& name,
+                                   int default_value,
+                                   bool bInheritable,
+                                   int subindex) {
   CPDF_Object* pAttr = GetAttr(owner, name, bInheritable, subindex);
   return ToNumber(pAttr) ? pAttr->GetInteger() : default_value;
 }
diff --git a/core/fpdfdoc/fpdf_tagged.h b/core/fpdfdoc/fpdf_tagged.h
index aa697ca..fbbb49f 100644
--- a/core/fpdfdoc/fpdf_tagged.h
+++ b/core/fpdfdoc/fpdf_tagged.h
@@ -21,46 +21,23 @@
       const CPDF_Document* pDoc,
       const CPDF_Dictionary* pPageDict);
 
-  virtual ~IPDF_StructTree() {}
 
   virtual int CountTopElements() const = 0;
   virtual IPDF_StructElement* GetTopElement(int i) const = 0;
-};
 
-struct CPDF_StructKid {
-  enum { Invalid, Element, PageContent, StreamContent, Object } m_Type;
-
-  union {
-    struct {
-      IPDF_StructElement* m_pElement;
-      CPDF_Dictionary* m_pDict;
-    } m_Element;
-    struct {
-      uint32_t m_PageObjNum;
-      uint32_t m_ContentId;
-    } m_PageContent;
-    struct {
-      uint32_t m_PageObjNum;
-      uint32_t m_ContentId;
-      uint32_t m_RefObjNum;
-    } m_StreamContent;
-    struct {
-      uint32_t m_PageObjNum;
-      uint32_t m_RefObjNum;
-    } m_Object;
-  };
+ protected:
+  friend std::default_delete<IPDF_StructTree>;
+  virtual ~IPDF_StructTree() {}
 };
 
 class IPDF_StructElement {
  public:
-  virtual ~IPDF_StructElement() {}
-
   virtual IPDF_StructTree* GetTree() const = 0;
   virtual const CFX_ByteString& GetType() const = 0;
   virtual IPDF_StructElement* GetParent() const = 0;
   virtual CPDF_Dictionary* GetDict() const = 0;
   virtual int CountKids() const = 0;
-  virtual const CPDF_StructKid& GetKid(int index) const = 0;
+  virtual IPDF_StructElement* GetKidIfElement(int index) const = 0;
 
   virtual CPDF_Object* GetAttr(const CFX_ByteStringC& owner,
                                const CFX_ByteStringC& name,
@@ -90,6 +67,9 @@
                          int default_value,
                          bool bInheritable = false,
                          int subindex = -1) = 0;
+
+ protected:
+  virtual ~IPDF_StructElement() {}
 };
 
 #endif  // CORE_FPDFDOC_FPDF_TAGGED_H_
diff --git a/core/fpdfdoc/tagged_int.h b/core/fpdfdoc/tagged_int.h
index 03f1c40..ce24602 100644
--- a/core/fpdfdoc/tagged_int.h
+++ b/core/fpdfdoc/tagged_int.h
@@ -15,39 +15,53 @@
 #include "core/fxcrt/cfx_retain_ptr.h"
 #include "third_party/base/stl_util.h"
 
-class CPDF_StructElementImpl;
+class CPDF_StructElement;
 
-class CPDF_StructTreeImpl final : public IPDF_StructTree {
+struct CPDF_StructKid {
+  CPDF_StructKid();
+  CPDF_StructKid(const CPDF_StructKid& that);
+  ~CPDF_StructKid();
+
+  enum { Invalid, Element, PageContent, StreamContent, Object } m_Type;
+
+  CFX_RetainPtr<CPDF_StructElement> m_pElement;  // For Element.
+  CPDF_Dictionary* m_pDict;                      // For Element.
+  uint32_t m_PageObjNum;  // For PageContent, StreamContent, Object.
+  uint32_t m_RefObjNum;   // For StreamContent, Object.
+  uint32_t m_ContentId;   // For PageContent, StreamContent.
+};
+
+class CPDF_StructTree final : public IPDF_StructTree {
  public:
-  explicit CPDF_StructTreeImpl(const CPDF_Document* pDoc);
-  ~CPDF_StructTreeImpl() override;
+  explicit CPDF_StructTree(const CPDF_Document* pDoc);
+  ~CPDF_StructTree() override;
 
   // IPDF_StructTree:
   int CountTopElements() const override;
   IPDF_StructElement* GetTopElement(int i) const override;
 
   void LoadPageTree(const CPDF_Dictionary* pPageDict);
-  CPDF_StructElementImpl* AddPageNode(
+  CFX_RetainPtr<CPDF_StructElement> AddPageNode(
       CPDF_Dictionary* pElement,
-      std::map<CPDF_Dictionary*, CPDF_StructElementImpl*>& map,
+      std::map<CPDF_Dictionary*, CFX_RetainPtr<CPDF_StructElement>>* map,
       int nLevel = 0);
   bool AddTopLevelNode(CPDF_Dictionary* pDict,
-                       CPDF_StructElementImpl* pElement);
+                       const CFX_RetainPtr<CPDF_StructElement>& pElement);
 
  protected:
   const CPDF_Dictionary* const m_pTreeRoot;
   const CPDF_Dictionary* const m_pRoleMap;
   const CPDF_Dictionary* m_pPage;
-  std::vector<CFX_RetainPtr<CPDF_StructElementImpl>> m_Kids;
+  std::vector<CFX_RetainPtr<CPDF_StructElement>> m_Kids;
 
-  friend class CPDF_StructElementImpl;
+  friend class CPDF_StructElement;
 };
 
-class CPDF_StructElementImpl final : public IPDF_StructElement {
+class CPDF_StructElement final : public CFX_Retainable,
+                                 public IPDF_StructElement {
  public:
-  CPDF_StructElementImpl(CPDF_StructTreeImpl* pTree,
-                         CPDF_StructElementImpl* pParent,
-                         CPDF_Dictionary* pDict);
+  template <typename T, typename... Args>
+  friend CFX_RetainPtr<T> pdfium::MakeRetain(Args&&... args);
 
   // IPDF_StructElement
   IPDF_StructTree* GetTree() const override;
@@ -55,7 +69,7 @@
   IPDF_StructElement* GetParent() const override;
   CPDF_Dictionary* GetDict() const override;
   int CountKids() const override;
-  const CPDF_StructKid& GetKid(int index) const override;
+  IPDF_StructElement* GetKidIfElement(int index) const override;
   CPDF_Object* GetAttr(const CFX_ByteStringC& owner,
                        const CFX_ByteStringC& name,
                        bool bInheritable = false,
@@ -81,26 +95,25 @@
                  bool bInheritable = false,
                  int subindex = -1) override;
 
+  std::vector<CPDF_StructKid>* GetKids() { return &m_Kids; }
   void LoadKids(CPDF_Dictionary* pDict);
   void LoadKid(uint32_t PageObjNum, CPDF_Object* pObj, CPDF_StructKid* pKid);
   CPDF_Object* GetAttr(const CFX_ByteStringC& owner,
                        const CFX_ByteStringC& name,
                        bool bInheritable,
                        int subindex);
-  CPDF_StructElementImpl* Retain();
-  void Release();
 
- protected:
-  ~CPDF_StructElementImpl() override;
+ private:
+  CPDF_StructElement(CPDF_StructTree* pTree,
+                     CPDF_StructElement* pParent,
+                     CPDF_Dictionary* pDict);
+  ~CPDF_StructElement() override;
 
-  int m_RefCount;
-  CPDF_StructTreeImpl* const m_pTree;
-  CPDF_StructElementImpl* const m_pParent;
+  CPDF_StructTree* const m_pTree;
+  CPDF_StructElement* const m_pParent;
   CPDF_Dictionary* const m_pDict;
   CFX_ByteString m_Type;
   std::vector<CPDF_StructKid> m_Kids;
-
-  friend class CPDF_StructTreeImpl;
 };
 
 #endif  // CORE_FPDFDOC_TAGGED_INT_H_
diff --git a/core/fpdftext/cpdf_textpage.cpp b/core/fpdftext/cpdf_textpage.cpp
index 9cde4f5..73a1a7e 100644
--- a/core/fpdftext/cpdf_textpage.cpp
+++ b/core/fpdftext/cpdf_textpage.cpp
@@ -55,7 +55,7 @@
       pTextObj->GetItemInfo(i, &item);
       if (item.m_CharCode == static_cast<uint32_t>(-1)) {
         FX_FLOAT fontsize_h = pTextObj->m_TextState.GetFontSizeH();
-        FX_FLOAT kerning = -fontsize_h * item.m_OriginX / 1000;
+        FX_FLOAT kerning = -fontsize_h * item.m_Origin.x / 1000;
         baseSpace = std::min(baseSpace, kerning + spacing);
         bAllChar = false;
       }
@@ -108,6 +108,22 @@
 
 }  // namespace
 
+FPDF_CHAR_INFO::FPDF_CHAR_INFO()
+    : m_Unicode(0),
+      m_Charcode(0),
+      m_Flag(0),
+      m_FontSize(0),
+      m_pTextObj(nullptr) {}
+
+FPDF_CHAR_INFO::~FPDF_CHAR_INFO() {}
+
+PAGECHAR_INFO::PAGECHAR_INFO()
+    : m_Index(0), m_CharCode(0), m_Unicode(0), m_Flag(0), m_pTextObj(nullptr) {}
+
+PAGECHAR_INFO::PAGECHAR_INFO(const PAGECHAR_INFO&) = default;
+
+PAGECHAR_INFO::~PAGECHAR_INFO() {}
+
 CPDF_TextPage::CPDF_TextPage(const CPDF_Page* pPage, FPDFText_Direction flags)
     : m_pPage(pPage),
       m_parserflag(flags),
@@ -115,8 +131,9 @@
       m_bIsParsed(false),
       m_TextlineDir(TextOrientation::Unknown) {
   m_TextBuf.EstimateSize(0, 10240);
-  pPage->GetDisplayMatrix(m_DisplayMatrix, 0, 0, (int)pPage->GetPageWidth(),
-                          (int)pPage->GetPageHeight(), 0);
+  m_DisplayMatrix =
+      pPage->GetDisplayMatrix(0, 0, static_cast<int>(pPage->GetPageWidth()),
+                              static_cast<int>(pPage->GetPageHeight()), 0);
 }
 
 CPDF_TextPage::~CPDF_TextPage() {}
@@ -238,32 +255,33 @@
       bFlagNewRect = true;
     }
     if (bFlagNewRect) {
-      FX_FLOAT orgX = info_curchar.m_OriginX, orgY = info_curchar.m_OriginY;
-      CFX_Matrix matrix, matrix_reverse;
-      info_curchar.m_pTextObj->GetTextMatrix(&matrix);
+      CFX_Matrix matrix = info_curchar.m_pTextObj->GetTextMatrix();
       matrix.Concat(info_curchar.m_Matrix);
+
+      CFX_Matrix matrix_reverse;
       matrix_reverse.SetReverse(matrix);
-      matrix_reverse.Transform(orgX, orgY);
+
+      CFX_PointF origin = matrix_reverse.Transform(info_curchar.m_Origin);
       rect.left = info_curchar.m_CharBox.left;
       rect.right = info_curchar.m_CharBox.right;
       if (pCurObj->GetFont()->GetTypeDescent()) {
-        rect.bottom = orgY +
+        rect.bottom = origin.y +
                       pCurObj->GetFont()->GetTypeDescent() *
                           pCurObj->GetFontSize() / 1000;
-        FX_FLOAT xPosTemp = orgX;
-        matrix.Transform(xPosTemp, rect.bottom);
+
+        rect.bottom = matrix.Transform(CFX_PointF(origin.x, rect.bottom)).y;
       } else {
         rect.bottom = info_curchar.m_CharBox.bottom;
       }
       if (pCurObj->GetFont()->GetTypeAscent()) {
         rect.top =
-            orgY +
+            origin.y +
             pCurObj->GetFont()->GetTypeAscent() * pCurObj->GetFontSize() / 1000;
         FX_FLOAT xPosTemp =
-            orgX +
+            origin.x +
             GetCharWidth(info_curchar.m_CharCode, pCurObj->GetFont()) *
                 pCurObj->GetFontSize() / 1000;
-        matrix.Transform(xPosTemp, rect.top);
+        rect.top = matrix.Transform(CFX_PointF(xPosTemp, rect.top)).y;
       } else {
         rect.top = info_curchar.m_CharBox.top;
       }
@@ -282,9 +300,8 @@
   return rectArray;
 }
 
-int CPDF_TextPage::GetIndexAtPos(CFX_FloatPoint point,
-                                 FX_FLOAT xTolerance,
-                                 FX_FLOAT yTolerance) const {
+int CPDF_TextPage::GetIndexAtPos(const CFX_PointF& point,
+                                 const CFX_SizeF& tolerance) const {
   if (!m_bIsParsed)
     return -3;
 
@@ -295,16 +312,16 @@
   while (pos < pdfium::CollectionSize<int>(m_CharList)) {
     PAGECHAR_INFO charinfo = m_CharList[pos];
     CFX_FloatRect charrect = charinfo.m_CharBox;
-    if (charrect.Contains(point.x, point.y))
+    if (charrect.Contains(point))
       break;
-    if (xTolerance > 0 || yTolerance > 0) {
+    if (tolerance.width > 0 || tolerance.height > 0) {
       CFX_FloatRect charRectExt;
       charrect.Normalize();
-      charRectExt.left = charrect.left - xTolerance / 2;
-      charRectExt.right = charrect.right + xTolerance / 2;
-      charRectExt.top = charrect.top + yTolerance / 2;
-      charRectExt.bottom = charrect.bottom - yTolerance / 2;
-      if (charRectExt.Contains(point.x, point.y)) {
+      charRectExt.left = charrect.left - tolerance.width / 2;
+      charRectExt.right = charrect.right + tolerance.width / 2;
+      charRectExt.top = charrect.top + tolerance.height / 2;
+      charRectExt.bottom = charrect.bottom - tolerance.height / 2;
+      if (charRectExt.Contains(point)) {
         double curXdif, curYdif;
         curXdif = FXSYS_fabs(point.x - charrect.left) <
                           FXSYS_fabs(point.x - charrect.right)
@@ -336,9 +353,9 @@
   CFX_WideString strText;
   for (const auto& charinfo : m_CharList) {
     if (IsRectIntersect(rect, charinfo.m_CharBox)) {
-      if (FXSYS_fabs(posy - charinfo.m_OriginY) > 0 && !IsContainPreChar &&
+      if (FXSYS_fabs(posy - charinfo.m_Origin.y) > 0 && !IsContainPreChar &&
           IsAddLineFeed) {
-        posy = charinfo.m_OriginY;
+        posy = charinfo.m_Origin.y;
         if (!strText.IsEmpty())
           strText += L"\r\n";
       }
@@ -360,14 +377,6 @@
   return strText;
 }
 
-int CPDF_TextPage::GetIndexAtPos(FX_FLOAT x,
-                                 FX_FLOAT y,
-                                 FX_FLOAT xTolerance,
-                                 FX_FLOAT yTolerance) const {
-  CFX_FloatPoint point(x, y);
-  return GetIndexAtPos(point, xTolerance, yTolerance);
-}
-
 void CPDF_TextPage::GetCharInfo(int index, FPDF_CHAR_INFO* info) const {
   if (!m_bIsParsed)
     return;
@@ -377,8 +386,7 @@
 
   const PAGECHAR_INFO& charinfo = m_CharList[index];
   info->m_Charcode = charinfo.m_CharCode;
-  info->m_OriginX = charinfo.m_OriginX;
-  info->m_OriginY = charinfo.m_OriginY;
+  info->m_Origin = charinfo.m_Origin;
   info->m_Unicode = charinfo.m_Unicode;
   info->m_Flag = charinfo.m_Flag;
   info->m_CharBox = charinfo.m_CharBox;
@@ -736,10 +744,9 @@
     const CFX_Matrix& formMatrix,
     const CPDF_PageObjectList* pObjList,
     CPDF_PageObjectList::const_iterator ObjPos) {
-  CFX_FloatRect re(pTextObj->m_Left, pTextObj->m_Bottom, pTextObj->m_Right,
-                   pTextObj->m_Top);
   if (FXSYS_fabs(pTextObj->m_Right - pTextObj->m_Left) < 0.01f)
     return;
+
   size_t count = m_LineObj.size();
   PDFTEXT_Obj Obj;
   Obj.m_pTextObj = pTextObj;
@@ -750,6 +757,7 @@
   }
   if (IsSameAsPreTextObject(pTextObj, pObjList, ObjPos))
     return;
+
   PDFTEXT_Obj prev_Obj = m_LineObj[count - 1];
   CPDF_TextObjectItem item;
   int nItem = prev_Obj.m_pTextObj->CountItems();
@@ -757,8 +765,8 @@
   FX_FLOAT prev_width =
       GetCharWidth(item.m_CharCode, prev_Obj.m_pTextObj->GetFont()) *
       prev_Obj.m_pTextObj->GetFontSize() / 1000;
-  CFX_Matrix prev_matrix;
-  prev_Obj.m_pTextObj->GetTextMatrix(&prev_matrix);
+
+  CFX_Matrix prev_matrix = prev_Obj.m_pTextObj->GetTextMatrix();
   prev_width = FXSYS_fabs(prev_width);
   prev_matrix.Concat(prev_Obj.m_formMatrix);
   prev_width = prev_matrix.TransformDistance(prev_width);
@@ -766,41 +774,37 @@
   FX_FLOAT this_width = GetCharWidth(item.m_CharCode, pTextObj->GetFont()) *
                         pTextObj->GetFontSize() / 1000;
   this_width = FXSYS_fabs(this_width);
-  CFX_Matrix this_matrix;
-  pTextObj->GetTextMatrix(&this_matrix);
+
+  CFX_Matrix this_matrix = pTextObj->GetTextMatrix();
   this_width = FXSYS_fabs(this_width);
   this_matrix.Concat(formMatrix);
   this_width = this_matrix.TransformDistance(this_width);
+
   FX_FLOAT threshold =
       prev_width > this_width ? prev_width / 4 : this_width / 4;
-  FX_FLOAT prev_x = prev_Obj.m_pTextObj->GetPosX(),
-           prev_y = prev_Obj.m_pTextObj->GetPosY();
-  prev_Obj.m_formMatrix.Transform(prev_x, prev_y);
-  m_DisplayMatrix.Transform(prev_x, prev_y);
-  FX_FLOAT this_x = pTextObj->GetPosX(), this_y = pTextObj->GetPosY();
-  formMatrix.Transform(this_x, this_y);
-  m_DisplayMatrix.Transform(this_x, this_y);
-  if (FXSYS_fabs(this_y - prev_y) > threshold * 2) {
+  CFX_PointF prev_pos = m_DisplayMatrix.Transform(
+      prev_Obj.m_formMatrix.Transform(prev_Obj.m_pTextObj->GetPos()));
+  CFX_PointF this_pos =
+      m_DisplayMatrix.Transform(formMatrix.Transform(pTextObj->GetPos()));
+  if (FXSYS_fabs(this_pos.y - prev_pos.y) > threshold * 2) {
     for (size_t i = 0; i < count; i++)
       ProcessTextObject(m_LineObj[i]);
     m_LineObj.clear();
     m_LineObj.push_back(Obj);
     return;
   }
-  size_t i;
-  for (i = count; i > 0; --i) {
+
+  for (size_t i = count; i > 0; --i) {
     PDFTEXT_Obj prev_text_obj = m_LineObj[i - 1];
-    FX_FLOAT Prev_x = prev_text_obj.m_pTextObj->GetPosX(),
-             Prev_y = prev_text_obj.m_pTextObj->GetPosY();
-    prev_text_obj.m_formMatrix.Transform(Prev_x, Prev_y);
-    m_DisplayMatrix.Transform(Prev_x, Prev_y);
-    if (this_x >= Prev_x) {
+    CFX_PointF new_prev_pos =
+        m_DisplayMatrix.Transform(prev_text_obj.m_formMatrix.Transform(
+            prev_text_obj.m_pTextObj->GetPos()));
+    if (this_pos.x >= new_prev_pos.x) {
       m_LineObj.insert(m_LineObj.begin() + i, Obj);
-      break;
+      return;
     }
   }
-  if (i == 0)
-    m_LineObj.insert(m_LineObj.begin(), Obj);
+  m_LineObj.insert(m_LineObj.begin(), Obj);
 }
 
 FPDFText_MarkedContent CPDF_TextPage::PreMarkedContent(PDFTEXT_Obj Obj) {
@@ -887,36 +891,24 @@
     return;
 
   CPDF_Font* pFont = pTextObj->GetFont();
-  CFX_Matrix formMatrix = Obj.m_formMatrix;
-  CFX_Matrix matrix;
-  pTextObj->GetTextMatrix(&matrix);
-  matrix.Concat(formMatrix);
-  FX_FLOAT fPosX = pTextObj->GetPosX();
-  FX_FLOAT fPosY = pTextObj->GetPosY();
-  int nCharInfoIndex = m_TextBuf.GetLength();
-  CFX_FloatRect charBox;
-  charBox.top = pTextObj->m_Top;
-  charBox.left = pTextObj->m_Left;
-  charBox.right = pTextObj->m_Right;
-  charBox.bottom = pTextObj->m_Bottom;
+  CFX_Matrix matrix = pTextObj->GetTextMatrix();
+  matrix.Concat(Obj.m_formMatrix);
+
   for (FX_STRSIZE k = 0; k < nItems; k++) {
     FX_WCHAR wChar = actText.GetAt(k);
     if (wChar <= 0x80 && !isprint(wChar))
       wChar = 0x20;
     if (wChar >= 0xFFFD)
       continue;
+
     PAGECHAR_INFO charinfo;
-    charinfo.m_OriginX = fPosX;
-    charinfo.m_OriginY = fPosY;
-    charinfo.m_Index = nCharInfoIndex;
+    charinfo.m_Origin = pTextObj->GetPos();
+    charinfo.m_Index = m_TextBuf.GetLength();
     charinfo.m_Unicode = wChar;
     charinfo.m_CharCode = pFont->CharCodeFromUnicode(wChar);
     charinfo.m_Flag = FPDFTEXT_CHAR_PIECE;
     charinfo.m_pTextObj = pTextObj;
-    charinfo.m_CharBox.top = charBox.top;
-    charinfo.m_CharBox.left = charBox.left;
-    charinfo.m_CharBox.right = charBox.right;
-    charinfo.m_CharBox.bottom = charBox.bottom;
+    charinfo.m_CharBox = pTextObj->GetRect();
     charinfo.m_Matrix = matrix;
     m_TempTextBuf.AppendChar(wChar);
     m_TempCharList.push_back(charinfo);
@@ -974,9 +966,9 @@
     return;
   CFX_Matrix formMatrix = Obj.m_formMatrix;
   CPDF_Font* pFont = pTextObj->GetFont();
-  CFX_Matrix matrix;
-  pTextObj->GetTextMatrix(&matrix);
+  CFX_Matrix matrix = pTextObj->GetTextMatrix();
   matrix.Concat(formMatrix);
+
   FPDFText_MarkedContent ePreMKC = PreMarkedContent(Obj);
   if (ePreMKC == FPDFText_MarkedContent::Done) {
     m_pPreTextObj = pTextObj;
@@ -986,15 +978,11 @@
   GenerateCharacter result = GenerateCharacter::None;
   if (m_pPreTextObj) {
     result = ProcessInsertObject(pTextObj, formMatrix);
-    if (result == GenerateCharacter::LineBreak) {
-      m_CurlineRect =
-          CFX_FloatRect(Obj.m_pTextObj->m_Left, Obj.m_pTextObj->m_Bottom,
-                        Obj.m_pTextObj->m_Right, Obj.m_pTextObj->m_Top);
-    } else {
-      m_CurlineRect.Union(
-          CFX_FloatRect(Obj.m_pTextObj->m_Left, Obj.m_pTextObj->m_Bottom,
-                        Obj.m_pTextObj->m_Right, Obj.m_pTextObj->m_Top));
-    }
+    if (result == GenerateCharacter::LineBreak)
+      m_CurlineRect = Obj.m_pTextObj->GetRect();
+    else
+      m_CurlineRect.Union(Obj.m_pTextObj->GetRect());
+
     switch (result) {
       case GenerateCharacter::None:
         break;
@@ -1041,10 +1029,9 @@
         break;
     }
   } else {
-    m_CurlineRect =
-        CFX_FloatRect(Obj.m_pTextObj->m_Left, Obj.m_pTextObj->m_Bottom,
-                      Obj.m_pTextObj->m_Right, Obj.m_pTextObj->m_Top);
+    m_CurlineRect = Obj.m_pTextObj->GetRect();
   }
+
   if (ePreMKC == FPDFText_MarkedContent::Delay) {
     ProcessMarkedContent(Obj);
     m_pPreTextObj = pTextObj;
@@ -1067,8 +1054,6 @@
   for (int i = 0; i < nItems; i++) {
     CPDF_TextObjectItem item;
     PAGECHAR_INFO charinfo;
-    charinfo.m_OriginX = 0;
-    charinfo.m_OriginY = 0;
     pTextObj->GetItemInfo(i, &item);
     if (item.m_CharCode == static_cast<uint32_t>(-1)) {
       CFX_WideString str = m_TempTextBuf.MakeString();
@@ -1078,7 +1063,7 @@
         continue;
 
       FX_FLOAT fontsize_h = pTextObj->m_TextState.GetFontSizeH();
-      spacing = -fontsize_h * item.m_OriginX / 1000;
+      spacing = -fontsize_h * item.m_Origin.x / 1000;
       continue;
     }
     FX_FLOAT charSpace = pTextObj->m_TextState.GetCharSpace();
@@ -1114,11 +1099,10 @@
         m_TempTextBuf.AppendChar(TEXT_SPACE_CHAR);
         charinfo.m_CharCode = CPDF_Font::kInvalidCharCode;
         charinfo.m_Matrix = formMatrix;
-        matrix.Transform(item.m_OriginX, item.m_OriginY, charinfo.m_OriginX,
-                         charinfo.m_OriginY);
+        charinfo.m_Origin = matrix.Transform(item.m_Origin);
         charinfo.m_CharBox =
-            CFX_FloatRect(charinfo.m_OriginX, charinfo.m_OriginY,
-                          charinfo.m_OriginX, charinfo.m_OriginY);
+            CFX_FloatRect(charinfo.m_Origin.x, charinfo.m_Origin.y,
+                          charinfo.m_Origin.x, charinfo.m_Origin.y);
         m_TempCharList.push_back(charinfo);
       }
       if (item.m_CharCode == CPDF_Font::kInvalidCharCode)
@@ -1137,20 +1121,20 @@
       charinfo.m_Flag = FPDFTEXT_CHAR_UNUNICODE;
     else
       charinfo.m_Flag = FPDFTEXT_CHAR_NORMAL;
+
     charinfo.m_pTextObj = pTextObj;
-    charinfo.m_OriginX = 0, charinfo.m_OriginY = 0;
-    matrix.Transform(item.m_OriginX, item.m_OriginY, charinfo.m_OriginX,
-                     charinfo.m_OriginY);
+    charinfo.m_Origin = matrix.Transform(item.m_Origin);
+
     FX_RECT rect =
         charinfo.m_pTextObj->GetFont()->GetCharBBox(charinfo.m_CharCode);
     charinfo.m_CharBox.top =
-        rect.top * pTextObj->GetFontSize() / 1000 + item.m_OriginY;
+        rect.top * pTextObj->GetFontSize() / 1000 + item.m_Origin.y;
     charinfo.m_CharBox.left =
-        rect.left * pTextObj->GetFontSize() / 1000 + item.m_OriginX;
+        rect.left * pTextObj->GetFontSize() / 1000 + item.m_Origin.x;
     charinfo.m_CharBox.right =
-        rect.right * pTextObj->GetFontSize() / 1000 + item.m_OriginX;
+        rect.right * pTextObj->GetFontSize() / 1000 + item.m_Origin.x;
     charinfo.m_CharBox.bottom =
-        rect.bottom * pTextObj->GetFontSize() / 1000 + item.m_OriginY;
+        rect.bottom * pTextObj->GetFontSize() / 1000 + item.m_Origin.y;
     if (fabsf(charinfo.m_CharBox.top - charinfo.m_CharBox.bottom) < 0.01f) {
       charinfo.m_CharBox.top =
           charinfo.m_CharBox.bottom + pTextObj->GetFontSize();
@@ -1176,10 +1160,10 @@
       for (int n = pdfium::CollectionSize<int>(m_TempCharList);
            n > pdfium::CollectionSize<int>(m_TempCharList) - count; n--) {
         const PAGECHAR_INFO& charinfo1 = m_TempCharList[n - 1];
+        CFX_PointF diff = charinfo1.m_Origin - charinfo.m_Origin;
         if (charinfo1.m_CharCode == charinfo.m_CharCode &&
             charinfo1.m_pTextObj->GetFont() == charinfo.m_pTextObj->GetFont() &&
-            FXSYS_fabs(charinfo1.m_OriginX - charinfo.m_OriginX) < threshold &&
-            FXSYS_fabs(charinfo1.m_OriginY - charinfo.m_OriginY) < threshold) {
+            FXSYS_fabs(diff.x) < threshold && FXSYS_fabs(diff.y) < threshold) {
           bDel = true;
           break;
         }
@@ -1218,12 +1202,13 @@
   CPDF_TextObjectItem first, last;
   pTextObj->GetCharInfo(0, &first);
   pTextObj->GetCharInfo(nChars - 1, &last);
-  CFX_Matrix textMatrix;
-  pTextObj->GetTextMatrix(&textMatrix);
-  textMatrix.TransformPoint(first.m_OriginX, first.m_OriginY);
-  textMatrix.TransformPoint(last.m_OriginX, last.m_OriginY);
-  FX_FLOAT dX = FXSYS_fabs(last.m_OriginX - first.m_OriginX);
-  FX_FLOAT dY = FXSYS_fabs(last.m_OriginY - first.m_OriginY);
+
+  CFX_Matrix textMatrix = pTextObj->GetTextMatrix();
+  first.m_Origin = textMatrix.Transform(first.m_Origin);
+  last.m_Origin = textMatrix.Transform(last.m_Origin);
+
+  FX_FLOAT dX = FXSYS_fabs(last.m_Origin.x - first.m_Origin.x);
+  FX_FLOAT dY = FXSYS_fabs(last.m_Origin.y - first.m_Origin.y);
   if (dX <= 0.0001f && dY <= 0.0001f)
     return TextOrientation::Unknown;
 
@@ -1280,11 +1265,10 @@
   if (WritingMode == TextOrientation::Unknown)
     WritingMode = GetTextObjectWritingMode(m_pPreTextObj);
 
-  CFX_FloatRect this_rect(pObj->m_Left, pObj->m_Bottom, pObj->m_Right,
-                          pObj->m_Top);
-  CFX_FloatRect prev_rect(m_pPreTextObj->m_Left, m_pPreTextObj->m_Bottom,
-                          m_pPreTextObj->m_Right, m_pPreTextObj->m_Top);
-  CPDF_TextObjectItem PrevItem, item;
+  CFX_FloatRect this_rect = pObj->GetRect();
+  CFX_FloatRect prev_rect = m_pPreTextObj->GetRect();
+  CPDF_TextObjectItem PrevItem;
+  CPDF_TextObjectItem item;
   int nItem = m_pPreTextObj->CountItems();
   m_pPreTextObj->GetItemInfo(nItem - 1, &PrevItem);
   pObj->GetItemInfo(0, &item);
@@ -1318,7 +1302,8 @@
       }
     }
   }
-  FX_FLOAT last_pos = PrevItem.m_OriginX;
+
+  FX_FLOAT last_pos = PrevItem.m_Origin.x;
   int nLastWidth = GetCharWidth(PrevItem.m_CharCode, m_pPreTextObj->GetFont());
   FX_FLOAT last_width = nLastWidth * m_pPreTextObj->GetFontSize() / 1000;
   last_width = FXSYS_fabs(last_width);
@@ -1327,47 +1312,45 @@
   this_width = FXSYS_fabs(this_width);
   FX_FLOAT threshold =
       last_width > this_width ? last_width / 4 : this_width / 4;
-  CFX_Matrix prev_matrix, prev_reverse;
-  m_pPreTextObj->GetTextMatrix(&prev_matrix);
+
+  CFX_Matrix prev_matrix = m_pPreTextObj->GetTextMatrix();
   prev_matrix.Concat(m_perMatrix);
+
+  CFX_Matrix prev_reverse;
   prev_reverse.SetReverse(prev_matrix);
-  FX_FLOAT x = pObj->GetPosX();
-  FX_FLOAT y = pObj->GetPosY();
-  formMatrix.Transform(x, y);
-  prev_reverse.Transform(x, y);
+
+  CFX_PointF pos = prev_reverse.Transform(formMatrix.Transform(pObj->GetPos()));
   if (last_width < this_width)
     threshold = prev_reverse.TransformDistance(threshold);
+
   bool bNewline = false;
   if (WritingMode == TextOrientation::Horizontal) {
     CFX_FloatRect rect1(m_pPreTextObj->m_Left, pObj->m_Bottom,
                         m_pPreTextObj->m_Right, pObj->m_Top);
-    CFX_FloatRect rect2(m_pPreTextObj->m_Left, m_pPreTextObj->m_Bottom,
-                        m_pPreTextObj->m_Right, m_pPreTextObj->m_Top);
+    CFX_FloatRect rect2 = m_pPreTextObj->GetRect();
     CFX_FloatRect rect3 = rect1;
     rect1.Intersect(rect2);
     if ((rect1.IsEmpty() && rect2.Height() > 5 && rect3.Height() > 5) ||
-        ((y > threshold * 2 || y < threshold * -3) &&
-         (FXSYS_fabs(y) < 1 ? FXSYS_fabs(x) < FXSYS_fabs(y) : true))) {
+        ((pos.y > threshold * 2 || pos.y < threshold * -3) &&
+         (FXSYS_fabs(pos.y) < 1 ? FXSYS_fabs(pos.x) < FXSYS_fabs(pos.y)
+                                : true))) {
       bNewline = true;
       if (nItem > 1) {
         CPDF_TextObjectItem tempItem;
         m_pPreTextObj->GetItemInfo(0, &tempItem);
-        CFX_Matrix m;
-        m_pPreTextObj->GetTextMatrix(&m);
-        if (PrevItem.m_OriginX > tempItem.m_OriginX &&
+        CFX_Matrix m = m_pPreTextObj->GetTextMatrix();
+        if (PrevItem.m_Origin.x > tempItem.m_Origin.x &&
             m_DisplayMatrix.a > 0.9 && m_DisplayMatrix.b < 0.1 &&
             m_DisplayMatrix.c < 0.1 && m_DisplayMatrix.d < -0.9 && m.b < 0.1 &&
             m.c < 0.1) {
           CFX_FloatRect re(0, m_pPreTextObj->m_Bottom, 1000,
                            m_pPreTextObj->m_Top);
-          if (re.Contains(pObj->GetPosX(), pObj->GetPosY())) {
+          if (re.Contains(pObj->GetPos())) {
             bNewline = false;
           } else {
             CFX_FloatRect rect(0, pObj->m_Bottom, 1000, pObj->m_Top);
-            if (rect.Contains(m_pPreTextObj->GetPosX(),
-                              m_pPreTextObj->GetPosY())) {
+            if (rect.Contains(m_pPreTextObj->GetPos()))
               bNewline = false;
-            }
           }
         }
       }
@@ -1386,9 +1369,9 @@
   CFX_WideString PrevStr =
       m_pPreTextObj->GetFont()->UnicodeFromCharCode(PrevItem.m_CharCode);
   FX_WCHAR preChar = PrevStr.GetAt(PrevStr.GetLength() - 1);
-  CFX_Matrix matrix;
-  pObj->GetTextMatrix(&matrix);
+  CFX_Matrix matrix = pObj->GetTextMatrix();
   matrix.Concat(formMatrix);
+
   threshold = (FX_FLOAT)(nLastWidth > nThisWidth ? nLastWidth : nThisWidth);
   threshold = threshold > 400
                   ? (threshold < 700
@@ -1407,17 +1390,17 @@
       (threshold < 1.39001 && threshold > 1.38999)) {
     threshold *= 1.5;
   }
-  if (FXSYS_fabs(last_pos + last_width - x) > threshold && curChar != L' ' &&
-      preChar != L' ') {
+  if (FXSYS_fabs(last_pos + last_width - pos.x) > threshold &&
+      curChar != L' ' && preChar != L' ') {
     if (curChar != L' ' && preChar != L' ') {
-      if ((x - last_pos - last_width) > threshold ||
-          (last_pos - x - last_width) > threshold) {
+      if ((pos.x - last_pos - last_width) > threshold ||
+          (last_pos - pos.x - last_width) > threshold) {
         return GenerateCharacter::Space;
       }
-      if (x < 0 && (last_pos - x - last_width) > threshold)
+      if (pos.x < 0 && (last_pos - pos.x - last_width) > threshold)
         return GenerateCharacter::Space;
-      if ((x - last_pos - last_width) > this_width ||
-          (x - last_pos - this_width) > last_width) {
+      if ((pos.x - last_pos - last_width) > this_width ||
+          (pos.x - last_pos - this_width) > last_width) {
         return GenerateCharacter::Space;
       }
     }
@@ -1429,10 +1412,9 @@
                                      CPDF_TextObject* pTextObj2) {
   if (!pTextObj1 || !pTextObj2)
     return false;
-  CFX_FloatRect rcPreObj(pTextObj2->m_Left, pTextObj2->m_Bottom,
-                         pTextObj2->m_Right, pTextObj2->m_Top);
-  CFX_FloatRect rcCurObj(pTextObj1->m_Left, pTextObj1->m_Bottom,
-                         pTextObj1->m_Right, pTextObj1->m_Top);
+
+  CFX_FloatRect rcPreObj = pTextObj2->GetRect();
+  CFX_FloatRect rcCurObj = pTextObj1->GetRect();
   if (rcPreObj.IsEmpty() && rcCurObj.IsEmpty()) {
     FX_FLOAT dbXdif = FXSYS_fabs(rcPreObj.left - rcCurObj.left);
     size_t nCount = m_CharList.size();
@@ -1462,21 +1444,22 @@
   if (!nPreCount)
     return true;
 
-  CPDF_TextObjectItem itemPer = {0, 0.0f, 0.0f};
-  CPDF_TextObjectItem itemCur = {0, 0.0f, 0.0f};
+  CPDF_TextObjectItem itemPer;
+  CPDF_TextObjectItem itemCur;
   for (int i = 0; i < nPreCount; i++) {
     pTextObj2->GetItemInfo(i, &itemPer);
     pTextObj1->GetItemInfo(i, &itemCur);
     if (itemCur.m_CharCode != itemPer.m_CharCode)
       return false;
   }
-  if (FXSYS_fabs(pTextObj1->GetPosX() - pTextObj2->GetPosX()) >
-          GetCharWidth(itemPer.m_CharCode, pTextObj2->GetFont()) *
-              pTextObj2->GetFontSize() / 1000 * 0.9 ||
-      FXSYS_fabs(pTextObj1->GetPosY() - pTextObj2->GetPosY()) >
-          std::max(std::max(rcPreObj.Height(), rcPreObj.Width()),
-                   pTextObj2->GetFontSize()) /
-              8) {
+
+  CFX_PointF diff = pTextObj1->GetPos() - pTextObj2->GetPos();
+  FX_FLOAT font_size = pTextObj2->GetFontSize();
+  FX_FLOAT char_size = GetCharWidth(itemPer.m_CharCode, pTextObj2->GetFont());
+  FX_FLOAT max_pre_size =
+      std::max(std::max(rcPreObj.Height(), rcPreObj.Width()), font_size);
+  if (FXSYS_fabs(diff.x) > char_size * font_size / 1000 * 0.9 ||
+      FXSYS_fabs(diff.y) > max_pre_size / 8) {
     return false;
   }
   return true;
@@ -1507,11 +1490,13 @@
     preChar = &m_CharList.back();
   else
     return false;
+
   info.m_Index = m_TextBuf.GetLength();
   info.m_Unicode = unicode;
   info.m_pTextObj = nullptr;
   info.m_CharCode = CPDF_Font::kInvalidCharCode;
   info.m_Flag = FPDFTEXT_CHAR_GENERATED;
+
   int preWidth = 0;
   if (preChar->m_pTextObj && preChar->m_CharCode != -1) {
     preWidth =
@@ -1523,10 +1508,10 @@
   if (!fFontSize)
     fFontSize = kDefaultFontSize;
 
-  info.m_OriginX = preChar->m_OriginX + preWidth * (fFontSize) / 1000;
-  info.m_OriginY = preChar->m_OriginY;
-  info.m_CharBox = CFX_FloatRect(info.m_OriginX, info.m_OriginY, info.m_OriginX,
-                                 info.m_OriginY);
+  info.m_Origin = CFX_PointF(
+      preChar->m_Origin.x + preWidth * (fFontSize) / 1000, preChar->m_Origin.y);
+  info.m_CharBox = CFX_FloatRect(info.m_Origin.x, info.m_Origin.y,
+                                 info.m_Origin.x, info.m_Origin.y);
   return true;
 }
 
diff --git a/core/fpdftext/cpdf_textpage.h b/core/fpdftext/cpdf_textpage.h
index 85ee705..91942d1 100644
--- a/core/fpdftext/cpdf_textpage.h
+++ b/core/fpdftext/cpdf_textpage.h
@@ -44,13 +44,16 @@
 
 enum class FPDFText_Direction { Left = -1, Right = 1 };
 
-struct FPDF_CHAR_INFO {
+class FPDF_CHAR_INFO {
+ public:
+  FPDF_CHAR_INFO();
+  ~FPDF_CHAR_INFO();
+
   FX_WCHAR m_Unicode;
   FX_WCHAR m_Charcode;
   int32_t m_Flag;
   FX_FLOAT m_FontSize;
-  FX_FLOAT m_OriginX;
-  FX_FLOAT m_OriginY;
+  CFX_PointF m_Origin;
   CFX_FloatRect m_CharBox;
   CPDF_TextObject* m_pTextObj;
   CFX_Matrix m_Matrix;
@@ -61,16 +64,20 @@
   int m_nCount;
 };
 
-struct PAGECHAR_INFO {
+class PAGECHAR_INFO {
+ public:
+  PAGECHAR_INFO();
+  PAGECHAR_INFO(const PAGECHAR_INFO&);
+  ~PAGECHAR_INFO();
+
+  int m_Index;
   int m_CharCode;
   FX_WCHAR m_Unicode;
-  FX_FLOAT m_OriginX;
-  FX_FLOAT m_OriginY;
   int32_t m_Flag;
+  CFX_PointF m_Origin;
   CFX_FloatRect m_CharBox;
   CPDF_TextObject* m_pTextObj;
   CFX_Matrix m_Matrix;
-  int m_Index;
 };
 
 struct PDFTEXT_Obj {
@@ -91,13 +98,7 @@
   int CountChars() const;
   void GetCharInfo(int index, FPDF_CHAR_INFO* info) const;
   std::vector<CFX_FloatRect> GetRectArray(int start, int nCount) const;
-  int GetIndexAtPos(CFX_FloatPoint point,
-                    FX_FLOAT xTolerance,
-                    FX_FLOAT yTolerance) const;
-  int GetIndexAtPos(FX_FLOAT x,
-                    FX_FLOAT y,
-                    FX_FLOAT xTolerance,
-                    FX_FLOAT yTolerance) const;
+  int GetIndexAtPos(const CFX_PointF& point, const CFX_SizeF& tolerance) const;
   CFX_WideString GetTextByRect(const CFX_FloatRect& rect) const;
   CFX_WideString GetPageText(int start = 0, int nCount = -1) const;
   int CountRects(int start, int nCount);
diff --git a/core/fxcodec/codec/fx_codec_bmp.cpp b/core/fxcodec/codec/ccodec_bmpmodule.cpp
similarity index 91%
rename from core/fxcodec/codec/fx_codec_bmp.cpp
rename to core/fxcodec/codec/ccodec_bmpmodule.cpp
index ae83d3f..9d64199 100644
--- a/core/fxcodec/codec/fx_codec_bmp.cpp
+++ b/core/fxcodec/codec/ccodec_bmpmodule.cpp
@@ -4,14 +4,16 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
+#include "core/fxcodec/codec/ccodec_bmpmodule.h"
+
 #include "core/fxcodec/codec/codec_int.h"
 #include "core/fxcodec/fx_codec.h"
 #include "core/fxcodec/lbmp/fx_bmp.h"
 #include "core/fxge/fx_dib.h"
+
 struct FXBMP_Context {
   bmp_decompress_struct_p bmp_ptr;
   void* parent_ptr;
-  void* child_ptr;
 
   void* (*m_AllocFunc)(unsigned int);
   void (*m_FreeFunc)(void*);
@@ -34,16 +36,22 @@
                               uint8_t* row_buf) {
   FXBMP_Context* p = (FXBMP_Context*)bmp_ptr->context_ptr;
   CCodec_BmpModule* pModule = (CCodec_BmpModule*)p->parent_ptr;
-  pModule->ReadScanlineCallback(p->child_ptr, row_num, row_buf);
+  pModule->GetDelegate()->BmpReadScanline(row_num, row_buf);
 }
 static bool bmp_get_data_position(bmp_decompress_struct_p bmp_ptr,
                                   uint32_t rcd_pos) {
   FXBMP_Context* p = (FXBMP_Context*)bmp_ptr->context_ptr;
   CCodec_BmpModule* pModule = (CCodec_BmpModule*)p->parent_ptr;
-  return pModule->InputImagePositionBufCallback(p->child_ptr, rcd_pos);
+  return pModule->GetDelegate()->BmpInputImagePositionBuf(rcd_pos);
 }
 
-FXBMP_Context* CCodec_BmpModule::Start(void* pModule) {
+CCodec_BmpModule::CCodec_BmpModule() {
+  memset(m_szLastError, 0, sizeof(m_szLastError));
+}
+
+CCodec_BmpModule::~CCodec_BmpModule() {}
+
+FXBMP_Context* CCodec_BmpModule::Start() {
   FXBMP_Context* p = FX_Alloc(FXBMP_Context, 1);
   if (!p)
     return nullptr;
@@ -56,7 +64,6 @@
   p->m_FreeFunc = bmp_free_func;
   p->bmp_ptr = nullptr;
   p->parent_ptr = (void*)this;
-  p->child_ptr = pModule;
   p->bmp_ptr = bmp_create_decompress();
   if (!p->bmp_ptr) {
     FX_Free(p);
diff --git a/core/fxcodec/codec/ccodec_bmpmodule.h b/core/fxcodec/codec/ccodec_bmpmodule.h
index 605bd62..11d5931 100644
--- a/core/fxcodec/codec/ccodec_bmpmodule.h
+++ b/core/fxcodec/codec/ccodec_bmpmodule.h
@@ -7,23 +7,21 @@
 #ifndef CORE_FXCODEC_CODEC_CCODEC_BMPMODULE_H_
 #define CORE_FXCODEC_CODEC_CCODEC_BMPMODULE_H_
 
+#include "core/fxcodec/codec/icodec_bmpmodule.h"
 #include "core/fxcrt/fx_system.h"
 
-struct FXBMP_Context;
-class CFX_DIBAttribute;
-
-class CCodec_BmpModule {
+class CCodec_BmpModule : public ICodec_BmpModule {
  public:
-  CCodec_BmpModule() { FXSYS_memset(m_szLastError, 0, sizeof(m_szLastError)); }
+  CCodec_BmpModule();
+  ~CCodec_BmpModule() override;
 
-  FXBMP_Context* Start(void* pModule);
-  void Finish(FXBMP_Context* pContext);
-
-  uint32_t GetAvailInput(FXBMP_Context* pContext, uint8_t** avail_buf_ptr);
+  FXBMP_Context* Start() override;
+  void Finish(FXBMP_Context* pContext) override;
+  uint32_t GetAvailInput(FXBMP_Context* pContext,
+                         uint8_t** avail_buf_ptr) override;
   void Input(FXBMP_Context* pContext,
              const uint8_t* src_buf,
-             uint32_t src_size);
-
+             uint32_t src_size) override;
   int32_t ReadHeader(FXBMP_Context* pContext,
                      int32_t* width,
                      int32_t* height,
@@ -31,13 +29,8 @@
                      int32_t* components,
                      int32_t* pal_num,
                      uint32_t** pal_pp,
-                     CFX_DIBAttribute* pAttribute);
-  int32_t LoadImage(FXBMP_Context* pContext);
-
-  bool (*InputImagePositionBufCallback)(void* pModule, uint32_t rcd_pos);
-  void (*ReadScanlineCallback)(void* pModule,
-                               int32_t row_num,
-                               uint8_t* row_buf);
+                     CFX_DIBAttribute* pAttribute) override;
+  int32_t LoadImage(FXBMP_Context* pContext) override;
 
  protected:
   FX_CHAR m_szLastError[256];
diff --git a/core/fxcodec/codec/fx_codec_gif.cpp b/core/fxcodec/codec/ccodec_gifmodule.cpp
similarity index 89%
rename from core/fxcodec/codec/fx_codec_gif.cpp
rename to core/fxcodec/codec/ccodec_gifmodule.cpp
index fadf18f..a85bc5e 100644
--- a/core/fxcodec/codec/fx_codec_gif.cpp
+++ b/core/fxcodec/codec/ccodec_gifmodule.cpp
@@ -4,18 +4,21 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
+#include "core/fxcodec/codec/ccodec_gifmodule.h"
+
 #include "core/fxcodec/codec/codec_int.h"
 #include "core/fxcodec/fx_codec.h"
 #include "core/fxcodec/lgif/fx_gif.h"
 #include "core/fxge/fx_dib.h"
+
 struct FXGIF_Context {
   gif_decompress_struct_p gif_ptr;
   void* parent_ptr;
-  void* child_ptr;
 
   void* (*m_AllocFunc)(unsigned int);
   void (*m_FreeFunc)(void*);
 };
+
 extern "C" {
 static void* gif_alloc_func(unsigned int size) {
   return FX_Alloc(char, size);
@@ -24,31 +27,36 @@
   FX_Free(p);
 }
 };
+
 static void gif_error_data(gif_decompress_struct_p gif_ptr,
                            const FX_CHAR* err_msg) {
   FXSYS_strncpy((char*)gif_ptr->err_ptr, err_msg, GIF_MAX_ERROR_SIZE - 1);
   longjmp(gif_ptr->jmpbuf, 1);
 }
+
 static uint8_t* gif_ask_buf_for_pal(gif_decompress_struct_p gif_ptr,
                                     int32_t pal_size) {
   FXGIF_Context* p = (FXGIF_Context*)gif_ptr->context_ptr;
   CCodec_GifModule* pModule = (CCodec_GifModule*)p->parent_ptr;
-  return pModule->AskLocalPaletteBufCallback(
-      p->child_ptr, gif_get_frame_num(gif_ptr), pal_size);
+  return pModule->GetDelegate()->GifAskLocalPaletteBuf(
+      gif_get_frame_num(gif_ptr), pal_size);
 }
+
 static void gif_record_current_position(gif_decompress_struct_p gif_ptr,
                                         uint32_t* cur_pos_ptr) {
   FXGIF_Context* p = (FXGIF_Context*)gif_ptr->context_ptr;
   CCodec_GifModule* pModule = (CCodec_GifModule*)p->parent_ptr;
-  pModule->RecordCurrentPositionCallback(p->child_ptr, *cur_pos_ptr);
+  pModule->GetDelegate()->GifRecordCurrentPosition(*cur_pos_ptr);
 }
+
 static void gif_read_scanline(gif_decompress_struct_p gif_ptr,
                               int32_t row_num,
                               uint8_t* row_buf) {
   FXGIF_Context* p = (FXGIF_Context*)gif_ptr->context_ptr;
   CCodec_GifModule* pModule = (CCodec_GifModule*)p->parent_ptr;
-  pModule->ReadScanlineCallback(p->child_ptr, row_num, row_buf);
+  pModule->GetDelegate()->GifReadScanline(row_num, row_buf);
 }
+
 static bool gif_get_record_position(gif_decompress_struct_p gif_ptr,
                                     uint32_t cur_pos,
                                     int32_t left,
@@ -64,13 +72,18 @@
                                     bool interlace) {
   FXGIF_Context* p = (FXGIF_Context*)gif_ptr->context_ptr;
   CCodec_GifModule* pModule = (CCodec_GifModule*)p->parent_ptr;
-  return pModule->InputRecordPositionBufCallback(
-      p->child_ptr, cur_pos, FX_RECT(left, top, left + width, top + height),
-      pal_num, pal_ptr, delay_time, user_input, trans_index, disposal_method,
-      interlace);
+  return pModule->GetDelegate()->GifInputRecordPositionBuf(
+      cur_pos, FX_RECT(left, top, left + width, top + height), pal_num, pal_ptr,
+      delay_time, user_input, trans_index, disposal_method, interlace);
 }
 
-FXGIF_Context* CCodec_GifModule::Start(void* pModule) {
+CCodec_GifModule::CCodec_GifModule() {
+  memset(m_szLastError, 0, sizeof(m_szLastError));
+}
+
+CCodec_GifModule::~CCodec_GifModule() {}
+
+FXGIF_Context* CCodec_GifModule::Start() {
   FXGIF_Context* p = FX_Alloc(FXGIF_Context, 1);
   if (!p)
     return nullptr;
@@ -80,7 +93,6 @@
   p->m_FreeFunc = gif_free_func;
   p->gif_ptr = nullptr;
   p->parent_ptr = (void*)this;
-  p->child_ptr = pModule;
   p->gif_ptr = gif_create_decompress();
   if (!p->gif_ptr) {
     FX_Free(p);
diff --git a/core/fxcodec/codec/ccodec_gifmodule.h b/core/fxcodec/codec/ccodec_gifmodule.h
index fac621d..7721d7a 100644
--- a/core/fxcodec/codec/ccodec_gifmodule.h
+++ b/core/fxcodec/codec/ccodec_gifmodule.h
@@ -7,22 +7,23 @@
 #ifndef CORE_FXCODEC_CODEC_CCODEC_GIFMODULE_H_
 #define CORE_FXCODEC_CODEC_CCODEC_GIFMODULE_H_
 
+#include "core/fxcodec/codec/icodec_gifmodule.h"
+#include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_system.h"
 
-struct FXGIF_Context;
-
-class CCodec_GifModule {
+class CCodec_GifModule : public ICodec_GifModule {
  public:
-  CCodec_GifModule() { FXSYS_memset(m_szLastError, 0, sizeof(m_szLastError)); }
+  CCodec_GifModule();
+  ~CCodec_GifModule() override;
 
-  FXGIF_Context* Start(void* pModule);
-  void Finish(FXGIF_Context* pContext);
-
+  FXGIF_Context* Start() override;
+  void Finish(FXGIF_Context* pContext) override;
   uint32_t GetAvailInput(FXGIF_Context* pContext,
-                         uint8_t** avail_buf_ptr = nullptr);
+                         uint8_t** avail_buf_ptr = nullptr) override;
+
   void Input(FXGIF_Context* pContext,
              const uint8_t* src_buf,
-             uint32_t src_size);
+             uint32_t src_size) override;
 
   int32_t ReadHeader(FXGIF_Context* pContext,
                      int* width,
@@ -30,31 +31,12 @@
                      int* pal_num,
                      void** pal_pp,
                      int* bg_index,
-                     CFX_DIBAttribute* pAttribute);
+                     CFX_DIBAttribute* pAttribute) override;
 
-  int32_t LoadFrameInfo(FXGIF_Context* pContext, int* frame_num);
-
+  int32_t LoadFrameInfo(FXGIF_Context* pContext, int* frame_num) override;
   int32_t LoadFrame(FXGIF_Context* pContext,
                     int frame_num,
-                    CFX_DIBAttribute* pAttribute);
-
-  void (*RecordCurrentPositionCallback)(void* pModule, uint32_t& cur_pos);
-  uint8_t* (*AskLocalPaletteBufCallback)(void* pModule,
-                                         int32_t frame_num,
-                                         int32_t pal_size);
-  bool (*InputRecordPositionBufCallback)(void* pModule,
-                                         uint32_t rcd_pos,
-                                         const FX_RECT& img_rc,
-                                         int32_t pal_num,
-                                         void* pal_ptr,
-                                         int32_t delay_time,
-                                         bool user_input,
-                                         int32_t trans_index,
-                                         int32_t disposal_method,
-                                         bool interlace);
-  void (*ReadScanlineCallback)(void* pModule,
-                               int32_t row_num,
-                               uint8_t* row_buf);
+                    CFX_DIBAttribute* pAttribute) override;
 
  protected:
   FX_CHAR m_szLastError[256];
diff --git a/core/fxcodec/codec/fx_codec_png.cpp b/core/fxcodec/codec/ccodec_pngmodule.cpp
similarity index 93%
rename from core/fxcodec/codec/fx_codec_png.cpp
rename to core/fxcodec/codec/ccodec_pngmodule.cpp
index 579c85b..028513b 100644
--- a/core/fxcodec/codec/fx_codec_png.cpp
+++ b/core/fxcodec/codec/ccodec_pngmodule.cpp
@@ -4,6 +4,8 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
+#include "core/fxcodec/codec/ccodec_pngmodule.h"
+
 #include <algorithm>
 
 #include "core/fxcodec/codec/codec_int.h"
@@ -95,7 +97,6 @@
   png_structp png_ptr;
   png_infop info_ptr;
   void* parent_ptr;
-  void* child_ptr;
 
   void* (*m_AllocFunc)(unsigned int);
   void (*m_FreeFunc)(void*);
@@ -133,8 +134,8 @@
     png_set_palette_to_rgb(png_ptr);
   }
   pass = png_set_interlace_handling(png_ptr);
-  if (!pModule->ReadHeaderCallback(p->child_ptr, width, height, bpc, pass,
-                                   &color_type, &gamma)) {
+  if (!pModule->GetDelegate()->PngReadHeader(width, height, bpc, pass,
+                                             &color_type, &gamma)) {
     png_error(p->png_ptr, "Read Header Callback Error");
   }
   int intent;
@@ -187,16 +188,22 @@
 
   CCodec_PngModule* pModule = (CCodec_PngModule*)p->parent_ptr;
   uint8_t* src_buf = nullptr;
-  if (!pModule->AskScanlineBufCallback(p->child_ptr, row_num, src_buf)) {
+  if (!pModule->GetDelegate()->PngAskScanlineBuf(row_num, src_buf)) {
     png_error(png_ptr, "Ask Scanline buffer Callback Error");
   }
   if (src_buf) {
     png_progressive_combine_row(png_ptr, src_buf, new_row);
   }
-  pModule->FillScanlineBufCompletedCallback(p->child_ptr, pass, row_num);
+  pModule->GetDelegate()->PngFillScanlineBufCompleted(pass, row_num);
 }
 
-FXPNG_Context* CCodec_PngModule::Start(void* pModule) {
+CCodec_PngModule::CCodec_PngModule() {
+  memset(m_szLastError, 0, sizeof(m_szLastError));
+}
+
+CCodec_PngModule::~CCodec_PngModule() {}
+
+FXPNG_Context* CCodec_PngModule::Start() {
   FXPNG_Context* p = FX_Alloc(FXPNG_Context, 1);
   if (!p)
     return nullptr;
@@ -206,7 +213,6 @@
   p->png_ptr = nullptr;
   p->info_ptr = nullptr;
   p->parent_ptr = (void*)this;
-  p->child_ptr = pModule;
   p->png_ptr =
       png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
   if (!p->png_ptr) {
diff --git a/core/fxcodec/codec/ccodec_pngmodule.h b/core/fxcodec/codec/ccodec_pngmodule.h
index 77c4af3..1f3a3d9 100644
--- a/core/fxcodec/codec/ccodec_pngmodule.h
+++ b/core/fxcodec/codec/ccodec_pngmodule.h
@@ -7,33 +7,22 @@
 #ifndef CORE_FXCODEC_CODEC_CCODEC_PNGMODULE_H_
 #define CORE_FXCODEC_CODEC_CCODEC_PNGMODULE_H_
 
+#include "core/fxcodec/codec/icodec_pngmodule.h"
 #include "core/fxcrt/fx_system.h"
 
-class CFX_DIBAttribute;
-struct FXPNG_Context;
-
 #define PNG_ERROR_SIZE 256
 
-class CCodec_PngModule {
+class CCodec_PngModule : public ICodec_PngModule {
  public:
-  CCodec_PngModule() { FXSYS_memset(m_szLastError, 0, sizeof(m_szLastError)); }
+  CCodec_PngModule();
+  ~CCodec_PngModule() override;
 
-  FXPNG_Context* Start(void* pModule);
-  void Finish(FXPNG_Context* pContext);
+  FXPNG_Context* Start() override;
+  void Finish(FXPNG_Context* pContext) override;
   bool Input(FXPNG_Context* pContext,
              const uint8_t* src_buf,
              uint32_t src_size,
-             CFX_DIBAttribute* pAttribute);
-
-  bool (*ReadHeaderCallback)(void* pModule,
-                             int width,
-                             int height,
-                             int bpc,
-                             int pass,
-                             int* color_type,
-                             double* gamma);
-  bool (*AskScanlineBufCallback)(void* pModule, int line, uint8_t*& src_buf);
-  void (*FillScanlineBufCompletedCallback)(void* pModule, int pass, int line);
+             CFX_DIBAttribute* pAttribute) override;
 
  protected:
   FX_CHAR m_szLastError[PNG_ERROR_SIZE];
diff --git a/core/fxcodec/codec/ccodec_progressivedecoder.h b/core/fxcodec/codec/ccodec_progressivedecoder.h
index 614146f..61703dd 100644
--- a/core/fxcodec/codec/ccodec_progressivedecoder.h
+++ b/core/fxcodec/codec/ccodec_progressivedecoder.h
@@ -9,27 +9,25 @@
 
 #include <vector>
 
+#include "core/fxcodec/codec/icodec_bmpmodule.h"
+#include "core/fxcodec/codec/icodec_gifmodule.h"
+#include "core/fxcodec/codec/icodec_pngmodule.h"
+#include "core/fxcodec/codec/icodec_tiffmodule.h"
 #include "core/fxcodec/fx_codec_def.h"
 #include "core/fxcrt/cfx_retain_ptr.h"
 #include "core/fxcrt/fx_system.h"
 #include "core/fxge/fx_dib.h"
 
-class CCodec_BmpModule;
-class CCodec_GifContext;
-class CCodec_GifModule;
 class CCodec_JpegModule;
 class CCodec_ModuleMgr;
-class CCodec_PngContext;
-class CCodec_TiffContext;
 class CFX_DIBAttribute;
 class IFX_SeekableReadStream;
 class IFX_Pause;
-struct FXBMP_Context;
-struct FXGIF_Context;
 struct FXJPEG_Context;
-struct FXPNG_Context;
 
-class CCodec_ProgressiveDecoder {
+class CCodec_ProgressiveDecoder : public ICodec_BmpModule::Delegate,
+                                  public ICodec_GifModule::Delegate,
+                                  public ICodec_PngModule::Delegate {
  public:
   enum FXCodec_Format {
     FXCodec_Invalid = 0,
@@ -44,7 +42,7 @@
   };
 
   explicit CCodec_ProgressiveDecoder(CCodec_ModuleMgr* pCodecMgr);
-  ~CCodec_ProgressiveDecoder();
+  virtual ~CCodec_ProgressiveDecoder();
 
   FXCODEC_STATUS LoadImageInfo(
       const CFX_RetainPtr<IFX_SeekableReadStream>& pFile,
@@ -170,41 +168,46 @@
   bool m_BmpIsTopBottom;
   FXCODEC_STATUS m_status;
 
- protected:
-  static bool PngReadHeaderFunc(void* pModule,
-                                int width,
-                                int height,
-                                int bpc,
-                                int pass,
-                                int* color_type,
-                                double* gamma);
-  static bool PngAskScanlineBufFunc(void* pModule, int line, uint8_t*& src_buf);
-  static void PngFillScanlineBufCompletedFunc(void* pModule,
-                                              int pass,
-                                              int line);
-  static void GifRecordCurrentPositionCallback(void* pModule,
-                                               uint32_t& cur_pos);
-  static uint8_t* GifAskLocalPaletteBufCallback(void* pModule,
-                                                int32_t frame_num,
-                                                int32_t pal_size);
-  static bool GifInputRecordPositionBufCallback(void* pModule,
-                                                uint32_t rcd_pos,
-                                                const FX_RECT& img_rc,
-                                                int32_t pal_num,
-                                                void* pal_ptr,
-                                                int32_t delay_time,
-                                                bool user_input,
-                                                int32_t trans_index,
-                                                int32_t disposal_method,
-                                                bool interlace);
-  static void GifReadScanlineCallback(void* pModule,
-                                      int32_t row_num,
-                                      uint8_t* row_buf);
-  static bool BmpInputImagePositionBufCallback(void* pModule, uint32_t rcd_pos);
-  static void BmpReadScanlineCallback(void* pModule,
-                                      int32_t row_num,
-                                      uint8_t* row_buf);
+  // ICodec_PngModule::Delegate
+  bool PngReadHeader(int width,
+                     int height,
+                     int bpc,
+                     int pass,
+                     int* color_type,
+                     double* gamma) override;
+  bool PngAskScanlineBuf(int line, uint8_t*& src_buf) override;
+  void PngFillScanlineBufCompleted(int pass, int line) override;
 
+  // ICodec_GifModule::Delegate
+  void GifRecordCurrentPosition(uint32_t& cur_pos) override;
+  uint8_t* GifAskLocalPaletteBuf(int32_t frame_num, int32_t pal_size) override;
+  bool GifInputRecordPositionBuf(uint32_t rcd_pos,
+                                 const FX_RECT& img_rc,
+                                 int32_t pal_num,
+                                 void* pal_ptr,
+                                 int32_t delay_time,
+                                 bool user_input,
+                                 int32_t trans_index,
+                                 int32_t disposal_method,
+                                 bool interlace) override;
+  void GifReadScanline(int32_t row_num, uint8_t* row_buf) override;
+
+  // ICodec_BmpModule::Delegate
+  bool BmpInputImagePositionBuf(uint32_t rcd_pos) override;
+  void BmpReadScanline(int32_t row_num, uint8_t* row_buf) override;
+
+ protected:
+  bool BmpReadMoreData(ICodec_BmpModule* pBmpModule,
+                       FXCODEC_STATUS& err_status);
+  bool GifReadMoreData(ICodec_GifModule* pGifModule,
+                       FXCODEC_STATUS& err_status);
+  void GifDoubleLineResampleVert(CFX_DIBitmap* pDeviceBitmap,
+                                 double scale_y,
+                                 int des_row);
+  void PngOneOneMapResampleHorz(CFX_DIBitmap* pDeviceBitmap,
+                                int32_t des_line,
+                                uint8_t* src_scan,
+                                FXCodec_Format src_format);
   bool DetectImageType(FXCODEC_IMAGE_TYPE imageType,
                        CFX_DIBAttribute* pAttribute);
   void GetDownScale(int& down_scale);
@@ -220,17 +223,6 @@
   void ResampleVert(CFX_DIBitmap* pDeviceBitmap, double scale_y, int des_row);
   bool JpegReadMoreData(CCodec_JpegModule* pJpegModule,
                         FXCODEC_STATUS& err_status);
-  void PngOneOneMapResampleHorz(CFX_DIBitmap* pDeviceBitmap,
-                                int32_t des_line,
-                                uint8_t* src_scan,
-                                FXCodec_Format src_format);
-  bool GifReadMoreData(CCodec_GifModule* pGifModule,
-                       FXCODEC_STATUS& err_status);
-  void GifDoubleLineResampleVert(CFX_DIBitmap* pDeviceBitmap,
-                                 double scale_y,
-                                 int des_row);
-  bool BmpReadMoreData(CCodec_BmpModule* pBmpModule,
-                       FXCODEC_STATUS& err_status);
   void ResampleVertBT(CFX_DIBitmap* pDeviceBitmap, double scale_y, int des_row);
 };
 
diff --git a/core/fxcodec/codec/fx_codec_tiff.cpp b/core/fxcodec/codec/ccodec_tiffmodule.cpp
similarity index 99%
rename from core/fxcodec/codec/fx_codec_tiff.cpp
rename to core/fxcodec/codec/ccodec_tiffmodule.cpp
index 7818a34..7367728 100644
--- a/core/fxcodec/codec/fx_codec_tiff.cpp
+++ b/core/fxcodec/codec/ccodec_tiffmodule.cpp
@@ -4,6 +4,8 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
+#include "core/fxcodec/codec/ccodec_tiffmodule.h"
+
 #include <limits>
 
 #include "core/fxcodec/codec/codec_int.h"
diff --git a/core/fxcodec/codec/ccodec_tiffmodule.h b/core/fxcodec/codec/ccodec_tiffmodule.h
index dd2cbd7..a8820f4 100644
--- a/core/fxcodec/codec/ccodec_tiffmodule.h
+++ b/core/fxcodec/codec/ccodec_tiffmodule.h
@@ -7,30 +7,25 @@
 #ifndef CORE_FXCODEC_CODEC_CCODEC_TIFFMODULE_H_
 #define CORE_FXCODEC_CODEC_CCODEC_TIFFMODULE_H_
 
+#include "core/fxcodec/codec/icodec_tiffmodule.h"
 #include "core/fxcrt/cfx_retain_ptr.h"
 #include "core/fxcrt/fx_system.h"
 
-class CCodec_TiffContext;
-class CFX_DIBAttribute;
-class CFX_DIBitmap;
-class IFX_SeekableReadStream;
-
-class CCodec_TiffModule {
+class CCodec_TiffModule : public ICodec_TiffModule {
  public:
-  ~CCodec_TiffModule() {}
+  ~CCodec_TiffModule() override {}
 
   CCodec_TiffContext* CreateDecoder(
-      const CFX_RetainPtr<IFX_SeekableReadStream>& file_ptr);
-
+      const CFX_RetainPtr<IFX_SeekableReadStream>& file_ptr) override;
   bool LoadFrameInfo(CCodec_TiffContext* ctx,
                      int32_t frame,
                      int32_t* width,
                      int32_t* height,
                      int32_t* comps,
                      int32_t* bpc,
-                     CFX_DIBAttribute* pAttribute);
-  bool Decode(CCodec_TiffContext* ctx, class CFX_DIBitmap* pDIBitmap);
-  void DestroyDecoder(CCodec_TiffContext* ctx);
+                     CFX_DIBAttribute* pAttribute) override;
+  bool Decode(CCodec_TiffContext* ctx, class CFX_DIBitmap* pDIBitmap) override;
+  void DestroyDecoder(CCodec_TiffContext* ctx) override;
 };
 
 #endif  // CORE_FXCODEC_CODEC_CCODEC_TIFFMODULE_H_
diff --git a/core/fxcodec/codec/fx_codec.cpp b/core/fxcodec/codec/fx_codec.cpp
index 23171cf..0d886b4 100644
--- a/core/fxcodec/codec/fx_codec.cpp
+++ b/core/fxcodec/codec/fx_codec.cpp
@@ -24,12 +24,6 @@
       m_pJpxModule(new CCodec_JpxModule),
       m_pJbig2Module(new CCodec_Jbig2Module),
       m_pIccModule(new CCodec_IccModule),
-#ifdef PDF_ENABLE_XFA
-      m_pPngModule(new CCodec_PngModule),
-      m_pGifModule(new CCodec_GifModule),
-      m_pBmpModule(new CCodec_BmpModule),
-      m_pTiffModule(new CCodec_TiffModule),
-#endif  // PDF_ENABLE_XFA
       m_pFlateModule(new CCodec_FlateModule) {
 }
 
@@ -229,7 +223,7 @@
     uint32_t val = 0;
     int count = 0;
     while (pos < src_size) {
-      val += (uint32_t)(src_buf[pos] << (8 * (3 - pos)));
+      val += (uint32_t)(src_buf[pos]) << (8 * (3 - count));
       count++;
       pos++;
     }
diff --git a/core/fxcodec/codec/fx_codec_a85_unittest.cpp b/core/fxcodec/codec/fx_codec_a85_unittest.cpp
index 7910881..78f9bd8 100644
--- a/core/fxcodec/codec/fx_codec_a85_unittest.cpp
+++ b/core/fxcodec/codec/fx_codec_a85_unittest.cpp
@@ -12,7 +12,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 TEST(fxcodec, A85TestBadInputs) {
-  uint8_t src_buf[4] = {1, 2, 3, 4};
+  const uint8_t src_buf[] = {1, 2, 3, 4};
   uint8_t* dest_buf = nullptr;
   uint32_t src_size = 4;
   uint32_t dest_size = 0;
@@ -30,7 +30,7 @@
 // No leftover bytes, just translate 2 sets of symbols.
 TEST(fxcodec, A85TestBasic) {
   // Make sure really big values don't break.
-  uint8_t src_buf[8] = {1, 2, 3, 4, 255, 255, 255, 255};
+  const uint8_t src_buf[] = {1, 2, 3, 4, 255, 255, 255, 255};
   uint8_t* dest_buf = nullptr;
   uint32_t src_size = 8;
   uint32_t dest_size = 0;
@@ -42,19 +42,20 @@
   EXPECT_TRUE(pEncoders->A85Encode(src_buf, src_size, &dest_buf, &dest_size));
 
   // Should have 5 chars for each set of 4 and 2 terminators.
-  EXPECT_EQ(12u, dest_size);
-  uint8_t expected_out[12] = {33, 60, 78, 63, 43, 115, 56, 87, 45, 33, 126, 62};
+  ASSERT_EQ(12u, dest_size);
+  const uint8_t expected_out[] = {33, 60, 78, 63, 43,  115,
+                                  56, 87, 45, 33, 126, 62};
 
   // Check the output
   for (uint32_t i = 0; i < 12; i++)
-    EXPECT_EQ(dest_buf[i], expected_out[i]) << " at " << i;
+    EXPECT_EQ(expected_out[i], dest_buf[i]) << " at " << i;
   FX_Free(dest_buf);
 }
 
 // Leftover bytes.
 TEST(fxcodec, A85TestLeftoverBytes) {
   // 1 Leftover Byte:
-  uint8_t src_buf_1leftover[5] = {1, 2, 3, 4, 255};
+  const uint8_t src_buf_1leftover[] = {1, 2, 3, 4, 255};
   uint8_t* dest_buf = nullptr;
   uint32_t src_size = 5;
   uint32_t dest_size = 0;
@@ -65,53 +66,53 @@
   // Should succeed
   EXPECT_TRUE(
       pEncoders->A85Encode(src_buf_1leftover, src_size, &dest_buf, &dest_size));
-  EXPECT_EQ(9u, dest_size);  // 5 chars for first symbol + 2 + 2 terminators.
-  uint8_t expected_out_1leftover[9] = {33, 60, 78, 63, 43, 114, 114, 126, 62};
+  ASSERT_EQ(9u, dest_size);  // 5 chars for first symbol + 2 + 2 terminators.
+  uint8_t expected_out_1leftover[] = {33, 60, 78, 63, 43, 114, 114, 126, 62};
 
   // Check the output
   for (uint32_t i = 0; i < 9; i++)
-    EXPECT_EQ(dest_buf[i], expected_out_1leftover[i]) << " at " << i;
+    EXPECT_EQ(expected_out_1leftover[i], dest_buf[i]) << " at " << i;
   FX_Free(dest_buf);
 
   // 2 Leftover bytes:
   src_size++;
   dest_buf = nullptr;
   dest_size = 0;
-  uint8_t src_buf_2leftover[6] = {1, 2, 3, 4, 255, 254};
+  const uint8_t src_buf_2leftover[] = {1, 2, 3, 4, 255, 254};
   // Should succeed
   EXPECT_TRUE(
       pEncoders->A85Encode(src_buf_2leftover, src_size, &dest_buf, &dest_size));
-  EXPECT_EQ(10u, dest_size);  // 5 chars for first symbol + 3 + 2 terminators.
-  uint8_t expected_out_2leftover[10] = {33,  60, 78, 63,  43,
-                                        115, 56, 68, 126, 62};
+  ASSERT_EQ(10u, dest_size);  // 5 chars for first symbol + 3 + 2 terminators.
+  const uint8_t expected_out_2leftover[] = {33,  60, 78, 63,  43,
+                                            115, 56, 68, 126, 62};
 
   // Check the output
   for (uint32_t i = 0; i < 10; i++)
-    EXPECT_EQ(dest_buf[i], expected_out_2leftover[i]) << " at " << i;
+    EXPECT_EQ(expected_out_2leftover[i], dest_buf[i]) << " at " << i;
   FX_Free(dest_buf);
 
   // 3 Leftover bytes:
   src_size++;
   dest_buf = nullptr;
   dest_size = 0;
-  uint8_t src_buf_3leftover[7] = {1, 2, 3, 4, 255, 254, 253};
+  const uint8_t src_buf_3leftover[] = {1, 2, 3, 4, 255, 254, 253};
   // Should succeed
   EXPECT_TRUE(
       pEncoders->A85Encode(src_buf_3leftover, src_size, &dest_buf, &dest_size));
-  EXPECT_EQ(11u, dest_size);  // 5 chars for first symbol + 4 + 2 terminators.
-  uint8_t expected_out_3leftover[11] = {33, 60, 78,  63,  43, 115,
-                                        56, 77, 114, 126, 62};
+  ASSERT_EQ(11u, dest_size);  // 5 chars for first symbol + 4 + 2 terminators.
+  const uint8_t expected_out_3leftover[] = {33, 60, 78,  63,  43, 115,
+                                            56, 77, 114, 126, 62};
 
   // Check the output
   for (uint32_t i = 0; i < 11; i++)
-    EXPECT_EQ(dest_buf[i], expected_out_3leftover[i]) << " at " << i;
+    EXPECT_EQ(expected_out_3leftover[i], dest_buf[i]) << " at " << i;
   FX_Free(dest_buf);
 }
 
 // Test all zeros comes through as "z".
 TEST(fxcodec, A85TestZeros) {
   // Make sure really big values don't break.
-  uint8_t src_buf[8] = {1, 2, 3, 4, 0, 0, 0, 0};
+  const uint8_t src_buf[] = {1, 2, 3, 4, 0, 0, 0, 0};
   uint8_t* dest_buf = nullptr;
   uint32_t src_size = 8;
   uint32_t dest_size = 0;
@@ -123,29 +124,29 @@
   EXPECT_TRUE(pEncoders->A85Encode(src_buf, src_size, &dest_buf, &dest_size));
 
   // Should have 5 chars for first set of 4 + 1 for z + 2 terminators.
-  EXPECT_EQ(8u, dest_size);
-  uint8_t expected_out[8] = {33, 60, 78, 63, 43, 122, 126, 62};
+  ASSERT_EQ(8u, dest_size);
+  const uint8_t expected_out[] = {33, 60, 78, 63, 43, 122, 126, 62};
 
   // Check the output
   for (uint32_t i = 0; i < 8; i++)
-    EXPECT_EQ(dest_buf[i], expected_out[i]) << " at " << i;
+    EXPECT_EQ(expected_out[i], dest_buf[i]) << " at " << i;
   FX_Free(dest_buf);
 
   // Should also work if it is at the start:
   dest_buf = nullptr;
   dest_size = 0;
-  uint8_t src_buf_2[8] = {0, 0, 0, 0, 1, 2, 3, 4};
+  const uint8_t src_buf_2[] = {0, 0, 0, 0, 1, 2, 3, 4};
 
   // Should succeed.
   EXPECT_TRUE(pEncoders->A85Encode(src_buf_2, src_size, &dest_buf, &dest_size));
 
   // Should have 5 chars for set of 4 + 1 for z + 2 terminators.
-  EXPECT_EQ(8u, dest_size);
-  uint8_t expected_out_2[8] = {122, 33, 60, 78, 63, 43, 126, 62};
+  ASSERT_EQ(8u, dest_size);
+  const uint8_t expected_out_2[] = {122, 33, 60, 78, 63, 43, 126, 62};
 
   // Check the output
   for (uint32_t i = 0; i < 8; i++)
-    EXPECT_EQ(dest_buf[i], expected_out_2[i]) << " at " << i;
+    EXPECT_EQ(expected_out_2[i], dest_buf[i]) << " at " << i;
   FX_Free(dest_buf);
 
   // Try with 2 leftover zero bytes. Make sure we don't get a "z".
@@ -157,12 +158,13 @@
   EXPECT_TRUE(pEncoders->A85Encode(src_buf, src_size, &dest_buf, &dest_size));
 
   // Should have 5 chars for set of 4 + 3 for last 2 + 2 terminators.
-  EXPECT_EQ(10u, dest_size);
-  uint8_t expected_out_leftover[10] = {33, 60, 78, 63, 43, 33, 33, 33, 126, 62};
+  ASSERT_EQ(10u, dest_size);
+  const uint8_t expected_out_leftover[] = {33, 60, 78, 63,  43,
+                                           33, 33, 33, 126, 62};
 
   // Check the output
   for (uint32_t i = 0; i < 10; i++)
-    EXPECT_EQ(dest_buf[i], expected_out_leftover[i]) << " at " << i;
+    EXPECT_EQ(expected_out_leftover[i], dest_buf[i]) << " at " << i;
   FX_Free(dest_buf);
 }
 
@@ -197,13 +199,13 @@
   // Should have 75 chars in the first row plus 2 char return,
   // 76 chars in the second row plus 2 char return,
   // and 9 chars in the last row with 2 terminators.
-  EXPECT_EQ(166u, dest_size);
+  ASSERT_EQ(166u, dest_size);
 
   // Check for the returns.
-  EXPECT_EQ(dest_buf[75], 13);
-  EXPECT_EQ(dest_buf[76], 10);
-  EXPECT_EQ(dest_buf[153], 13);
-  EXPECT_EQ(dest_buf[154], 10);
+  EXPECT_EQ(13, dest_buf[75]);
+  EXPECT_EQ(10, dest_buf[76]);
+  EXPECT_EQ(13, dest_buf[153]);
+  EXPECT_EQ(10, dest_buf[154]);
 
   FX_Free(dest_buf);
 }
diff --git a/core/fxcodec/codec/fx_codec_progress.cpp b/core/fxcodec/codec/fx_codec_progress.cpp
index 386b66a..1f2f50c 100644
--- a/core/fxcodec/codec/fx_codec_progress.cpp
+++ b/core/fxcodec/codec/fx_codec_progress.cpp
@@ -12,6 +12,7 @@
 #include "core/fxcodec/fx_codec.h"
 #include "core/fxge/fx_dib.h"
 #include "third_party/base/numerics/safe_math.h"
+#include "third_party/base/ptr_util.h"
 
 #define FXCODEC_BLOCK_SIZE 4096
 
@@ -19,9 +20,9 @@
 
 #if _FX_OS_ == _FX_MACOSX_ || _FX_OS_ == _FX_IOS_
 const double kPngGamma = 1.7;
-#else
+#else  // _FX_OS_ == _FX_MACOSX_ || _FX_OS_ == _FX_IOS_
 const double kPngGamma = 2.2;
-#endif
+#endif  // _FX_OS_ == _FX_MACOSX_ || _FX_OS_ == _FX_IOS_
 
 void RGB2BGR(uint8_t* buffer, int width = 1) {
   if (buffer && width > 0) {
@@ -299,12 +300,12 @@
   m_pFile = nullptr;
   if (m_pJpegContext)
     m_pCodecMgr->GetJpegModule()->Finish(m_pJpegContext);
-  if (m_pPngContext)
-    m_pCodecMgr->GetPngModule()->Finish(m_pPngContext);
-  if (m_pGifContext)
-    m_pCodecMgr->GetGifModule()->Finish(m_pGifContext);
   if (m_pBmpContext)
     m_pCodecMgr->GetBmpModule()->Finish(m_pBmpContext);
+  if (m_pGifContext)
+    m_pCodecMgr->GetGifModule()->Finish(m_pGifContext);
+  if (m_pPngContext)
+    m_pCodecMgr->GetPngModule()->Finish(m_pPngContext);
   if (m_pTiffContext)
     m_pCodecMgr->GetTiffModule()->DestroyDecoder(m_pTiffContext);
   FX_Free(m_pSrcBuf);
@@ -349,41 +350,39 @@
   return true;
 }
 
-bool CCodec_ProgressiveDecoder::PngReadHeaderFunc(void* pModule,
-                                                  int width,
-                                                  int height,
-                                                  int bpc,
-                                                  int pass,
-                                                  int* color_type,
-                                                  double* gamma) {
-  CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule;
-  if (!pCodec->m_pDeviceBitmap) {
-    pCodec->m_SrcWidth = width;
-    pCodec->m_SrcHeight = height;
-    pCodec->m_SrcBPC = bpc;
-    pCodec->m_SrcPassNumber = pass;
+bool CCodec_ProgressiveDecoder::PngReadHeader(int width,
+                                              int height,
+                                              int bpc,
+                                              int pass,
+                                              int* color_type,
+                                              double* gamma) {
+  if (!m_pDeviceBitmap) {
+    m_SrcWidth = width;
+    m_SrcHeight = height;
+    m_SrcBPC = bpc;
+    m_SrcPassNumber = pass;
     switch (*color_type) {
       case 0:
-        pCodec->m_SrcComponents = 1;
+        m_SrcComponents = 1;
         break;
       case 4:
-        pCodec->m_SrcComponents = 2;
+        m_SrcComponents = 2;
         break;
       case 2:
-        pCodec->m_SrcComponents = 3;
+        m_SrcComponents = 3;
         break;
       case 3:
       case 6:
-        pCodec->m_SrcComponents = 4;
+        m_SrcComponents = 4;
         break;
       default:
-        pCodec->m_SrcComponents = 0;
+        m_SrcComponents = 0;
         break;
     }
-    pCodec->m_clipBox = FX_RECT(0, 0, width, height);
+    m_clipBox = FX_RECT(0, 0, width, height);
     return false;
   }
-  FXDIB_Format format = pCodec->m_pDeviceBitmap->GetFormat();
+  FXDIB_Format format = m_pDeviceBitmap->GetFormat();
   switch (format) {
     case FXDIB_1bppMask:
     case FXDIB_1bppRgb:
@@ -408,32 +407,26 @@
   return true;
 }
 
-bool CCodec_ProgressiveDecoder::PngAskScanlineBufFunc(void* pModule,
-                                                      int line,
-                                                      uint8_t*& src_buf) {
-  CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule;
-  CFX_DIBitmap* pDIBitmap = pCodec->m_pDeviceBitmap;
+bool CCodec_ProgressiveDecoder::PngAskScanlineBuf(int line, uint8_t*& src_buf) {
+  CFX_DIBitmap* pDIBitmap = m_pDeviceBitmap;
   if (!pDIBitmap) {
     ASSERT(false);
     return false;
   }
-  if (line >= pCodec->m_clipBox.top && line < pCodec->m_clipBox.bottom) {
-    double scale_y =
-        (double)pCodec->m_sizeY / (double)pCodec->m_clipBox.Height();
-    int32_t row =
-        (int32_t)((line - pCodec->m_clipBox.top) * scale_y) + pCodec->m_startY;
+  if (line >= m_clipBox.top && line < m_clipBox.bottom) {
+    double scale_y = (double)m_sizeY / (double)m_clipBox.Height();
+    int32_t row = (int32_t)((line - m_clipBox.top) * scale_y) + m_startY;
     uint8_t* src_scan = (uint8_t*)pDIBitmap->GetScanline(row);
-    uint8_t* des_scan = pCodec->m_pDecodeBuf;
-    src_buf = pCodec->m_pDecodeBuf;
+    uint8_t* des_scan = m_pDecodeBuf;
+    src_buf = m_pDecodeBuf;
     int32_t src_Bpp = pDIBitmap->GetBPP() >> 3;
-    int32_t des_Bpp = (pCodec->m_SrcFormat & 0xff) >> 3;
-    int32_t src_left = pCodec->m_startX;
-    int32_t des_left = pCodec->m_clipBox.left;
+    int32_t des_Bpp = (m_SrcFormat & 0xff) >> 3;
+    int32_t src_left = m_startX;
+    int32_t des_left = m_clipBox.left;
     src_scan += src_left * src_Bpp;
     des_scan += des_left * des_Bpp;
-    for (int32_t src_col = 0; src_col < pCodec->m_sizeX; src_col++) {
-      PixelWeight* pPixelWeights =
-          pCodec->m_WeightHorzOO.GetPixelWeight(src_col);
+    for (int32_t src_col = 0; src_col < m_sizeX; src_col++) {
+      PixelWeight* pPixelWeights = m_WeightHorzOO.GetPixelWeight(src_col);
       if (pPixelWeights->m_SrcStart != pPixelWeights->m_SrcEnd) {
         continue;
       }
@@ -555,17 +548,15 @@
   }
 }
 
-void CCodec_ProgressiveDecoder::PngFillScanlineBufCompletedFunc(void* pModule,
-                                                                int pass,
-                                                                int line) {
-  CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule;
-  CFX_DIBitmap* pDIBitmap = pCodec->m_pDeviceBitmap;
+void CCodec_ProgressiveDecoder::PngFillScanlineBufCompleted(int pass,
+                                                            int line) {
+  CFX_DIBitmap* pDIBitmap = m_pDeviceBitmap;
   ASSERT(pDIBitmap);
-  int src_top = pCodec->m_clipBox.top;
-  int src_bottom = pCodec->m_clipBox.bottom;
-  int des_top = pCodec->m_startY;
-  int src_hei = pCodec->m_clipBox.Height();
-  int des_hei = pCodec->m_sizeY;
+  int src_top = m_clipBox.top;
+  int src_bottom = m_clipBox.bottom;
+  int des_top = m_startY;
+  int src_hei = m_clipBox.Height();
+  int des_hei = m_sizeY;
   if (line >= src_top && line < src_bottom) {
     double scale_y = (double)des_hei / (double)src_hei;
     int src_row = line - src_top;
@@ -573,19 +564,18 @@
     if (des_row >= des_top + des_hei) {
       return;
     }
-    pCodec->PngOneOneMapResampleHorz(pDIBitmap, des_row, pCodec->m_pDecodeBuf,
-                                     pCodec->m_SrcFormat);
-    if (pCodec->m_SrcPassNumber == 1 && scale_y > 1.0) {
-      pCodec->ResampleVert(pDIBitmap, scale_y, des_row);
+    PngOneOneMapResampleHorz(pDIBitmap, des_row, m_pDecodeBuf, m_SrcFormat);
+    if (m_SrcPassNumber == 1 && scale_y > 1.0) {
+      ResampleVert(pDIBitmap, scale_y, des_row);
       return;
     }
     if (pass == 6 && scale_y > 1.0) {
-      pCodec->ResampleVert(pDIBitmap, scale_y, des_row);
+      ResampleVert(pDIBitmap, scale_y, des_row);
     }
   }
 }
 
-bool CCodec_ProgressiveDecoder::GifReadMoreData(CCodec_GifModule* pGifModule,
+bool CCodec_ProgressiveDecoder::GifReadMoreData(ICodec_GifModule* pGifModule,
                                                 FXCODEC_STATUS& err_status) {
   uint32_t dwSize = (uint32_t)m_pFile->GetSize();
   if (dwSize <= m_offSet) {
@@ -622,24 +612,18 @@
   return true;
 }
 
-void CCodec_ProgressiveDecoder::GifRecordCurrentPositionCallback(
-    void* pModule,
-    uint32_t& cur_pos) {
-  CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule;
+void CCodec_ProgressiveDecoder::GifRecordCurrentPosition(uint32_t& cur_pos) {
   uint32_t remain_size =
-      pCodec->m_pCodecMgr->GetGifModule()->GetAvailInput(pCodec->m_pGifContext);
-  cur_pos = pCodec->m_offSet - remain_size;
+      m_pCodecMgr->GetGifModule()->GetAvailInput(m_pGifContext);
+  cur_pos = m_offSet - remain_size;
 }
 
-uint8_t* CCodec_ProgressiveDecoder::GifAskLocalPaletteBufCallback(
-    void* pModule,
-    int32_t frame_num,
-    int32_t pal_size) {
+uint8_t* CCodec_ProgressiveDecoder::GifAskLocalPaletteBuf(int32_t frame_num,
+                                                          int32_t pal_size) {
   return FX_Alloc(uint8_t, pal_size);
 }
 
-bool CCodec_ProgressiveDecoder::GifInputRecordPositionBufCallback(
-    void* pModule,
+bool CCodec_ProgressiveDecoder::GifInputRecordPositionBuf(
     uint32_t rcd_pos,
     const FX_RECT& img_rc,
     int32_t pal_num,
@@ -649,58 +633,56 @@
     int32_t trans_index,
     int32_t disposal_method,
     bool interlace) {
-  CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule;
-  pCodec->m_offSet = rcd_pos;
+  m_offSet = rcd_pos;
   FXCODEC_STATUS error_status = FXCODEC_STATUS_ERROR;
-  if (!pCodec->GifReadMoreData(pCodec->m_pCodecMgr->GetGifModule(),
-                               error_status)) {
+  if (!GifReadMoreData(m_pCodecMgr->GetGifModule(), error_status)) {
     return false;
   }
   uint8_t* pPalette = nullptr;
   if (pal_num != 0 && pal_ptr) {
     pPalette = (uint8_t*)pal_ptr;
   } else {
-    pal_num = pCodec->m_GifPltNumber;
-    pPalette = pCodec->m_pGifPalette;
+    pal_num = m_GifPltNumber;
+    pPalette = m_pGifPalette;
   }
-  if (!pCodec->m_pSrcPalette) {
-    pCodec->m_pSrcPalette = FX_Alloc(FX_ARGB, pal_num);
-  } else if (pal_num > pCodec->m_SrcPaletteNumber) {
-    pCodec->m_pSrcPalette = FX_Realloc(FX_ARGB, pCodec->m_pSrcPalette, pal_num);
-  }
-  if (!pCodec->m_pSrcPalette)
+  if (!m_pSrcPalette)
+    m_pSrcPalette = FX_Alloc(FX_ARGB, pal_num);
+  else if (pal_num > m_SrcPaletteNumber)
+    m_pSrcPalette = FX_Realloc(FX_ARGB, m_pSrcPalette, pal_num);
+  if (!m_pSrcPalette)
     return false;
 
-  pCodec->m_SrcPaletteNumber = pal_num;
+  m_SrcPaletteNumber = pal_num;
   for (int i = 0; i < pal_num; i++) {
     uint32_t j = i * 3;
-    pCodec->m_pSrcPalette[i] =
+    m_pSrcPalette[i] =
         ArgbEncode(0xff, pPalette[j], pPalette[j + 1], pPalette[j + 2]);
   }
-  pCodec->m_GifTransIndex = trans_index;
-  pCodec->m_GifFrameRect = img_rc;
-  pCodec->m_SrcPassNumber = interlace ? 4 : 1;
-  int32_t pal_index = pCodec->m_GifBgIndex;
-  CFX_DIBitmap* pDevice = pCodec->m_pDeviceBitmap;
-  if (trans_index >= pal_num) {
+  m_GifTransIndex = trans_index;
+  m_GifFrameRect = img_rc;
+  m_SrcPassNumber = interlace ? 4 : 1;
+  int32_t pal_index = m_GifBgIndex;
+  CFX_DIBitmap* pDevice = m_pDeviceBitmap;
+  if (trans_index >= pal_num)
     trans_index = -1;
-  }
   if (trans_index != -1) {
-    pCodec->m_pSrcPalette[trans_index] &= 0x00ffffff;
-    if (pDevice->HasAlpha()) {
+    m_pSrcPalette[trans_index] &= 0x00ffffff;
+    if (pDevice->HasAlpha())
       pal_index = trans_index;
-    }
   }
-  int startX = pCodec->m_startX;
-  int startY = pCodec->m_startY;
-  int sizeX = pCodec->m_sizeX;
-  int sizeY = pCodec->m_sizeY;
+  if (pal_index >= pal_num)
+    return false;
+
+  int startX = m_startX;
+  int startY = m_startY;
+  int sizeX = m_sizeX;
+  int sizeY = m_sizeY;
   int Bpp = pDevice->GetBPP() / 8;
-  FX_ARGB argb = pCodec->m_pSrcPalette[pal_index];
+  FX_ARGB argb = m_pSrcPalette[pal_index];
   for (int row = 0; row < sizeY; row++) {
     uint8_t* pScanline =
         (uint8_t*)pDevice->GetScanline(row + startY) + startX * Bpp;
-    switch (pCodec->m_TransMethod) {
+    switch (m_TransMethod) {
       case 3: {
         uint8_t gray =
             FXRGB2GRAY(FXARGB_R(argb), FXARGB_G(argb), FXARGB_B(argb));
@@ -728,36 +710,34 @@
   return true;
 }
 
-void CCodec_ProgressiveDecoder::GifReadScanlineCallback(void* pModule,
-                                                        int32_t row_num,
-                                                        uint8_t* row_buf) {
-  CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule;
-  CFX_DIBitmap* pDIBitmap = pCodec->m_pDeviceBitmap;
+void CCodec_ProgressiveDecoder::GifReadScanline(int32_t row_num,
+                                                uint8_t* row_buf) {
+  CFX_DIBitmap* pDIBitmap = m_pDeviceBitmap;
   ASSERT(pDIBitmap);
-  int32_t img_width = pCodec->m_GifFrameRect.Width();
+  int32_t img_width = m_GifFrameRect.Width();
   if (!pDIBitmap->HasAlpha()) {
     uint8_t* byte_ptr = row_buf;
     for (int i = 0; i < img_width; i++) {
-      if (*byte_ptr == pCodec->m_GifTransIndex) {
-        *byte_ptr = pCodec->m_GifBgIndex;
+      if (*byte_ptr == m_GifTransIndex) {
+        *byte_ptr = m_GifBgIndex;
       }
       byte_ptr++;
     }
   }
-  int32_t pal_index = pCodec->m_GifBgIndex;
-  if (pCodec->m_GifTransIndex != -1 && pCodec->m_pDeviceBitmap->HasAlpha()) {
-    pal_index = pCodec->m_GifTransIndex;
+  int32_t pal_index = m_GifBgIndex;
+  if (m_GifTransIndex != -1 && m_pDeviceBitmap->HasAlpha()) {
+    pal_index = m_GifTransIndex;
   }
-  FXSYS_memset(pCodec->m_pDecodeBuf, pal_index, pCodec->m_SrcWidth);
+  FXSYS_memset(m_pDecodeBuf, pal_index, m_SrcWidth);
   bool bLastPass = (row_num % 2) == 1;
-  int32_t line = row_num + pCodec->m_GifFrameRect.top;
-  int32_t left = pCodec->m_GifFrameRect.left;
-  FXSYS_memcpy(pCodec->m_pDecodeBuf + left, row_buf, img_width);
-  int src_top = pCodec->m_clipBox.top;
-  int src_bottom = pCodec->m_clipBox.bottom;
-  int des_top = pCodec->m_startY;
-  int src_hei = pCodec->m_clipBox.Height();
-  int des_hei = pCodec->m_sizeY;
+  int32_t line = row_num + m_GifFrameRect.top;
+  int32_t left = m_GifFrameRect.left;
+  FXSYS_memcpy(m_pDecodeBuf + left, row_buf, img_width);
+  int src_top = m_clipBox.top;
+  int src_bottom = m_clipBox.bottom;
+  int des_top = m_startY;
+  int src_hei = m_clipBox.Height();
+  int des_hei = m_sizeY;
   if (line < src_top || line >= src_bottom)
     return;
 
@@ -767,18 +747,17 @@
   if (des_row >= des_top + des_hei)
     return;
 
-  pCodec->ReSampleScanline(pDIBitmap, des_row, pCodec->m_pDecodeBuf,
-                           pCodec->m_SrcFormat);
-  if (scale_y > 1.0 && (!pCodec->m_bInterpol || pCodec->m_SrcPassNumber == 1)) {
-    pCodec->ResampleVert(pDIBitmap, scale_y, des_row);
+  ReSampleScanline(pDIBitmap, des_row, m_pDecodeBuf, m_SrcFormat);
+  if (scale_y > 1.0 && (!m_bInterpol || m_SrcPassNumber == 1)) {
+    ResampleVert(pDIBitmap, scale_y, des_row);
     return;
   }
   if (scale_y <= 1.0)
     return;
 
-  int des_bottom = des_top + pCodec->m_sizeY;
+  int des_bottom = des_top + m_sizeY;
   int des_Bpp = pDIBitmap->GetBPP() >> 3;
-  uint32_t des_ScanOffet = pCodec->m_startX * des_Bpp;
+  uint32_t des_ScanOffet = m_startX * des_Bpp;
   if (des_row + (int)scale_y >= des_bottom - 1) {
     uint8_t* scan_src =
         (uint8_t*)pDIBitmap->GetScanline(des_row) + des_ScanOffet;
@@ -786,12 +765,12 @@
     while (++cur_row < des_bottom) {
       uint8_t* scan_des =
           (uint8_t*)pDIBitmap->GetScanline(cur_row) + des_ScanOffet;
-      uint32_t size = pCodec->m_sizeX * des_Bpp;
+      uint32_t size = m_sizeX * des_Bpp;
       FXSYS_memmove(scan_des, scan_src, size);
     }
   }
   if (bLastPass)
-    pCodec->GifDoubleLineResampleVert(pDIBitmap, scale_y, des_row);
+    GifDoubleLineResampleVert(pDIBitmap, scale_y, des_row);
 }
 
 void CCodec_ProgressiveDecoder::GifDoubleLineResampleVert(
@@ -875,7 +854,7 @@
   }
 }
 
-bool CCodec_ProgressiveDecoder::BmpReadMoreData(CCodec_BmpModule* pBmpModule,
+bool CCodec_ProgressiveDecoder::BmpReadMoreData(ICodec_BmpModule* pBmpModule,
                                                 FXCODEC_STATUS& err_status) {
   uint32_t dwSize = (uint32_t)m_pFile->GetSize();
   if (dwSize <= m_offSet)
@@ -912,28 +891,22 @@
   return true;
 }
 
-bool CCodec_ProgressiveDecoder::BmpInputImagePositionBufCallback(
-    void* pModule,
-    uint32_t rcd_pos) {
-  CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule;
-  pCodec->m_offSet = rcd_pos;
+bool CCodec_ProgressiveDecoder::BmpInputImagePositionBuf(uint32_t rcd_pos) {
+  m_offSet = rcd_pos;
   FXCODEC_STATUS error_status = FXCODEC_STATUS_ERROR;
-  return pCodec->BmpReadMoreData(pCodec->m_pCodecMgr->GetBmpModule(),
-                                 error_status);
+  return BmpReadMoreData(m_pCodecMgr->GetBmpModule(), error_status);
 }
 
-void CCodec_ProgressiveDecoder::BmpReadScanlineCallback(void* pModule,
-                                                        int32_t row_num,
-                                                        uint8_t* row_buf) {
-  CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule;
-  CFX_DIBitmap* pDIBitmap = pCodec->m_pDeviceBitmap;
+void CCodec_ProgressiveDecoder::BmpReadScanline(int32_t row_num,
+                                                uint8_t* row_buf) {
+  CFX_DIBitmap* pDIBitmap = m_pDeviceBitmap;
   ASSERT(pDIBitmap);
-  FXSYS_memcpy(pCodec->m_pDecodeBuf, row_buf, pCodec->m_ScanlineSize);
-  int src_top = pCodec->m_clipBox.top;
-  int src_bottom = pCodec->m_clipBox.bottom;
-  int des_top = pCodec->m_startY;
-  int src_hei = pCodec->m_clipBox.Height();
-  int des_hei = pCodec->m_sizeY;
+  FXSYS_memcpy(m_pDecodeBuf, row_buf, m_ScanlineSize);
+  int src_top = m_clipBox.top;
+  int src_bottom = m_clipBox.bottom;
+  int des_top = m_startY;
+  int src_hei = m_clipBox.Height();
+  int des_hei = m_sizeY;
   if (row_num < src_top || row_num >= src_bottom)
     return;
 
@@ -943,16 +916,15 @@
   if (des_row >= des_top + des_hei)
     return;
 
-  pCodec->ReSampleScanline(pDIBitmap, des_row, pCodec->m_pDecodeBuf,
-                           pCodec->m_SrcFormat);
+  ReSampleScanline(pDIBitmap, des_row, m_pDecodeBuf, m_SrcFormat);
   if (scale_y <= 1.0)
     return;
 
-  if (pCodec->m_BmpIsTopBottom || !pCodec->m_bInterpol) {
-    pCodec->ResampleVert(pDIBitmap, scale_y, des_row);
+  if (m_BmpIsTopBottom || !m_bInterpol) {
+    ResampleVert(pDIBitmap, scale_y, des_row);
     return;
   }
-  pCodec->ResampleVertBT(pDIBitmap, scale_y, des_row);
+  ResampleVertBT(pDIBitmap, scale_y, des_row);
 }
 
 void CCodec_ProgressiveDecoder::ResampleVertBT(CFX_DIBitmap* pDeviceBitmap,
@@ -1052,15 +1024,13 @@
   m_SrcSize = size;
   switch (imageType) {
     case FXCODEC_IMAGE_BMP: {
-      CCodec_BmpModule* pBmpModule = m_pCodecMgr->GetBmpModule();
+      ICodec_BmpModule* pBmpModule = m_pCodecMgr->GetBmpModule();
       if (!pBmpModule) {
         m_status = FXCODEC_STATUS_ERR_MEMORY;
         return false;
       }
-      pBmpModule->InputImagePositionBufCallback =
-          BmpInputImagePositionBufCallback;
-      pBmpModule->ReadScanlineCallback = BmpReadScanlineCallback;
-      m_pBmpContext = pBmpModule->Start((void*)this);
+      pBmpModule->SetDelegate(this);
+      m_pBmpContext = pBmpModule->Start();
       if (!m_pBmpContext) {
         m_status = FXCODEC_STATUS_ERR_MEMORY;
         return false;
@@ -1150,18 +1120,13 @@
       return false;
     }
     case FXCODEC_IMAGE_PNG: {
-      CCodec_PngModule* pPngModule = m_pCodecMgr->GetPngModule();
+      ICodec_PngModule* pPngModule = m_pCodecMgr->GetPngModule();
       if (!pPngModule) {
         m_status = FXCODEC_STATUS_ERR_MEMORY;
         return false;
       }
-      pPngModule->ReadHeaderCallback =
-          CCodec_ProgressiveDecoder::PngReadHeaderFunc;
-      pPngModule->AskScanlineBufCallback =
-          CCodec_ProgressiveDecoder::PngAskScanlineBufFunc;
-      pPngModule->FillScanlineBufCompletedCallback =
-          CCodec_ProgressiveDecoder::PngFillScanlineBufCompletedFunc;
-      m_pPngContext = pPngModule->Start((void*)this);
+      pPngModule->SetDelegate(this);
+      m_pPngContext = pPngModule->Start();
       if (!m_pPngContext) {
         m_status = FXCODEC_STATUS_ERR_MEMORY;
         return false;
@@ -1212,20 +1177,13 @@
       return true;
     }
     case FXCODEC_IMAGE_GIF: {
-      CCodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule();
+      ICodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule();
       if (!pGifModule) {
         m_status = FXCODEC_STATUS_ERR_MEMORY;
         return false;
       }
-      pGifModule->RecordCurrentPositionCallback =
-          CCodec_ProgressiveDecoder::GifRecordCurrentPositionCallback;
-      pGifModule->AskLocalPaletteBufCallback =
-          CCodec_ProgressiveDecoder::GifAskLocalPaletteBufCallback;
-      pGifModule->InputRecordPositionBufCallback =
-          CCodec_ProgressiveDecoder::GifInputRecordPositionBufCallback;
-      pGifModule->ReadScanlineCallback =
-          CCodec_ProgressiveDecoder::GifReadScanlineCallback;
-      m_pGifContext = pGifModule->Start((void*)this);
+      pGifModule->SetDelegate(this);
+      m_pGifContext = pGifModule->Start();
       if (!m_pGifContext) {
         m_status = FXCODEC_STATUS_ERR_MEMORY;
         return false;
@@ -1264,7 +1222,7 @@
       return false;
     }
     case FXCODEC_IMAGE_TIF: {
-      CCodec_TiffModule* pTiffModule = m_pCodecMgr->GetTiffModule();
+      ICodec_TiffModule* pTiffModule = m_pCodecMgr->GetTiffModule();
       if (!pTiffModule) {
         m_status = FXCODEC_STATUS_ERR_FORMAT;
         return false;
@@ -1832,15 +1790,19 @@
     return FXCODEC_STATUS_ERROR;
   }
   switch (m_imagType) {
-    case FXCODEC_IMAGE_BMP:
     case FXCODEC_IMAGE_JPG:
+    case FXCODEC_IMAGE_BMP:
     case FXCODEC_IMAGE_PNG:
     case FXCODEC_IMAGE_TIF:
       frames = m_FrameNumber = 1;
       m_status = FXCODEC_STATUS_DECODE_READY;
       return m_status;
     case FXCODEC_IMAGE_GIF: {
-      CCodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule();
+      ICodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule();
+      if (!pGifModule) {
+        m_status = FXCODEC_STATUS_ERR_MEMORY;
+        return m_status;
+      }
       while (true) {
         int32_t readResult =
             pGifModule->LoadFrameInfo(m_pGifContext, &m_FrameNumber);
@@ -1969,7 +1931,7 @@
       return m_status;
     }
     case FXCODEC_IMAGE_PNG: {
-      CCodec_PngModule* pPngModule = m_pCodecMgr->GetPngModule();
+      ICodec_PngModule* pPngModule = m_pCodecMgr->GetPngModule();
       if (!pPngModule) {
         m_pDeviceBitmap = nullptr;
         m_pFile = nullptr;
@@ -1980,7 +1942,7 @@
         pPngModule->Finish(m_pPngContext);
         m_pPngContext = nullptr;
       }
-      m_pPngContext = pPngModule->Start((void*)this);
+      m_pPngContext = pPngModule->Start();
       if (!m_pPngContext) {
         m_pDeviceBitmap = nullptr;
         m_pFile = nullptr;
@@ -2021,7 +1983,7 @@
       return m_status;
     }
     case FXCODEC_IMAGE_GIF: {
-      CCodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule();
+      ICodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule();
       if (!pGifModule) {
         m_pDeviceBitmap = nullptr;
         m_pFile = nullptr;
@@ -2042,7 +2004,7 @@
       return m_status;
     }
     case FXCODEC_IMAGE_BMP: {
-      CCodec_BmpModule* pBmpModule = m_pCodecMgr->GetBmpModule();
+      ICodec_BmpModule* pBmpModule = m_pCodecMgr->GetBmpModule();
       if (!pBmpModule) {
         m_pDeviceBitmap = nullptr;
         m_pFile = nullptr;
@@ -2117,7 +2079,11 @@
       }
     }
     case FXCODEC_IMAGE_PNG: {
-      CCodec_PngModule* pPngModule = m_pCodecMgr->GetPngModule();
+      ICodec_PngModule* pPngModule = m_pCodecMgr->GetPngModule();
+      if (!pPngModule) {
+        m_status = FXCODEC_STATUS_ERR_MEMORY;
+        return m_status;
+      }
       while (true) {
         uint32_t remain_size = (uint32_t)m_pFile->GetSize() - m_offSet;
         uint32_t input_size =
@@ -2161,7 +2127,11 @@
       }
     }
     case FXCODEC_IMAGE_GIF: {
-      CCodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule();
+      ICodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule();
+      if (!pGifModule) {
+        m_status = FXCODEC_STATUS_ERR_MEMORY;
+        return m_status;
+      }
       while (true) {
         int32_t readRes =
             pGifModule->LoadFrame(m_pGifContext, m_FrameCur, nullptr);
@@ -2192,7 +2162,11 @@
       }
     }
     case FXCODEC_IMAGE_BMP: {
-      CCodec_BmpModule* pBmpModule = m_pCodecMgr->GetBmpModule();
+      ICodec_BmpModule* pBmpModule = m_pCodecMgr->GetBmpModule();
+      if (!pBmpModule) {
+        m_status = FXCODEC_STATUS_ERR_MEMORY;
+        return m_status;
+      }
       while (true) {
         int32_t readRes = pBmpModule->LoadImage(m_pBmpContext);
         while (readRes == 2) {
@@ -2220,9 +2194,13 @@
         m_status = FXCODEC_STATUS_ERROR;
         return m_status;
       }
-    };
+    }
     case FXCODEC_IMAGE_TIF: {
-      CCodec_TiffModule* pTiffModule = m_pCodecMgr->GetTiffModule();
+      ICodec_TiffModule* pTiffModule = m_pCodecMgr->GetTiffModule();
+      if (!pTiffModule) {
+        m_status = FXCODEC_STATUS_ERR_MEMORY;
+        return m_status;
+      }
       bool ret = false;
       if (m_pDeviceBitmap->GetBPP() == 32 &&
           m_pDeviceBitmap->GetWidth() == m_SrcWidth && m_SrcWidth == m_sizeX &&
@@ -2369,6 +2347,7 @@
   }
 }
 
-CCodec_ProgressiveDecoder* CCodec_ModuleMgr::CreateProgressiveDecoder() {
-  return new CCodec_ProgressiveDecoder(this);
+std::unique_ptr<CCodec_ProgressiveDecoder>
+CCodec_ModuleMgr::CreateProgressiveDecoder() {
+  return pdfium::MakeUnique<CCodec_ProgressiveDecoder>(this);
 }
diff --git a/core/fxcodec/codec/fx_codec_rle_unittest.cpp b/core/fxcodec/codec/fx_codec_rle_unittest.cpp
index 94d87cd..d90a515 100644
--- a/core/fxcodec/codec/fx_codec_rle_unittest.cpp
+++ b/core/fxcodec/codec/fx_codec_rle_unittest.cpp
@@ -13,7 +13,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 TEST(fxcodec, RLETestBadInputs) {
-  uint8_t src_buf[1] = {1};
+  const uint8_t src_buf[] = {1};
   uint8_t* dest_buf = nullptr;
   uint32_t src_size = 4;
   uint32_t dest_size = 0;
@@ -33,7 +33,7 @@
 
 // Check length 1 input works. Check terminating character is applied.
 TEST(fxcodec, RLETestShortInput) {
-  uint8_t src_buf[1] = {1};
+  const uint8_t src_buf[] = {1};
   uint8_t* dest_buf = nullptr;
   uint32_t src_size = 1;
   uint32_t dest_size = 0;
@@ -43,25 +43,25 @@
 
   EXPECT_TRUE(
       pEncoders->RunLengthEncode(src_buf, src_size, &dest_buf, &dest_size));
-  EXPECT_EQ(3u, dest_size);
-  EXPECT_EQ(dest_buf[0], 0);
-  EXPECT_EQ(dest_buf[1], 1);
-  EXPECT_EQ(dest_buf[2], 128);
+  ASSERT_EQ(3u, dest_size);
+  EXPECT_EQ(0, dest_buf[0]);
+  EXPECT_EQ(1, dest_buf[1]);
+  EXPECT_EQ(128, dest_buf[2]);
 
   FX_Free(dest_buf);
 }
 
 // Check a few basic cases (2 matching runs in a row, matching run followed
-// by a nonmatching run, and nonmatching run followed by a matching run).
+// by a non-matching run, and non-matching run followed by a matching run).
 TEST(fxcodec, RLETestNormalInputs) {
   // Match, match
-  uint8_t src_buf_1[10] = {2, 2, 2, 2, 4, 4, 4, 4, 4, 4};
+  const uint8_t src_buf_1[] = {2, 2, 2, 2, 4, 4, 4, 4, 4, 4};
 
-  // Match, nonmatch
-  uint8_t src_buf_2[10] = {2, 2, 2, 2, 1, 2, 3, 4, 5, 6};
+  // Match, non-match
+  const uint8_t src_buf_2[] = {2, 2, 2, 2, 1, 2, 3, 4, 5, 6};
 
-  // Nonmatch, match
-  uint8_t src_buf_3[10] = {1, 2, 3, 4, 5, 3, 3, 3, 3, 3};
+  // Non-match, match
+  const uint8_t src_buf_3[] = {1, 2, 3, 4, 5, 3, 3, 3, 3, 3};
 
   uint32_t src_size = 10;
   uint32_t dest_size = 0;
@@ -76,9 +76,9 @@
   uint8_t* decoded_buf = nullptr;
   uint32_t decoded_size = 0;
   RunLengthDecode(dest_buf, dest_size, decoded_buf, decoded_size);
-  EXPECT_EQ(decoded_size, src_size);
+  ASSERT_EQ(src_size, decoded_size);
   for (uint32_t i = 0; i < src_size; i++)
-    EXPECT_EQ(decoded_buf[i], src_buf_1[i]) << " at " << i;
+    EXPECT_EQ(src_buf_1[i], decoded_buf[i]) << " at " << i;
   FX_Free(dest_buf);
   FX_Free(decoded_buf);
 
@@ -90,9 +90,9 @@
   decoded_buf = nullptr;
   decoded_size = 0;
   RunLengthDecode(dest_buf, dest_size, decoded_buf, decoded_size);
-  EXPECT_EQ(decoded_size, src_size);
+  ASSERT_EQ(src_size, decoded_size);
   for (uint32_t i = 0; i < src_size; i++)
-    EXPECT_EQ(decoded_buf[i], src_buf_2[i]) << " at " << i;
+    EXPECT_EQ(src_buf_2[i], decoded_buf[i]) << " at " << i;
   FX_Free(dest_buf);
   FX_Free(decoded_buf);
 
@@ -104,30 +104,30 @@
   decoded_buf = nullptr;
   decoded_size = 0;
   RunLengthDecode(dest_buf, dest_size, decoded_buf, decoded_size);
-  EXPECT_EQ(decoded_size, src_size);
+  ASSERT_EQ(src_size, decoded_size);
   for (uint32_t i = 0; i < src_size; i++)
-    EXPECT_EQ(decoded_buf[i], src_buf_3[i]) << " at " << i;
+    EXPECT_EQ(src_buf_3[i], decoded_buf[i]) << " at " << i;
   FX_Free(dest_buf);
   FX_Free(decoded_buf);
 }
 
 // Check that runs longer than 128 are broken up properly, both matched and
-// nonmatched.
+// non-matched.
 TEST(fxcodec, RLETestFullLengthInputs) {
   // Match, match
-  uint8_t src_buf_1[260] = {1};
+  const uint8_t src_buf_1[260] = {1};
 
-  // Match, nonmatch
+  // Match, non-match
   uint8_t src_buf_2[260] = {2};
   for (uint16_t i = 128; i < 260; i++)
     src_buf_2[i] = (uint8_t)(i - 125);
 
-  // Nonmatch, match
+  // Non-match, match
   uint8_t src_buf_3[260] = {3};
   for (uint8_t i = 0; i < 128; i++)
     src_buf_3[i] = i;
 
-  // Nonmatch, nonmatch
+  // Non-match, non-match
   uint8_t src_buf_4[260];
   for (uint16_t i = 0; i < 260; i++)
     src_buf_4[i] = (uint8_t)(i);
@@ -145,9 +145,9 @@
   uint8_t* decoded_buf = nullptr;
   uint32_t decoded_size = 0;
   RunLengthDecode(dest_buf, dest_size, decoded_buf, decoded_size);
-  EXPECT_EQ(decoded_size, src_size);
+  ASSERT_EQ(src_size, decoded_size);
   for (uint32_t i = 0; i < src_size; i++)
-    EXPECT_EQ(decoded_buf[i], src_buf_1[i]) << " at " << i;
+    EXPECT_EQ(src_buf_1[i], decoded_buf[i]) << " at " << i;
   FX_Free(dest_buf);
   FX_Free(decoded_buf);
 
@@ -159,9 +159,9 @@
   decoded_buf = nullptr;
   decoded_size = 0;
   RunLengthDecode(dest_buf, dest_size, decoded_buf, decoded_size);
-  EXPECT_EQ(decoded_size, src_size);
+  ASSERT_EQ(src_size, decoded_size);
   for (uint32_t i = 0; i < src_size; i++)
-    EXPECT_EQ(decoded_buf[i], src_buf_2[i]) << " at " << i;
+    EXPECT_EQ(src_buf_2[i], decoded_buf[i]) << " at " << i;
   FX_Free(dest_buf);
   FX_Free(decoded_buf);
 
@@ -173,9 +173,9 @@
   decoded_buf = nullptr;
   decoded_size = 0;
   RunLengthDecode(dest_buf, dest_size, decoded_buf, decoded_size);
-  EXPECT_EQ(decoded_size, src_size);
+  ASSERT_EQ(src_size, decoded_size);
   for (uint32_t i = 0; i < src_size; i++)
-    EXPECT_EQ(decoded_buf[i], src_buf_3[i]) << " at " << i;
+    EXPECT_EQ(src_buf_3[i], decoded_buf[i]) << " at " << i;
   FX_Free(dest_buf);
   FX_Free(decoded_buf);
 
@@ -187,9 +187,9 @@
   decoded_buf = nullptr;
   decoded_size = 0;
   RunLengthDecode(dest_buf, dest_size, decoded_buf, decoded_size);
-  EXPECT_EQ(decoded_size, src_size);
+  ASSERT_EQ(src_size, decoded_size);
   for (uint32_t i = 0; i < src_size; i++)
-    EXPECT_EQ(decoded_buf[i], src_buf_4[i]) << " at " << i;
+    EXPECT_EQ(src_buf_4[i], decoded_buf[i]) << " at " << i;
   FX_Free(dest_buf);
   FX_Free(decoded_buf);
 }
diff --git a/core/fxcodec/codec/icodec_bmpmodule.h b/core/fxcodec/codec/icodec_bmpmodule.h
new file mode 100644
index 0000000..a67e20c
--- /dev/null
+++ b/core/fxcodec/codec/icodec_bmpmodule.h
@@ -0,0 +1,51 @@
+// 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 CORE_FXCODEC_CODEC_ICODEC_BMPMODULE_H_
+#define CORE_FXCODEC_CODEC_ICODEC_BMPMODULE_H_
+
+#include "core/fxcrt/fx_system.h"
+
+struct FXBMP_Context;
+class CFX_DIBAttribute;
+
+// Virtual interface to avoid linking in a concrete implementation
+// if we do not enable this codec.
+class ICodec_BmpModule {
+ public:
+  class Delegate {
+   public:
+    virtual bool BmpInputImagePositionBuf(uint32_t rcd_pos) = 0;
+    virtual void BmpReadScanline(int32_t row_num, uint8_t* row_buf) = 0;
+  };
+
+  virtual ~ICodec_BmpModule() {}
+
+  virtual FXBMP_Context* Start() = 0;
+  virtual void Finish(FXBMP_Context* pContext) = 0;
+  virtual uint32_t GetAvailInput(FXBMP_Context* pContext,
+                                 uint8_t** avail_buf_ptr) = 0;
+  virtual void Input(FXBMP_Context* pContext,
+                     const uint8_t* src_buf,
+                     uint32_t src_size) = 0;
+  virtual int32_t ReadHeader(FXBMP_Context* pContext,
+                             int32_t* width,
+                             int32_t* height,
+                             bool* tb_flag,
+                             int32_t* components,
+                             int32_t* pal_num,
+                             uint32_t** pal_pp,
+                             CFX_DIBAttribute* pAttribute) = 0;
+  virtual int32_t LoadImage(FXBMP_Context* pContext) = 0;
+
+  Delegate* GetDelegate() const { return m_pDelegate; }
+  void SetDelegate(Delegate* pDelegate) { m_pDelegate = pDelegate; }
+
+ protected:
+  Delegate* m_pDelegate;
+};
+
+#endif  // CORE_FXCODEC_CODEC_ICODEC_BMPMODULE_H_
diff --git a/core/fxcodec/codec/icodec_gifmodule.h b/core/fxcodec/codec/icodec_gifmodule.h
new file mode 100644
index 0000000..9dc0708
--- /dev/null
+++ b/core/fxcodec/codec/icodec_gifmodule.h
@@ -0,0 +1,68 @@
+// 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 CORE_FXCODEC_CODEC_ICODEC_GIFMODULE_H_
+#define CORE_FXCODEC_CODEC_ICODEC_GIFMODULE_H_
+
+#include "core/fxcrt/fx_coordinates.h"
+#include "core/fxcrt/fx_system.h"
+
+class CFX_DIBAttribute;
+struct FXGIF_Context;
+
+// Virtual interface to avoid linking in a concrete implementation
+// if we do not enable this codec.
+class ICodec_GifModule {
+ public:
+  class Delegate {
+   public:
+    virtual void GifRecordCurrentPosition(uint32_t& cur_pos) = 0;
+    virtual uint8_t* GifAskLocalPaletteBuf(int32_t frame_num,
+                                           int32_t pal_size) = 0;
+    virtual bool GifInputRecordPositionBuf(uint32_t rcd_pos,
+                                           const FX_RECT& img_rc,
+                                           int32_t pal_num,
+                                           void* pal_ptr,
+                                           int32_t delay_time,
+                                           bool user_input,
+                                           int32_t trans_index,
+                                           int32_t disposal_method,
+                                           bool interlace) = 0;
+    virtual void GifReadScanline(int32_t row_num, uint8_t* row_buf) = 0;
+  };
+
+  virtual ~ICodec_GifModule() {}
+
+  virtual FXGIF_Context* Start() = 0;
+  virtual void Finish(FXGIF_Context* pContext) = 0;
+  virtual uint32_t GetAvailInput(FXGIF_Context* pContext,
+                                 uint8_t** avail_buf_ptr = nullptr) = 0;
+
+  virtual void Input(FXGIF_Context* pContext,
+                     const uint8_t* src_buf,
+                     uint32_t src_size) = 0;
+
+  virtual int32_t ReadHeader(FXGIF_Context* pContext,
+                             int* width,
+                             int* height,
+                             int* pal_num,
+                             void** pal_pp,
+                             int* bg_index,
+                             CFX_DIBAttribute* pAttribute) = 0;
+
+  virtual int32_t LoadFrameInfo(FXGIF_Context* pContext, int* frame_num) = 0;
+  virtual int32_t LoadFrame(FXGIF_Context* pContext,
+                            int frame_num,
+                            CFX_DIBAttribute* pAttribute) = 0;
+
+  Delegate* GetDelegate() const { return m_pDelegate; }
+  void SetDelegate(Delegate* pDelegate) { m_pDelegate = pDelegate; }
+
+ protected:
+  Delegate* m_pDelegate;
+};
+
+#endif  // CORE_FXCODEC_CODEC_ICODEC_GIFMODULE_H_
diff --git a/core/fxcodec/codec/icodec_pngmodule.h b/core/fxcodec/codec/icodec_pngmodule.h
new file mode 100644
index 0000000..63e61fe
--- /dev/null
+++ b/core/fxcodec/codec/icodec_pngmodule.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 CORE_FXCODEC_CODEC_ICODEC_PNGMODULE_H_
+#define CORE_FXCODEC_CODEC_ICODEC_PNGMODULE_H_
+
+#include "core/fxcrt/fx_system.h"
+
+class CFX_DIBAttribute;
+struct FXPNG_Context;
+
+// Virtual interface to avoid linking in a concrete implementation
+// if we do not enable this codec.
+class ICodec_PngModule {
+ public:
+  class Delegate {
+   public:
+    virtual bool PngReadHeader(int width,
+                               int height,
+                               int bpc,
+                               int pass,
+                               int* color_type,
+                               double* gamma) = 0;
+    virtual bool PngAskScanlineBuf(int line, uint8_t*& src_buf) = 0;
+    virtual void PngFillScanlineBufCompleted(int pass, int line) = 0;
+  };
+
+  virtual ~ICodec_PngModule() {}
+
+  virtual FXPNG_Context* Start() = 0;
+  virtual void Finish(FXPNG_Context* pContext) = 0;
+  virtual bool Input(FXPNG_Context* pContext,
+                     const uint8_t* src_buf,
+                     uint32_t src_size,
+                     CFX_DIBAttribute* pAttribute) = 0;
+
+  Delegate* GetDelegate() const { return m_pDelegate; }
+  void SetDelegate(Delegate* delegate) { m_pDelegate = delegate; }
+
+ protected:
+  Delegate* m_pDelegate;
+};
+
+#endif  // CORE_FXCODEC_CODEC_ICODEC_PNGMODULE_H_
diff --git a/core/fxcodec/codec/icodec_tiffmodule.h b/core/fxcodec/codec/icodec_tiffmodule.h
new file mode 100644
index 0000000..540d82f
--- /dev/null
+++ b/core/fxcodec/codec/icodec_tiffmodule.h
@@ -0,0 +1,36 @@
+// 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 CORE_FXCODEC_CODEC_ICODEC_TIFFMODULE_H_
+#define CORE_FXCODEC_CODEC_ICODEC_TIFFMODULE_H_
+
+#include "core/fxcrt/cfx_retain_ptr.h"
+#include "core/fxcrt/fx_system.h"
+
+class CCodec_TiffContext;
+class CFX_DIBAttribute;
+class CFX_DIBitmap;
+class IFX_SeekableReadStream;
+
+class ICodec_TiffModule {
+ public:
+  virtual ~ICodec_TiffModule() {}
+
+  virtual CCodec_TiffContext* CreateDecoder(
+      const CFX_RetainPtr<IFX_SeekableReadStream>& file_ptr) = 0;
+  virtual bool LoadFrameInfo(CCodec_TiffContext* ctx,
+                             int32_t frame,
+                             int32_t* width,
+                             int32_t* height,
+                             int32_t* comps,
+                             int32_t* bpc,
+                             CFX_DIBAttribute* pAttribute) = 0;
+  virtual bool Decode(CCodec_TiffContext* ctx,
+                      class CFX_DIBitmap* pDIBitmap) = 0;
+  virtual void DestroyDecoder(CCodec_TiffContext* ctx) = 0;
+};
+
+#endif  // CORE_FXCODEC_CODEC_ICODEC_TIFFMODULE_H_
diff --git a/core/fxcodec/fx_codec.h b/core/fxcodec/fx_codec.h
index bb47665..b0b9fa1 100644
--- a/core/fxcodec/fx_codec.h
+++ b/core/fxcodec/fx_codec.h
@@ -9,6 +9,7 @@
 
 #include <map>
 #include <memory>
+#include <utility>
 #include <vector>
 
 #include "core/fxcodec/codec/ccodec_basicmodule.h"
@@ -23,17 +24,19 @@
 #include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_coordinates.h"
 
+#ifdef PDF_ENABLE_XFA
+#include "core/fxcodec/codec/icodec_bmpmodule.h"
+#include "core/fxcodec/codec/icodec_gifmodule.h"
+#include "core/fxcodec/codec/icodec_pngmodule.h"
+#include "core/fxcodec/codec/icodec_tiffmodule.h"
+#endif  // PDF_ENABLE_XFA
+
 class CFX_DIBSource;
 class CJPX_Decoder;
 class CPDF_ColorSpace;
 class CPDF_StreamAcc;
 
 #ifdef PDF_ENABLE_XFA
-#include "core/fxcodec/codec/ccodec_bmpmodule.h"
-#include "core/fxcodec/codec/ccodec_gifmodule.h"
-#include "core/fxcodec/codec/ccodec_pngmodule.h"
-#include "core/fxcodec/codec/ccodec_tiffmodule.h"
-
 class CCodec_ProgressiveDecoder;
 
 class CFX_DIBAttribute {
@@ -70,11 +73,23 @@
   CCodec_FlateModule* GetFlateModule() const { return m_pFlateModule.get(); }
 
 #ifdef PDF_ENABLE_XFA
-  CCodec_ProgressiveDecoder* CreateProgressiveDecoder();
-  CCodec_PngModule* GetPngModule() const { return m_pPngModule.get(); }
-  CCodec_GifModule* GetGifModule() const { return m_pGifModule.get(); }
-  CCodec_BmpModule* GetBmpModule() const { return m_pBmpModule.get(); }
-  CCodec_TiffModule* GetTiffModule() const { return m_pTiffModule.get(); }
+  std::unique_ptr<CCodec_ProgressiveDecoder> CreateProgressiveDecoder();
+  void SetBmpModule(std::unique_ptr<ICodec_BmpModule> module) {
+    m_pBmpModule = std::move(module);
+  }
+  void SetGifModule(std::unique_ptr<ICodec_GifModule> module) {
+    m_pGifModule = std::move(module);
+  }
+  void SetPngModule(std::unique_ptr<ICodec_PngModule> module) {
+    m_pPngModule = std::move(module);
+  }
+  void SetTiffModule(std::unique_ptr<ICodec_TiffModule> module) {
+    m_pTiffModule = std::move(module);
+  }
+  ICodec_BmpModule* GetBmpModule() const { return m_pBmpModule.get(); }
+  ICodec_GifModule* GetGifModule() const { return m_pGifModule.get(); }
+  ICodec_PngModule* GetPngModule() const { return m_pPngModule.get(); }
+  ICodec_TiffModule* GetTiffModule() const { return m_pTiffModule.get(); }
 #endif  // PDF_ENABLE_XFA
 
  protected:
@@ -86,10 +101,10 @@
   std::unique_ptr<CCodec_IccModule> m_pIccModule;
 
 #ifdef PDF_ENABLE_XFA
-  std::unique_ptr<CCodec_PngModule> m_pPngModule;
-  std::unique_ptr<CCodec_GifModule> m_pGifModule;
-  std::unique_ptr<CCodec_BmpModule> m_pBmpModule;
-  std::unique_ptr<CCodec_TiffModule> m_pTiffModule;
+  std::unique_ptr<ICodec_BmpModule> m_pBmpModule;
+  std::unique_ptr<ICodec_GifModule> m_pGifModule;
+  std::unique_ptr<ICodec_PngModule> m_pPngModule;
+  std::unique_ptr<ICodec_TiffModule> m_pTiffModule;
 #endif  // PDF_ENABLE_XFA
 
   std::unique_ptr<CCodec_FlateModule> m_pFlateModule;
diff --git a/core/fxcodec/lgif/fx_gif.cpp b/core/fxcodec/lgif/fx_gif.cpp
index 93db181..d62dacb 100644
--- a/core/fxcodec/lgif/fx_gif.cpp
+++ b/core/fxcodec/lgif/fx_gif.cpp
@@ -114,7 +114,17 @@
           FXSYS_strncpy(err_msg_ptr, "Decode Error", GIF_MAX_ERROR_SIZE - 1);
         return 0;
       }
-      code_store |= (*next_in++) << bits_left;
+      pdfium::base::CheckedNumeric<uint32_t> safe_code = *next_in++;
+      safe_code <<= bits_left;
+      safe_code |= code_store;
+      if (!safe_code.IsValid()) {
+        if (err_msg_ptr) {
+          FXSYS_strncpy(err_msg_ptr, "Code Store Out Of Range",
+                        GIF_MAX_ERROR_SIZE - 1);
+        }
+        return 0;
+      }
+      code_store = safe_code.ValueOrDie();
       avail_in--;
       bits_left += 8;
     }
diff --git a/core/fxcrt/cfx_retain_ptr.h b/core/fxcrt/cfx_retain_ptr.h
index 62b2694..0267ae0 100644
--- a/core/fxcrt/cfx_retain_ptr.h
+++ b/core/fxcrt/cfx_retain_ptr.h
@@ -30,6 +30,11 @@
   template <class U>
   CFX_RetainPtr(const CFX_RetainPtr<U>& that) : CFX_RetainPtr(that.Get()) {}
 
+  template <class U>
+  CFX_RetainPtr<U> As() const {
+    return CFX_RetainPtr<U>(static_cast<U*>(Get()));
+  }
+
   void Reset(T* obj = nullptr) {
     if (obj)
       obj->Retain();
diff --git a/core/fxcrt/cfx_string_data_template.h b/core/fxcrt/cfx_string_data_template.h
index affd610..c3e090f 100644
--- a/core/fxcrt/cfx_string_data_template.h
+++ b/core/fxcrt/cfx_string_data_template.h
@@ -30,7 +30,8 @@
     // where we can save a re-alloc when adding a few characters to a string
     // by using this otherwise wasted space.
     nSize += 7;
-    int totalSize = nSize.ValueOrDie() & ~7;
+    nSize &= ~7;
+    int totalSize = nSize.ValueOrDie();
     int usableLen = (totalSize - overhead) / sizeof(CharType);
     ASSERT(usableLen >= nLen);
 
diff --git a/core/fxcrt/fx_arabic.cpp b/core/fxcrt/fx_arabic.cpp
index d6b3c65..108c6c1 100644
--- a/core/fxcrt/fx_arabic.cpp
+++ b/core/fxcrt/fx_arabic.cpp
@@ -5,7 +5,12 @@
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
 #include "core/fxcrt/fx_arabic.h"
+
+#include <algorithm>
+#include <vector>
+
 #include "core/fxcrt/fx_ucd.h"
+#include "third_party/base/stl_util.h"
 
 namespace {
 
@@ -374,7 +379,7 @@
 
 int32_t FX_BidiReorderLevel(int32_t iBaseLevel,
                             CFX_WideString& wsText,
-                            const CFX_Int32Array& levels,
+                            const CFX_ArrayTemplate<int32_t>& levels,
                             int32_t iStart,
                             bool bReverse) {
   ASSERT(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
@@ -403,7 +408,7 @@
 }
 void FX_BidiReorder(int32_t iBaseLevel,
                     CFX_WideString& wsText,
-                    const CFX_Int32Array& levels) {
+                    const CFX_ArrayTemplate<int32_t>& levels) {
   ASSERT(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
   ASSERT(wsText.GetLength() == levels.GetSize());
   int32_t iSize = wsText.GetLength();
@@ -419,81 +424,62 @@
 template <class baseType>
 class CFX_BidiLineTemplate {
  public:
-  void FX_BidiReverseString(CFX_ArrayTemplate<baseType>& chars,
+  void FX_BidiReverseString(std::vector<baseType>& chars,
                             int32_t iStart,
                             int32_t iCount) {
-    ASSERT(iStart > -1 && iStart < chars.GetSize());
-    ASSERT(iCount >= 0 && iStart + iCount <= chars.GetSize());
-    baseType *pStart, *pEnd;
-    int32_t iEnd = iStart + iCount - 1, iTemp;
-    while (iStart < iEnd) {
-      pStart = chars.GetDataPtr(iStart++);
-      pEnd = chars.GetDataPtr(iEnd--);
-      iTemp = pStart->m_iBidiPos;
-      pStart->m_iBidiPos = pEnd->m_iBidiPos;
-      pEnd->m_iBidiPos = iTemp;
-    }
+    ASSERT(iStart >= 0 && iStart < pdfium::CollectionSize<int32_t>(chars));
+    ASSERT(iCount >= 0 &&
+           iStart + iCount <= pdfium::CollectionSize<int32_t>(chars));
+    std::reverse(chars.begin() + iStart, chars.begin() + iStart + iCount);
   }
-  void FX_BidiSetDeferredRun(CFX_ArrayTemplate<baseType>& chars,
+
+  void FX_BidiSetDeferredRun(std::vector<baseType>& chars,
                              bool bClass,
                              int32_t iStart,
                              int32_t iCount,
                              int32_t iValue) {
-    ASSERT(iStart > -1 && iStart <= chars.GetSize());
+    ASSERT(iStart >= 0 && iStart <= pdfium::CollectionSize<int32_t>(chars));
     ASSERT(iStart - iCount > -1);
-    baseType* pTC;
     int32_t iLast = iStart - iCount;
     if (bClass) {
-      for (int32_t i = iStart - 1; i >= iLast; i--) {
-        pTC = chars.GetDataPtr(i);
-        pTC->m_iBidiClass = (int16_t)iValue;
-      }
+      for (int32_t i = iStart - 1; i >= iLast; i--)
+        chars[i].m_iBidiClass = (int16_t)iValue;
     } else {
-      for (int32_t i = iStart - 1; i >= iLast; i--) {
-        pTC = chars.GetDataPtr(i);
-        pTC->m_iBidiLevel = (int16_t)iValue;
-      }
+      for (int32_t i = iStart - 1; i >= iLast; i--)
+        chars[i].m_iBidiLevel = (int16_t)iValue;
     }
   }
-  void FX_BidiClassify(CFX_ArrayTemplate<baseType>& chars,
-                       int32_t iCount,
-                       bool bWS) {
-    ASSERT(iCount > -1 && iCount <= chars.GetSize());
-    baseType* pTC;
+
+  void FX_BidiClassify(std::vector<baseType>& chars, int32_t iCount, bool bWS) {
+    ASSERT(iCount >= 0 && iCount <= pdfium::CollectionSize<int32_t>(chars));
     if (bWS) {
       for (int32_t i = 0; i < iCount; i++) {
-        pTC = chars.GetDataPtr(i);
-        pTC->m_iBidiClass =
-            (int16_t)(pTC->m_dwCharProps & FX_BIDICLASSBITSMASK) >>
+        chars[i].m_iBidiClass =
+            (int16_t)(chars[i].m_dwCharProps & FX_BIDICLASSBITSMASK) >>
             FX_BIDICLASSBITS;
       }
     } else {
       for (int32_t i = 0; i < iCount; i++) {
-        pTC = chars.GetDataPtr(i);
-        pTC->m_iBidiClass = (int16_t)
-            gc_FX_BidiNTypes[(pTC->m_dwCharProps & FX_BIDICLASSBITSMASK) >>
+        chars[i].m_iBidiClass = (int16_t)
+            gc_FX_BidiNTypes[(chars[i].m_dwCharProps & FX_BIDICLASSBITSMASK) >>
                              FX_BIDICLASSBITS];
       }
     }
   }
-  void FX_BidiResolveExplicit(CFX_ArrayTemplate<baseType>& chars,
+
+  void FX_BidiResolveExplicit(std::vector<baseType>& chars,
                               int32_t iCount,
                               int32_t iBaseLevel) {
-    ASSERT(iCount > -1 && iCount <= chars.GetSize());
+    ASSERT(iCount >= 0 && iCount <= pdfium::CollectionSize<int32_t>(chars));
     ASSERT(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
-    if (iCount < 1) {
-      return;
-    }
-    baseType* pTC;
-    for (int32_t i = 0; i < iCount; i++) {
-      pTC = chars.GetDataPtr(i);
-      pTC->m_iBidiLevel = (int16_t)iBaseLevel;
-    }
+    for (int32_t i = 0; i < iCount; i++)
+      chars[i].m_iBidiLevel = static_cast<int16_t>(iBaseLevel);
   }
-  void FX_BidiResolveWeak(CFX_ArrayTemplate<baseType>& chars,
+
+  void FX_BidiResolveWeak(std::vector<baseType>& chars,
                           int32_t iCount,
                           int32_t iBaseLevel) {
-    ASSERT(iCount > -1 && iCount <= chars.GetSize());
+    ASSERT(iCount >= 0 && iCount <= pdfium::CollectionSize<int32_t>(chars));
     iCount--;
     if (iCount < 1) {
       return;
@@ -503,7 +489,7 @@
     int32_t iState = FX_IsOdd(iBaseLevel) ? FX_BWSxr : FX_BWSxl;
     int32_t i = 0, iNum = 0, iClsCur, iClsRun, iClsNew, iAction;
     for (; i <= iCount; i++) {
-      pTC = chars.GetDataPtr(i);
+      pTC = &chars[i];
       iClsCur = pTC->m_iBidiClass;
       if (iClsCur == FX_BIDICLASS_BN) {
         pTC->m_iBidiLevel = (int16_t)iLevelCur;
@@ -511,7 +497,7 @@
           iClsCur = FX_BidiDirection(iLevelCur);
           pTC->m_iBidiClass = (int16_t)iClsCur;
         } else if (i < iCount) {
-          pTCNext = chars.GetDataPtr(i + 1);
+          pTCNext = &chars[i + 1];
           int32_t iLevelNext, iLevelNew;
           iClsNew = pTCNext->m_iBidiClass;
           iLevelNext = pTCNext->m_iBidiLevel;
@@ -561,10 +547,11 @@
       }
     }
   }
-  void FX_BidiResolveNeutrals(CFX_ArrayTemplate<baseType>& chars,
+
+  void FX_BidiResolveNeutrals(std::vector<baseType>& chars,
                               int32_t iCount,
                               int32_t iBaseLevel) {
-    ASSERT(iCount > -1 && iCount <= chars.GetSize());
+    ASSERT(iCount >= 0 && iCount <= pdfium::CollectionSize<int32_t>(chars));
     ASSERT(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
     iCount--;
     if (iCount < 1) {
@@ -575,7 +562,7 @@
     int32_t iState = FX_IsOdd(iBaseLevel) ? FX_BNSr : FX_BNSl;
     int32_t i = 0, iNum = 0, iClsCur, iClsRun, iClsNew, iAction;
     for (; i <= iCount; i++) {
-      pTC = chars.GetDataPtr(i);
+      pTC = &chars[i];
       iClsCur = pTC->m_iBidiClass;
       if (iClsCur == FX_BIDICLASS_BN) {
         if (iNum) {
@@ -609,27 +596,25 @@
       }
     }
   }
-  void FX_BidiResolveImplicit(CFX_ArrayTemplate<baseType>& chars,
-                              int32_t iCount) {
-    ASSERT(iCount > -1 && iCount <= chars.GetSize());
-    baseType* pTC;
-    int32_t iCls, iLevel;
+
+  void FX_BidiResolveImplicit(std::vector<baseType>& chars, int32_t iCount) {
+    ASSERT(iCount >= 0 && iCount <= pdfium::CollectionSize<int32_t>(chars));
     for (int32_t i = 0; i < iCount; i++) {
-      pTC = chars.GetDataPtr(i);
-      iCls = pTC->m_iBidiClass;
+      int32_t iCls = chars[i].m_iBidiClass;
       if (iCls == FX_BIDICLASS_BN) {
         continue;
       }
       ASSERT(iCls > FX_BIDICLASS_ON && iCls < FX_BIDICLASS_AL);
-      iLevel = pTC->m_iBidiLevel;
+      int32_t iLevel = chars[i].m_iBidiLevel;
       iLevel += gc_FX_BidiAddLevel[FX_IsOdd(iLevel)][iCls - 1];
-      pTC->m_iBidiLevel = (int16_t)iLevel;
+      chars[i].m_iBidiLevel = (int16_t)iLevel;
     }
   }
-  void FX_BidiResolveWhitespace(CFX_ArrayTemplate<baseType>& chars,
+
+  void FX_BidiResolveWhitespace(std::vector<baseType>& chars,
                                 int32_t iCount,
                                 int32_t iBaseLevel) {
-    ASSERT(iCount > -1 && iCount <= chars.GetSize());
+    ASSERT(iCount >= 0 && iCount <= pdfium::CollectionSize<int32_t>(chars));
     ASSERT(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
     if (iCount < 1) {
       return;
@@ -637,10 +622,8 @@
     iCount--;
     int32_t iLevel = iBaseLevel;
     int32_t i = 0, iNum = 0;
-    baseType* pTC;
     for (; i <= iCount; i++) {
-      pTC = chars.GetDataPtr(i);
-      switch (pTC->m_iBidiClass) {
+      switch (chars[i].m_iBidiClass) {
         case FX_BIDICLASS_WS:
           iNum++;
           break;
@@ -650,7 +633,7 @@
         case FX_BIDICLASS_RLO:
         case FX_BIDICLASS_PDF:
         case FX_BIDICLASS_BN:
-          pTC->m_iBidiLevel = (int16_t)iLevel;
+          chars[i].m_iBidiLevel = (int16_t)iLevel;
           iNum++;
           break;
         case FX_BIDICLASS_S:
@@ -658,41 +641,39 @@
           if (iNum > 0) {
             FX_BidiSetDeferredRun(chars, false, i, iNum, iBaseLevel);
           }
-          pTC->m_iBidiLevel = (int16_t)iBaseLevel;
+          chars[i].m_iBidiLevel = (int16_t)iBaseLevel;
           iNum = 0;
           break;
         default:
           iNum = 0;
           break;
       }
-      iLevel = pTC->m_iBidiLevel;
+      iLevel = chars[i].m_iBidiLevel;
     }
     if (iNum > 0) {
       FX_BidiSetDeferredRun(chars, false, i, iNum, iBaseLevel);
     }
   }
-  int32_t FX_BidiReorderLevel(CFX_ArrayTemplate<baseType>& chars,
+
+  int32_t FX_BidiReorderLevel(std::vector<baseType>& chars,
                               int32_t iCount,
                               int32_t iBaseLevel,
                               int32_t iStart,
                               bool bReverse) {
-    ASSERT(iCount > -1 && iCount <= chars.GetSize());
+    ASSERT(iCount >= 0 && iCount <= pdfium::CollectionSize<int32_t>(chars));
     ASSERT(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
     ASSERT(iStart >= 0 && iStart < iCount);
     if (iCount < 1) {
       return 0;
     }
-    baseType* pTC;
     bReverse = bReverse || FX_IsOdd(iBaseLevel);
-    int32_t i = iStart, iLevel;
+    int32_t i = iStart;
     for (; i < iCount; i++) {
-      pTC = chars.GetDataPtr(i);
-      if ((iLevel = pTC->m_iBidiLevel) == iBaseLevel) {
+      int32_t iLevel = chars[i].m_iBidiLevel;
+      if (iLevel == iBaseLevel)
         continue;
-      }
-      if (iLevel < iBaseLevel) {
+      if (iLevel < iBaseLevel)
         break;
-      }
       i += FX_BidiReorderLevel(chars, iCount, iBaseLevel + 1, i, bReverse) - 1;
     }
     int32_t iNum = i - iStart;
@@ -701,31 +682,28 @@
     }
     return iNum;
   }
-  void FX_BidiReorder(CFX_ArrayTemplate<baseType>& chars,
+
+  void FX_BidiReorder(std::vector<baseType>& chars,
                       int32_t iCount,
                       int32_t iBaseLevel) {
-    ASSERT(iCount > -1 && iCount <= chars.GetSize());
+    ASSERT(iCount >= 0 && iCount <= pdfium::CollectionSize<int32_t>(chars));
     ASSERT(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
     int32_t i = 0;
     while (i < iCount) {
       i += FX_BidiReorderLevel(chars, iCount, iBaseLevel, i, false);
     }
   }
-  void FX_BidiPosition(CFX_ArrayTemplate<baseType>& chars, int32_t iCount) {
-    ASSERT(iCount > -1 && iCount <= chars.GetSize());
-    baseType* pTC;
-    int32_t i = 0;
-    while (i < iCount) {
-      pTC = chars.GetDataPtr(i);
-      pTC = chars.GetDataPtr(pTC->m_iBidiPos);
-      pTC->m_iBidiOrder = i++;
-    }
+
+  void FX_BidiPosition(std::vector<baseType>& chars, int32_t iCount) {
+    ASSERT(iCount >= 0 && iCount <= pdfium::CollectionSize<int32_t>(chars));
+    for (int32_t i = 0; i < iCount; ++i)
+      chars[chars[i].m_iBidiPos].m_iBidiOrder = i;
   }
 
-  void FX_BidiLine(CFX_ArrayTemplate<baseType>& chars,
+  void FX_BidiLine(std::vector<baseType>& chars,
                    int32_t iCount,
                    int32_t iBaseLevel) {
-    ASSERT(iCount > -1 && iCount <= chars.GetSize());
+    ASSERT(iCount >= 0 && iCount <= pdfium::CollectionSize<int32_t>(chars));
     if (iCount < 2) {
       return;
     }
@@ -740,11 +718,16 @@
     FX_BidiPosition(chars, iCount);
   }
 };
-void FX_BidiLine(CFX_TxtCharArray& chars, int32_t iCount, int32_t iBaseLevel) {
+
+void FX_BidiLine(std::vector<CFX_TxtChar>& chars,
+                 int32_t iCount,
+                 int32_t iBaseLevel) {
   CFX_BidiLineTemplate<CFX_TxtChar> blt;
   blt.FX_BidiLine(chars, iCount, iBaseLevel);
 }
-void FX_BidiLine(CFX_RTFCharArray& chars, int32_t iCount, int32_t iBaseLevel) {
+void FX_BidiLine(std::vector<CFX_RTFChar>& chars,
+                 int32_t iCount,
+                 int32_t iBaseLevel) {
   CFX_BidiLineTemplate<CFX_RTFChar> blt;
   blt.FX_BidiLine(chars, iCount, iBaseLevel);
 }
diff --git a/core/fxcrt/fx_arabic.h b/core/fxcrt/fx_arabic.h
index 1f4d38b..e7ba079 100644
--- a/core/fxcrt/fx_arabic.h
+++ b/core/fxcrt/fx_arabic.h
@@ -30,17 +30,17 @@
 void FX_BidiReverseString(CFX_WideString& wsText,
                           int32_t iStart,
                           int32_t iCount);
-void FX_BidiSetDeferredRun(CFX_Int32Array& values,
+void FX_BidiSetDeferredRun(CFX_ArrayTemplate<int32_t>& values,
                            int32_t iStart,
                            int32_t iCount,
                            int32_t iValue);
 void FX_BidiClassify(const CFX_WideString& wsText,
-                     CFX_Int32Array& classes,
+                     CFX_ArrayTemplate<int32_t>& classes,
                      bool bWS = false);
 int32_t FX_BidiResolveExplicit(int32_t iBaseLevel,
                                int32_t iDirection,
-                               CFX_Int32Array& classes,
-                               CFX_Int32Array& levels,
+                               CFX_ArrayTemplate<int32_t>& classes,
+                               CFX_ArrayTemplate<int32_t>& levels,
                                int32_t iStart,
                                int32_t iCount,
                                int32_t iNest = 0);
@@ -136,8 +136,8 @@
 #define FX_BWALxx FX_BIDIWEAKACTION_Lxx
 
 void FX_BidiResolveWeak(int32_t iBaseLevel,
-                        CFX_Int32Array& classes,
-                        CFX_Int32Array& levels);
+                        CFX_ArrayTemplate<int32_t>& classes,
+                        CFX_ArrayTemplate<int32_t>& levels);
 enum FX_BIDINEUTRALSTATE {
   FX_BIDINEUTRALSTATE_r = 0,
   FX_BIDINEUTRALSTATE_l,
@@ -169,20 +169,20 @@
 int32_t FX_BidiGetDeferredNeutrals(int32_t iAction, int32_t iLevel);
 int32_t FX_BidiGetResolvedNeutrals(int32_t iAction);
 void FX_BidiResolveNeutrals(int32_t iBaseLevel,
-                            CFX_Int32Array& classes,
-                            const CFX_Int32Array& levels);
-void FX_BidiResolveImplicit(const CFX_Int32Array& classes,
-                            CFX_Int32Array& levels);
+                            CFX_ArrayTemplate<int32_t>& classes,
+                            const CFX_ArrayTemplate<int32_t>& levels);
+void FX_BidiResolveImplicit(const CFX_ArrayTemplate<int32_t>& classes,
+                            CFX_ArrayTemplate<int32_t>& levels);
 void FX_BidiResolveWhitespace(int32_t iBaseLevel,
-                              const CFX_Int32Array& classes,
-                              CFX_Int32Array& levels);
+                              const CFX_ArrayTemplate<int32_t>& classes,
+                              CFX_ArrayTemplate<int32_t>& levels);
 int32_t FX_BidiReorderLevel(int32_t iBaseLevel,
                             CFX_WideString& wsText,
-                            const CFX_Int32Array& levels,
+                            const CFX_ArrayTemplate<int32_t>& levels,
                             int32_t iStart,
                             bool bReverse = false);
 void FX_BidiReorder(int32_t iBaseLevel,
                     CFX_WideString& wsText,
-                    const CFX_Int32Array& levels);
+                    const CFX_ArrayTemplate<int32_t>& levels);
 
 #endif  // CORE_FXCRT_FX_ARABIC_H_
diff --git a/core/fxcrt/fx_arb.h b/core/fxcrt/fx_arb.h
index 6d556fe..d24197c 100644
--- a/core/fxcrt/fx_arb.h
+++ b/core/fxcrt/fx_arb.h
@@ -7,6 +7,8 @@
 #ifndef CORE_FXCRT_FX_ARB_H_
 #define CORE_FXCRT_FX_ARB_H_
 
+#include <vector>
+
 #include "core/fxcrt/fx_system.h"
 #include "core/fxcrt/fx_ucd.h"
 
@@ -39,10 +41,10 @@
 };
 
 void FX_BidiLine(CFX_WideString& wsText, int32_t iBaseLevel = 0);
-void FX_BidiLine(CFX_TxtCharArray& chars,
+void FX_BidiLine(std::vector<CFX_TxtChar>& chars,
                  int32_t iCount,
                  int32_t iBaseLevel = 0);
-void FX_BidiLine(CFX_RTFCharArray& chars,
+void FX_BidiLine(std::vector<CFX_RTFChar>& chars,
                  int32_t iCount,
                  int32_t iBaseLevel = 0);
 
diff --git a/core/fxcrt/fx_basic.h b/core/fxcrt/fx_basic.h
index 5adcf70..18413b2 100644
--- a/core/fxcrt/fx_basic.h
+++ b/core/fxcrt/fx_basic.h
@@ -16,6 +16,10 @@
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
 
+#ifdef PDF_ENABLE_XFA
+#define FX_IsOdd(a) ((a)&1)
+#endif  // PDF_ENABLE_XFA
+
 class CFX_BinaryBuf {
  public:
   CFX_BinaryBuf();
@@ -313,11 +317,6 @@
   }
 };
 
-#ifdef PDF_ENABLE_XFA
-typedef CFX_ArrayTemplate<uint8_t> CFX_ByteArray;
-typedef CFX_ArrayTemplate<int32_t> CFX_Int32Array;
-#endif  // PDF_ENABLE_XFA
-
 template <class DataType, int FixedSize>
 class CFX_FixedBufGrow {
  public:
@@ -357,9 +356,7 @@
 
  protected:
   uint32_t m_BitPos;
-
   uint32_t m_BitSize;
-
   const uint8_t* m_pData;
 };
 
@@ -505,18 +502,6 @@
                               FX_FILESIZE>
     CFX_FileSizeListArray;
 
-#ifdef PDF_ENABLE_XFA
-class IFX_Retainable {
- public:
-  virtual uint32_t Retain() = 0;
-  virtual uint32_t Release() = 0;
-
- protected:
-  virtual ~IFX_Retainable() {}
-};
-#define FX_IsOdd(a) ((a)&1)
-#endif  // PDF_ENABLE_XFA
-
 class CFX_Vector_3by1 {
  public:
   CFX_Vector_3by1() : a(0.0f), b(0.0f), c(0.0f) {}
diff --git a/core/fxcrt/fx_basic_array.cpp b/core/fxcrt/fx_basic_array.cpp
index 92df0e0..83c981e 100644
--- a/core/fxcrt/fx_basic_array.cpp
+++ b/core/fxcrt/fx_basic_array.cpp
@@ -33,7 +33,8 @@
       m_nSize = m_nMaxSize = 0;
       return false;
     }
-    m_pData = FX_Alloc(uint8_t, totalSize.ValueOrDie());
+    m_pData =
+        FX_Alloc(uint8_t, pdfium::base::ValueOrDieForType<size_t>(totalSize));
     m_nSize = m_nMaxSize = nNewSize;
   } else if (nNewSize <= m_nMaxSize) {
     if (nNewSize > m_nSize) {
@@ -48,7 +49,8 @@
     if (!totalSize.IsValid() || nNewMax < m_nSize) {
       return false;
     }
-    uint8_t* pNewData = FX_Realloc(uint8_t, m_pData, totalSize.ValueOrDie());
+    uint8_t* pNewData = FX_Realloc(
+        uint8_t, m_pData, pdfium::base::ValueOrDieForType<size_t>(totalSize));
     if (!pNewData) {
       return false;
     }
diff --git a/core/fxcrt/fx_basic_coords.cpp b/core/fxcrt/fx_basic_coords.cpp
index d2bcc2b..cb5a010 100644
--- a/core/fxcrt/fx_basic_coords.cpp
+++ b/core/fxcrt/fx_basic_coords.cpp
@@ -6,9 +6,26 @@
 
 #include <limits.h>
 
+#include <algorithm>
+
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_ext.h"
 
+namespace {
+
+void MatchFloatRange(FX_FLOAT f1, FX_FLOAT f2, int* i1, int* i2) {
+  int length = static_cast<int>(FXSYS_ceil(f2 - f1));
+  int i1_1 = static_cast<int>(FXSYS_floor(f1));
+  int i1_2 = static_cast<int>(FXSYS_ceil(f1));
+  FX_FLOAT error1 = f1 - i1_1 + (FX_FLOAT)FXSYS_fabs(f2 - i1_1 - length);
+  FX_FLOAT error2 = i1_2 - f1 + (FX_FLOAT)FXSYS_fabs(f2 - i1_2 - length);
+
+  *i1 = (error1 > error2) ? i1_2 : i1_1;
+  *i2 = *i1 + length;
+}
+
+}  // namespace
+
 void FX_RECT::Normalize() {
   if (left > right) {
     int temp = left;
@@ -33,15 +50,7 @@
     left = top = right = bottom = 0;
   }
 }
-void FX_RECT::Union(const FX_RECT& other_rect) {
-  Normalize();
-  FX_RECT other = other_rect;
-  other.Normalize();
-  left = left < other.left ? left : other.left;
-  right = right > other.right ? right : other.right;
-  bottom = bottom > other.bottom ? bottom : other.bottom;
-  top = top < other.top ? top : other.top;
-}
+
 bool GetIntersection(FX_FLOAT low1,
                      FX_FLOAT high1,
                      FX_FLOAT low2,
@@ -105,9 +114,7 @@
   bottom = bottom < other.bottom ? bottom : other.bottom;
   top = top > other.top ? top : other.top;
 }
-void CFX_FloatRect::Transform(const CFX_Matrix* pMatrix) {
-  pMatrix->TransformRect(left, right, top, bottom);
-}
+
 int CFX_FloatRect::Substract4(CFX_FloatRect& s, CFX_FloatRect* pRects) {
   Normalize();
   s.Normalize();
@@ -150,6 +157,7 @@
   }
   return nRects;
 }
+
 FX_RECT CFX_FloatRect::GetOuterRect() const {
   CFX_FloatRect rect1 = *this;
   FX_RECT rect;
@@ -160,6 +168,7 @@
   rect.Normalize();
   return rect;
 }
+
 FX_RECT CFX_FloatRect::GetInnerRect() const {
   CFX_FloatRect rect1 = *this;
   FX_RECT rect;
@@ -170,24 +179,23 @@
   rect.Normalize();
   return rect;
 }
-static void _MatchFloatRange(FX_FLOAT f1, FX_FLOAT f2, int& i1, int& i2) {
-  int length = (int)FXSYS_ceil(f2 - f1);
-  int i1_1 = (int)FXSYS_floor(f1);
-  int i1_2 = (int)FXSYS_ceil(f1);
-  FX_FLOAT error1 = f1 - i1_1 + (FX_FLOAT)FXSYS_fabs(f2 - i1_1 - length);
-  FX_FLOAT error2 = i1_2 - f1 + (FX_FLOAT)FXSYS_fabs(f2 - i1_2 - length);
-  i1 = (error1 > error2) ? i1_2 : i1_1;
-  i2 = i1 + length;
-}
+
 FX_RECT CFX_FloatRect::GetClosestRect() const {
   CFX_FloatRect rect1 = *this;
   FX_RECT rect;
-  _MatchFloatRange(rect1.left, rect1.right, rect.left, rect.right);
-  _MatchFloatRange(rect1.bottom, rect1.top, rect.top, rect.bottom);
+  MatchFloatRange(rect1.left, rect1.right, &rect.left, &rect.right);
+  MatchFloatRange(rect1.bottom, rect1.top, &rect.top, &rect.bottom);
   rect.Normalize();
   return rect;
 }
 
+bool CFX_FloatRect::Contains(const CFX_PointF& point) const {
+  CFX_FloatRect n1(*this);
+  n1.Normalize();
+  return point.x <= n1.right && point.x >= n1.left && point.y <= n1.top &&
+         point.y >= n1.bottom;
+}
+
 bool CFX_FloatRect::Contains(const CFX_FloatRect& other_rect) const {
   CFX_FloatRect n1(*this);
   CFX_FloatRect n2(other_rect);
@@ -197,74 +205,35 @@
          n2.top <= n1.top;
 }
 
-bool CFX_FloatRect::Contains(FX_FLOAT x, FX_FLOAT y) const {
-  CFX_FloatRect n1(*this);
-  n1.Normalize();
-  return x <= n1.right && x >= n1.left && y <= n1.top && y >= n1.bottom;
+void CFX_FloatRect::UpdateRect(FX_FLOAT x, FX_FLOAT y) {
+  left = std::min(left, x);
+  right = std::max(right, x);
+  bottom = std::min(bottom, y);
+  top = std::max(top, y);
 }
 
-void CFX_FloatRect::UpdateRect(FX_FLOAT x, FX_FLOAT y) {
-  if (left > x) {
-    left = x;
-  }
-  if (right < x) {
-    right = x;
-  }
-  if (bottom > y) {
-    bottom = y;
-  }
-  if (top < y) {
-    top = y;
-  }
-}
 CFX_FloatRect CFX_FloatRect::GetBBox(const CFX_PointF* pPoints, int nPoints) {
-  if (nPoints == 0) {
+  if (nPoints == 0)
     return CFX_FloatRect();
-  }
-  FX_FLOAT min_x = pPoints->x, max_x = pPoints->x, min_y = pPoints->y,
-           max_y = pPoints->y;
+
+  FX_FLOAT min_x = pPoints->x;
+  FX_FLOAT max_x = pPoints->x;
+  FX_FLOAT min_y = pPoints->y;
+  FX_FLOAT max_y = pPoints->y;
   for (int i = 1; i < nPoints; i++) {
-    if (min_x > pPoints[i].x) {
-      min_x = pPoints[i].x;
-    }
-    if (max_x < pPoints[i].x) {
-      max_x = pPoints[i].x;
-    }
-    if (min_y > pPoints[i].y) {
-      min_y = pPoints[i].y;
-    }
-    if (max_y < pPoints[i].y) {
-      max_y = pPoints[i].y;
-    }
+    min_x = std::min(min_x, pPoints[i].x);
+    max_x = std::max(max_x, pPoints[i].x);
+    min_y = std::min(min_y, pPoints[i].y);
+    max_y = std::max(max_y, pPoints[i].y);
   }
   return CFX_FloatRect(min_x, min_y, max_x, max_y);
 }
-void CFX_Matrix::Set(FX_FLOAT other_a,
-                     FX_FLOAT other_b,
-                     FX_FLOAT other_c,
-                     FX_FLOAT other_d,
-                     FX_FLOAT other_e,
-                     FX_FLOAT other_f) {
-  a = other_a;
-  b = other_b;
-  c = other_c;
-  d = other_d;
-  e = other_e;
-  f = other_f;
-}
-void CFX_Matrix::Set(const FX_FLOAT n[6]) {
-  a = n[0];
-  b = n[1];
-  c = n[2];
-  d = n[3];
-  e = n[4];
-  f = n[5];
-}
+
 void CFX_Matrix::SetReverse(const CFX_Matrix& m) {
   FX_FLOAT i = m.a * m.d - m.b * m.c;
-  if (FXSYS_fabs(i) == 0) {
+  if (FXSYS_fabs(i) == 0)
     return;
-  }
+
   FX_FLOAT j = -i;
   a = m.d / i;
   b = m.b / j;
@@ -273,82 +242,59 @@
   e = (m.c * m.f - m.d * m.e) / i;
   f = (m.a * m.f - m.b * m.e) / j;
 }
-static void FXCRT_Matrix_Concat(CFX_Matrix& m,
-                                const CFX_Matrix& m1,
-                                const CFX_Matrix& m2) {
-  FX_FLOAT aa = m1.a * m2.a + m1.b * m2.c;
-  FX_FLOAT bb = m1.a * m2.b + m1.b * m2.d;
-  FX_FLOAT cc = m1.c * m2.a + m1.d * m2.c;
-  FX_FLOAT dd = m1.c * m2.b + m1.d * m2.d;
-  FX_FLOAT ee = m1.e * m2.a + m1.f * m2.c + m2.e;
-  FX_FLOAT ff = m1.e * m2.b + m1.f * m2.d + m2.f;
-  m.a = aa, m.b = bb, m.c = cc, m.d = dd, m.e = ee, m.f = ff;
-}
-void CFX_Matrix::Concat(FX_FLOAT a_in,
-                        FX_FLOAT b_in,
-                        FX_FLOAT c_in,
-                        FX_FLOAT d_in,
-                        FX_FLOAT e_in,
-                        FX_FLOAT f_in,
-                        bool bPrepended) {
-  CFX_Matrix m;
-  m.Set(a_in, b_in, c_in, d_in, e_in, f_in);
-  Concat(m, bPrepended);
-}
+
 void CFX_Matrix::Concat(const CFX_Matrix& m, bool bPrepended) {
-  if (bPrepended) {
-    FXCRT_Matrix_Concat(*this, m, *this);
-  } else {
-    FXCRT_Matrix_Concat(*this, *this, m);
-  }
+  ConcatInternal(m, bPrepended);
 }
+
 void CFX_Matrix::ConcatInverse(const CFX_Matrix& src, bool bPrepended) {
   CFX_Matrix m;
   m.SetReverse(src);
   Concat(m, bPrepended);
 }
-bool CFX_Matrix::IsInvertible() const {
-  return FXSYS_fabs(a * d - b * c) >= 0.0001f;
-}
+
 bool CFX_Matrix::Is90Rotated() const {
   return FXSYS_fabs(a * 1000) < FXSYS_fabs(b) &&
          FXSYS_fabs(d * 1000) < FXSYS_fabs(c);
 }
+
 bool CFX_Matrix::IsScaled() const {
   return FXSYS_fabs(b * 1000) < FXSYS_fabs(a) &&
          FXSYS_fabs(c * 1000) < FXSYS_fabs(d);
 }
+
 void CFX_Matrix::Translate(FX_FLOAT x, FX_FLOAT y, bool bPrepended) {
   if (bPrepended) {
     e += x * a + y * c;
     f += y * d + x * b;
-  } else {
-    e += x, f += y;
+    return;
   }
+  e += x;
+  f += y;
 }
+
 void CFX_Matrix::Scale(FX_FLOAT sx, FX_FLOAT sy, bool bPrepended) {
-  a *= sx, d *= sy;
+  a *= sx;
+  d *= sy;
   if (bPrepended) {
     b *= sx;
     c *= sy;
-  } else {
-    b *= sy;
-    c *= sx;
-    e *= sx;
-    f *= sy;
+    return;
   }
+
+  b *= sy;
+  c *= sx;
+  e *= sx;
+  f *= sy;
 }
+
 void CFX_Matrix::Rotate(FX_FLOAT fRadian, bool bPrepended) {
   FX_FLOAT cosValue = FXSYS_cos(fRadian);
   FX_FLOAT sinValue = FXSYS_sin(fRadian);
-  CFX_Matrix m;
-  m.Set(cosValue, sinValue, -sinValue, cosValue, 0, 0);
-  if (bPrepended) {
-    FXCRT_Matrix_Concat(*this, m, *this);
-  } else {
-    FXCRT_Matrix_Concat(*this, *this, m);
-  }
+  ConcatInternal(CFX_Matrix(cosValue, sinValue, -sinValue, cosValue, 0, 0),
+                 bPrepended);
 }
+
 void CFX_Matrix::RotateAt(FX_FLOAT fRadian,
                           FX_FLOAT dx,
                           FX_FLOAT dy,
@@ -357,21 +303,20 @@
   Rotate(fRadian, bPrepended);
   Translate(-dx, -dy, bPrepended);
 }
+
 void CFX_Matrix::Shear(FX_FLOAT fAlphaRadian,
                        FX_FLOAT fBetaRadian,
                        bool bPrepended) {
-  CFX_Matrix m;
-  m.Set(1, FXSYS_tan(fAlphaRadian), FXSYS_tan(fBetaRadian), 1, 0, 0);
-  if (bPrepended) {
-    FXCRT_Matrix_Concat(*this, m, *this);
-  } else {
-    FXCRT_Matrix_Concat(*this, *this, m);
-  }
+  ConcatInternal(
+      CFX_Matrix(1, FXSYS_tan(fAlphaRadian), FXSYS_tan(fBetaRadian), 1, 0, 0),
+      bPrepended);
 }
+
 void CFX_Matrix::MatchRect(const CFX_FloatRect& dest,
                            const CFX_FloatRect& src) {
   FX_FLOAT fDiff = src.left - src.right;
   a = FXSYS_fabs(fDiff) < 0.001f ? 1 : (dest.left - dest.right) / fDiff;
+
   fDiff = src.bottom - src.top;
   d = FXSYS_fabs(fDiff) < 0.001f ? 1 : (dest.bottom - dest.top) / fDiff;
   e = dest.left - src.left * a;
@@ -379,139 +324,93 @@
   b = 0;
   c = 0;
 }
+
 FX_FLOAT CFX_Matrix::GetXUnit() const {
-  if (b == 0) {
+  if (b == 0)
     return (a > 0 ? a : -a);
-  }
-  if (a == 0) {
+  if (a == 0)
     return (b > 0 ? b : -b);
-  }
   return FXSYS_sqrt(a * a + b * b);
 }
+
 FX_FLOAT CFX_Matrix::GetYUnit() const {
-  if (c == 0) {
+  if (c == 0)
     return (d > 0 ? d : -d);
-  }
-  if (d == 0) {
+  if (d == 0)
     return (c > 0 ? c : -c);
-  }
   return FXSYS_sqrt(c * c + d * d);
 }
-void CFX_Matrix::GetUnitRect(CFX_RectF& rect) const {
-  rect.left = rect.top = 0;
-  rect.width = rect.height = 1;
-  TransformRect(rect);
-}
+
 CFX_FloatRect CFX_Matrix::GetUnitRect() const {
   CFX_FloatRect rect(0, 0, 1, 1);
-  rect.Transform((const CFX_Matrix*)this);
+  TransformRect(rect);
   return rect;
 }
-FX_FLOAT CFX_Matrix::GetUnitArea() const {
-  FX_FLOAT A = FXSYS_sqrt(a * a + b * b);
-  FX_FLOAT B = FXSYS_sqrt(c * c + d * d);
-  FX_FLOAT ac = a + c, bd = b + d;
-  FX_FLOAT C = FXSYS_sqrt(ac * ac + bd * bd);
-  FX_FLOAT P = (A + B + C) / 2;
-  return FXSYS_sqrt(P * (P - A) * (P - B) * (P - C)) * 2;
-}
+
 FX_FLOAT CFX_Matrix::TransformXDistance(FX_FLOAT dx) const {
-  FX_FLOAT fx = a * dx, fy = b * dx;
+  FX_FLOAT fx = a * dx;
+  FX_FLOAT fy = b * dx;
   return FXSYS_sqrt(fx * fx + fy * fy);
 }
-int32_t CFX_Matrix::TransformXDistance(int32_t dx) const {
-  FX_FLOAT fx = a * dx, fy = b * dx;
-  return FXSYS_round(FXSYS_sqrt(fx * fx + fy * fy));
-}
-FX_FLOAT CFX_Matrix::TransformYDistance(FX_FLOAT dy) const {
-  FX_FLOAT fx = c * dy, fy = d * dy;
-  return FXSYS_sqrt(fx * fx + fy * fy);
-}
-int32_t CFX_Matrix::TransformYDistance(int32_t dy) const {
-  FX_FLOAT fx = c * dy, fy = d * dy;
-  return FXSYS_round(FXSYS_sqrt(fx * fx + fy * fy));
-}
+
 FX_FLOAT CFX_Matrix::TransformDistance(FX_FLOAT dx, FX_FLOAT dy) const {
-  FX_FLOAT fx = a * dx + c * dy, fy = b * dx + d * dy;
+  FX_FLOAT fx = a * dx + c * dy;
+  FX_FLOAT fy = b * dx + d * dy;
   return FXSYS_sqrt(fx * fx + fy * fy);
 }
-int32_t CFX_Matrix::TransformDistance(int32_t dx, int32_t dy) const {
-  FX_FLOAT fx = a * dx + c * dy, fy = b * dx + d * dy;
-  return FXSYS_round(FXSYS_sqrt(fx * fx + fy * fy));
-}
+
 FX_FLOAT CFX_Matrix::TransformDistance(FX_FLOAT distance) const {
   return distance * (GetXUnit() + GetYUnit()) / 2;
 }
-void CFX_Matrix::TransformVector(CFX_VectorF& v) const {
-  FX_FLOAT fx = a * v.x + c * v.y;
-  FX_FLOAT fy = b * v.x + d * v.y;
-  v.x = fx, v.y = fy;
+
+CFX_PointF CFX_Matrix::Transform(const CFX_PointF& point) const {
+  return CFX_PointF(a * point.x + c * point.y + e,
+                    b * point.x + d * point.y + f);
 }
-void CFX_Matrix::TransformVector(CFX_Vector& v) const {
-  FX_FLOAT fx = a * v.x + c * v.y;
-  FX_FLOAT fy = b * v.x + d * v.y;
-  v.x = FXSYS_round(fx);
-  v.y = FXSYS_round(fy);
-}
-void CFX_Matrix::TransformPoint(FX_FLOAT& x, FX_FLOAT& y) const {
-  FX_FLOAT fx = a * x + c * y + e;
-  FX_FLOAT fy = b * x + d * y + f;
-  x = fx, y = fy;
-}
-void CFX_Matrix::TransformPoint(int32_t& x, int32_t& y) const {
-  FX_FLOAT fx = a * x + c * y + e;
-  FX_FLOAT fy = b * x + d * y + f;
-  x = FXSYS_round(fx);
-  y = FXSYS_round(fy);
-}
+
 void CFX_Matrix::TransformRect(CFX_RectF& rect) const {
   FX_FLOAT right = rect.right(), bottom = rect.bottom();
   TransformRect(rect.left, right, bottom, rect.top);
   rect.width = right - rect.left;
   rect.height = bottom - rect.top;
 }
-void CFX_Matrix::TransformRect(CFX_Rect& rect) const {
-  FX_FLOAT left = (FX_FLOAT)rect.left;
-  FX_FLOAT top = (FX_FLOAT)rect.bottom();
-  FX_FLOAT right = (FX_FLOAT)rect.right();
-  FX_FLOAT bottom = (FX_FLOAT)rect.top;
-  TransformRect(left, right, top, bottom);
-  rect.left = FXSYS_round(left);
-  rect.top = FXSYS_round(bottom);
-  rect.width = FXSYS_round(right - left);
-  rect.height = FXSYS_round(top - bottom);
-}
+
 void CFX_Matrix::TransformRect(FX_FLOAT& left,
                                FX_FLOAT& right,
                                FX_FLOAT& top,
                                FX_FLOAT& bottom) const {
-  FX_FLOAT x[4], y[4];
-  x[0] = left;
-  y[0] = top;
-  x[1] = left;
-  y[1] = bottom;
-  x[2] = right;
-  y[2] = top;
-  x[3] = right;
-  y[3] = bottom;
-  int i;
-  for (i = 0; i < 4; i++) {
-    Transform(x[i], y[i], x[i], y[i]);
+  CFX_PointF points[] = {
+      {left, top}, {left, bottom}, {right, top}, {right, bottom}};
+  for (int i = 0; i < 4; i++)
+    points[i] = Transform(points[i]);
+
+  right = points[0].x;
+  left = points[0].x;
+  top = points[0].y;
+  bottom = points[0].y;
+  for (int i = 1; i < 4; i++) {
+    right = std::max(right, points[i].x);
+    left = std::min(left, points[i].x);
+    top = std::max(top, points[i].y);
+    bottom = std::min(bottom, points[i].y);
   }
-  right = left = x[0];
-  top = bottom = y[0];
-  for (i = 1; i < 4; i++) {
-    if (right < x[i]) {
-      right = x[i];
-    }
-    if (left > x[i]) {
-      left = x[i];
-    }
-    if (top < y[i]) {
-      top = y[i];
-    }
-    if (bottom > y[i]) {
-      bottom = y[i];
-    }
+}
+
+void CFX_Matrix::ConcatInternal(const CFX_Matrix& other, bool prepend) {
+  CFX_Matrix left;
+  CFX_Matrix right;
+  if (prepend) {
+    left = other;
+    right = *this;
+  } else {
+    left = *this;
+    right = other;
   }
+
+  a = left.a * right.a + left.b * right.c;
+  b = left.a * right.b + left.b * right.d;
+  c = left.c * right.a + left.d * right.c;
+  d = left.c * right.b + left.d * right.d;
+  e = left.e * right.a + left.f * right.c + right.e;
+  f = left.e * right.b + left.f * right.d + right.f;
 }
diff --git a/core/fxcrt/fx_basic_utf.cpp b/core/fxcrt/fx_basic_utf.cpp
index 8dbbb28..c0f14c8 100644
--- a/core/fxcrt/fx_basic_utf.cpp
+++ b/core/fxcrt/fx_basic_utf.cpp
@@ -73,13 +73,13 @@
     }
   }
 }
-CFX_ByteString FX_UTF8Encode(const FX_WCHAR* pwsStr, FX_STRSIZE len) {
-  if (len < 0)
-    len = FXSYS_wcslen(pwsStr);
 
+CFX_ByteString FX_UTF8Encode(const CFX_WideStringC& wsStr) {
+  FX_STRSIZE len = wsStr.GetLength();
+  const FX_WCHAR* pStr = wsStr.c_str();
   CFX_UTF8Encoder encoder;
   while (len-- > 0)
-    encoder.Input(*pwsStr++);
+    encoder.Input(*pStr++);
 
   return CFX_ByteString(encoder.GetResult());
 }
diff --git a/core/fxcrt/fx_basic_util.cpp b/core/fxcrt/fx_basic_util.cpp
index e52ff2e..f608e29 100644
--- a/core/fxcrt/fx_basic_util.cpp
+++ b/core/fxcrt/fx_basic_util.cpp
@@ -12,12 +12,6 @@
 #include <limits>
 #include <memory>
 
-namespace {
-
-const int kDefaultIntValue = 0;
-
-}  // namespace
-
 bool FX_atonum(const CFX_ByteStringC& strc, void* pData) {
   if (strc.Find('.') != -1) {
     FX_FLOAT* pFloat = static_cast<FX_FLOAT*>(pData);
@@ -54,18 +48,19 @@
   // we've overflowed, reset to the default value.
   if (bSigned) {
     if (bNegative) {
-      if (integer.ValueOrDefault(kDefaultIntValue) >
+      if (integer.ValueOrDefault(0) >
           static_cast<uint32_t>(std::numeric_limits<int>::max()) + 1) {
-        integer = kDefaultIntValue;
+        integer = 0;
       }
-    } else if (integer.ValueOrDefault(kDefaultIntValue) >
+    } else if (integer.ValueOrDefault(0) >
                static_cast<uint32_t>(std::numeric_limits<int>::max())) {
-      integer = kDefaultIntValue;
+      integer = 0;
     }
   }
 
   // Switch back to the int space so we can flip to a negative if we need.
-  int value = static_cast<int>(integer.ValueOrDefault(kDefaultIntValue));
+  uint32_t uValue = integer.ValueOrDefault(0);
+  int32_t value = static_cast<int>(uValue);
   if (bNegative)
     value = -value;
 
diff --git a/core/fxcrt/fx_basic_wstring.cpp b/core/fxcrt/fx_basic_wstring.cpp
index e779621..93b9ba7 100644
--- a/core/fxcrt/fx_basic_wstring.cpp
+++ b/core/fxcrt/fx_basic_wstring.cpp
@@ -343,12 +343,10 @@
   m_pData.Swap(pNewData);
 }
 
-// static
 CFX_ByteString CFX_WideString::UTF8Encode() const {
-  return FX_UTF8Encode(*this);
+  return FX_UTF8Encode(AsStringC());
 }
 
-// static
 CFX_ByteString CFX_WideString::UTF16LE_Encode() const {
   if (!m_pData) {
     return CFX_ByteString("\0\0", 2);
diff --git a/core/fxcrt/fx_coordinates.h b/core/fxcrt/fx_coordinates.h
index d8ad4ef..2c84d07 100644
--- a/core/fxcrt/fx_coordinates.h
+++ b/core/fxcrt/fx_coordinates.h
@@ -12,89 +12,155 @@
 class CFX_Matrix;
 
 template <class BaseType>
-class CFX_PSTemplate {
+class CFX_PTemplate {
  public:
-  CFX_PSTemplate() : x(0), y(0) {}
-  CFX_PSTemplate(BaseType new_x, BaseType new_y) : x(new_x), y(new_y) {}
-  CFX_PSTemplate(const CFX_PSTemplate& other) : x(other.x), y(other.y) {}
+  CFX_PTemplate() : x(0), y(0) {}
+  CFX_PTemplate(BaseType new_x, BaseType new_y) : x(new_x), y(new_y) {}
+  CFX_PTemplate(const CFX_PTemplate& other) : x(other.x), y(other.y) {}
   void clear() {
     x = 0;
     y = 0;
   }
-  CFX_PSTemplate operator=(const CFX_PSTemplate& other) {
+  CFX_PTemplate operator=(const CFX_PTemplate& other) {
     if (this != &other) {
       x = other.x;
       y = other.y;
     }
     return *this;
   }
-  bool operator==(const CFX_PSTemplate& other) const {
+  bool operator==(const CFX_PTemplate& other) const {
     return x == other.x && y == other.y;
   }
-  bool operator!=(const CFX_PSTemplate& other) const {
+  bool operator!=(const CFX_PTemplate& other) const {
     return !(*this == other);
   }
-  CFX_PSTemplate& operator+=(const CFX_PSTemplate<BaseType>& obj) {
+  CFX_PTemplate& operator+=(const CFX_PTemplate<BaseType>& obj) {
     x += obj.x;
     y += obj.y;
     return *this;
   }
-  CFX_PSTemplate& operator-=(const CFX_PSTemplate<BaseType>& obj) {
+  CFX_PTemplate& operator-=(const CFX_PTemplate<BaseType>& obj) {
     x -= obj.x;
     y -= obj.y;
     return *this;
   }
-  CFX_PSTemplate& operator*=(BaseType factor) {
+  CFX_PTemplate& operator*=(BaseType factor) {
     x *= factor;
     y *= factor;
     return *this;
   }
-  CFX_PSTemplate& operator/=(BaseType divisor) {
+  CFX_PTemplate& operator/=(BaseType divisor) {
     x /= divisor;
     y /= divisor;
     return *this;
   }
-  CFX_PSTemplate operator+(const CFX_PSTemplate& other) {
-    return CFX_PSTemplate(x + other.x, y + other.y);
+  CFX_PTemplate operator+(const CFX_PTemplate& other) const {
+    return CFX_PTemplate(x + other.x, y + other.y);
   }
-  CFX_PSTemplate operator-(const CFX_PSTemplate& other) {
-    return CFX_PSTemplate(x - other.x, y - other.y);
+  CFX_PTemplate operator-(const CFX_PTemplate& other) const {
+    return CFX_PTemplate(x - other.x, y - other.y);
   }
-  CFX_PSTemplate operator*(BaseType factor) {
-    return CFX_PSTemplate(x * factor, y * factor);
+  CFX_PTemplate operator*(BaseType factor) const {
+    return CFX_PTemplate(x * factor, y * factor);
   }
-  CFX_PSTemplate operator/(BaseType divisor) {
-    return CFX_PSTemplate(x / divisor, y / divisor);
+  CFX_PTemplate operator/(BaseType divisor) const {
+    return CFX_PTemplate(x / divisor, y / divisor);
   }
 
   BaseType x;
   BaseType y;
 };
-typedef CFX_PSTemplate<int32_t> CFX_Point;
-typedef CFX_PSTemplate<FX_FLOAT> CFX_PointF;
-typedef CFX_PSTemplate<int32_t> CFX_Size;
-typedef CFX_PSTemplate<FX_FLOAT> CFX_SizeF;
-
-#ifdef PDF_ENABLE_XFA
-typedef CFX_ArrayTemplate<CFX_Point> CFX_Points;
-typedef CFX_ArrayTemplate<CFX_PointF> CFX_PointsF;
-#endif  // PDF_ENABLE_XFA
+using CFX_Point = CFX_PTemplate<int32_t>;
+using CFX_PointF = CFX_PTemplate<FX_FLOAT>;
 
 template <class BaseType>
-class CFX_VTemplate : public CFX_PSTemplate<BaseType> {
+class CFX_STemplate {
  public:
-  using CFX_PSTemplate<BaseType>::x;
-  using CFX_PSTemplate<BaseType>::y;
+  CFX_STemplate() : width(0), height(0) {}
 
-  CFX_VTemplate() : CFX_PSTemplate<BaseType>() {}
+  CFX_STemplate(BaseType new_width, BaseType new_height)
+      : width(new_width), height(new_height) {}
+
+  CFX_STemplate(const CFX_STemplate& other)
+      : width(other.width), height(other.height) {}
+
+  template <typename OtherType>
+  CFX_STemplate<OtherType> As() const {
+    return CFX_STemplate<OtherType>(static_cast<OtherType>(width),
+                                    static_cast<OtherType>(height));
+  }
+
+  void clear() {
+    width = 0;
+    height = 0;
+  }
+  CFX_STemplate operator=(const CFX_STemplate& other) {
+    if (this != &other) {
+      width = other.width;
+      height = other.height;
+    }
+    return *this;
+  }
+  bool operator==(const CFX_STemplate& other) const {
+    return width == other.width && height == other.height;
+  }
+  bool operator!=(const CFX_STemplate& other) const {
+    return !(*this == other);
+  }
+  CFX_STemplate& operator+=(const CFX_STemplate<BaseType>& obj) {
+    width += obj.width;
+    height += obj.height;
+    return *this;
+  }
+  CFX_STemplate& operator-=(const CFX_STemplate<BaseType>& obj) {
+    width -= obj.width;
+    height -= obj.height;
+    return *this;
+  }
+  CFX_STemplate& operator*=(BaseType factor) {
+    width *= factor;
+    height *= factor;
+    return *this;
+  }
+  CFX_STemplate& operator/=(BaseType divisor) {
+    width /= divisor;
+    height /= divisor;
+    return *this;
+  }
+  CFX_STemplate operator+(const CFX_STemplate& other) const {
+    return CFX_STemplate(width + other.width, height + other.height);
+  }
+  CFX_STemplate operator-(const CFX_STemplate& other) const {
+    return CFX_STemplate(width - other.width, height - other.height);
+  }
+  CFX_STemplate operator*(BaseType factor) const {
+    return CFX_STemplate(width * factor, height * factor);
+  }
+  CFX_STemplate operator/(BaseType divisor) const {
+    return CFX_STemplate(width / divisor, height / divisor);
+  }
+
+  BaseType width;
+  BaseType height;
+};
+using CFX_Size = CFX_STemplate<int32_t>;
+using CFX_SizeF = CFX_STemplate<FX_FLOAT>;
+
+template <class BaseType>
+class CFX_VTemplate : public CFX_PTemplate<BaseType> {
+ public:
+  using CFX_PTemplate<BaseType>::x;
+  using CFX_PTemplate<BaseType>::y;
+
+  CFX_VTemplate() : CFX_PTemplate<BaseType>() {}
   CFX_VTemplate(BaseType new_x, BaseType new_y)
-      : CFX_PSTemplate<BaseType>(new_x, new_y) {}
+      : CFX_PTemplate<BaseType>(new_x, new_y) {}
 
-  CFX_VTemplate(const CFX_VTemplate& other) : CFX_PSTemplate<BaseType>(other) {}
+  CFX_VTemplate(const CFX_VTemplate& other) : CFX_PTemplate<BaseType>(other) {}
 
-  CFX_VTemplate(const CFX_PSTemplate<BaseType>& point1,
-                const CFX_PSTemplate<BaseType>& point2)
-      : CFX_PSTemplate<BaseType>(point2.x - point1.x, point2.y - point1.y) {}
+  CFX_VTemplate(const CFX_PTemplate<BaseType>& point1,
+                const CFX_PTemplate<BaseType>& point2)
+      : CFX_PTemplate<BaseType>(point2.x - point1.x, point2.y - point1.y) {}
 
   FX_FLOAT Length() const { return FXSYS_sqrt(x * x + y * y); }
   void Normalize() {
@@ -120,16 +186,229 @@
     y = x * sinValue + y * cosValue;
   }
 };
-typedef CFX_VTemplate<int32_t> CFX_Vector;
-typedef CFX_VTemplate<FX_FLOAT> CFX_VectorF;
+using CFX_Vector = CFX_VTemplate<int32_t>;
+using CFX_VectorF = CFX_VTemplate<FX_FLOAT>;
 
 // Rectangles.
 // TODO(tsepez): Consolidate all these different rectangle classes.
 
+// LTWH rectangles (y-axis runs downwards).
+template <class BaseType>
+class CFX_RTemplate {
+ public:
+  using PointType = CFX_PTemplate<BaseType>;
+  using SizeType = CFX_STemplate<BaseType>;
+  using VectorType = CFX_VTemplate<BaseType>;
+  using RectType = CFX_RTemplate<BaseType>;
+
+  CFX_RTemplate() : left(0), top(0), width(0), height(0) {}
+  CFX_RTemplate(BaseType dst_left,
+                BaseType dst_top,
+                BaseType dst_width,
+                BaseType dst_height)
+      : left(dst_left), top(dst_top), width(dst_width), height(dst_height) {}
+  CFX_RTemplate(BaseType dst_left, BaseType dst_top, const SizeType& dst_size)
+      : left(dst_left),
+        top(dst_top),
+        width(dst_size.width),
+        height(dst_size.height) {}
+  CFX_RTemplate(const PointType& p, BaseType dst_width, BaseType dst_height)
+      : left(p.x), top(p.y), width(dst_width), height(dst_height) {}
+  CFX_RTemplate(const PointType& p1, const SizeType& s2)
+      : left(p1.x), top(p1.y), width(s2.width), height(s2.height) {}
+  CFX_RTemplate(const PointType& p1, const PointType& p2)
+      : left(p1.x),
+        top(p1.y),
+        width(p2.width - p1.width),
+        height(p2.height - p1.height) {
+    Normalize();
+  }
+  CFX_RTemplate(const PointType& p, const VectorType& v)
+      : left(p.x), top(p.y), width(v.x), height(v.y) {
+    Normalize();
+  }
+
+  // NOLINTNEXTLINE(runtime/explicit)
+  CFX_RTemplate(const RectType& other)
+      : left(other.left),
+        top(other.top),
+        width(other.width),
+        height(other.height) {}
+
+  template <typename OtherType>
+  CFX_RTemplate<OtherType> As() const {
+    return CFX_RTemplate<OtherType>(
+        static_cast<OtherType>(left), static_cast<OtherType>(top),
+        static_cast<OtherType>(width), static_cast<OtherType>(height));
+  }
+
+  void Reset() {
+    left = 0;
+    top = 0;
+    width = 0;
+    height = 0;
+  }
+  RectType& operator+=(const PointType& p) {
+    left += p.x;
+    top += p.y;
+    return *this;
+  }
+  RectType& operator-=(const PointType& p) {
+    left -= p.x;
+    top -= p.y;
+    return *this;
+  }
+  BaseType right() const { return left + width; }
+  BaseType bottom() const { return top + height; }
+  void Normalize() {
+    if (width < 0) {
+      left += width;
+      width = -width;
+    }
+    if (height < 0) {
+      top += height;
+      height = -height;
+    }
+  }
+  void Offset(BaseType dx, BaseType dy) {
+    left += dx;
+    top += dy;
+  }
+  void Inflate(BaseType x, BaseType y) {
+    left -= x;
+    width += x * 2;
+    top -= y;
+    height += y * 2;
+  }
+  void Inflate(const PointType& p) { Inflate(p.x, p.y); }
+  void Inflate(BaseType off_left,
+               BaseType off_top,
+               BaseType off_right,
+               BaseType off_bottom) {
+    left -= off_left;
+    top -= off_top;
+    width += off_left + off_right;
+    height += off_top + off_bottom;
+  }
+  void Inflate(const RectType& rt) {
+    Inflate(rt.left, rt.top, rt.left + rt.width, rt.top + rt.height);
+  }
+  void Deflate(BaseType x, BaseType y) {
+    left += x;
+    width -= x * 2;
+    top += y;
+    height -= y * 2;
+  }
+  void Deflate(const PointType& p) { Deflate(p.x, p.y); }
+  void Deflate(BaseType off_left,
+               BaseType off_top,
+               BaseType off_right,
+               BaseType off_bottom) {
+    left += off_left;
+    top += off_top;
+    width -= off_left + off_right;
+    height -= off_top + off_bottom;
+  }
+  void Deflate(const RectType& rt) {
+    Deflate(rt.left, rt.top, rt.top + rt.width, rt.top + rt.height);
+  }
+  bool IsEmpty() const { return width <= 0 || height <= 0; }
+  bool IsEmpty(FX_FLOAT fEpsilon) const {
+    return width <= fEpsilon || height <= fEpsilon;
+  }
+  void Empty() { width = height = 0; }
+  bool Contains(const PointType& p) const {
+    return p.x >= left && p.x < left + width && p.y >= top &&
+           p.y < top + height;
+  }
+  bool Contains(const RectType& rt) const {
+    return rt.left >= left && rt.right() <= right() && rt.top >= top &&
+           rt.bottom() <= bottom();
+  }
+  BaseType Width() const { return width; }
+  BaseType Height() const { return height; }
+  SizeType Size() const { return SizeType(width, height); }
+  PointType TopLeft() const { return PointType(left, top); }
+  PointType TopRight() const { return PointType(left + width, top); }
+  PointType BottomLeft() const { return PointType(left, top + height); }
+  PointType BottomRight() const {
+    return PointType(left + width, top + height);
+  }
+  PointType Center() const {
+    return PointType(left + width / 2, top + height / 2);
+  }
+  void Union(BaseType x, BaseType y) {
+    BaseType r = right();
+    BaseType b = bottom();
+    if (left > x)
+      left = x;
+    if (r < x)
+      r = x;
+    if (top > y)
+      top = y;
+    if (b < y)
+      b = y;
+    width = r - left;
+    height = b - top;
+  }
+  void Union(const PointType& p) { Union(p.x, p.y); }
+  void Union(const RectType& rt) {
+    BaseType r = right();
+    BaseType b = bottom();
+    if (left > rt.left)
+      left = rt.left;
+    if (r < rt.right())
+      r = rt.right();
+    if (top > rt.top)
+      top = rt.top;
+    if (b < rt.bottom())
+      b = rt.bottom();
+    width = r - left;
+    height = b - top;
+  }
+  void Intersect(const RectType& rt) {
+    BaseType r = right();
+    BaseType b = bottom();
+    if (left < rt.left)
+      left = rt.left;
+    if (r > rt.right())
+      r = rt.right();
+    if (top < rt.top)
+      top = rt.top;
+    if (b > rt.bottom())
+      b = rt.bottom();
+    width = r - left;
+    height = b - top;
+  }
+  bool IntersectWith(const RectType& rt) const {
+    RectType rect = rt;
+    rect.Intersect(*this);
+    return !rect.IsEmpty();
+  }
+  bool IntersectWith(const RectType& rt, FX_FLOAT fEpsilon) const {
+    RectType rect = rt;
+    rect.Intersect(*this);
+    return !rect.IsEmpty(fEpsilon);
+  }
+  friend bool operator==(const RectType& rc1, const RectType& rc2) {
+    return rc1.left == rc2.left && rc1.top == rc2.top &&
+           rc1.width == rc2.width && rc1.height == rc2.height;
+  }
+  friend bool operator!=(const RectType& rc1, const RectType& rc2) {
+    return !(rc1 == rc2);
+  }
+
+  BaseType left;
+  BaseType top;
+  BaseType width;
+  BaseType height;
+};
+using CFX_Rect = CFX_RTemplate<int32_t>;
+using CFX_RectF = CFX_RTemplate<FX_FLOAT>;
+
 // LTRB rectangles (y-axis runs downwards).
 struct FX_RECT {
   FX_RECT() : left(0), top(0), right(0), bottom(0) {}
-
   FX_RECT(int l, int t, int r, int b) : left(l), top(t), right(r), bottom(b) {}
 
   int Width() const { return right - left; }
@@ -149,9 +428,6 @@
   void Intersect(const FX_RECT& src);
   void Intersect(int l, int t, int r, int b) { Intersect(FX_RECT(l, t, r, b)); }
 
-  void Union(const FX_RECT& other_rect);
-  void Union(int l, int t, int r, int b) { Union(FX_RECT(l, t, r, b)); }
-
   void Offset(int dx, int dy) {
     left += dx;
     right += dx;
@@ -164,11 +440,6 @@
            bottom == src.bottom;
   }
 
-  bool Contains(const FX_RECT& other_rect) const {
-    return other_rect.left >= left && other_rect.right <= right &&
-           other_rect.top >= top && other_rect.bottom <= bottom;
-  }
-
   bool Contains(int x, int y) const {
     return x >= left && x < right && y >= top && y < bottom;
   }
@@ -179,267 +450,7 @@
   int32_t bottom;
 };
 
-// LBRT rectangles (y-axis runs upwards).
-class CFX_FloatPoint {
- public:
-  CFX_FloatPoint() : x(0.0f), y(0.0f) {}
-  CFX_FloatPoint(FX_FLOAT xx, FX_FLOAT yy) : x(xx), y(yy) {}
-
-  bool operator==(const CFX_FloatPoint& that) const {
-    return x == that.x && y == that.y;
-  }
-  bool operator!=(const CFX_FloatPoint& that) const { return !(*this == that); }
-
-  FX_FLOAT x;
-  FX_FLOAT y;
-};
-
-// LTWH rectangles (y-axis runs downwards).
-template <class baseType>
-class CFX_RTemplate {
- public:
-  typedef CFX_PSTemplate<baseType> FXT_POINT;
-  typedef CFX_PSTemplate<baseType> FXT_SIZE;
-  typedef CFX_VTemplate<baseType> FXT_VECTOR;
-  typedef CFX_RTemplate<baseType> FXT_RECT;
-  void Set(baseType dst_left,
-           baseType dst_top,
-           baseType dst_width,
-           baseType dst_height) {
-    left = dst_left;
-    top = dst_top;
-    width = dst_width;
-    height = dst_height;
-  }
-  void Set(baseType dst_left, baseType dst_top, const FXT_SIZE& dst_size) {
-    left = dst_left;
-    top = dst_top;
-    Size(dst_size);
-  }
-  void Set(const FXT_POINT& p, baseType dst_width, baseType dst_height) {
-    TopLeft(p);
-    width = dst_width;
-    height = dst_height;
-  }
-  void Set(const FXT_POINT& p1, const FXT_POINT& p2) {
-    TopLeft(p1);
-    width = p2.x - p1.x;
-    height = p2.y - p1.y;
-    Normalize();
-  }
-  void Set(const FXT_POINT& p, const FXT_VECTOR& v) {
-    TopLeft(p);
-    width = v.x;
-    height = v.y;
-    Normalize();
-  }
-  void Reset() {
-    left = 0;
-    top = 0;
-    width = 0;
-    height = 0;
-  }
-  FXT_RECT& operator+=(const FXT_POINT& p) {
-    left += p.x;
-    top += p.y;
-    return *this;
-  }
-  FXT_RECT& operator-=(const FXT_POINT& p) {
-    left -= p.x;
-    top -= p.y;
-    return *this;
-  }
-  baseType right() const { return left + width; }
-  baseType bottom() const { return top + height; }
-  void Normalize() {
-    if (width < 0) {
-      left += width;
-      width = -width;
-    }
-    if (height < 0) {
-      top += height;
-      height = -height;
-    }
-  }
-  void Offset(baseType dx, baseType dy) {
-    left += dx;
-    top += dy;
-  }
-  void Inflate(baseType x, baseType y) {
-    left -= x;
-    width += x * 2;
-    top -= y;
-    height += y * 2;
-  }
-  void Inflate(const FXT_POINT& p) { Inflate(p.x, p.y); }
-  void Inflate(baseType off_left,
-               baseType off_top,
-               baseType off_right,
-               baseType off_bottom) {
-    left -= off_left;
-    top -= off_top;
-    width += off_left + off_right;
-    height += off_top + off_bottom;
-  }
-  void Inflate(const FXT_RECT& rt) {
-    Inflate(rt.left, rt.top, rt.left + rt.width, rt.top + rt.height);
-  }
-  void Deflate(baseType x, baseType y) {
-    left += x;
-    width -= x * 2;
-    top += y;
-    height -= y * 2;
-  }
-  void Deflate(const FXT_POINT& p) { Deflate(p.x, p.y); }
-  void Deflate(baseType off_left,
-               baseType off_top,
-               baseType off_right,
-               baseType off_bottom) {
-    left += off_left;
-    top += off_top;
-    width -= off_left + off_right;
-    height -= off_top + off_bottom;
-  }
-  void Deflate(const FXT_RECT& rt) {
-    Deflate(rt.left, rt.top, rt.top + rt.width, rt.top + rt.height);
-  }
-  bool IsEmpty() const { return width <= 0 || height <= 0; }
-  bool IsEmpty(FX_FLOAT fEpsilon) const {
-    return width <= fEpsilon || height <= fEpsilon;
-  }
-  void Empty() { width = height = 0; }
-  bool Contains(baseType x, baseType y) const {
-    return x >= left && x < left + width && y >= top && y < top + height;
-  }
-  bool Contains(const FXT_POINT& p) const { return Contains(p.x, p.y); }
-  bool Contains(const FXT_RECT& rt) const {
-    return rt.left >= left && rt.right() <= right() && rt.top >= top &&
-           rt.bottom() <= bottom();
-  }
-  baseType Width() const { return width; }
-  baseType Height() const { return height; }
-  FXT_SIZE Size() const {
-    FXT_SIZE size;
-    size.Set(width, height);
-    return size;
-  }
-  void Size(FXT_SIZE s) { width = s.x, height = s.y; }
-  FXT_POINT TopLeft() const {
-    FXT_POINT p;
-    p.x = left;
-    p.y = top;
-    return p;
-  }
-  FXT_POINT TopRight() const {
-    FXT_POINT p;
-    p.x = left + width;
-    p.y = top;
-    return p;
-  }
-  FXT_POINT BottomLeft() const {
-    FXT_POINT p;
-    p.x = left;
-    p.y = top + height;
-    return p;
-  }
-  FXT_POINT BottomRight() const {
-    FXT_POINT p;
-    p.x = left + width;
-    p.y = top + height;
-    return p;
-  }
-  void TopLeft(FXT_POINT tl) {
-    left = tl.x;
-    top = tl.y;
-  }
-  void TopRight(FXT_POINT tr) {
-    width = tr.x - left;
-    top = tr.y;
-  }
-  void BottomLeft(FXT_POINT bl) {
-    left = bl.x;
-    height = bl.y - top;
-  }
-  void BottomRight(FXT_POINT br) {
-    width = br.x - left;
-    height = br.y - top;
-  }
-  FXT_POINT Center() const {
-    FXT_POINT p;
-    p.x = left + width / 2;
-    p.y = top + height / 2;
-    return p;
-  }
-  void Union(baseType x, baseType y) {
-    baseType r = right();
-    baseType b = bottom();
-    if (left > x)
-      left = x;
-    if (r < x)
-      r = x;
-    if (top > y)
-      top = y;
-    if (b < y)
-      b = y;
-    width = r - left;
-    height = b - top;
-  }
-  void Union(const FXT_POINT& p) { Union(p.x, p.y); }
-  void Union(const FXT_RECT& rt) {
-    baseType r = right();
-    baseType b = bottom();
-    if (left > rt.left)
-      left = rt.left;
-    if (r < rt.right())
-      r = rt.right();
-    if (top > rt.top)
-      top = rt.top;
-    if (b < rt.bottom())
-      b = rt.bottom();
-    width = r - left;
-    height = b - top;
-  }
-  void Intersect(const FXT_RECT& rt) {
-    baseType r = right();
-    baseType b = bottom();
-    if (left < rt.left)
-      left = rt.left;
-    if (r > rt.right())
-      r = rt.right();
-    if (top < rt.top)
-      top = rt.top;
-    if (b > rt.bottom())
-      b = rt.bottom();
-    width = r - left;
-    height = b - top;
-  }
-  bool IntersectWith(const FXT_RECT& rt) const {
-    FXT_RECT rect = rt;
-    rect.Intersect(*this);
-    return !rect.IsEmpty();
-  }
-  bool IntersectWith(const FXT_RECT& rt, FX_FLOAT fEpsilon) const {
-    FXT_RECT rect = rt;
-    rect.Intersect(*this);
-    return !rect.IsEmpty(fEpsilon);
-  }
-  friend bool operator==(const FXT_RECT& rc1, const FXT_RECT& rc2) {
-    return rc1.left == rc2.left && rc1.top == rc2.top &&
-           rc1.width == rc2.width && rc1.height == rc2.height;
-  }
-  friend bool operator!=(const FXT_RECT& rc1, const FXT_RECT& rc2) {
-    return !(rc1 == rc2);
-  }
-  baseType left, top;
-  baseType width, height;
-};
-typedef CFX_RTemplate<int32_t> CFX_Rect;
-typedef CFX_RTemplate<FX_FLOAT> CFX_RectF;
-
-#ifdef PDF_ENABLE_XFA
-typedef CFX_ArrayTemplate<CFX_RectF> CFX_RectFArray;
-#endif  // PDF_ENABLE_XFA
-
+// LTRB rectangles (y-axis runs upwards).
 class CFX_FloatRect {
  public:
   CFX_FloatRect() : CFX_FloatRect(0.0f, 0.0f, 0.0f, 0.0f) {}
@@ -461,10 +472,10 @@
   }
 
   bool IsEmpty() const { return left >= right || bottom >= top; }
-  bool Contains(const CFX_FloatRect& other_rect) const;
-  bool Contains(FX_FLOAT x, FX_FLOAT y) const;
 
-  void Transform(const CFX_Matrix* pMatrix);
+  bool Contains(const CFX_PointF& point) const;
+  bool Contains(const CFX_FloatRect& other_rect) const;
+
   void Intersect(const CFX_FloatRect& other_rect);
   void Union(const CFX_FloatRect& other_rect);
 
@@ -559,42 +570,45 @@
  public:
   CFX_Matrix() { SetIdentity(); }
 
+  explicit CFX_Matrix(const FX_FLOAT n[6])
+      : a(n[0]), b(n[1]), c(n[2]), d(n[3]), e(n[4]), f(n[5]) {}
+
+  CFX_Matrix(const CFX_Matrix& other)
+      : a(other.a),
+        b(other.b),
+        c(other.c),
+        d(other.d),
+        e(other.e),
+        f(other.f) {}
+
   CFX_Matrix(FX_FLOAT a1,
              FX_FLOAT b1,
              FX_FLOAT c1,
              FX_FLOAT d1,
              FX_FLOAT e1,
-             FX_FLOAT f1) {
-    a = a1;
-    b = b1;
-    c = c1;
-    d = d1;
-    e = e1;
-    f = f1;
+             FX_FLOAT f1)
+      : a(a1), b(b1), c(c1), d(d1), e(e1), f(f1) {}
+
+  void operator=(const CFX_Matrix& other) {
+    a = other.a;
+    b = other.b;
+    c = other.c;
+    d = other.d;
+    e = other.e;
+    f = other.f;
   }
 
-  void Set(FX_FLOAT a,
-           FX_FLOAT b,
-           FX_FLOAT c,
-           FX_FLOAT d,
-           FX_FLOAT e,
-           FX_FLOAT f);
-  void Set(const FX_FLOAT n[6]);
-
   void SetIdentity() {
-    a = d = 1;
-    b = c = e = f = 0;
+    a = 1;
+    b = 0;
+    c = 0;
+    d = 1;
+    e = 0;
+    f = 0;
   }
 
   void SetReverse(const CFX_Matrix& m);
 
-  void Concat(FX_FLOAT a,
-              FX_FLOAT b,
-              FX_FLOAT c,
-              FX_FLOAT d,
-              FX_FLOAT e,
-              FX_FLOAT f,
-              bool bPrepended = false);
   void Concat(const CFX_Matrix& m, bool bPrepended = false);
   void ConcatInverse(const CFX_Matrix& m, bool bPrepended = false);
 
@@ -602,13 +616,13 @@
     return a == 1 && b == 0 && c == 0 && d == 1 && e == 0 && f == 0;
   }
 
-  bool IsInvertible() const;
   bool Is90Rotated() const;
   bool IsScaled() const;
+  bool WillScale() const { return a != 1.0f || b != 0 || c != 0 || d != 1.0f; }
 
   void Translate(FX_FLOAT x, FX_FLOAT y, bool bPrepended = false);
-  void TranslateI(int32_t x, int32_t y, bool bPrepended = false) {
-    Translate((FX_FLOAT)x, (FX_FLOAT)y, bPrepended);
+  void Translate(int32_t x, int32_t y, bool bPrepended = false) {
+    Translate(static_cast<FX_FLOAT>(x), static_cast<FX_FLOAT>(y), bPrepended);
   }
 
   void Scale(FX_FLOAT sx, FX_FLOAT sy, bool bPrepended = false);
@@ -623,33 +637,18 @@
              bool bPrepended = false);
 
   void MatchRect(const CFX_FloatRect& dest, const CFX_FloatRect& src);
+
   FX_FLOAT GetXUnit() const;
   FX_FLOAT GetYUnit() const;
-  void GetUnitRect(CFX_RectF& rect) const;
   CFX_FloatRect GetUnitRect() const;
 
-  FX_FLOAT GetUnitArea() const;
   FX_FLOAT TransformXDistance(FX_FLOAT dx) const;
-  int32_t TransformXDistance(int32_t dx) const;
-  FX_FLOAT TransformYDistance(FX_FLOAT dy) const;
-  int32_t TransformYDistance(int32_t dy) const;
   FX_FLOAT TransformDistance(FX_FLOAT dx, FX_FLOAT dy) const;
-  int32_t TransformDistance(int32_t dx, int32_t dy) const;
   FX_FLOAT TransformDistance(FX_FLOAT distance) const;
 
-  void TransformPoint(FX_FLOAT& x, FX_FLOAT& y) const;
-  void TransformPoint(int32_t& x, int32_t& y) const;
+  CFX_PointF Transform(const CFX_PointF& point) const;
 
-  void Transform(FX_FLOAT& x, FX_FLOAT& y) const { TransformPoint(x, y); }
-  void Transform(FX_FLOAT x, FX_FLOAT y, FX_FLOAT& x1, FX_FLOAT& y1) const {
-    x1 = x, y1 = y;
-    TransformPoint(x1, y1);
-  }
-
-  void TransformVector(CFX_VectorF& v) const;
-  void TransformVector(CFX_Vector& v) const;
   void TransformRect(CFX_RectF& rect) const;
-  void TransformRect(CFX_Rect& rect) const;
   void TransformRect(FX_FLOAT& left,
                      FX_FLOAT& right,
                      FX_FLOAT& top,
@@ -658,20 +657,15 @@
     TransformRect(rect.left, rect.right, rect.top, rect.bottom);
   }
 
-  FX_FLOAT GetA() const { return a; }
-  FX_FLOAT GetB() const { return b; }
-  FX_FLOAT GetC() const { return c; }
-  FX_FLOAT GetD() const { return d; }
-  FX_FLOAT GetE() const { return e; }
-  FX_FLOAT GetF() const { return f; }
-
- public:
   FX_FLOAT a;
   FX_FLOAT b;
   FX_FLOAT c;
   FX_FLOAT d;
   FX_FLOAT e;
   FX_FLOAT f;
+
+ private:
+  void ConcatInternal(const CFX_Matrix& other, bool prepend);
 };
 
 #endif  // CORE_FXCRT_FX_COORDINATES_H_
diff --git a/core/fxcrt/fx_extension.cpp b/core/fxcrt/fx_extension.cpp
index f1e2583..5b577f7 100644
--- a/core/fxcrt/fx_extension.cpp
+++ b/core/fxcrt/fx_extension.cpp
@@ -204,7 +204,7 @@
 bool CFX_MemoryStream::ReadBlock(void* buffer,
                                  FX_FILESIZE offset,
                                  size_t size) {
-  if (!buffer || !size)
+  if (!buffer || !size || offset < 0)
     return false;
 
   FX_SAFE_SIZE_T newPos = size;
diff --git a/core/fxcrt/fx_string.h b/core/fxcrt/fx_string.h
index 540c0c4..cd93f27 100644
--- a/core/fxcrt/fx_string.h
+++ b/core/fxcrt/fx_string.h
@@ -28,8 +28,6 @@
   (((uint32_t)c1 << 24) | ((uint32_t)c2 << 16) | ((uint32_t)c3 << 8) | \
    ((uint32_t)c4))
 
-#define FX_WSTRC(wstr) CFX_WideStringC(wstr, FX_ArraySize(wstr) - 1)
-
 // A mutable string with shared buffers using copy-on-write semantics that
 // avoids the cost of std::string's iterator stability guarantees.
 class CFX_ByteString {
@@ -426,17 +424,10 @@
   return rhs != lhs;
 }
 
-CFX_ByteString FX_UTF8Encode(const FX_WCHAR* pwsStr, FX_STRSIZE len);
-inline CFX_ByteString FX_UTF8Encode(const CFX_WideStringC& wsStr) {
-  return FX_UTF8Encode(wsStr.c_str(), wsStr.GetLength());
-}
-inline CFX_ByteString FX_UTF8Encode(const CFX_WideString& wsStr) {
-  return FX_UTF8Encode(wsStr.c_str(), wsStr.GetLength());
-}
-
+CFX_ByteString FX_UTF8Encode(const CFX_WideStringC& wsStr);
 FX_FLOAT FX_atof(const CFX_ByteStringC& str);
 inline FX_FLOAT FX_atof(const CFX_WideStringC& wsStr) {
-  return FX_atof(FX_UTF8Encode(wsStr.c_str(), wsStr.GetLength()).c_str());
+  return FX_atof(FX_UTF8Encode(wsStr).c_str());
 }
 bool FX_atonum(const CFX_ByteStringC& str, void* pData);
 FX_STRSIZE FX_ftoa(FX_FLOAT f, FX_CHAR* buf);
diff --git a/core/fxcrt/fx_ucd.h b/core/fxcrt/fx_ucd.h
index d79693b..eb4bad0 100644
--- a/core/fxcrt/fx_ucd.h
+++ b/core/fxcrt/fx_ucd.h
@@ -7,6 +7,7 @@
 #ifndef CORE_FXCRT_FX_UCD_H_
 #define CORE_FXCRT_FX_UCD_H_
 
+#include "core/fxcrt/cfx_retain_ptr.h"
 #include "core/fxcrt/fx_basic.h"
 
 #define FX_BIDICLASSBITS 6
@@ -121,43 +122,43 @@
   CFX_Char()
       : m_wCharCode(0),
         m_nBreakType(0),
-        m_nRotation(0),
         m_dwCharProps(0),
-        m_dwCharStyles(0),
         m_iCharWidth(0),
         m_iHorizontalScale(100),
-        m_iVertialScale(100) {}
+        m_iVerticalScale(100) {}
+
   CFX_Char(uint16_t wCharCode, uint32_t dwCharProps)
       : m_wCharCode(wCharCode),
         m_nBreakType(0),
-        m_nRotation(0),
         m_dwCharProps(dwCharProps),
-        m_dwCharStyles(0),
         m_iCharWidth(0),
         m_iHorizontalScale(100),
-        m_iVertialScale(100) {}
+        m_iVerticalScale(100) {}
 
   FX_CHARTYPE GetCharType() const { return GetCharTypeFromProp(m_dwCharProps); }
 
   uint16_t m_wCharCode;
   uint8_t m_nBreakType;
-  int8_t m_nRotation;
   uint32_t m_dwCharProps;
-  uint32_t m_dwCharStyles;
   int32_t m_iCharWidth;
   int32_t m_iHorizontalScale;
-  int32_t m_iVertialScale;
+  int32_t m_iVerticalScale;
 };
-typedef CFX_ArrayTemplate<CFX_Char> CFX_CharArray;
+
 class CFX_TxtChar : public CFX_Char {
  public:
   CFX_TxtChar()
-      : m_dwStatus(0),
+      : m_nRotation(0),
+        m_dwCharStyles(0),
+        m_dwStatus(0),
         m_iBidiClass(0),
         m_iBidiLevel(0),
         m_iBidiPos(0),
         m_iBidiOrder(0),
         m_pUserData(nullptr) {}
+
+  int8_t m_nRotation;
+  uint32_t m_dwCharStyles;
   uint32_t m_dwStatus;
   int16_t m_iBidiClass;
   int16_t m_iBidiLevel;
@@ -165,38 +166,39 @@
   int16_t m_iBidiOrder;
   void* m_pUserData;
 };
-typedef CFX_ArrayTemplate<CFX_TxtChar> CFX_TxtCharArray;
+
+enum class CFX_RTFBreakType { None = 0, Piece, Line, Paragraph, Page };
+
 class CFX_RTFChar : public CFX_Char {
  public:
   CFX_RTFChar();
   CFX_RTFChar(const CFX_RTFChar& other);
+  ~CFX_RTFChar();
 
-  uint32_t m_dwStatus;
+  CFX_RTFBreakType m_dwStatus;
   int32_t m_iFontSize;
   int32_t m_iFontHeight;
   int16_t m_iBidiClass;
   int16_t m_iBidiLevel;
   int16_t m_iBidiPos;
   int16_t m_iBidiOrder;
-  uint32_t m_dwLayoutStyles;
   uint32_t m_dwIdentity;
-  IFX_Retainable* m_pUserData;
+  CFX_RetainPtr<CFX_Retainable> m_pUserData;
 };
 
 inline CFX_RTFChar::CFX_RTFChar()
-    : m_dwStatus(0),
+    : m_dwStatus(CFX_RTFBreakType::None),
       m_iFontSize(0),
       m_iFontHeight(0),
       m_iBidiClass(0),
       m_iBidiLevel(0),
       m_iBidiPos(0),
-      m_dwLayoutStyles(0),
       m_dwIdentity(0),
       m_pUserData(nullptr) {}
 
 inline CFX_RTFChar::CFX_RTFChar(const CFX_RTFChar& other) = default;
+inline CFX_RTFChar::~CFX_RTFChar() = default;
 
-typedef CFX_ArrayTemplate<CFX_RTFChar> CFX_RTFCharArray;
 #endif  // PDF_ENABLE_XFA
 
 #endif  // CORE_FXCRT_FX_UCD_H_
diff --git a/core/fxcrt/fx_xml.h b/core/fxcrt/fx_xml.h
index 7f42a7f..87f1915 100644
--- a/core/fxcrt/fx_xml.h
+++ b/core/fxcrt/fx_xml.h
@@ -54,28 +54,18 @@
  public:
   enum ChildType { Invalid, Element, Content };
 
-  static CXML_Element* Parse(const void* pBuffer,
-                             size_t size,
-                             bool bSaveSpaceChars = false,
-                             FX_FILESIZE* pParsedSize = nullptr);
-  static CXML_Element* Parse(const CFX_RetainPtr<IFX_SeekableReadStream>& pFile,
-                             bool bSaveSpaceChars = false,
-                             FX_FILESIZE* pParsedSize = nullptr);
-  static CXML_Element* Parse(
-      const CFX_RetainPtr<IFX_BufferedReadStream>& pBuffer,
-      bool bSaveSpaceChars = false,
-      FX_FILESIZE* pParsedSize = nullptr);
+  static std::unique_ptr<CXML_Element> Parse(const void* pBuffer, size_t size);
 
-  CXML_Element(const CFX_ByteStringC& qSpace, const CFX_ByteStringC& tagName);
-  explicit CXML_Element(const CFX_ByteStringC& qTagName);
-  CXML_Element();
+  CXML_Element(const CXML_Element* pParent,
+               const CFX_ByteStringC& qSpace,
+               const CFX_ByteStringC& tagname);
   ~CXML_Element();
 
   void Empty();
   CFX_ByteString GetTagName(bool bQualified = false) const;
   CFX_ByteString GetNamespace(bool bQualified = false) const;
   CFX_ByteString GetNamespaceURI(const CFX_ByteString& qName) const;
-  CXML_Element* GetParent() const { return m_pParent; }
+  const CXML_Element* GetParent() const { return m_pParent; }
   uint32_t CountAttrs() const { return m_AttrMap.GetSize(); }
   void GetAttrByIndex(int index,
                       CFX_ByteString& space,
@@ -150,7 +140,6 @@
                            int index) const;
 
   uint32_t FindElement(CXML_Element* pChild) const;
-  void SetTag(const CFX_ByteStringC& qSpace, const CFX_ByteStringC& tagname);
   void SetTag(const CFX_ByteStringC& qTagName);
   void RemoveChildren();
   void RemoveChild(uint32_t index);
@@ -161,7 +150,7 @@
     void* child;  // CXML_Element and CXML_Content lack a common ancestor.
   };
 
-  CXML_Element* m_pParent;
+  const CXML_Element* const m_pParent;
   CFX_ByteString m_QSpaceName;
   CFX_ByteString m_TagName;
   CXML_AttrMap m_AttrMap;
diff --git a/core/fxcrt/fx_xml_composer.cpp b/core/fxcrt/fx_xml_composer.cpp
index 91118a0..637d64c 100644
--- a/core/fxcrt/fx_xml_composer.cpp
+++ b/core/fxcrt/fx_xml_composer.cpp
@@ -23,14 +23,10 @@
   }
 }
 
-void CXML_Element::SetTag(const CFX_ByteStringC& qSpace,
-                          const CFX_ByteStringC& tagname) {
-  m_QSpaceName = qSpace;
-  m_TagName = tagname;
-}
 void CXML_Element::SetTag(const CFX_ByteStringC& qTagName) {
   ASSERT(!qTagName.IsEmpty());
-  CFX_ByteStringC bsSpace, bsName;
+  CFX_ByteStringC bsSpace;
+  CFX_ByteStringC bsName;
   FX_XML_SplitQualifiedName(qTagName, bsSpace, bsName);
   m_QSpaceName = bsSpace;
   m_TagName = bsName;
diff --git a/core/fxcrt/fx_xml_parser.cpp b/core/fxcrt/fx_xml_parser.cpp
index 1b562c2..761aae7 100644
--- a/core/fxcrt/fx_xml_parser.cpp
+++ b/core/fxcrt/fx_xml_parser.cpp
@@ -4,13 +4,13 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
-#include "core/fxcrt/xml_int.h"
-
 #include <algorithm>
+#include <memory>
 #include <vector>
 
 #include "core/fxcrt/fx_ext.h"
 #include "core/fxcrt/fx_xml.h"
+#include "core/fxcrt/xml_int.h"
 #include "third_party/base/ptr_util.h"
 #include "third_party/base/stl_util.h"
 
@@ -101,7 +101,7 @@
 }
 
 FX_FILESIZE CXML_DataBufAcc::GetPosition() {
-  return (FX_FILESIZE)m_dwCurPos;
+  return static_cast<FX_FILESIZE>(m_dwCurPos);
 }
 
 size_t CXML_DataBufAcc::ReadBlock(void* buffer, size_t size) {
@@ -167,11 +167,12 @@
 }
 
 bool CXML_DataStmAcc::IsEOF() {
-  return m_nStart + (FX_FILESIZE)m_dwSize >= m_pFileRead->GetSize();
+  return m_nStart + static_cast<FX_FILESIZE>(m_dwSize) >=
+         m_pFileRead->GetSize();
 }
 
 FX_FILESIZE CXML_DataStmAcc::GetPosition() {
-  return m_nStart + (FX_FILESIZE)m_dwSize;
+  return m_nStart + static_cast<FX_FILESIZE>(m_dwSize);
 }
 
 size_t CXML_DataStmAcc::ReadBlock(void* buffer, size_t size) {
@@ -183,7 +184,7 @@
     m_nStart = 0;
 
   FX_FILESIZE nLength = m_pFileRead->GetSize();
-  m_nStart += (FX_FILESIZE)m_dwSize;
+  m_nStart += static_cast<FX_FILESIZE>(m_dwSize);
   if (m_nStart >= nLength)
     return false;
 
@@ -212,7 +213,6 @@
 
 CXML_Parser::CXML_Parser()
     : m_nOffset(0),
-      m_bSaveSpaceChars(false),
       m_pBuffer(nullptr),
       m_dwBufferSize(0),
       m_nBufferOffset(0),
@@ -220,25 +220,8 @@
 
 CXML_Parser::~CXML_Parser() {}
 
-bool CXML_Parser::Init(uint8_t* pBuffer, size_t size) {
+bool CXML_Parser::Init(const uint8_t* pBuffer, size_t size) {
   m_pDataAcc = pdfium::MakeRetain<CXML_DataBufAcc>(pBuffer, size);
-  return Init();
-}
-
-bool CXML_Parser::Init(const CFX_RetainPtr<IFX_SeekableReadStream>& pFileRead) {
-  m_pDataAcc = pdfium::MakeRetain<CXML_DataStmAcc>(pFileRead);
-  return Init();
-}
-
-bool CXML_Parser::Init(const CFX_RetainPtr<IFX_BufferedReadStream>& pBuffer) {
-  if (!pBuffer)
-    return false;
-
-  m_pDataAcc = pBuffer;
-  return Init();
-}
-
-bool CXML_Parser::Init() {
   m_nOffset = 0;
   return ReadNextBlock();
 }
@@ -259,33 +242,33 @@
 }
 
 void CXML_Parser::SkipWhiteSpaces() {
-  m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
-  if (IsEOF()) {
+  m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
+  if (IsEOF())
     return;
-  }
+
   do {
     while (m_dwIndex < m_dwBufferSize &&
            g_FXCRT_XML_IsWhiteSpace(m_pBuffer[m_dwIndex])) {
       m_dwIndex++;
     }
-    m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
-    if (m_dwIndex < m_dwBufferSize || IsEOF()) {
+    m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
+    if (m_dwIndex < m_dwBufferSize || IsEOF())
       break;
-    }
   } while (ReadNextBlock());
 }
-void CXML_Parser::GetName(CFX_ByteString& space, CFX_ByteString& name) {
-  m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
-  if (IsEOF()) {
+
+void CXML_Parser::GetName(CFX_ByteString* space, CFX_ByteString* name) {
+  m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
+  if (IsEOF())
     return;
-  }
+
   CFX_ByteTextBuf buf;
   uint8_t ch;
   do {
     while (m_dwIndex < m_dwBufferSize) {
       ch = m_pBuffer[m_dwIndex];
       if (ch == ':') {
-        space = buf.AsStringC();
+        *space = buf.AsStringC();
         buf.Clear();
       } else if (g_FXCRT_XML_IsNameChar(ch)) {
         buf.AppendChar(ch);
@@ -294,15 +277,15 @@
       }
       m_dwIndex++;
     }
-    m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
-    if (m_dwIndex < m_dwBufferSize || IsEOF()) {
+    m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
+    if (m_dwIndex < m_dwBufferSize || IsEOF())
       break;
-    }
   } while (ReadNextBlock());
-  name = buf.AsStringC();
+  *name = buf.AsStringC();
 }
+
 void CXML_Parser::SkipLiterals(const CFX_ByteStringC& str) {
-  m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+  m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
   if (IsEOF()) {
     return;
   }
@@ -311,32 +294,31 @@
     while (m_dwIndex < m_dwBufferSize) {
       if (str.GetAt(i) != m_pBuffer[m_dwIndex++]) {
         i = 0;
-      } else {
-        i++;
-        if (i == iLen) {
-          break;
-        }
+        continue;
       }
+      i++;
+      if (i == iLen)
+        break;
     }
-    m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
-    if (i == iLen) {
+    m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
+    if (i == iLen)
       return;
-    }
-    if (m_dwIndex < m_dwBufferSize || IsEOF()) {
+
+    if (m_dwIndex < m_dwBufferSize || IsEOF())
       break;
-    }
   } while (ReadNextBlock());
   while (!m_pDataAcc->IsEOF()) {
     ReadNextBlock();
-    m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwBufferSize;
+    m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwBufferSize);
   }
   m_dwIndex = m_dwBufferSize;
 }
+
 uint32_t CXML_Parser::GetCharRef() {
-  m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
-  if (IsEOF()) {
+  m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
+  if (IsEOF())
     return 0;
-  }
+
   uint8_t ch;
   int32_t iState = 0;
   CFX_ByteTextBuf buf;
@@ -356,17 +338,16 @@
           m_dwIndex++;
           if (ch == ';') {
             CFX_ByteStringC ref = buf.AsStringC();
-            if (ref == "gt") {
+            if (ref == "gt")
               code = '>';
-            } else if (ref == "lt") {
+            else if (ref == "lt")
               code = '<';
-            } else if (ref == "amp") {
+            else if (ref == "amp")
               code = '&';
-            } else if (ref == "apos") {
+            else if (ref == "apos")
               code = '\'';
-            } else if (ref == "quot") {
+            else if (ref == "quot")
               code = '"';
-            }
             iState = 10;
             break;
           }
@@ -408,40 +389,40 @@
           }
           break;
       }
-      if (iState == 10) {
+      if (iState == 10)
         break;
-      }
     }
-    m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+    m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
     if (iState == 10 || m_dwIndex < m_dwBufferSize || IsEOF()) {
       break;
     }
   } while (ReadNextBlock());
   return code;
 }
+
 void CXML_Parser::GetAttrValue(CFX_WideString& value) {
-  m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
-  if (IsEOF()) {
+  m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
+  if (IsEOF())
     return;
-  }
+
   CFX_UTF8Decoder decoder;
   uint8_t mark = 0, ch = 0;
   do {
     while (m_dwIndex < m_dwBufferSize) {
       ch = m_pBuffer[m_dwIndex];
       if (mark == 0) {
-        if (ch != '\'' && ch != '"') {
+        if (ch != '\'' && ch != '"')
           return;
-        }
+
         mark = ch;
         m_dwIndex++;
         ch = 0;
         continue;
       }
       m_dwIndex++;
-      if (ch == mark) {
+      if (ch == mark)
         break;
-      }
+
       if (ch == '&') {
         decoder.AppendChar(GetCharRef());
         if (IsEOF()) {
@@ -452,22 +433,22 @@
         decoder.Input(ch);
       }
     }
-    m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
-    if (ch == mark || m_dwIndex < m_dwBufferSize || IsEOF()) {
+    m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
+    if (ch == mark || m_dwIndex < m_dwBufferSize || IsEOF())
       break;
-    }
   } while (ReadNextBlock());
   value = decoder.GetResult();
 }
-void CXML_Parser::GetTagName(CFX_ByteString& space,
-                             CFX_ByteString& name,
-                             bool& bEndTag,
-                             bool bStartTag) {
-  m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
-  if (IsEOF()) {
+
+void CXML_Parser::GetTagName(bool bStartTag,
+                             bool* bEndTag,
+                             CFX_ByteString* space,
+                             CFX_ByteString* name) {
+  m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
+  if (IsEOF())
     return;
-  }
-  bEndTag = false;
+
+  *bEndTag = false;
   uint8_t ch;
   int32_t iState = bStartTag ? 1 : 0;
   do {
@@ -476,9 +457,9 @@
       switch (iState) {
         case 0:
           m_dwIndex++;
-          if (ch != '<') {
+          if (ch != '<')
             break;
-          }
+
           iState = 1;
           break;
         case 1:
@@ -487,7 +468,8 @@
             SkipLiterals("?>");
             iState = 0;
             break;
-          } else if (ch == '!') {
+          }
+          if (ch == '!') {
             m_dwIndex++;
             SkipLiterals("-->");
             iState = 0;
@@ -496,85 +478,85 @@
           if (ch == '/') {
             m_dwIndex++;
             GetName(space, name);
-            bEndTag = true;
+            *bEndTag = true;
           } else {
             GetName(space, name);
-            bEndTag = false;
+            *bEndTag = false;
           }
           return;
       }
     }
-    m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
-    if (m_dwIndex < m_dwBufferSize || IsEOF()) {
+    m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
+    if (m_dwIndex < m_dwBufferSize || IsEOF())
       break;
-    }
   } while (ReadNextBlock());
 }
-CXML_Element* CXML_Parser::ParseElement(CXML_Element* pParent, bool bStartTag) {
-  m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
-  if (IsEOF()) {
+
+std::unique_ptr<CXML_Element> CXML_Parser::ParseElement(CXML_Element* pParent,
+                                                        bool bStartTag) {
+  m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
+  if (IsEOF())
     return nullptr;
-  }
-  CFX_ByteString tag_name, tag_space;
+
+  CFX_ByteString tag_name;
+  CFX_ByteString tag_space;
   bool bEndTag;
-  GetTagName(tag_space, tag_name, bEndTag, bStartTag);
-  if (tag_name.IsEmpty() || bEndTag) {
+  GetTagName(bStartTag, &bEndTag, &tag_space, &tag_name);
+  if (tag_name.IsEmpty() || bEndTag)
     return nullptr;
-  }
-  CXML_Element* pElement = new CXML_Element;
-  pElement->m_pParent = pParent;
-  pElement->SetTag(tag_space.AsStringC(), tag_name.AsStringC());
+
+  auto pElement = pdfium::MakeUnique<CXML_Element>(
+      pParent, tag_space.AsStringC(), tag_name.AsStringC());
   do {
-    CFX_ByteString attr_space, attr_name;
+    CFX_ByteString attr_space;
+    CFX_ByteString attr_name;
     while (m_dwIndex < m_dwBufferSize) {
       SkipWhiteSpaces();
-      if (IsEOF()) {
+      if (IsEOF())
         break;
-      }
-      if (!g_FXCRT_XML_IsNameIntro(m_pBuffer[m_dwIndex])) {
+
+      if (!g_FXCRT_XML_IsNameIntro(m_pBuffer[m_dwIndex]))
         break;
-      }
-      GetName(attr_space, attr_name);
+
+      GetName(&attr_space, &attr_name);
       SkipWhiteSpaces();
-      if (IsEOF()) {
+      if (IsEOF())
         break;
-      }
-      if (m_pBuffer[m_dwIndex] != '=') {
+
+      if (m_pBuffer[m_dwIndex] != '=')
         break;
-      }
+
       m_dwIndex++;
       SkipWhiteSpaces();
-      if (IsEOF()) {
+      if (IsEOF())
         break;
-      }
+
       CFX_WideString attr_value;
       GetAttrValue(attr_value);
       pElement->m_AttrMap.SetAt(attr_space, attr_name, attr_value);
     }
-    m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
-    if (m_dwIndex < m_dwBufferSize || IsEOF()) {
+    m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
+    if (m_dwIndex < m_dwBufferSize || IsEOF())
       break;
-    }
   } while (ReadNextBlock());
   SkipWhiteSpaces();
-  if (IsEOF()) {
+  if (IsEOF())
     return pElement;
-  }
+
   uint8_t ch = m_pBuffer[m_dwIndex++];
   if (ch == '/') {
     m_dwIndex++;
-    m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+    m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
     return pElement;
   }
   if (ch != '>') {
-    m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
-    delete pElement;
+    m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
     return nullptr;
   }
   SkipWhiteSpaces();
-  if (IsEOF()) {
+  if (IsEOF())
     return pElement;
-  }
+
   CFX_UTF8Decoder decoder;
   CFX_WideTextBuf content;
   bool bCDATA = false;
@@ -601,30 +583,31 @@
             SkipWhiteSpaces();
             iState = 0;
           } else if (ch == '/') {
-            CFX_ByteString space, name;
-            GetName(space, name);
+            CFX_ByteString space;
+            CFX_ByteString name;
+            GetName(&space, &name);
             SkipWhiteSpaces();
             m_dwIndex++;
             iState = 10;
           } else {
             content << decoder.GetResult();
             CFX_WideString dataStr = content.MakeString();
-            if (!bCDATA && !m_bSaveSpaceChars) {
+            if (!bCDATA)
               dataStr.TrimRight(L" \t\r\n");
-            }
-            InsertContentSegment(bCDATA, dataStr.AsStringC(), pElement);
+
+            InsertContentSegment(bCDATA, dataStr.AsStringC(), pElement.get());
             content.Clear();
             decoder.Clear();
             bCDATA = false;
             iState = 0;
             m_dwIndex--;
-            CXML_Element* pSubElement = ParseElement(pElement, true);
-            if (!pSubElement) {
+            std::unique_ptr<CXML_Element> pSubElement(
+                ParseElement(pElement.get(), true));
+            if (!pSubElement)
               break;
-            }
-            pSubElement->m_pParent = pElement;
+
             pElement->m_Children.push_back(
-                {CXML_Element::Element, pSubElement});
+                {CXML_Element::Element, pSubElement.release()});
             SkipWhiteSpaces();
           }
           break;
@@ -646,89 +629,49 @@
         break;
       }
     }
-    m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
-    if (iState == 10 || m_dwIndex < m_dwBufferSize || IsEOF()) {
+    m_nOffset = m_nBufferOffset + static_cast<FX_FILESIZE>(m_dwIndex);
+    if (iState == 10 || m_dwIndex < m_dwBufferSize || IsEOF())
       break;
-    }
   } while (ReadNextBlock());
   content << decoder.GetResult();
   CFX_WideString dataStr = content.MakeString();
-  if (!m_bSaveSpaceChars) {
-    dataStr.TrimRight(L" \t\r\n");
-  }
-  InsertContentSegment(bCDATA, dataStr.AsStringC(), pElement);
+  dataStr.TrimRight(L" \t\r\n");
+
+  InsertContentSegment(bCDATA, dataStr.AsStringC(), pElement.get());
   content.Clear();
   decoder.Clear();
   bCDATA = false;
   return pElement;
 }
+
 void CXML_Parser::InsertContentSegment(bool bCDATA,
                                        const CFX_WideStringC& content,
                                        CXML_Element* pElement) {
-  if (content.IsEmpty()) {
+  if (content.IsEmpty())
     return;
-  }
+
   CXML_Content* pContent = new CXML_Content;
   pContent->Set(bCDATA, content);
   pElement->m_Children.push_back({CXML_Element::Content, pContent});
 }
-static CXML_Element* XML_ContinueParse(CXML_Parser& parser,
-                                       bool bSaveSpaceChars,
-                                       FX_FILESIZE* pParsedSize) {
-  parser.m_bSaveSpaceChars = bSaveSpaceChars;
-  CXML_Element* pElement = parser.ParseElement(nullptr, false);
-  if (pParsedSize) {
-    *pParsedSize = parser.m_nOffset;
-  }
-  return pElement;
-}
-CXML_Element* CXML_Element::Parse(const void* pBuffer,
-                                  size_t size,
-                                  bool bSaveSpaceChars,
-                                  FX_FILESIZE* pParsedSize) {
+
+std::unique_ptr<CXML_Element> CXML_Element::Parse(const void* pBuffer,
+                                                  size_t size) {
   CXML_Parser parser;
-  if (!parser.Init((uint8_t*)pBuffer, size)) {
+  if (!parser.Init(static_cast<const uint8_t*>(pBuffer), size))
     return nullptr;
-  }
-  return XML_ContinueParse(parser, bSaveSpaceChars, pParsedSize);
+  return parser.ParseElement(nullptr, false);
 }
 
-CXML_Element* CXML_Element::Parse(
-    const CFX_RetainPtr<IFX_SeekableReadStream>& pFile,
-    bool bSaveSpaceChars,
-    FX_FILESIZE* pParsedSize) {
-  CXML_Parser parser;
-  if (!parser.Init(pFile))
-    return nullptr;
+CXML_Element::CXML_Element(const CXML_Element* pParent,
+                           const CFX_ByteStringC& qSpace,
+                           const CFX_ByteStringC& tagname)
+    : m_pParent(pParent), m_QSpaceName(qSpace), m_TagName(tagname) {}
 
-  return XML_ContinueParse(parser, bSaveSpaceChars, pParsedSize);
-}
-
-CXML_Element* CXML_Element::Parse(
-    const CFX_RetainPtr<IFX_BufferedReadStream>& pBuffer,
-    bool bSaveSpaceChars,
-    FX_FILESIZE* pParsedSize) {
-  CXML_Parser parser;
-  if (!parser.Init(pBuffer))
-    return nullptr;
-
-  return XML_ContinueParse(parser, bSaveSpaceChars, pParsedSize);
-}
-
-CXML_Element::CXML_Element() : m_QSpaceName(), m_TagName(), m_AttrMap() {}
-CXML_Element::CXML_Element(const CFX_ByteStringC& qSpace,
-                           const CFX_ByteStringC& tagName)
-    : m_QSpaceName(), m_TagName(), m_AttrMap() {
-  m_QSpaceName = qSpace;
-  m_TagName = tagName;
-}
-CXML_Element::CXML_Element(const CFX_ByteStringC& qTagName)
-    : m_pParent(nullptr), m_QSpaceName(), m_TagName(), m_AttrMap() {
-  SetTag(qTagName);
-}
 CXML_Element::~CXML_Element() {
   Empty();
 }
+
 void CXML_Element::Empty() {
   RemoveChildren();
 }
@@ -763,36 +706,38 @@
   const CFX_WideString* pwsSpace;
   const CXML_Element* pElement = this;
   do {
-    if (qName.IsEmpty()) {
+    if (qName.IsEmpty())
       pwsSpace = pElement->m_AttrMap.Lookup("", "xmlns");
-    } else {
+    else
       pwsSpace = pElement->m_AttrMap.Lookup("xmlns", qName);
-    }
-    if (pwsSpace) {
+    if (pwsSpace)
       break;
-    }
+
     pElement = pElement->GetParent();
   } while (pElement);
-  return pwsSpace ? FX_UTF8Encode(*pwsSpace) : CFX_ByteString();
+  return pwsSpace ? pwsSpace->UTF8Encode() : CFX_ByteString();
 }
+
 void CXML_Element::GetAttrByIndex(int index,
                                   CFX_ByteString& space,
                                   CFX_ByteString& name,
                                   CFX_WideString& value) const {
-  if (index < 0 || index >= m_AttrMap.GetSize()) {
+  if (index < 0 || index >= m_AttrMap.GetSize())
     return;
-  }
+
   CXML_AttrItem& item = m_AttrMap.GetAt(index);
   space = item.m_QSpaceName;
   name = item.m_AttrName;
   value = item.m_Value;
 }
+
 bool CXML_Element::HasAttr(const CFX_ByteStringC& name) const {
   CFX_ByteStringC bsSpace;
   CFX_ByteStringC bsName;
   FX_XML_SplitQualifiedName(name, bsSpace, bsName);
   return !!m_AttrMap.Lookup(CFX_ByteString(bsSpace), CFX_ByteString(bsName));
 }
+
 bool CXML_Element::GetAttrValue(const CFX_ByteStringC& name,
                                 CFX_WideString& attribute) const {
   CFX_ByteStringC bsSpace;
@@ -800,17 +745,19 @@
   FX_XML_SplitQualifiedName(name, bsSpace, bsName);
   return GetAttrValue(bsSpace, bsName, attribute);
 }
+
 bool CXML_Element::GetAttrValue(const CFX_ByteStringC& space,
                                 const CFX_ByteStringC& name,
                                 CFX_WideString& attribute) const {
   const CFX_WideString* pValue =
       m_AttrMap.Lookup(CFX_ByteString(space), CFX_ByteString(name));
-  if (pValue) {
-    attribute = *pValue;
-    return true;
-  }
-  return false;
+  if (!pValue)
+    return false;
+
+  attribute = *pValue;
+  return true;
 }
+
 bool CXML_Element::GetAttrInteger(const CFX_ByteStringC& name,
                                   int& attribute) const {
   CFX_ByteStringC bsSpace;
@@ -818,43 +765,49 @@
   FX_XML_SplitQualifiedName(name, bsSpace, bsName);
   const CFX_WideString* pwsValue =
       m_AttrMap.Lookup(CFX_ByteString(bsSpace), CFX_ByteString(bsName));
-  if (pwsValue) {
-    attribute = pwsValue->GetInteger();
-    return true;
-  }
-  return false;
+  if (!pwsValue)
+    return false;
+
+  attribute = pwsValue->GetInteger();
+  return true;
 }
+
 bool CXML_Element::GetAttrInteger(const CFX_ByteStringC& space,
                                   const CFX_ByteStringC& name,
                                   int& attribute) const {
   const CFX_WideString* pwsValue =
       m_AttrMap.Lookup(CFX_ByteString(space), CFX_ByteString(name));
-  if (pwsValue) {
-    attribute = pwsValue->GetInteger();
-    return true;
-  }
-  return false;
+  if (!pwsValue)
+    return false;
+
+  attribute = pwsValue->GetInteger();
+  return true;
 }
+
 bool CXML_Element::GetAttrFloat(const CFX_ByteStringC& name,
                                 FX_FLOAT& attribute) const {
-  CFX_ByteStringC bsSpace, bsName;
+  CFX_ByteStringC bsSpace;
+  CFX_ByteStringC bsName;
   FX_XML_SplitQualifiedName(name, bsSpace, bsName);
   return GetAttrFloat(bsSpace, bsName, attribute);
 }
+
 bool CXML_Element::GetAttrFloat(const CFX_ByteStringC& space,
                                 const CFX_ByteStringC& name,
                                 FX_FLOAT& attribute) const {
   const CFX_WideString* pValue =
       m_AttrMap.Lookup(CFX_ByteString(space), CFX_ByteString(name));
-  if (pValue) {
-    attribute = pValue->GetFloat();
-    return true;
-  }
-  return false;
+  if (!pValue)
+    return false;
+
+  attribute = pValue->GetFloat();
+  return true;
 }
+
 CXML_Element::ChildType CXML_Element::GetChildType(uint32_t index) const {
   return index < m_Children.size() ? m_Children[index].type : Invalid;
 }
+
 CFX_WideString CXML_Element::GetContent(uint32_t index) const {
   if (index < m_Children.size() && m_Children[index].type == Content) {
     CXML_Content* pContent =
@@ -864,12 +817,13 @@
   }
   return CFX_WideString();
 }
+
 CXML_Element* CXML_Element::GetElement(uint32_t index) const {
-  if (index < m_Children.size() && m_Children[index].type == Element) {
+  if (index < m_Children.size() && m_Children[index].type == Element)
     return static_cast<CXML_Element*>(m_Children[index].child);
-  }
   return nullptr;
 }
+
 uint32_t CXML_Element::CountElements(const CFX_ByteStringC& space,
                                      const CFX_ByteStringC& tag) const {
   int count = 0;
@@ -885,6 +839,7 @@
   }
   return count;
 }
+
 CXML_Element* CXML_Element::GetElement(const CFX_ByteStringC& space,
                                        const CFX_ByteStringC& tag,
                                        int index) const {
@@ -904,6 +859,7 @@
   }
   return nullptr;
 }
+
 uint32_t CXML_Element::FindElement(CXML_Element* pChild) const {
   int index = 0;
   for (const ChildRecord& record : m_Children) {
diff --git a/core/fxcrt/xml_int.h b/core/fxcrt/xml_int.h
index e617a77..96a7da9 100644
--- a/core/fxcrt/xml_int.h
+++ b/core/fxcrt/xml_int.h
@@ -8,6 +8,7 @@
 #define CORE_FXCRT_XML_INT_H_
 
 #include <algorithm>
+#include <memory>
 
 #include "core/fxcrt/fx_stream.h"
 
@@ -19,23 +20,21 @@
   CXML_Parser();
   ~CXML_Parser();
 
-  bool Init(uint8_t* pBuffer, size_t size);
-  bool Init(const CFX_RetainPtr<IFX_SeekableReadStream>& pFileRead);
-  bool Init(const CFX_RetainPtr<IFX_BufferedReadStream>& pBuffer);
-  bool Init();
+  bool Init(const uint8_t* pBuffer, size_t size);
   bool ReadNextBlock();
   bool IsEOF();
   bool HaveAvailData();
   void SkipWhiteSpaces();
-  void GetName(CFX_ByteString& space, CFX_ByteString& name);
+  void GetName(CFX_ByteString* space, CFX_ByteString* name);
   void GetAttrValue(CFX_WideString& value);
   uint32_t GetCharRef();
-  void GetTagName(CFX_ByteString& space,
-                  CFX_ByteString& name,
-                  bool& bEndTag,
-                  bool bStartTag = false);
+  void GetTagName(bool bStartTag,
+                  bool* bEndTag,
+                  CFX_ByteString* space,
+                  CFX_ByteString* name);
   void SkipLiterals(const CFX_ByteStringC& str);
-  CXML_Element* ParseElement(CXML_Element* pParent, bool bStartTag = false);
+  std::unique_ptr<CXML_Element> ParseElement(CXML_Element* pParent,
+                                             bool bStartTag);
   void InsertContentSegment(bool bCDATA,
                             const CFX_WideStringC& content,
                             CXML_Element* pElement);
@@ -43,7 +42,6 @@
 
   CFX_RetainPtr<IFX_BufferedReadStream> m_pDataAcc;
   FX_FILESIZE m_nOffset;
-  bool m_bSaveSpaceChars;
   const uint8_t* m_pBuffer;
   size_t m_dwBufferSize;
   FX_FILESIZE m_nBufferOffset;
diff --git a/core/fxge/agg/fx_agg_driver.cpp b/core/fxge/agg/fx_agg_driver.cpp
index 94fe72d..8c72777 100644
--- a/core/fxge/agg/fx_agg_driver.cpp
+++ b/core/fxge/agg/fx_agg_driver.cpp
@@ -32,9 +32,9 @@
 
 namespace {
 
-void HardClip(FX_FLOAT& x, FX_FLOAT& y) {
-  x = std::max(std::min(x, 50000.0f), -50000.0f);
-  y = std::max(std::min(y, 50000.0f), -50000.0f);
+CFX_PointF HardClip(const CFX_PointF& pos) {
+  return CFX_PointF(std::max(std::min(pos.x, 50000.0f), -50000.0f),
+                    std::max(std::min(pos.y, 50000.0f), -50000.0f));
 }
 
 void RgbByteOrderSetPixel(CFX_DIBitmap* pBitmap, int x, int y, uint32_t argb) {
@@ -273,46 +273,46 @@
 
 void CAgg_PathData::BuildPath(const CFX_PathData* pPathData,
                               const CFX_Matrix* pObject2Device) {
-  int nPoints = pPathData->GetPointCount();
-  FX_PATHPOINT* pPoints = pPathData->GetPoints();
-  for (int i = 0; i < nPoints; i++) {
-    FX_FLOAT x = pPoints[i].m_PointX, y = pPoints[i].m_PointY;
-    if (pObject2Device) {
-      pObject2Device->Transform(x, y);
-    }
-    HardClip(x, y);
-    int point_type = pPoints[i].m_Flag & FXPT_TYPE;
-    if (point_type == FXPT_MOVETO) {
-      m_PathData.move_to(x, y);
-    } else if (point_type == FXPT_LINETO) {
-      if (pPoints[i - 1].m_Flag == FXPT_MOVETO &&
-          (i == nPoints - 1 || pPoints[i + 1].m_Flag == FXPT_MOVETO) &&
-          pPoints[i].m_PointX == pPoints[i - 1].m_PointX &&
-          pPoints[i].m_PointY == pPoints[i - 1].m_PointY) {
-        x += 1;
+  const std::vector<FX_PATHPOINT>& pPoints = pPathData->GetPoints();
+  for (size_t i = 0; i < pPoints.size(); i++) {
+    CFX_PointF pos = pPoints[i].m_Point;
+    if (pObject2Device)
+      pos = pObject2Device->Transform(pos);
+
+    pos = HardClip(pos);
+    FXPT_TYPE point_type = pPoints[i].m_Type;
+    if (point_type == FXPT_TYPE::MoveTo) {
+      m_PathData.move_to(pos.x, pos.y);
+    } else if (point_type == FXPT_TYPE::LineTo) {
+      if (pPoints[i - 1].IsTypeAndOpen(FXPT_TYPE::MoveTo) &&
+          (i == pPoints.size() - 1 ||
+           pPoints[i + 1].IsTypeAndOpen(FXPT_TYPE::MoveTo)) &&
+          pPoints[i].m_Point == pPoints[i - 1].m_Point) {
+        pos.x += 1;
       }
-      m_PathData.line_to(x, y);
-    } else if (point_type == FXPT_BEZIERTO) {
-      FX_FLOAT x0 = pPoints[i - 1].m_PointX, y0 = pPoints[i - 1].m_PointY;
-      FX_FLOAT x2 = pPoints[i + 1].m_PointX, y2 = pPoints[i + 1].m_PointY;
-      FX_FLOAT x3 = pPoints[i + 2].m_PointX, y3 = pPoints[i + 2].m_PointY;
+      m_PathData.line_to(pos.x, pos.y);
+    } else if (point_type == FXPT_TYPE::BezierTo) {
+      CFX_PointF pos0 = pPoints[i - 1].m_Point;
+      CFX_PointF pos2 = pPoints[i + 1].m_Point;
+      CFX_PointF pos3 = pPoints[i + 2].m_Point;
       if (pObject2Device) {
-        pObject2Device->Transform(x0, y0);
-        pObject2Device->Transform(x2, y2);
-        pObject2Device->Transform(x3, y3);
+        pos0 = pObject2Device->Transform(pos0);
+        pos2 = pObject2Device->Transform(pos2);
+        pos3 = pObject2Device->Transform(pos3);
       }
-      HardClip(x0, y0);
-      HardClip(x2, y2);
-      HardClip(x3, y3);
-      agg::curve4 curve(x0, y0, x, y, x2, y2, x3, y3);
+      pos0 = HardClip(pos0);
+      pos2 = HardClip(pos2);
+      pos3 = HardClip(pos3);
+      agg::curve4 curve(pos0.x, pos0.y, pos.x, pos.y, pos2.x, pos2.y, pos3.x,
+                        pos3.y);
       i += 2;
       m_PathData.add_path_curve(curve);
     }
-    if (pPoints[i].m_Flag & FXPT_CLOSEFIGURE) {
+    if (pPoints[i].m_CloseFigure)
       m_PathData.end_poly();
-    }
   }
 }
+
 namespace agg {
 
 template <class BaseRenderer>
@@ -552,7 +552,8 @@
     m_pClipRgn = pdfium::MakeUnique<CFX_ClipRgn>(
         GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT));
   }
-  if (pPathData->GetPointCount() == 5 || pPathData->GetPointCount() == 4) {
+  size_t size = pPathData->GetPoints().size();
+  if (size == 5 || size == 4) {
     CFX_FloatRect rectf;
     if (pPathData->IsRect(pObject2Device, &rectf)) {
       rectf.Intersect(
@@ -1500,14 +1501,16 @@
     matrix1.a =
         std::max(FXSYS_fabs(pObject2Device->a), FXSYS_fabs(pObject2Device->b));
     matrix1.d = matrix1.a;
-    matrix2.Set(pObject2Device->a / matrix1.a, pObject2Device->b / matrix1.a,
-                pObject2Device->c / matrix1.d, pObject2Device->d / matrix1.d, 0,
-                0);
+    matrix2 = CFX_Matrix(
+        pObject2Device->a / matrix1.a, pObject2Device->b / matrix1.a,
+        pObject2Device->c / matrix1.d, pObject2Device->d / matrix1.d, 0, 0);
+
     CFX_Matrix mtRervese;
     mtRervese.SetReverse(matrix2);
     matrix1 = *pObject2Device;
     matrix1.Concat(mtRervese);
   }
+
   CAgg_PathData path_data;
   path_data.BuildPath(pPathData, &matrix1);
   agg::rasterizer_scanline_aa rasterizer;
diff --git a/core/fxge/apple/fx_apple_platform.cpp b/core/fxge/apple/fx_apple_platform.cpp
index 7fc12fd..f576eb0 100644
--- a/core/fxge/apple/fx_apple_platform.cpp
+++ b/core/fxge/apple/fx_apple_platform.cpp
@@ -35,13 +35,11 @@
   if (nChars == 0)
     return true;
 
-  CFX_Matrix new_matrix;
   bool bNegSize = font_size < 0;
   if (bNegSize)
     font_size = -font_size;
 
-  FX_FLOAT ori_x = pCharPos[0].m_OriginX, ori_y = pCharPos[0].m_OriginY;
-  new_matrix.Transform(ori_x, ori_y);
+  CFX_Matrix new_matrix;
   if (pObject2Device)
     new_matrix.Concat(*pObject2Device);
 
@@ -63,10 +61,10 @@
     glyph_indices[i] =
         pCharPos[i].m_ExtGID ? pCharPos[i].m_ExtGID : pCharPos[i].m_GlyphIndex;
     if (bNegSize)
-      glyph_positions[i].x = -pCharPos[i].m_OriginX;
+      glyph_positions[i].x = -pCharPos[i].m_Origin.x;
     else
-      glyph_positions[i].x = pCharPos[i].m_OriginX;
-    glyph_positions[i].y = pCharPos[i].m_OriginY;
+      glyph_positions[i].x = pCharPos[i].m_Origin.x;
+    glyph_positions[i].y = pCharPos[i].m_Origin.y;
   }
   if (bNegSize) {
     new_matrix.a = -new_matrix.a;
diff --git a/core/fxge/cfx_pathdata.h b/core/fxge/cfx_pathdata.h
index 3e0e11c..b0e30e3 100644
--- a/core/fxge/cfx_pathdata.h
+++ b/core/fxge/cfx_pathdata.h
@@ -7,14 +7,26 @@
 #ifndef CORE_FXGE_CFX_PATHDATA_H_
 #define CORE_FXGE_CFX_PATHDATA_H_
 
+#include <vector>
+
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_system.h"
 #include "core/fxge/cfx_renderdevice.h"
 
-struct FX_PATHPOINT {
-  FX_FLOAT m_PointX;
-  FX_FLOAT m_PointY;
-  int m_Flag;
+class FX_PATHPOINT {
+ public:
+  FX_PATHPOINT();
+  FX_PATHPOINT(const CFX_PointF& point, FXPT_TYPE type, bool close);
+  FX_PATHPOINT(const FX_PATHPOINT& other);
+  ~FX_PATHPOINT();
+
+  bool IsTypeAndOpen(FXPT_TYPE type) const {
+    return m_Type == type && !m_CloseFigure;
+  }
+
+  CFX_PointF m_Point;
+  FXPT_TYPE m_Type;
+  bool m_CloseFigure;
 };
 
 class CFX_PathData {
@@ -23,34 +35,36 @@
   CFX_PathData(const CFX_PathData& src);
   ~CFX_PathData();
 
-  int GetPointCount() const { return m_PointCount; }
-  int GetFlag(int index) const { return m_pPoints[index].m_Flag; }
-  FX_FLOAT GetPointX(int index) const { return m_pPoints[index].m_PointX; }
-  FX_FLOAT GetPointY(int index) const { return m_pPoints[index].m_PointY; }
-  FX_PATHPOINT* GetPoints() const { return m_pPoints; }
+  void Clear();
 
-  void SetPointCount(int nPoints);
-  void AllocPointCount(int nPoints);
-  void AddPointCount(int addPoints);
+  FXPT_TYPE GetType(int index) const { return m_Points[index].m_Type; }
+  bool IsClosingFigure(int index) const {
+    return m_Points[index].m_CloseFigure;
+  }
+
+  CFX_PointF GetPoint(int index) const { return m_Points[index].m_Point; }
+  const std::vector<FX_PATHPOINT>& GetPoints() const { return m_Points; }
+  std::vector<FX_PATHPOINT>& GetPoints() { return m_Points; }
+
   CFX_FloatRect GetBoundingBox() const;
   CFX_FloatRect GetBoundingBox(FX_FLOAT line_width, FX_FLOAT miter_limit) const;
+
   void Transform(const CFX_Matrix* pMatrix);
   bool IsRect() const;
-  bool GetZeroAreaPath(CFX_PathData& NewPath,
-                       CFX_Matrix* pMatrix,
-                       bool& bThin,
-                       bool bAdjust) const;
+  bool GetZeroAreaPath(const CFX_Matrix* pMatrix,
+                       bool bAdjust,
+                       CFX_PathData* NewPath,
+                       bool* bThin,
+                       bool* setIdentity) const;
   bool IsRect(const CFX_Matrix* pMatrix, CFX_FloatRect* rect) const;
+
   void Append(const CFX_PathData* pSrc, const CFX_Matrix* pMatrix);
   void AppendRect(FX_FLOAT left, FX_FLOAT bottom, FX_FLOAT right, FX_FLOAT top);
-  void SetPoint(int index, FX_FLOAT x, FX_FLOAT y, int flag);
-  void TrimPoints(int nPoints);
-  void Copy(const CFX_PathData& src);
+  void AppendPoint(const CFX_PointF& pos, FXPT_TYPE type, bool closeFigure);
+  void ClosePath();
 
  private:
-  int m_PointCount;
-  int m_AllocCount;
-  FX_PATHPOINT* m_pPoints;
+  std::vector<FX_PATHPOINT> m_Points;
 };
 
 #endif  // CORE_FXGE_CFX_PATHDATA_H_
diff --git a/core/fxge/cfx_renderdevice.h b/core/fxge/cfx_renderdevice.h
index 800d0c7..2e9abf9 100644
--- a/core/fxge/cfx_renderdevice.h
+++ b/core/fxge/cfx_renderdevice.h
@@ -27,12 +27,6 @@
 #define FXDC_DISPLAY 1
 #define FXDC_PRINTER 2
 
-#define FXPT_CLOSEFIGURE 0x01
-#define FXPT_LINETO 0x02
-#define FXPT_BEZIERTO 0x04
-#define FXPT_MOVETO 0x06
-#define FXPT_TYPE 0x06
-
 #define FXRC_GET_BITS 0x01
 #define FXRC_BIT_MASK 0x02
 #define FXRC_ALPHA_MASK 0x04
@@ -66,10 +60,16 @@
 #define FXTEXT_PRINTIMAGETEXT 0x10
 #define FXTEXT_NOSMOOTH 0x20
 
-struct FXTEXT_CHARPOS {
+enum class FXPT_TYPE : uint8_t { LineTo, BezierTo, MoveTo };
+
+class FXTEXT_CHARPOS {
+ public:
+  FXTEXT_CHARPOS();
+  FXTEXT_CHARPOS(const FXTEXT_CHARPOS&);
+  ~FXTEXT_CHARPOS();
+
   FX_FLOAT m_AdjustMatrix[4];
-  FX_FLOAT m_OriginX;
-  FX_FLOAT m_OriginY;
+  CFX_PointF m_Origin;
   uint32_t m_GlyphIndex;
   int32_t m_FontCharWidth;
 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
diff --git a/core/fxge/dib/fx_dib_composite.cpp b/core/fxge/dib/fx_dib_composite.cpp
index e3dc740..072ebbd 100644
--- a/core/fxge/dib/fx_dib_composite.cpp
+++ b/core/fxge/dib/fx_dib_composite.cpp
@@ -4014,6 +4014,7 @@
   m_CacheSize = 0;
   m_bRgbByteOrder = false;
   m_BlendType = FXDIB_BLEND_NORMAL;
+  m_pIccTransform = nullptr;
 }
 
 CFX_ScanlineCompositor::~CFX_ScanlineCompositor() {
diff --git a/core/fxge/dib/fx_dib_main.cpp b/core/fxge/dib/fx_dib_main.cpp
index 8e6366d..96cae9d 100644
--- a/core/fxge/dib/fx_dib_main.cpp
+++ b/core/fxge/dib/fx_dib_main.cpp
@@ -1471,6 +1471,7 @@
 
 CFX_ImageRenderer::CFX_ImageRenderer() {
   m_Status = 0;
+  m_pIccTransform = nullptr;
   m_bRgbByteOrder = false;
   m_BlendType = FXDIB_BLEND_NORMAL;
 }
diff --git a/core/fxge/dib/fx_dib_transform.cpp b/core/fxge/dib/fx_dib_transform.cpp
index 1c29ada..bd88272 100644
--- a/core/fxge/dib/fx_dib_transform.cpp
+++ b/core/fxge/dib/fx_dib_transform.cpp
@@ -396,12 +396,13 @@
   CFX_Matrix stretch2dest(1.0f, 0.0f, 0.0f, -1.0f, 0.0f,
                           (FX_FLOAT)(stretch_height));
   stretch2dest.Concat(
-      m_pMatrix->a / stretch_width, m_pMatrix->b / stretch_width,
-      m_pMatrix->c / stretch_height, m_pMatrix->d / stretch_height,
-      m_pMatrix->e, m_pMatrix->f);
+      CFX_Matrix(m_pMatrix->a / stretch_width, m_pMatrix->b / stretch_width,
+                 m_pMatrix->c / stretch_height, m_pMatrix->d / stretch_height,
+                 m_pMatrix->e, m_pMatrix->f));
   m_dest2stretch.SetReverse(stretch2dest);
+
   CFX_FloatRect clip_rect_f(result_clip);
-  clip_rect_f.Transform(&m_dest2stretch);
+  m_dest2stretch.TransformRect(clip_rect_f);
   m_StretchClip = clip_rect_f.GetOuterRect();
   m_StretchClip.Intersect(0, 0, stretch_width, stretch_height);
   m_Stretcher = pdfium::MakeUnique<CFX_ImageStretcher>(
@@ -455,7 +456,7 @@
   CFX_Matrix result2stretch(1.0f, 0.0f, 0.0f, 1.0f, (FX_FLOAT)(m_result.left),
                             (FX_FLOAT)(m_result.top));
   result2stretch.Concat(m_dest2stretch);
-  result2stretch.TranslateI(-m_StretchClip.left, -m_StretchClip.top);
+  result2stretch.Translate(-m_StretchClip.left, -m_StretchClip.top);
   if (!stretch_buf_mask && pTransformed->m_pAlphaMask) {
     pTransformed->m_pAlphaMask->Clear(0xff000000);
   } else if (pTransformed->m_pAlphaMask) {
diff --git a/core/fxge/fx_font.h b/core/fxge/fx_font.h
index 224720f..07392fa 100644
--- a/core/fxge/fx_font.h
+++ b/core/fxge/fx_font.h
@@ -58,13 +58,18 @@
 #define FXFONT_FW_NORMAL 400
 #define FXFONT_FW_BOLD 700
 
-/* Font styles */
-#define FXFONT_FIXED_PITCH 0x01
-#define FXFONT_SERIF 0x02
-#define FXFONT_SYMBOLIC 0x04
-#define FXFONT_SCRIPT 0x08
-#define FXFONT_ITALIC 0x40
-#define FXFONT_BOLD 0x40000
+/* Font styles as defined in PDF 1.7 Table 5.20 */
+#define FXFONT_FIXED_PITCH (1 << 0)
+#define FXFONT_SERIF (1 << 1)
+#define FXFONT_SYMBOLIC (1 << 2)
+#define FXFONT_SCRIPT (1 << 3)
+#define FXFONT_NONSYMBOLIC (1 << 5)
+#define FXFONT_ITALIC (1 << 6)
+#define FXFONT_ALLCAP (1 << 16)
+#define FXFONT_SMALLCAP (1 << 17)
+#define FXFONT_BOLD (1 << 18)
+
+/* Other font flags */
 #define FXFONT_USEEXTERNATTR 0x80000
 #define FXFONT_CIDFONT 0x100000
 #ifdef PDF_ENABLE_XFA
@@ -222,12 +227,15 @@
   CFX_DIBitmap m_Bitmap;
 };
 
-struct FXTEXT_GLYPHPOS {
+class FXTEXT_GLYPHPOS {
+ public:
+  FXTEXT_GLYPHPOS();
+  FXTEXT_GLYPHPOS(const FXTEXT_GLYPHPOS&);
+  ~FXTEXT_GLYPHPOS();
+
   const CFX_GlyphBitmap* m_pGlyph;
-  int m_OriginX;
-  int m_OriginY;
-  FX_FLOAT m_fOriginX;
-  FX_FLOAT m_fOriginY;
+  CFX_Point m_Origin;
+  CFX_PointF m_fOrigin;
 };
 
 FX_RECT FXGE_GetGlyphsBBox(const std::vector<FXTEXT_GLYPHPOS>& glyphs,
diff --git a/core/fxge/ge/cfx_facecache.cpp b/core/fxge/ge/cfx_facecache.cpp
index cbaa07e..314c95b 100644
--- a/core/fxge/ge/cfx_facecache.cpp
+++ b/core/fxge/ge/cfx_facecache.cpp
@@ -101,10 +101,10 @@
     return nullptr;
 
   FXFT_Matrix ft_matrix;
-  ft_matrix.xx = (signed long)(pMatrix->GetA() / 64 * 65536);
-  ft_matrix.xy = (signed long)(pMatrix->GetC() / 64 * 65536);
-  ft_matrix.yx = (signed long)(pMatrix->GetB() / 64 * 65536);
-  ft_matrix.yy = (signed long)(pMatrix->GetD() / 64 * 65536);
+  ft_matrix.xx = (signed long)(pMatrix->a / 64 * 65536);
+  ft_matrix.xy = (signed long)(pMatrix->c / 64 * 65536);
+  ft_matrix.yx = (signed long)(pMatrix->b / 64 * 65536);
+  ft_matrix.yy = (signed long)(pMatrix->d / 64 * 65536);
   bool bUseCJKSubFont = false;
   const CFX_SubstFont* pSubstFont = pFont->GetSubstFont();
   if (pSubstFont) {
diff --git a/core/fxge/ge/cfx_font.cpp b/core/fxge/ge/cfx_font.cpp
index 24dcb87..87157b0 100644
--- a/core/fxge/ge/cfx_font.cpp
+++ b/core/fxge/ge/cfx_font.cpp
@@ -28,9 +28,7 @@
 namespace {
 
 typedef struct {
-  bool m_bCount;
-  int m_PointCount;
-  FX_PATHPOINT* m_pPoints;
+  CFX_PathData* m_pPath;
   int m_CurX;
   int m_CurY;
   FX_FLOAT m_CoordUnit;
@@ -86,59 +84,47 @@
 }
 
 void Outline_CheckEmptyContour(OUTLINE_PARAMS* param) {
-  if (param->m_PointCount >= 2 &&
-      param->m_pPoints[param->m_PointCount - 2].m_Flag == FXPT_MOVETO &&
-      param->m_pPoints[param->m_PointCount - 2].m_PointX ==
-          param->m_pPoints[param->m_PointCount - 1].m_PointX &&
-      param->m_pPoints[param->m_PointCount - 2].m_PointY ==
-          param->m_pPoints[param->m_PointCount - 1].m_PointY) {
-    param->m_PointCount -= 2;
+  std::vector<FX_PATHPOINT>& points = param->m_pPath->GetPoints();
+  size_t size = points.size();
+
+  if (size >= 2 && points[size - 2].IsTypeAndOpen(FXPT_TYPE::MoveTo) &&
+      points[size - 2].m_Point == points[size - 1].m_Point) {
+    size -= 2;
   }
-  if (param->m_PointCount >= 4 &&
-      param->m_pPoints[param->m_PointCount - 4].m_Flag == FXPT_MOVETO &&
-      param->m_pPoints[param->m_PointCount - 3].m_Flag == FXPT_BEZIERTO &&
-      param->m_pPoints[param->m_PointCount - 3].m_PointX ==
-          param->m_pPoints[param->m_PointCount - 4].m_PointX &&
-      param->m_pPoints[param->m_PointCount - 3].m_PointY ==
-          param->m_pPoints[param->m_PointCount - 4].m_PointY &&
-      param->m_pPoints[param->m_PointCount - 2].m_PointX ==
-          param->m_pPoints[param->m_PointCount - 4].m_PointX &&
-      param->m_pPoints[param->m_PointCount - 2].m_PointY ==
-          param->m_pPoints[param->m_PointCount - 4].m_PointY &&
-      param->m_pPoints[param->m_PointCount - 1].m_PointX ==
-          param->m_pPoints[param->m_PointCount - 4].m_PointX &&
-      param->m_pPoints[param->m_PointCount - 1].m_PointY ==
-          param->m_pPoints[param->m_PointCount - 4].m_PointY) {
-    param->m_PointCount -= 4;
+  if (size >= 4 && points[size - 4].IsTypeAndOpen(FXPT_TYPE::MoveTo) &&
+      points[size - 3].IsTypeAndOpen(FXPT_TYPE::BezierTo) &&
+      points[size - 3].m_Point == points[size - 4].m_Point &&
+      points[size - 2].m_Point == points[size - 4].m_Point &&
+      points[size - 1].m_Point == points[size - 4].m_Point) {
+    size -= 4;
   }
+  points.resize(size);
 }
 
 int Outline_MoveTo(const FXFT_Vector* to, void* user) {
   OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
-  if (!param->m_bCount) {
-    Outline_CheckEmptyContour(param);
-    param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit;
-    param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit;
-    param->m_pPoints[param->m_PointCount].m_Flag = FXPT_MOVETO;
-    param->m_CurX = to->x;
-    param->m_CurY = to->y;
-    if (param->m_PointCount)
-      param->m_pPoints[param->m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
-  }
-  param->m_PointCount++;
+
+  Outline_CheckEmptyContour(param);
+
+  param->m_pPath->ClosePath();
+  param->m_pPath->AppendPoint(
+      CFX_PointF(to->x / param->m_CoordUnit, to->y / param->m_CoordUnit),
+      FXPT_TYPE::MoveTo, false);
+
+  param->m_CurX = to->x;
+  param->m_CurY = to->y;
   return 0;
 }
 
 int Outline_LineTo(const FXFT_Vector* to, void* user) {
   OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
-  if (!param->m_bCount) {
-    param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit;
-    param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit;
-    param->m_pPoints[param->m_PointCount].m_Flag = FXPT_LINETO;
-    param->m_CurX = to->x;
-    param->m_CurY = to->y;
-  }
-  param->m_PointCount++;
+
+  param->m_pPath->AppendPoint(
+      CFX_PointF(to->x / param->m_CoordUnit, to->y / param->m_CoordUnit),
+      FXPT_TYPE::LineTo, false);
+
+  param->m_CurX = to->x;
+  param->m_CurY = to->y;
   return 0;
 }
 
@@ -146,28 +132,25 @@
                     const FXFT_Vector* to,
                     void* user) {
   OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
-  if (!param->m_bCount) {
-    param->m_pPoints[param->m_PointCount].m_PointX =
-        (param->m_CurX + (control->x - param->m_CurX) * 2 / 3) /
-        param->m_CoordUnit;
-    param->m_pPoints[param->m_PointCount].m_PointY =
-        (param->m_CurY + (control->y - param->m_CurY) * 2 / 3) /
-        param->m_CoordUnit;
-    param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO;
-    param->m_pPoints[param->m_PointCount + 1].m_PointX =
-        (control->x + (to->x - control->x) / 3) / param->m_CoordUnit;
-    param->m_pPoints[param->m_PointCount + 1].m_PointY =
-        (control->y + (to->y - control->y) / 3) / param->m_CoordUnit;
-    param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO;
-    param->m_pPoints[param->m_PointCount + 2].m_PointX =
-        to->x / param->m_CoordUnit;
-    param->m_pPoints[param->m_PointCount + 2].m_PointY =
-        to->y / param->m_CoordUnit;
-    param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO;
-    param->m_CurX = to->x;
-    param->m_CurY = to->y;
-  }
-  param->m_PointCount += 3;
+
+  param->m_pPath->AppendPoint(
+      CFX_PointF((param->m_CurX + (control->x - param->m_CurX) * 2 / 3) /
+                     param->m_CoordUnit,
+                 (param->m_CurY + (control->y - param->m_CurY) * 2 / 3) /
+                     param->m_CoordUnit),
+      FXPT_TYPE::BezierTo, false);
+
+  param->m_pPath->AppendPoint(
+      CFX_PointF((control->x + (to->x - control->x) / 3) / param->m_CoordUnit,
+                 (control->y + (to->y - control->y) / 3) / param->m_CoordUnit),
+      FXPT_TYPE::BezierTo, false);
+
+  param->m_pPath->AppendPoint(
+      CFX_PointF(to->x / param->m_CoordUnit, to->y / param->m_CoordUnit),
+      FXPT_TYPE::BezierTo, false);
+
+  param->m_CurX = to->x;
+  param->m_CurY = to->y;
   return 0;
 }
 
@@ -176,26 +159,21 @@
                     const FXFT_Vector* to,
                     void* user) {
   OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
-  if (!param->m_bCount) {
-    param->m_pPoints[param->m_PointCount].m_PointX =
-        control1->x / param->m_CoordUnit;
-    param->m_pPoints[param->m_PointCount].m_PointY =
-        control1->y / param->m_CoordUnit;
-    param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO;
-    param->m_pPoints[param->m_PointCount + 1].m_PointX =
-        control2->x / param->m_CoordUnit;
-    param->m_pPoints[param->m_PointCount + 1].m_PointY =
-        control2->y / param->m_CoordUnit;
-    param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO;
-    param->m_pPoints[param->m_PointCount + 2].m_PointX =
-        to->x / param->m_CoordUnit;
-    param->m_pPoints[param->m_PointCount + 2].m_PointY =
-        to->y / param->m_CoordUnit;
-    param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO;
-    param->m_CurX = to->x;
-    param->m_CurY = to->y;
-  }
-  param->m_PointCount += 3;
+
+  param->m_pPath->AppendPoint(CFX_PointF(control1->x / param->m_CoordUnit,
+                                         control1->y / param->m_CoordUnit),
+                              FXPT_TYPE::BezierTo, false);
+
+  param->m_pPath->AppendPoint(CFX_PointF(control2->x / param->m_CoordUnit,
+                                         control2->y / param->m_CoordUnit),
+                              FXPT_TYPE::BezierTo, false);
+
+  param->m_pPath->AppendPoint(
+      CFX_PointF(to->x / param->m_CoordUnit, to->y / param->m_CoordUnit),
+      FXPT_TYPE::BezierTo, false);
+
+  param->m_CurX = to->x;
+  param->m_CurY = to->y;
   return 0;
 }
 
@@ -672,6 +650,7 @@
       level = s_WeightPow[index] * 2;
     FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
   }
+
   FXFT_Outline_Funcs funcs;
   funcs.move_to = Outline_MoveTo;
   funcs.line_to = Outline_LineTo;
@@ -679,25 +658,21 @@
   funcs.cubic_to = Outline_CubicTo;
   funcs.shift = 0;
   funcs.delta = 0;
+
   OUTLINE_PARAMS params;
-  params.m_bCount = true;
-  params.m_PointCount = 0;
-  FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, &params);
-  if (params.m_PointCount == 0)
-    return nullptr;
-  CFX_PathData* pPath = new CFX_PathData;
-  pPath->SetPointCount(params.m_PointCount);
-  params.m_bCount = false;
-  params.m_PointCount = 0;
-  params.m_pPoints = pPath->GetPoints();
+  auto pPath = pdfium::MakeUnique<CFX_PathData>();
+  params.m_pPath = pPath.get();
   params.m_CurX = params.m_CurY = 0;
   params.m_CoordUnit = 64 * 64.0;
+
   FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, &params);
+  if (pPath->GetPoints().empty())
+    return nullptr;
+
   Outline_CheckEmptyContour(&params);
-  pPath->TrimPoints(params.m_PointCount);
-  if (params.m_PointCount)
-    pPath->GetPoints()[params.m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
-  return pPath;
+  pPath->ClosePath();
+
+  return pPath.release();
 }
 
 const CFX_GlyphBitmap* CFX_Font::LoadGlyphBitmap(uint32_t glyph_index,
diff --git a/core/fxge/ge/cfx_fontmapper.cpp b/core/fxge/ge/cfx_fontmapper.cpp
index 02143ec..064fc96 100644
--- a/core/fxge/ge/cfx_fontmapper.cpp
+++ b/core/fxge/ge/cfx_fontmapper.cpp
@@ -582,15 +582,16 @@
         bItalic = italic_angle != 0;
         weight = old_weight;
       }
-      if (family.Find("Narrow") > 0 || family.Find("Condensed") > 0) {
 #if _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_
+      if (SubstName.Find("Narrow") > 0 || SubstName.Find("Condensed") > 0)
         family = "LiberationSansNarrow";
 #elif _FXM_PLATFORM_ == _FXM_PLATFORM_ANDROID_
+      if (family.Find("Narrow") > 0 || family.Find("Condensed") > 0)
         family = "RobotoCondensed";
 #else
+      if (family.Find("Narrow") > 0 || family.Find("Condensed") > 0)
         family = "ArialNarrow";
-#endif
-      }
+#endif  // _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_
     } else {
       pSubstFont->m_bSubstCJK = true;
       if (nStyle)
diff --git a/core/fxge/ge/cfx_graphstate.cpp b/core/fxge/ge/cfx_graphstate.cpp
index 7eb6d3d..6357aa5 100644
--- a/core/fxge/ge/cfx_graphstate.cpp
+++ b/core/fxge/ge/cfx_graphstate.cpp
@@ -30,7 +30,7 @@
 }
 
 FX_FLOAT CFX_GraphState::GetLineWidth() const {
-  return m_Ref.GetObject()->m_LineWidth;
+  return m_Ref.GetObject() ? m_Ref.GetObject()->m_LineWidth : 1.f;
 }
 
 void CFX_GraphState::SetLineWidth(FX_FLOAT width) {
@@ -53,7 +53,7 @@
 }
 
 FX_FLOAT CFX_GraphState::GetMiterLimit() const {
-  return m_Ref.GetObject()->m_MiterLimit;
+  return m_Ref.GetObject() ? m_Ref.GetObject()->m_MiterLimit : 10.f;
 }
 
 void CFX_GraphState::SetMiterLimit(FX_FLOAT limit) {
diff --git a/core/fxge/ge/cfx_pathdata.cpp b/core/fxge/ge/cfx_pathdata.cpp
index 19e8bdb..9fa2cd2 100644
--- a/core/fxge/ge/cfx_pathdata.cpp
+++ b/core/fxge/ge/cfx_pathdata.cpp
@@ -9,263 +9,250 @@
 #include "core/fxcrt/fx_system.h"
 #include "third_party/base/numerics/safe_math.h"
 
-CFX_PathData::CFX_PathData()
-    : m_PointCount(0), m_AllocCount(0), m_pPoints(nullptr) {}
+namespace {
 
-CFX_PathData::~CFX_PathData() {
-  FX_Free(m_pPoints);
-}
-
-void CFX_PathData::SetPointCount(int nPoints) {
-  m_PointCount = nPoints;
-  if (m_AllocCount < nPoints) {
-    FX_Free(m_pPoints);
-    m_pPoints = FX_Alloc(FX_PATHPOINT, nPoints);
-    m_AllocCount = nPoints;
-  }
-}
-
-void CFX_PathData::AllocPointCount(int nPoints) {
-  if (m_AllocCount < nPoints) {
-    FX_PATHPOINT* pNewBuf = FX_Alloc(FX_PATHPOINT, nPoints);
-    if (m_PointCount) {
-      FXSYS_memcpy(pNewBuf, m_pPoints, m_PointCount * sizeof(FX_PATHPOINT));
+void UpdateLineEndPoints(CFX_FloatRect* rect,
+                         const CFX_PointF& start_pos,
+                         const CFX_PointF& end_pos,
+                         FX_FLOAT hw) {
+  if (start_pos.x == end_pos.x) {
+    if (start_pos.y == end_pos.y) {
+      rect->UpdateRect(end_pos.x + hw, end_pos.y + hw);
+      rect->UpdateRect(end_pos.x - hw, end_pos.y - hw);
+      return;
     }
-    FX_Free(m_pPoints);
-    m_pPoints = pNewBuf;
-    m_AllocCount = nPoints;
-  }
-}
 
-CFX_PathData::CFX_PathData(const CFX_PathData& src) {
-  m_PointCount = m_AllocCount = src.m_PointCount;
-  m_pPoints = FX_Alloc(FX_PATHPOINT, src.m_PointCount);
-  FXSYS_memcpy(m_pPoints, src.m_pPoints, sizeof(FX_PATHPOINT) * m_PointCount);
-}
+    FX_FLOAT point_y;
+    if (end_pos.y < start_pos.y)
+      point_y = end_pos.y - hw;
+    else
+      point_y = end_pos.y + hw;
 
-void CFX_PathData::TrimPoints(int nPoints) {
-  if (m_PointCount <= nPoints) {
+    rect->UpdateRect(end_pos.x + hw, point_y);
+    rect->UpdateRect(end_pos.x - hw, point_y);
     return;
   }
-  SetPointCount(nPoints);
+
+  if (start_pos.y == end_pos.y) {
+    FX_FLOAT point_x;
+    if (end_pos.x < start_pos.x)
+      point_x = end_pos.x - hw;
+    else
+      point_x = end_pos.x + hw;
+
+    rect->UpdateRect(point_x, end_pos.y + hw);
+    rect->UpdateRect(point_x, end_pos.y - hw);
+    return;
+  }
+
+  CFX_PointF diff = end_pos - start_pos;
+  FX_FLOAT ll = FXSYS_sqrt2(diff.x, diff.y);
+  FX_FLOAT mx = end_pos.x + hw * diff.x / ll;
+  FX_FLOAT my = end_pos.y + hw * diff.y / ll;
+  FX_FLOAT dx1 = hw * diff.y / ll;
+  FX_FLOAT dy1 = hw * diff.x / ll;
+  rect->UpdateRect(mx - dx1, my + dy1);
+  rect->UpdateRect(mx + dx1, my - dy1);
 }
 
-void CFX_PathData::AddPointCount(int addPoints) {
-  pdfium::base::CheckedNumeric<int> safe_new_count = m_PointCount;
-  safe_new_count += addPoints;
-  int new_count = safe_new_count.ValueOrDie();
-  AllocPointCount(new_count);
-  m_PointCount = new_count;
+void UpdateLineJoinPoints(CFX_FloatRect* rect,
+                          const CFX_PointF& start_pos,
+                          const CFX_PointF& mid_pos,
+                          const CFX_PointF& end_pos,
+                          FX_FLOAT half_width,
+                          FX_FLOAT miter_limit) {
+  FX_FLOAT start_k = 0;
+  FX_FLOAT start_c = 0;
+  FX_FLOAT end_k = 0;
+  FX_FLOAT end_c = 0;
+  FX_FLOAT start_len = 0;
+  FX_FLOAT start_dc = 0;
+  FX_FLOAT end_len = 0;
+  FX_FLOAT end_dc = 0;
+  FX_FLOAT one_twentieth = 1.0f / 20;
+
+  bool bStartVert = FXSYS_fabs(start_pos.x - mid_pos.x) < one_twentieth;
+  bool bEndVert = FXSYS_fabs(mid_pos.x - end_pos.x) < one_twentieth;
+  if (bStartVert && bEndVert) {
+    int start_dir = mid_pos.y > start_pos.y ? 1 : -1;
+    FX_FLOAT point_y = mid_pos.y + half_width * start_dir;
+    rect->UpdateRect(mid_pos.x + half_width, point_y);
+    rect->UpdateRect(mid_pos.x - half_width, point_y);
+    return;
+  }
+
+  if (!bStartVert) {
+    CFX_PointF start_to_mid = start_pos - mid_pos;
+    start_k = (mid_pos.y - start_pos.y) / (mid_pos.x - start_pos.x);
+    start_c = mid_pos.y - (start_k * mid_pos.x);
+    start_len = FXSYS_sqrt2(start_to_mid.x, start_to_mid.y);
+    start_dc = static_cast<FX_FLOAT>(
+        FXSYS_fabs(half_width * start_len / start_to_mid.x));
+  }
+  if (!bEndVert) {
+    CFX_PointF end_to_mid = end_pos - mid_pos;
+    end_k = end_to_mid.y / end_to_mid.x;
+    end_c = mid_pos.y - (end_k * mid_pos.x);
+    end_len = FXSYS_sqrt2(end_to_mid.x, end_to_mid.y);
+    end_dc =
+        static_cast<FX_FLOAT>(FXSYS_fabs(half_width * end_len / end_to_mid.x));
+  }
+  if (bStartVert) {
+    CFX_PointF outside(start_pos.x, 0);
+    if (end_pos.x < start_pos.x)
+      outside.x += half_width;
+    else
+      outside.x -= half_width;
+
+    if (start_pos.y < (end_k * start_pos.x) + end_c)
+      outside.y = (end_k * outside.x) + end_c + end_dc;
+    else
+      outside.y = (end_k * outside.x) + end_c - end_dc;
+
+    rect->UpdateRect(outside.x, outside.y);
+    return;
+  }
+
+  if (bEndVert) {
+    CFX_PointF outside(end_pos.x, 0);
+    if (start_pos.x < end_pos.x)
+      outside.x += half_width;
+    else
+      outside.x -= half_width;
+
+    if (end_pos.y < (start_k * end_pos.x) + start_c)
+      outside.y = (start_k * outside.x) + start_c + start_dc;
+    else
+      outside.y = (start_k * outside.x) + start_c - start_dc;
+
+    rect->UpdateRect(outside.x, outside.y);
+    return;
+  }
+
+  if (FXSYS_fabs(start_k - end_k) < one_twentieth) {
+    int start_dir = mid_pos.x > start_pos.x ? 1 : -1;
+    int end_dir = end_pos.x > mid_pos.x ? 1 : -1;
+    if (start_dir == end_dir)
+      UpdateLineEndPoints(rect, mid_pos, end_pos, half_width);
+    else
+      UpdateLineEndPoints(rect, start_pos, mid_pos, half_width);
+    return;
+  }
+
+  FX_FLOAT start_outside_c = start_c;
+  if (end_pos.y < (start_k * end_pos.x) + start_c)
+    start_outside_c += start_dc;
+  else
+    start_outside_c -= start_dc;
+
+  FX_FLOAT end_outside_c = end_c;
+  if (start_pos.y < (end_k * start_pos.x) + end_c)
+    end_outside_c += end_dc;
+  else
+    end_outside_c -= end_dc;
+
+  FX_FLOAT join_x = (end_outside_c - start_outside_c) / (start_k - end_k);
+  FX_FLOAT join_y = start_k * join_x + start_outside_c;
+  rect->UpdateRect(join_x, join_y);
+}
+
+}  // namespace
+
+FX_PATHPOINT::FX_PATHPOINT() = default;
+
+FX_PATHPOINT::FX_PATHPOINT(const CFX_PointF& point, FXPT_TYPE type, bool close)
+    : m_Point(point), m_Type(type), m_CloseFigure(close) {}
+
+FX_PATHPOINT::FX_PATHPOINT(const FX_PATHPOINT& other) = default;
+
+FX_PATHPOINT::~FX_PATHPOINT() = default;
+
+CFX_PathData::CFX_PathData() {}
+
+CFX_PathData::~CFX_PathData() {}
+
+CFX_PathData::CFX_PathData(const CFX_PathData& src) : m_Points(src.m_Points) {}
+
+void CFX_PathData::Clear() {
+  m_Points.clear();
+}
+
+void CFX_PathData::ClosePath() {
+  if (m_Points.empty())
+    return;
+  m_Points.back().m_CloseFigure = true;
 }
 
 void CFX_PathData::Append(const CFX_PathData* pSrc, const CFX_Matrix* pMatrix) {
-  int old_count = m_PointCount;
-  AddPointCount(pSrc->m_PointCount);
-  FXSYS_memcpy(m_pPoints + old_count, pSrc->m_pPoints,
-               pSrc->m_PointCount * sizeof(FX_PATHPOINT));
-  if (pMatrix) {
-    for (int i = 0; i < pSrc->m_PointCount; i++) {
-      pMatrix->Transform(m_pPoints[old_count + i].m_PointX,
-                         m_pPoints[old_count + i].m_PointY);
-    }
-  }
+  if (pSrc->m_Points.empty())
+    return;
+
+  size_t cur_size = m_Points.size();
+  m_Points.insert(m_Points.end(), pSrc->m_Points.begin(), pSrc->m_Points.end());
+
+  if (!pMatrix)
+    return;
+
+  for (size_t i = cur_size; i < m_Points.size(); i++)
+    m_Points[i].m_Point = pMatrix->Transform(m_Points[i].m_Point);
 }
 
-void CFX_PathData::SetPoint(int index, FX_FLOAT x, FX_FLOAT y, int flag) {
-  ASSERT(index < m_PointCount);
-  m_pPoints[index].m_PointX = x;
-  m_pPoints[index].m_PointY = y;
-  m_pPoints[index].m_Flag = flag;
+void CFX_PathData::AppendPoint(const CFX_PointF& point,
+                               FXPT_TYPE type,
+                               bool closeFigure) {
+  m_Points.push_back(FX_PATHPOINT(point, type, closeFigure));
 }
 
 void CFX_PathData::AppendRect(FX_FLOAT left,
                               FX_FLOAT bottom,
                               FX_FLOAT right,
                               FX_FLOAT top) {
-  int old_count = m_PointCount;
-  AddPointCount(5);
-  FX_PATHPOINT* pPoints = m_pPoints + old_count;
-  pPoints[0].m_PointX = pPoints[1].m_PointX = pPoints[4].m_PointX = left;
-  pPoints[2].m_PointX = pPoints[3].m_PointX = right;
-  pPoints[0].m_PointY = pPoints[3].m_PointY = pPoints[4].m_PointY = bottom;
-  pPoints[1].m_PointY = pPoints[2].m_PointY = top;
-  pPoints[0].m_Flag = FXPT_MOVETO;
-  pPoints[1].m_Flag = pPoints[2].m_Flag = pPoints[3].m_Flag = FXPT_LINETO;
-  pPoints[4].m_Flag = FXPT_LINETO | FXPT_CLOSEFIGURE;
+  m_Points.push_back(
+      FX_PATHPOINT(CFX_PointF(left, bottom), FXPT_TYPE::MoveTo, false));
+  m_Points.push_back(
+      FX_PATHPOINT(CFX_PointF(left, top), FXPT_TYPE::LineTo, false));
+  m_Points.push_back(
+      FX_PATHPOINT(CFX_PointF(right, top), FXPT_TYPE::LineTo, false));
+  m_Points.push_back(
+      FX_PATHPOINT(CFX_PointF(right, bottom), FXPT_TYPE::LineTo, false));
+  m_Points.push_back(
+      FX_PATHPOINT(CFX_PointF(left, bottom), FXPT_TYPE::LineTo, true));
 }
 
 CFX_FloatRect CFX_PathData::GetBoundingBox() const {
+  if (m_Points.empty())
+    return CFX_FloatRect();
+
   CFX_FloatRect rect;
-  if (m_PointCount) {
-    rect.InitRect(m_pPoints[0].m_PointX, m_pPoints[0].m_PointY);
-    for (int i = 1; i < m_PointCount; i++) {
-      rect.UpdateRect(m_pPoints[i].m_PointX, m_pPoints[i].m_PointY);
-    }
-  }
+  rect.InitRect(m_Points[0].m_Point.x, m_Points[0].m_Point.y);
+  for (size_t i = 1; i < m_Points.size(); i++)
+    rect.UpdateRect(m_Points[i].m_Point.x, m_Points[i].m_Point.y);
   return rect;
 }
 
-static void _UpdateLineEndPoints(CFX_FloatRect& rect,
-                                 FX_FLOAT start_x,
-                                 FX_FLOAT start_y,
-                                 FX_FLOAT end_x,
-                                 FX_FLOAT end_y,
-                                 FX_FLOAT hw) {
-  if (start_x == end_x) {
-    if (start_y == end_y) {
-      rect.UpdateRect(end_x + hw, end_y + hw);
-      rect.UpdateRect(end_x - hw, end_y - hw);
-      return;
-    }
-    FX_FLOAT point_y;
-    if (end_y < start_y) {
-      point_y = end_y - hw;
-    } else {
-      point_y = end_y + hw;
-    }
-    rect.UpdateRect(end_x + hw, point_y);
-    rect.UpdateRect(end_x - hw, point_y);
-    return;
-  }
-  if (start_y == end_y) {
-    FX_FLOAT point_x;
-    if (end_x < start_x) {
-      point_x = end_x - hw;
-    } else {
-      point_x = end_x + hw;
-    }
-    rect.UpdateRect(point_x, end_y + hw);
-    rect.UpdateRect(point_x, end_y - hw);
-    return;
-  }
-  FX_FLOAT dx = end_x - start_x;
-  FX_FLOAT dy = end_y - start_y;
-  FX_FLOAT ll = FXSYS_sqrt2(dx, dy);
-  FX_FLOAT mx = end_x + hw * dx / ll;
-  FX_FLOAT my = end_y + hw * dy / ll;
-  FX_FLOAT dx1 = hw * dy / ll;
-  FX_FLOAT dy1 = hw * dx / ll;
-  rect.UpdateRect(mx - dx1, my + dy1);
-  rect.UpdateRect(mx + dx1, my - dy1);
-}
-
-static void _UpdateLineJoinPoints(CFX_FloatRect& rect,
-                                  FX_FLOAT start_x,
-                                  FX_FLOAT start_y,
-                                  FX_FLOAT middle_x,
-                                  FX_FLOAT middle_y,
-                                  FX_FLOAT end_x,
-                                  FX_FLOAT end_y,
-                                  FX_FLOAT half_width,
-                                  FX_FLOAT miter_limit) {
-  FX_FLOAT start_k = 0, start_c = 0, end_k = 0, end_c = 0, start_len = 0,
-           start_dc = 0, end_len = 0, end_dc = 0;
-  bool bStartVert = FXSYS_fabs(start_x - middle_x) < 1.0f / 20;
-  bool bEndVert = FXSYS_fabs(middle_x - end_x) < 1.0f / 20;
-  if (bStartVert && bEndVert) {
-    int start_dir = middle_y > start_y ? 1 : -1;
-    FX_FLOAT point_y = middle_y + half_width * start_dir;
-    rect.UpdateRect(middle_x + half_width, point_y);
-    rect.UpdateRect(middle_x - half_width, point_y);
-    return;
-  }
-  if (!bStartVert) {
-    start_k = (middle_y - start_y) / (middle_x - start_x);
-    start_c = middle_y - (start_k * middle_x);
-    start_len = FXSYS_sqrt2(start_x - middle_x, start_y - middle_y);
-    start_dc =
-        (FX_FLOAT)FXSYS_fabs(half_width * start_len / (start_x - middle_x));
-  }
-  if (!bEndVert) {
-    end_k = (end_y - middle_y) / (end_x - middle_x);
-    end_c = middle_y - (end_k * middle_x);
-    end_len = FXSYS_sqrt2(end_x - middle_x, end_y - middle_y);
-    end_dc = (FX_FLOAT)FXSYS_fabs(half_width * end_len / (end_x - middle_x));
-  }
-  if (bStartVert) {
-    FX_FLOAT outside_x = start_x;
-    if (end_x < start_x) {
-      outside_x += half_width;
-    } else {
-      outside_x -= half_width;
-    }
-    FX_FLOAT outside_y;
-    if (start_y < (end_k * start_x) + end_c) {
-      outside_y = (end_k * outside_x) + end_c + end_dc;
-    } else {
-      outside_y = (end_k * outside_x) + end_c - end_dc;
-    }
-    rect.UpdateRect(outside_x, outside_y);
-    return;
-  }
-  if (bEndVert) {
-    FX_FLOAT outside_x = end_x;
-    if (start_x < end_x) {
-      outside_x += half_width;
-    } else {
-      outside_x -= half_width;
-    }
-    FX_FLOAT outside_y;
-    if (end_y < (start_k * end_x) + start_c) {
-      outside_y = (start_k * outside_x) + start_c + start_dc;
-    } else {
-      outside_y = (start_k * outside_x) + start_c - start_dc;
-    }
-    rect.UpdateRect(outside_x, outside_y);
-    return;
-  }
-  if (FXSYS_fabs(start_k - end_k) < 1.0f / 20) {
-    int start_dir = middle_x > start_x ? 1 : -1;
-    int end_dir = end_x > middle_x ? 1 : -1;
-    if (start_dir == end_dir) {
-      _UpdateLineEndPoints(rect, middle_x, middle_y, end_x, end_y, half_width);
-    } else {
-      _UpdateLineEndPoints(rect, start_x, start_y, middle_x, middle_y,
-                           half_width);
-    }
-    return;
-  }
-  FX_FLOAT start_outside_c = start_c;
-  if (end_y < (start_k * end_x) + start_c) {
-    start_outside_c += start_dc;
-  } else {
-    start_outside_c -= start_dc;
-  }
-  FX_FLOAT end_outside_c = end_c;
-  if (start_y < (end_k * start_x) + end_c) {
-    end_outside_c += end_dc;
-  } else {
-    end_outside_c -= end_dc;
-  }
-  FX_FLOAT join_x = (end_outside_c - start_outside_c) / (start_k - end_k);
-  FX_FLOAT join_y = (start_k * join_x) + start_outside_c;
-  rect.UpdateRect(join_x, join_y);
-}
-
 CFX_FloatRect CFX_PathData::GetBoundingBox(FX_FLOAT line_width,
                                            FX_FLOAT miter_limit) const {
-  CFX_FloatRect rect(100000 * 1.0f, 100000 * 1.0f, -100000 * 1.0f,
-                     -100000 * 1.0f);
-  int iPoint = 0;
+  CFX_FloatRect rect(100000.0f, 100000.0f, -100000.0f, -100000.0f);
+  size_t iPoint = 0;
   FX_FLOAT half_width = line_width;
   int iStartPoint = 0;
   int iEndPoint = 0;
   int iMiddlePoint = 0;
   bool bJoin;
-  while (iPoint < m_PointCount) {
-    if (m_pPoints[iPoint].m_Flag == FXPT_MOVETO) {
+  while (iPoint < m_Points.size()) {
+    if (m_Points[iPoint].IsTypeAndOpen(FXPT_TYPE::MoveTo)) {
       iStartPoint = iPoint + 1;
       iEndPoint = iPoint;
       bJoin = false;
     } else {
-      if (m_pPoints[iPoint].m_Flag == FXPT_BEZIERTO) {
-        rect.UpdateRect(m_pPoints[iPoint].m_PointX, m_pPoints[iPoint].m_PointY);
-        rect.UpdateRect(m_pPoints[iPoint + 1].m_PointX,
-                        m_pPoints[iPoint + 1].m_PointY);
+      if (m_Points[iPoint].IsTypeAndOpen(FXPT_TYPE::BezierTo)) {
+        rect.UpdateRect(m_Points[iPoint].m_Point.x, m_Points[iPoint].m_Point.y);
+        rect.UpdateRect(m_Points[iPoint + 1].m_Point.x,
+                        m_Points[iPoint + 1].m_Point.y);
         iPoint += 2;
       }
-      if (iPoint == m_PointCount - 1 ||
-          m_pPoints[iPoint + 1].m_Flag == FXPT_MOVETO) {
+      if (iPoint == m_Points.size() - 1 ||
+          m_Points[iPoint + 1].IsTypeAndOpen(FXPT_TYPE::MoveTo)) {
         iStartPoint = iPoint - 1;
         iEndPoint = iPoint;
         bJoin = false;
@@ -276,17 +263,15 @@
         bJoin = true;
       }
     }
-    FX_FLOAT start_x = m_pPoints[iStartPoint].m_PointX;
-    FX_FLOAT start_y = m_pPoints[iStartPoint].m_PointY;
-    FX_FLOAT end_x = m_pPoints[iEndPoint].m_PointX;
-    FX_FLOAT end_y = m_pPoints[iEndPoint].m_PointY;
+
+    CFX_PointF start_pos = m_Points[iStartPoint].m_Point;
+    CFX_PointF end_pos = m_Points[iEndPoint].m_Point;
     if (bJoin) {
-      FX_FLOAT middle_x = m_pPoints[iMiddlePoint].m_PointX;
-      FX_FLOAT middle_y = m_pPoints[iMiddlePoint].m_PointY;
-      _UpdateLineJoinPoints(rect, start_x, start_y, middle_x, middle_y, end_x,
-                            end_y, half_width, miter_limit);
+      CFX_PointF mid_pos = m_Points[iMiddlePoint].m_Point;
+      UpdateLineJoinPoints(&rect, start_pos, mid_pos, end_pos, half_width,
+                           miter_limit);
     } else {
-      _UpdateLineEndPoints(rect, start_x, start_y, end_x, end_y, half_width);
+      UpdateLineEndPoints(&rect, start_pos, end_pos, half_width);
     }
     iPoint++;
   }
@@ -294,239 +279,207 @@
 }
 
 void CFX_PathData::Transform(const CFX_Matrix* pMatrix) {
-  if (!pMatrix) {
+  if (!pMatrix)
     return;
-  }
-  for (int i = 0; i < m_PointCount; i++) {
-    pMatrix->Transform(m_pPoints[i].m_PointX, m_pPoints[i].m_PointY);
-  }
+  for (auto& point : m_Points)
+    point.m_Point = pMatrix->Transform(point.m_Point);
 }
 
-bool CFX_PathData::GetZeroAreaPath(CFX_PathData& NewPath,
-                                   CFX_Matrix* pMatrix,
-                                   bool& bThin,
-                                   bool bAdjust) const {
-  if (m_PointCount < 3) {
+bool CFX_PathData::GetZeroAreaPath(const CFX_Matrix* pMatrix,
+                                   bool bAdjust,
+                                   CFX_PathData* NewPath,
+                                   bool* bThin,
+                                   bool* setIdentity) const {
+  *setIdentity = false;
+  if (m_Points.size() < 3)
     return false;
-  }
-  if (m_PointCount == 3 && (m_pPoints[0].m_Flag & FXPT_TYPE) == FXPT_MOVETO &&
-      (m_pPoints[1].m_Flag & FXPT_TYPE) == FXPT_LINETO &&
-      (m_pPoints[2].m_Flag & FXPT_TYPE) == FXPT_LINETO &&
-      m_pPoints[0].m_PointX == m_pPoints[2].m_PointX &&
-      m_pPoints[0].m_PointY == m_pPoints[2].m_PointY) {
-    NewPath.AddPointCount(2);
-    if (bAdjust) {
-      if (pMatrix) {
-        FX_FLOAT x = m_pPoints[0].m_PointX, y = m_pPoints[0].m_PointY;
-        pMatrix->TransformPoint(x, y);
-        x = (int)x + 0.5f;
-        y = (int)y + 0.5f;
-        NewPath.SetPoint(0, x, y, FXPT_MOVETO);
-        x = m_pPoints[1].m_PointX, y = m_pPoints[1].m_PointY;
-        pMatrix->TransformPoint(x, y);
-        x = (int)x + 0.5f;
-        y = (int)y + 0.5f;
-        NewPath.SetPoint(1, x, y, FXPT_LINETO);
-        pMatrix->SetIdentity();
-      } else {
-        FX_FLOAT x = (int)m_pPoints[0].m_PointX + 0.5f,
-                 y = (int)m_pPoints[0].m_PointY + 0.5f;
-        NewPath.SetPoint(0, x, y, FXPT_MOVETO);
-        x = (int)m_pPoints[1].m_PointX + 0.5f,
-        y = (int)m_pPoints[1].m_PointY + 0.5f;
-        NewPath.SetPoint(1, x, y, FXPT_LINETO);
+
+  if (m_Points.size() == 3 && m_Points[0].m_Type == FXPT_TYPE::MoveTo &&
+      m_Points[1].m_Type == FXPT_TYPE::LineTo &&
+      m_Points[2].m_Type == FXPT_TYPE::LineTo &&
+      m_Points[0].m_Point == m_Points[2].m_Point) {
+    for (size_t i = 0; i < 2; i++) {
+      CFX_PointF point = m_Points[i].m_Point;
+      if (bAdjust) {
+        if (pMatrix)
+          point = pMatrix->Transform(point);
+
+        point = CFX_PointF(static_cast<int>(point.x) + 0.5f,
+                           static_cast<int>(point.y) + 0.5f);
       }
-    } else {
-      NewPath.SetPoint(0, m_pPoints[0].m_PointX, m_pPoints[0].m_PointY,
-                       FXPT_MOVETO);
-      NewPath.SetPoint(1, m_pPoints[1].m_PointX, m_pPoints[1].m_PointY,
-                       FXPT_LINETO);
+      NewPath->AppendPoint(
+          point, i == 0 ? FXPT_TYPE::MoveTo : FXPT_TYPE::LineTo, false);
     }
-    if (m_pPoints[0].m_PointX != m_pPoints[1].m_PointX &&
-        m_pPoints[0].m_PointY != m_pPoints[1].m_PointY) {
-      bThin = true;
+    if (bAdjust && pMatrix)
+      *setIdentity = true;
+
+    // Note, they both have to be not equal.
+    if (m_Points[0].m_Point.x != m_Points[1].m_Point.x &&
+        m_Points[0].m_Point.y != m_Points[1].m_Point.y) {
+      *bThin = true;
     }
     return true;
   }
-  if (((m_PointCount > 3) && (m_PointCount % 2))) {
-    int mid = m_PointCount / 2;
+
+  if (((m_Points.size() > 3) && (m_Points.size() % 2))) {
+    int mid = m_Points.size() / 2;
     bool bZeroArea = false;
     CFX_PathData t_path;
     for (int i = 0; i < mid; i++) {
-      if (!(m_pPoints[mid - i - 1].m_PointX ==
-                m_pPoints[mid + i + 1].m_PointX &&
-            m_pPoints[mid - i - 1].m_PointY ==
-                m_pPoints[mid + i + 1].m_PointY &&
-            ((m_pPoints[mid - i - 1].m_Flag & FXPT_TYPE) != FXPT_BEZIERTO &&
-             (m_pPoints[mid + i + 1].m_Flag & FXPT_TYPE) != FXPT_BEZIERTO))) {
+      if (!(m_Points[mid - i - 1].m_Point == m_Points[mid + i + 1].m_Point &&
+            m_Points[mid - i - 1].m_Type != FXPT_TYPE::BezierTo &&
+            m_Points[mid + i + 1].m_Type != FXPT_TYPE::BezierTo)) {
         bZeroArea = true;
         break;
       }
-      int new_count = t_path.GetPointCount();
-      t_path.AddPointCount(2);
-      t_path.SetPoint(new_count, m_pPoints[mid - i].m_PointX,
-                      m_pPoints[mid - i].m_PointY, FXPT_MOVETO);
-      t_path.SetPoint(new_count + 1, m_pPoints[mid - i - 1].m_PointX,
-                      m_pPoints[mid - i - 1].m_PointY, FXPT_LINETO);
+
+      t_path.AppendPoint(m_Points[mid - i].m_Point, FXPT_TYPE::MoveTo, false);
+      t_path.AppendPoint(m_Points[mid - i - 1].m_Point, FXPT_TYPE::LineTo,
+                         false);
     }
     if (!bZeroArea) {
-      NewPath.Append(&t_path, nullptr);
-      bThin = true;
+      NewPath->Append(&t_path, nullptr);
+      *bThin = true;
       return true;
     }
   }
+
   int stratPoint = 0;
-  int next = 0, i;
-  for (i = 0; i < m_PointCount; i++) {
-    int point_type = m_pPoints[i].m_Flag & FXPT_TYPE;
-    if (point_type == FXPT_MOVETO) {
+  int next = 0;
+  for (size_t i = 0; i < m_Points.size(); i++) {
+    FXPT_TYPE point_type = m_Points[i].m_Type;
+    if (point_type == FXPT_TYPE::MoveTo) {
       stratPoint = i;
-    } else if (point_type == FXPT_LINETO) {
-      next = (i + 1 - stratPoint) % (m_PointCount - stratPoint) + stratPoint;
-      if ((m_pPoints[next].m_Flag & FXPT_TYPE) != FXPT_BEZIERTO &&
-          (m_pPoints[next].m_Flag & FXPT_TYPE) != FXPT_MOVETO) {
-        if ((m_pPoints[i - 1].m_PointX == m_pPoints[i].m_PointX &&
-             m_pPoints[i].m_PointX == m_pPoints[next].m_PointX) &&
-            ((m_pPoints[i].m_PointY - m_pPoints[i - 1].m_PointY) *
-                 (m_pPoints[i].m_PointY - m_pPoints[next].m_PointY) >
+    } else if (point_type == FXPT_TYPE::LineTo) {
+      next = (i + 1 - stratPoint) % (m_Points.size() - stratPoint) + stratPoint;
+      if (m_Points[next].m_Type != FXPT_TYPE::BezierTo &&
+          m_Points[next].m_Type != FXPT_TYPE::MoveTo) {
+        if ((m_Points[i - 1].m_Point.x == m_Points[i].m_Point.x &&
+             m_Points[i].m_Point.x == m_Points[next].m_Point.x) &&
+            ((m_Points[i].m_Point.y - m_Points[i - 1].m_Point.y) *
+                 (m_Points[i].m_Point.y - m_Points[next].m_Point.y) >
              0)) {
           int pre = i;
-          if (FXSYS_fabs(m_pPoints[i].m_PointY - m_pPoints[i - 1].m_PointY) <
-              FXSYS_fabs(m_pPoints[i].m_PointY - m_pPoints[next].m_PointY)) {
+          if (FXSYS_fabs(m_Points[i].m_Point.y - m_Points[i - 1].m_Point.y) <
+              FXSYS_fabs(m_Points[i].m_Point.y - m_Points[next].m_Point.y)) {
             pre--;
             next--;
           }
-          int new_count = NewPath.GetPointCount();
-          NewPath.AddPointCount(2);
-          NewPath.SetPoint(new_count, m_pPoints[pre].m_PointX,
-                           m_pPoints[pre].m_PointY, FXPT_MOVETO);
-          NewPath.SetPoint(new_count + 1, m_pPoints[next].m_PointX,
-                           m_pPoints[next].m_PointY, FXPT_LINETO);
-        } else if ((m_pPoints[i - 1].m_PointY == m_pPoints[i].m_PointY &&
-                    m_pPoints[i].m_PointY == m_pPoints[next].m_PointY) &&
-                   ((m_pPoints[i].m_PointX - m_pPoints[i - 1].m_PointX) *
-                        (m_pPoints[i].m_PointX - m_pPoints[next].m_PointX) >
+
+          NewPath->AppendPoint(m_Points[pre].m_Point, FXPT_TYPE::MoveTo, false);
+          NewPath->AppendPoint(m_Points[next].m_Point, FXPT_TYPE::LineTo,
+                               false);
+        } else if ((m_Points[i - 1].m_Point.y == m_Points[i].m_Point.y &&
+                    m_Points[i].m_Point.y == m_Points[next].m_Point.y) &&
+                   ((m_Points[i].m_Point.x - m_Points[i - 1].m_Point.x) *
+                        (m_Points[i].m_Point.x - m_Points[next].m_Point.x) >
                     0)) {
           int pre = i;
-          if (FXSYS_fabs(m_pPoints[i].m_PointX - m_pPoints[i - 1].m_PointX) <
-              FXSYS_fabs(m_pPoints[i].m_PointX - m_pPoints[next].m_PointX)) {
+          if (FXSYS_fabs(m_Points[i].m_Point.x - m_Points[i - 1].m_Point.x) <
+              FXSYS_fabs(m_Points[i].m_Point.x - m_Points[next].m_Point.x)) {
             pre--;
             next--;
           }
-          int new_count = NewPath.GetPointCount();
-          NewPath.AddPointCount(2);
-          NewPath.SetPoint(new_count, m_pPoints[pre].m_PointX,
-                           m_pPoints[pre].m_PointY, FXPT_MOVETO);
-          NewPath.SetPoint(new_count + 1, m_pPoints[next].m_PointX,
-                           m_pPoints[next].m_PointY, FXPT_LINETO);
-        } else if ((m_pPoints[i - 1].m_Flag & FXPT_TYPE) == FXPT_MOVETO &&
-                   (m_pPoints[next].m_Flag & FXPT_TYPE) == FXPT_LINETO &&
-                   m_pPoints[i - 1].m_PointX == m_pPoints[next].m_PointX &&
-                   m_pPoints[i - 1].m_PointY == m_pPoints[next].m_PointY &&
-                   m_pPoints[next].m_Flag & FXPT_CLOSEFIGURE) {
-          int new_count = NewPath.GetPointCount();
-          NewPath.AddPointCount(2);
-          NewPath.SetPoint(new_count, m_pPoints[i - 1].m_PointX,
-                           m_pPoints[i - 1].m_PointY, FXPT_MOVETO);
-          NewPath.SetPoint(new_count + 1, m_pPoints[i].m_PointX,
-                           m_pPoints[i].m_PointY, FXPT_LINETO);
-          bThin = true;
+
+          NewPath->AppendPoint(m_Points[pre].m_Point, FXPT_TYPE::MoveTo, false);
+          NewPath->AppendPoint(m_Points[next].m_Point, FXPT_TYPE::LineTo,
+                               false);
+        } else if (m_Points[i - 1].m_Type == FXPT_TYPE::MoveTo &&
+                   m_Points[next].m_Type == FXPT_TYPE::LineTo &&
+                   m_Points[i - 1].m_Point == m_Points[next].m_Point &&
+                   m_Points[next].m_CloseFigure) {
+          NewPath->AppendPoint(m_Points[i - 1].m_Point, FXPT_TYPE::MoveTo,
+                               false);
+          NewPath->AppendPoint(m_Points[i].m_Point, FXPT_TYPE::LineTo, false);
+          *bThin = true;
         }
       }
-    } else if (point_type == FXPT_BEZIERTO) {
+    } else if (point_type == FXPT_TYPE::BezierTo) {
       i += 2;
       continue;
     }
   }
-  if (m_PointCount > 3 && NewPath.GetPointCount()) {
-    bThin = true;
-  }
-  if (NewPath.GetPointCount() == 0) {
-    return false;
-  }
-  return true;
+
+  size_t new_path_size = NewPath->GetPoints().size();
+  if (m_Points.size() > 3 && new_path_size > 0)
+    *bThin = true;
+  return new_path_size != 0;
 }
 
 bool CFX_PathData::IsRect() const {
-  if (m_PointCount != 5 && m_PointCount != 4) {
+  if (m_Points.size() != 5 && m_Points.size() != 4)
+    return false;
+
+  if ((m_Points.size() == 5 && m_Points[0].m_Point != m_Points[4].m_Point) ||
+      m_Points[0].m_Point == m_Points[2].m_Point ||
+      m_Points[1].m_Point == m_Points[3].m_Point) {
     return false;
   }
-  if ((m_PointCount == 5 && (m_pPoints[0].m_PointX != m_pPoints[4].m_PointX ||
-                             m_pPoints[0].m_PointY != m_pPoints[4].m_PointY)) ||
-      (m_pPoints[0].m_PointX == m_pPoints[2].m_PointX &&
-       m_pPoints[0].m_PointY == m_pPoints[2].m_PointY) ||
-      (m_pPoints[1].m_PointX == m_pPoints[3].m_PointX &&
-       m_pPoints[1].m_PointY == m_pPoints[3].m_PointY)) {
+  // Note, both x,y have to not equal.
+  if (m_Points[0].m_Point.x != m_Points[3].m_Point.x &&
+      m_Points[0].m_Point.y != m_Points[3].m_Point.y) {
     return false;
   }
-  if (m_pPoints[0].m_PointX != m_pPoints[3].m_PointX &&
-      m_pPoints[0].m_PointY != m_pPoints[3].m_PointY) {
-    return false;
-  }
+
   for (int i = 1; i < 4; i++) {
-    if ((m_pPoints[i].m_Flag & FXPT_TYPE) != FXPT_LINETO) {
+    if (m_Points[i].m_Type != FXPT_TYPE::LineTo)
       return false;
-    }
-    if (m_pPoints[i].m_PointX != m_pPoints[i - 1].m_PointX &&
-        m_pPoints[i].m_PointY != m_pPoints[i - 1].m_PointY) {
+    // Note, both x,y have to not equal.
+    if (m_Points[i].m_Point.x != m_Points[i - 1].m_Point.x &&
+        m_Points[i].m_Point.y != m_Points[i - 1].m_Point.y) {
       return false;
     }
   }
-  return m_PointCount == 5 || (m_pPoints[3].m_Flag & FXPT_CLOSEFIGURE);
+  return m_Points.size() == 5 || m_Points[3].m_CloseFigure;
 }
 
 bool CFX_PathData::IsRect(const CFX_Matrix* pMatrix,
                           CFX_FloatRect* pRect) const {
   if (!pMatrix) {
-    if (!IsRect()) {
+    if (!IsRect())
       return false;
-    }
+
     if (pRect) {
-      pRect->left = m_pPoints[0].m_PointX;
-      pRect->right = m_pPoints[2].m_PointX;
-      pRect->bottom = m_pPoints[0].m_PointY;
-      pRect->top = m_pPoints[2].m_PointY;
+      pRect->left = m_Points[0].m_Point.x;
+      pRect->right = m_Points[2].m_Point.x;
+      pRect->bottom = m_Points[0].m_Point.y;
+      pRect->top = m_Points[2].m_Point.y;
       pRect->Normalize();
     }
     return true;
   }
-  if (m_PointCount != 5 && m_PointCount != 4) {
+
+  if (m_Points.size() != 5 && m_Points.size() != 4)
+    return false;
+
+  if ((m_Points.size() == 5 && m_Points[0].m_Point != m_Points[4].m_Point) ||
+      m_Points[1].m_Point == m_Points[3].m_Point) {
     return false;
   }
-  if ((m_PointCount == 5 && (m_pPoints[0].m_PointX != m_pPoints[4].m_PointX ||
-                             m_pPoints[0].m_PointY != m_pPoints[4].m_PointY)) ||
-      (m_pPoints[1].m_PointX == m_pPoints[3].m_PointX &&
-       m_pPoints[1].m_PointY == m_pPoints[3].m_PointY)) {
+  // Note, both x,y not equal.
+  if (m_Points.size() == 4 && m_Points[0].m_Point.x != m_Points[3].m_Point.x &&
+      m_Points[0].m_Point.y != m_Points[3].m_Point.y) {
     return false;
   }
-  if (m_PointCount == 4 && m_pPoints[0].m_PointX != m_pPoints[3].m_PointX &&
-      m_pPoints[0].m_PointY != m_pPoints[3].m_PointY) {
-    return false;
+
+  CFX_PointF points[5];
+  for (size_t i = 0; i < m_Points.size(); i++) {
+    points[i] = pMatrix->Transform(m_Points[i].m_Point);
+
+    if (i == 0)
+      continue;
+    if (m_Points[i].m_Type != FXPT_TYPE::LineTo)
+      return false;
+    if (points[i].x != points[i - 1].x && points[i].y != points[i - 1].y)
+      return false;
   }
-  FX_FLOAT x[5], y[5];
-  for (int i = 0; i < m_PointCount; i++) {
-    pMatrix->Transform(m_pPoints[i].m_PointX, m_pPoints[i].m_PointY, x[i],
-                       y[i]);
-    if (i) {
-      if ((m_pPoints[i].m_Flag & FXPT_TYPE) != FXPT_LINETO) {
-        return false;
-      }
-      if (x[i] != x[i - 1] && y[i] != y[i - 1]) {
-        return false;
-      }
-    }
-  }
+
   if (pRect) {
-    pRect->left = x[0];
-    pRect->right = x[2];
-    pRect->bottom = y[0];
-    pRect->top = y[2];
+    pRect->left = points[0].x;
+    pRect->right = points[2].x;
+    pRect->bottom = points[0].y;
+    pRect->top = points[2].y;
     pRect->Normalize();
   }
   return true;
 }
-
-void CFX_PathData::Copy(const CFX_PathData& src) {
-  SetPointCount(src.m_PointCount);
-  FXSYS_memcpy(m_pPoints, src.m_pPoints, sizeof(FX_PATHPOINT) * m_PointCount);
-}
diff --git a/core/fxge/ge/cfx_renderdevice.cpp b/core/fxge/ge/cfx_renderdevice.cpp
index 9c67a7d..daa67cc 100644
--- a/core/fxge/ge/cfx_renderdevice.cpp
+++ b/core/fxge/ge/cfx_renderdevice.cpp
@@ -27,19 +27,19 @@
 void AdjustGlyphSpace(std::vector<FXTEXT_GLYPHPOS>* pGlyphAndPos) {
   ASSERT(pGlyphAndPos->size() > 1);
   std::vector<FXTEXT_GLYPHPOS>& glyphs = *pGlyphAndPos;
-  bool bVertical = glyphs.back().m_OriginX == glyphs.front().m_OriginX;
-  if (!bVertical && (glyphs.back().m_OriginY != glyphs.front().m_OriginY))
+  bool bVertical = glyphs.back().m_Origin.x == glyphs.front().m_Origin.x;
+  if (!bVertical && (glyphs.back().m_Origin.y != glyphs.front().m_Origin.y))
     return;
 
   for (size_t i = glyphs.size() - 1; i > 1; --i) {
     FXTEXT_GLYPHPOS& next = glyphs[i];
-    int next_origin = bVertical ? next.m_OriginY : next.m_OriginX;
-    FX_FLOAT next_origin_f = bVertical ? next.m_fOriginY : next.m_fOriginX;
+    int next_origin = bVertical ? next.m_Origin.y : next.m_Origin.x;
+    FX_FLOAT next_origin_f = bVertical ? next.m_fOrigin.y : next.m_fOrigin.x;
 
     FXTEXT_GLYPHPOS& current = glyphs[i - 1];
-    int& current_origin = bVertical ? current.m_OriginY : current.m_OriginX;
+    int& current_origin = bVertical ? current.m_Origin.y : current.m_Origin.x;
     FX_FLOAT current_origin_f =
-        bVertical ? current.m_fOriginY : current.m_fOriginX;
+        bVertical ? current.m_fOrigin.y : current.m_fOrigin.x;
 
     int space = next_origin - current_origin;
     FX_FLOAT space_f = next_origin_f - current_origin_f;
@@ -346,6 +346,21 @@
 
 }  // namespace
 
+FXTEXT_CHARPOS::FXTEXT_CHARPOS()
+    : m_GlyphIndex(0),
+      m_FontCharWidth(0),
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
+      m_ExtGID(0),
+#endif
+      m_FallbackFontPosition(0),
+      m_bGlyphAdjust(false),
+      m_bFontStyle(false) {
+}
+
+FXTEXT_CHARPOS::FXTEXT_CHARPOS(const FXTEXT_CHARPOS&) = default;
+
+FXTEXT_CHARPOS::~FXTEXT_CHARPOS(){};
+
 CFX_RenderDevice::CFX_RenderDevice()
     : m_pBitmap(nullptr),
       m_Width(0),
@@ -473,25 +488,20 @@
                                          int blend_type) {
   uint8_t stroke_alpha = pGraphState ? FXARGB_A(stroke_color) : 0;
   uint8_t fill_alpha = (fill_mode & 3) ? FXARGB_A(fill_color) : 0;
-  if (stroke_alpha == 0 && pPathData->GetPointCount() == 2) {
-    FX_PATHPOINT* pPoints = pPathData->GetPoints();
-    FX_FLOAT x1, x2, y1, y2;
+  const std::vector<FX_PATHPOINT>& pPoints = pPathData->GetPoints();
+  if (stroke_alpha == 0 && pPoints.size() == 2) {
+    CFX_PointF pos1 = pPoints[0].m_Point;
+    CFX_PointF pos2 = pPoints[1].m_Point;
     if (pObject2Device) {
-      pObject2Device->Transform(pPoints[0].m_PointX, pPoints[0].m_PointY, x1,
-                                y1);
-      pObject2Device->Transform(pPoints[1].m_PointX, pPoints[1].m_PointY, x2,
-                                y2);
-    } else {
-      x1 = pPoints[0].m_PointX;
-      y1 = pPoints[0].m_PointY;
-      x2 = pPoints[1].m_PointX;
-      y2 = pPoints[1].m_PointY;
+      pos1 = pObject2Device->Transform(pos1);
+      pos2 = pObject2Device->Transform(pos2);
     }
-    DrawCosmeticLine(x1, y1, x2, y2, fill_color, fill_mode, blend_type);
+    DrawCosmeticLine(pos1.x, pos1.y, pos2.x, pos2.y, fill_color, fill_mode,
+                     blend_type);
     return true;
   }
-  if ((pPathData->GetPointCount() == 5 || pPathData->GetPointCount() == 4) &&
-      stroke_alpha == 0) {
+
+  if ((pPoints.size() == 5 || pPoints.size() == 4) && stroke_alpha == 0) {
     CFX_FloatRect rect_f;
     if (!(fill_mode & FXFILL_RECT_AA) &&
         pPathData->IsRect(pObject2Device, &rect_f)) {
@@ -539,19 +549,25 @@
       !(fill_mode & FX_FILL_TEXT_MODE)) {
     CFX_PathData newPath;
     bool bThin = false;
-    if (pPathData->GetZeroAreaPath(newPath, (CFX_Matrix*)pObject2Device, bThin,
-                                   !!m_pDeviceDriver->GetDriverType())) {
+    bool setIdentity = false;
+    if (pPathData->GetZeroAreaPath(pObject2Device,
+                                   !!m_pDeviceDriver->GetDriverType(), &newPath,
+                                   &bThin, &setIdentity)) {
       CFX_GraphStateData graphState;
       graphState.m_LineWidth = 0.0f;
+
       uint32_t strokecolor = fill_color;
       if (bThin)
         strokecolor = (((fill_alpha >> 2) << 24) | (strokecolor & 0x00ffffff));
-      CFX_Matrix* pMatrix = nullptr;
-      if (pObject2Device && !pObject2Device->IsIdentity())
-        pMatrix = (CFX_Matrix*)pObject2Device;
+
+      const CFX_Matrix* pMatrix = nullptr;
+      if (pObject2Device && !pObject2Device->IsIdentity() && !setIdentity)
+        pMatrix = pObject2Device;
+
       int smooth_path = FX_ZEROAREA_FILL;
       if (fill_mode & FXFILL_NOPATHSMOOTH)
         smooth_path |= FXFILL_NOPATHSMOOTH;
+
       m_pDeviceDriver->DrawPath(&newPath, pMatrix, &graphState, 0, strokecolor,
                                 smooth_path, blend_type);
     }
@@ -589,7 +605,8 @@
     bbox = pPathData->GetBoundingBox();
   }
   if (pObject2Device)
-    bbox.Transform(pObject2Device);
+    pObject2Device->TransformRect(bbox);
+
   CFX_Matrix ctm = GetCTM();
   FX_FLOAT fScaleX = FXSYS_fabs(ctm.a);
   FX_FLOAT fScaleY = FXSYS_fabs(ctm.d);
@@ -612,8 +629,8 @@
   CFX_Matrix matrix;
   if (pObject2Device)
     matrix = *pObject2Device;
-  matrix.TranslateI(-rect.left, -rect.top);
-  matrix.Concat(fScaleX, 0, 0, fScaleY, 0, 0);
+  matrix.Translate(-rect.left, -rect.top);
+  matrix.Concat(CFX_Matrix(fScaleX, 0, 0, fScaleY, 0, 0));
   if (!bitmap_device.GetDeviceDriver()->DrawPath(
           pPathData, &matrix, pGraphState, fill_color, stroke_color, fill_mode,
           blend_type)) {
@@ -675,9 +692,8 @@
   }
   CFX_GraphStateData graph_state;
   CFX_PathData path;
-  path.SetPointCount(2);
-  path.SetPoint(0, x1, y1, FXPT_MOVETO);
-  path.SetPoint(1, x2, y2, FXPT_LINETO);
+  path.AppendPoint(CFX_PointF(x1, y1), FXPT_TYPE::MoveTo, false);
+  path.AppendPoint(CFX_PointF(x2, y2), FXPT_TYPE::LineTo, false);
   return m_pDeviceDriver->DrawPath(&path, nullptr, &graph_state, 0, color,
                                    fill_mode, blend_type);
 }
@@ -860,6 +876,7 @@
     char2device = *pText2Device;
     text2Device = *pText2Device;
   }
+
   char2device.Scale(font_size, -font_size);
   if (FXSYS_fabs(char2device.a) + FXSYS_fabs(char2device.b) > 50 * 1.0f ||
       ((m_DeviceClass == FXDC_PRINTER) &&
@@ -902,19 +919,21 @@
   FX_FLOAT scale_x = FXSYS_fabs(matrixCTM.a);
   FX_FLOAT scale_y = FXSYS_fabs(matrixCTM.d);
   CFX_Matrix deviceCtm = char2device;
-  deviceCtm.Concat(scale_x, 0, 0, scale_y, 0, 0);
-  text2Device.Concat(scale_x, 0, 0, scale_y, 0, 0);
+  CFX_Matrix m(scale_x, 0, 0, scale_y, 0, 0);
+  deviceCtm.Concat(m);
+  text2Device.Concat(m);
+
   for (size_t i = 0; i < glyphs.size(); ++i) {
     FXTEXT_GLYPHPOS& glyph = glyphs[i];
     const FXTEXT_CHARPOS& charpos = pCharPos[i];
-    glyph.m_fOriginX = charpos.m_OriginX;
-    glyph.m_fOriginY = charpos.m_OriginY;
-    text2Device.Transform(glyph.m_fOriginX, glyph.m_fOriginY);
+
+    glyph.m_fOrigin = text2Device.Transform(charpos.m_Origin);
     if (anti_alias < FXFT_RENDER_MODE_LCD)
-      glyph.m_OriginX = FXSYS_round(glyph.m_fOriginX);
+      glyph.m_Origin.x = FXSYS_round(glyph.m_fOrigin.x);
     else
-      glyph.m_OriginX = (int)FXSYS_floor(glyph.m_fOriginX);
-    glyph.m_OriginY = FXSYS_round(glyph.m_fOriginY);
+      glyph.m_Origin.x = static_cast<int>(FXSYS_floor(glyph.m_fOrigin.x));
+    glyph.m_Origin.y = FXSYS_round(glyph.m_fOrigin.y);
+
     if (charpos.m_bGlyphAdjust) {
       CFX_Matrix new_matrix(
           charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
@@ -960,8 +979,8 @@
         continue;
       const CFX_DIBitmap* pGlyph = &glyph.m_pGlyph->m_Bitmap;
       bitmap.TransferBitmap(
-          glyph.m_OriginX + glyph.m_pGlyph->m_Left - pixel_left,
-          glyph.m_OriginY - glyph.m_pGlyph->m_Top - pixel_top,
+          glyph.m_Origin.x + glyph.m_pGlyph->m_Left - pixel_left,
+          glyph.m_Origin.y - glyph.m_pGlyph->m_Top - pixel_top,
           pGlyph->GetWidth(), pGlyph->GetHeight(), pGlyph, 0, 0);
     }
     return SetBitMask(&bitmap, bmp_rect.left, bmp_rect.top, fill_color);
@@ -995,13 +1014,13 @@
     if (!glyph.m_pGlyph)
       continue;
 
-    pdfium::base::CheckedNumeric<int> left = glyph.m_OriginX;
+    pdfium::base::CheckedNumeric<int> left = glyph.m_Origin.x;
     left += glyph.m_pGlyph->m_Left;
     left -= pixel_left;
     if (!left.IsValid())
       return false;
 
-    pdfium::base::CheckedNumeric<int> top = glyph.m_OriginY;
+    pdfium::base::CheckedNumeric<int> top = glyph.m_Origin.y;
     top -= glyph.m_pGlyph->m_Top;
     top -= pixel_top;
     if (!top.IsValid())
@@ -1021,14 +1040,16 @@
     }
     bool bBGRStripe = !!(text_flags & FXTEXT_BGR_STRIPE);
     ncols /= 3;
-    int x_subpixel = (int)(glyph.m_fOriginX * 3) % 3;
-    int start_col = std::max(left.ValueOrDie(), 0);
+    int x_subpixel = static_cast<int>(glyph.m_fOrigin.x * 3) % 3;
+    int start_col =
+        pdfium::base::ValueOrDieForType<int>(pdfium::base::CheckMax(left, 0));
     pdfium::base::CheckedNumeric<int> end_col_safe = left;
     end_col_safe += ncols;
     if (!end_col_safe.IsValid())
       return false;
 
-    int end_col = std::min(end_col_safe.ValueOrDie(), dest_width);
+    int end_col =
+        std::min(static_cast<int>(end_col_safe.ValueOrDie<int>()), dest_width);
     if (start_col >= end_col)
       continue;
 
@@ -1058,16 +1079,19 @@
     const FXTEXT_CHARPOS& charpos = pCharPos[iChar];
     CFX_Matrix matrix;
     if (charpos.m_bGlyphAdjust) {
-      matrix.Set(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
-                 charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
+      matrix = CFX_Matrix(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
+                          charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3],
+                          0, 0);
     }
-    matrix.Concat(font_size, 0, 0, font_size, charpos.m_OriginX,
-                  charpos.m_OriginY);
+    matrix.Concat(CFX_Matrix(font_size, 0, 0, font_size, charpos.m_Origin.x,
+                             charpos.m_Origin.y));
     const CFX_PathData* pPath =
         pFont->LoadGlyphPath(charpos.m_GlyphIndex, charpos.m_FontCharWidth);
     if (!pPath)
       continue;
+
     matrix.Concat(*pText2User);
+
     CFX_PathData TransformedPath(*pPath);
     TransformedPath.Transform(&matrix);
     if (fill_color || stroke_color) {
diff --git a/core/fxge/ge/fx_ge_text.cpp b/core/fxge/ge/fx_ge_text.cpp
index ca88879..669969d 100644
--- a/core/fxge/ge/fx_ge_text.cpp
+++ b/core/fxge/ge/fx_ge_text.cpp
@@ -28,6 +28,12 @@
 
 }  // namespace
 
+FXTEXT_GLYPHPOS::FXTEXT_GLYPHPOS() : m_pGlyph(nullptr) {}
+
+FXTEXT_GLYPHPOS::FXTEXT_GLYPHPOS(const FXTEXT_GLYPHPOS&) = default;
+
+FXTEXT_GLYPHPOS::~FXTEXT_GLYPHPOS(){};
+
 ScopedFontTransform::ScopedFontTransform(FT_Face face, FXFT_Matrix* matrix)
     : m_Face(face) {
   FXFT_Set_Transform(m_Face, matrix, 0);
@@ -48,7 +54,7 @@
     if (!pGlyph)
       continue;
 
-    FX_SAFE_INT32 char_left = glyph.m_OriginX;
+    FX_SAFE_INT32 char_left = glyph.m_Origin.x;
     char_left += pGlyph->m_Left;
     if (!char_left.IsValid())
       continue;
@@ -64,7 +70,7 @@
     if (!char_right.IsValid())
       continue;
 
-    FX_SAFE_INT32 char_top = glyph.m_OriginY;
+    FX_SAFE_INT32 char_top = glyph.m_Origin.y;
     char_top -= pGlyph->m_Top;
     if (!char_top.IsValid())
       continue;
@@ -79,10 +85,14 @@
       continue;
 
     if (bStarted) {
-      rect.left = std::min(rect.left, char_left.ValueOrDie());
-      rect.right = std::max(rect.right, char_right.ValueOrDie());
-      rect.top = std::min(rect.top, char_top.ValueOrDie());
-      rect.bottom = std::max(rect.bottom, char_bottom.ValueOrDie());
+      rect.left = pdfium::base::ValueOrDieForType<int32_t>(
+          pdfium::base::CheckMin(rect.left, char_left));
+      rect.right = pdfium::base::ValueOrDieForType<int32_t>(
+          pdfium::base::CheckMax(rect.right, char_right));
+      rect.top = pdfium::base::ValueOrDieForType<int32_t>(
+          pdfium::base::CheckMin(rect.top, char_top));
+      rect.bottom = pdfium::base::ValueOrDieForType<int32_t>(
+          pdfium::base::CheckMax(rect.bottom, char_bottom));
       continue;
     }
 
diff --git a/core/fxge/ifx_renderdevicedriver.h b/core/fxge/ifx_renderdevicedriver.h
index 6a5b63b..fd35149 100644
--- a/core/fxge/ifx_renderdevicedriver.h
+++ b/core/fxge/ifx_renderdevicedriver.h
@@ -16,8 +16,8 @@
 class CFX_Matrix;
 class CFX_PathData;
 class CPDF_ShadingPattern;
+class FXTEXT_CHARPOS;
 class IFX_Pause;
-struct FXTEXT_CHARPOS;
 struct FX_RECT;
 
 class IFX_RenderDeviceDriver {
diff --git a/core/fxge/skia/fx_skia_device.cpp b/core/fxge/skia/fx_skia_device.cpp
index 2a00483..7e23f97 100644
--- a/core/fxge/skia/fx_skia_device.cpp
+++ b/core/fxge/skia/fx_skia_device.cpp
@@ -45,10 +45,6 @@
 #include "third_party/skia/include/core/SkPictureRecorder.h"
 #endif  // _SKIA_SUPPORT_
 
-#ifdef SK_DEBUG
-#include "third_party/skia/include/core/SkClipStack.h"
-#endif  // SK_DEBUG
-
 namespace {
 
 #ifdef _SKIA_SUPPORT_PATHS_
@@ -195,8 +191,6 @@
   canvas->getClipDeviceBounds(&device);
   printf("device bounds %d %d %d %d\n", device.fLeft, device.fTop,
          device.fRight, device.fBottom);
-  const SkClipStack* clipStack = canvas->getClipStack();
-  clipStack->dump();
 #endif  // SHOW_SKIA_PATH
 }
 
@@ -284,23 +278,21 @@
 SkPath BuildPath(const CFX_PathData* pPathData) {
   SkPath skPath;
   const CFX_PathData* pFPath = pPathData;
-  int nPoints = pFPath->GetPointCount();
-  FX_PATHPOINT* pPoints = pFPath->GetPoints();
-  for (int i = 0; i < nPoints; i++) {
-    FX_FLOAT x = pPoints[i].m_PointX;
-    FX_FLOAT y = pPoints[i].m_PointY;
-    int point_type = pPoints[i].m_Flag & FXPT_TYPE;
-    if (point_type == FXPT_MOVETO) {
-      skPath.moveTo(x, y);
-    } else if (point_type == FXPT_LINETO) {
-      skPath.lineTo(x, y);
-    } else if (point_type == FXPT_BEZIERTO) {
-      FX_FLOAT x2 = pPoints[i + 1].m_PointX, y2 = pPoints[i + 1].m_PointY;
-      FX_FLOAT x3 = pPoints[i + 2].m_PointX, y3 = pPoints[i + 2].m_PointY;
-      skPath.cubicTo(x, y, x2, y2, x3, y3);
+  const std::vector<FX_PATHPOINT>& pPoints = pFPath->GetPoints();
+  for (size_t i = 0; i < pPoints.size(); i++) {
+    CFX_PointF point = pPoints[i].m_Point;
+    FXPT_TYPE point_type = pPoints[i].m_Type;
+    if (point_type == FXPT_TYPE::MoveTo) {
+      skPath.moveTo(point.x, point.y);
+    } else if (point_type == FXPT_TYPE::LineTo) {
+      skPath.lineTo(point.x, point.y);
+    } else if (point_type == FXPT_TYPE::BezierTo) {
+      CFX_PointF point2 = pPoints[i + 1].m_Point;
+      CFX_PointF point3 = pPoints[i + 2].m_Point;
+      skPath.cubicTo(point.x, point.y, point2.x, point2.y, point3.x, point3.y);
       i += 2;
     }
-    if (pPoints[i].m_Flag & FXPT_CLOSEFIGURE)
+    if (pPoints[i].m_CloseFigure)
       skPath.close();
   }
   return skPath;
@@ -312,7 +304,7 @@
   return skMatrix;
 }
 
-// use when pdf's y-axis points up insead of down
+// use when pdf's y-axis points up instead of down
 SkMatrix ToFlippedSkMatrix(const CFX_Matrix& m, SkScalar flip) {
   SkMatrix skMatrix;
   skMatrix.setAll(m.a * flip, -m.c * flip, m.e, m.b * flip, -m.d * flip, m.f, 0,
@@ -809,8 +801,9 @@
       vFlip *= -1;
     for (int index = 0; index < nChars; ++index) {
       const FXTEXT_CHARPOS& cp = pCharPos[index];
-      m_positions[index + count] = {cp.m_OriginX * flip, cp.m_OriginY * vFlip};
-      m_glyphs[index + count] = (uint16_t)cp.m_GlyphIndex;
+      m_positions[index + count] = {cp.m_Origin.x * flip,
+                                    cp.m_Origin.y * vFlip};
+      m_glyphs[index + count] = static_cast<uint16_t>(cp.m_GlyphIndex);
     }
     SkPoint delta;
     if (MatrixOffset(pMatrix, &delta)) {
@@ -1086,7 +1079,6 @@
 #if SHOW_SKIA_PATH
     printf("\n%s\nSkia Save Count %d:\n", where,
            m_pDriver->m_pCanvas->getSaveCount());
-    m_pDriver->m_pCanvas->getClipStack()->dump();
     printf("Cache:\n");
     for (int index = 0; index < m_commands.count(); ++index) {
       DumpPrefix(index);
@@ -1297,8 +1289,8 @@
   glyphs.setCount(nChars);
   for (int index = 0; index < nChars; ++index) {
     const FXTEXT_CHARPOS& cp = pCharPos[index];
-    positions[index] = {cp.m_OriginX * flip, cp.m_OriginY * vFlip};
-    glyphs[index] = (uint16_t)cp.m_GlyphIndex;
+    positions[index] = {cp.m_Origin.x * flip, cp.m_Origin.y * vFlip};
+    glyphs[index] = static_cast<uint16_t>(cp.m_GlyphIndex);
   }
 #ifdef _SKIA_SUPPORT_PATHS_
   m_pBitmap->PreMultiply();
@@ -1439,7 +1431,8 @@
         GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT));
   }
 #endif  // _SKIA_SUPPORT_PATHS_
-  if (pPathData->GetPointCount() == 5 || pPathData->GetPointCount() == 4) {
+  if (pPathData->GetPoints().size() == 5 ||
+      pPathData->GetPoints().size() == 4) {
     CFX_FloatRect rectf;
     if (pPathData->IsRect(deviceMatrix, &rectf)) {
       rectf.Intersect(
@@ -1749,7 +1742,7 @@
       m_pCanvas->clipPath(skClip, SkClipOp::kIntersect, true);
     m_pCanvas->concat(skMatrix);
     while (!stream.BitStream()->IsEOF()) {
-      uint32_t flag = stream.GetFlag();
+      uint32_t flag = stream.ReadFlag();
       int iStartPoint = flag ? 4 : 0;
       int iStartColor = flag ? 2 : 0;
       if (flag) {
@@ -1762,11 +1755,16 @@
         tempColors[1] = colors[(flag + 1) % 4];
         FXSYS_memcpy(colors, tempColors, sizeof(tempColors));
       }
-      for (int i = iStartPoint; i < (int)SK_ARRAY_COUNT(cubics); i++)
-        stream.GetCoords(cubics[i].fX, cubics[i].fY);
+      for (int i = iStartPoint; i < (int)SK_ARRAY_COUNT(cubics); i++) {
+        CFX_PointF point = stream.ReadCoords();
+        cubics[i].fX = point.x;
+        cubics[i].fY = point.y;
+      }
       for (int i = iStartColor; i < (int)SK_ARRAY_COUNT(colors); i++) {
-        FX_FLOAT r = 0.0f, g = 0.0f, b = 0.0f;
-        stream.GetColor(r, g, b);
+        FX_FLOAT r;
+        FX_FLOAT g;
+        FX_FLOAT b;
+        std::tie(r, g, b) = stream.ReadColor();
         colors[i] = SkColorSetARGBInline(0xFF, (U8CPU)(r * 255),
                                          (U8CPU)(g * 255), (U8CPU)(b * 255));
       }
diff --git a/core/fxge/skia/fx_skia_device.h b/core/fxge/skia/fx_skia_device.h
index ff81dae..ecb1104 100644
--- a/core/fxge/skia/fx_skia_device.h
+++ b/core/fxge/skia/fx_skia_device.h
@@ -13,13 +13,13 @@
 #include "core/fxge/cfx_pathdata.h"
 #include "core/fxge/ifx_renderdevicedriver.h"
 
+class FXTEXT_CHARPOS;
 class SkCanvas;
 class SkMatrix;
 class SkPaint;
 class SkPath;
 class SkPictureRecorder;
 class SkiaState;
-struct FXTEXT_CHARPOS;
 struct SkIRect;
 
 class CFX_SkiaDeviceDriver : public IFX_RenderDeviceDriver {
diff --git a/core/fxge/skia/fx_skia_device_unittest.cpp b/core/fxge/skia/fx_skia_device_unittest.cpp
index c77c8f8..afd4778 100644
--- a/core/fxge/skia/fx_skia_device_unittest.cpp
+++ b/core/fxge/skia/fx_skia_device_unittest.cpp
@@ -35,7 +35,11 @@
 }
 
 void CommonTest(CFX_SkiaDeviceDriver* driver, const State& state) {
-  FXTEXT_CHARPOS charPos[] = {{{0, 0, 0, 0}, 0, 1, 1, 4, false, false}};
+  FXTEXT_CHARPOS charPos[1];
+  charPos[0].m_Origin = CFX_PointF(0, 1);
+  charPos[0].m_GlyphIndex = 1;
+  charPos[0].m_FontCharWidth = 4;
+
   CFX_Font font;
   FX_FLOAT fontSize = 1;
   CFX_PathData clipPath, clipPath2;
@@ -46,7 +50,9 @@
   driver->SaveState();
   CFX_PathData path1;
   path1.AppendRect(0, 0, 1, 2);
-  CFX_Matrix matrix, matrix2;
+
+  CFX_Matrix matrix;
+  CFX_Matrix matrix2;
   matrix2.Translate(1, 0);
   CFX_GraphStateData graphState;
   if (state.m_save == State::Save::kYes)
diff --git a/core/fxge/win32/cfx_psrenderer.cpp b/core/fxge/win32/cfx_psrenderer.cpp
index b62d0cb..74fae08 100644
--- a/core/fxge/win32/cfx_psrenderer.cpp
+++ b/core/fxge/win32/cfx_psrenderer.cpp
@@ -109,37 +109,37 @@
 
 void CFX_PSRenderer::OutputPath(const CFX_PathData* pPathData,
                                 const CFX_Matrix* pObject2Device) {
-  int nPoints = pPathData->GetPointCount();
   CFX_ByteTextBuf buf;
-  buf.EstimateSize(nPoints * 10);
-  for (int i = 0; i < nPoints; i++) {
-    uint8_t flag = pPathData->GetFlag(i);
-    FX_FLOAT x = pPathData->GetPointX(i);
-    FX_FLOAT y = pPathData->GetPointY(i);
-    if (pObject2Device) {
-      pObject2Device->Transform(x, y);
-    }
-    buf << x << " " << y;
-    switch (flag & FXPT_TYPE) {
-      case FXPT_MOVETO:
+  size_t size = pPathData->GetPoints().size();
+  buf.EstimateSize(size * 10);
+
+  for (size_t i = 0; i < size; i++) {
+    FXPT_TYPE type = pPathData->GetType(i);
+    bool closing = pPathData->IsClosingFigure(i);
+    CFX_PointF pos = pPathData->GetPoint(i);
+    if (pObject2Device)
+      pos = pObject2Device->Transform(pos);
+
+    buf << pos.x << " " << pos.y;
+    switch (type) {
+      case FXPT_TYPE::MoveTo:
         buf << " m ";
         break;
-      case FXPT_LINETO:
+      case FXPT_TYPE::LineTo:
         buf << " l ";
-        if (flag & FXPT_CLOSEFIGURE)
+        if (closing)
           buf << "h ";
         break;
-      case FXPT_BEZIERTO: {
-        FX_FLOAT x1 = pPathData->GetPointX(i + 1);
-        FX_FLOAT x2 = pPathData->GetPointX(i + 2);
-        FX_FLOAT y1 = pPathData->GetPointY(i + 1);
-        FX_FLOAT y2 = pPathData->GetPointY(i + 2);
+      case FXPT_TYPE::BezierTo: {
+        CFX_PointF pos1 = pPathData->GetPoint(i + 1);
+        CFX_PointF pos2 = pPathData->GetPoint(i + 2);
         if (pObject2Device) {
-          pObject2Device->Transform(x1, y1);
-          pObject2Device->Transform(x2, y2);
+          pos1 = pObject2Device->Transform(pos1);
+          pos2 = pObject2Device->Transform(pos2);
         }
-        buf << " " << x1 << " " << y1 << " " << x2 << " " << y2 << " c";
-        if (flag & FXPT_CLOSEFIGURE)
+        buf << " " << pos1.x << " " << pos1.y << " " << pos2.x << " " << pos2.y
+            << " c";
+        if (closing)
           buf << " h";
         buf << "\n";
         i += 2;
@@ -157,7 +157,8 @@
   OutputPath(pPathData, pObject2Device);
   CFX_FloatRect rect = pPathData->GetBoundingBox();
   if (pObject2Device)
-    rect.Transform(pObject2Device);
+    pObject2Device->TransformRect(rect);
+
   m_ClipBox.left = static_cast<int>(rect.left);
   m_ClipBox.right = static_cast<int>(rect.left + rect.right);
   m_ClipBox.top = static_cast<int>(rect.top + rect.bottom);
@@ -184,7 +185,7 @@
   OutputPath(pPathData, nullptr);
   CFX_FloatRect rect = pPathData->GetBoundingBox(pGraphState->m_LineWidth,
                                                  pGraphState->m_MiterLimit);
-  rect.Transform(pObject2Device);
+  pObject2Device->TransformRect(rect);
   m_ClipBox.Intersect(rect.GetOuterRect());
   if (pObject2Device) {
     OUTPUT_PS("strokepath W n sm\n");
@@ -580,39 +581,42 @@
     pPSFont->m_Glyphs[glyphindex].m_AdjustMatrix[3] = charpos.m_AdjustMatrix[3];
   }
   pPSFont->m_nGlyphs++;
+
   CFX_Matrix matrix;
-  if (charpos.m_bGlyphAdjust)
-    matrix.Set(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
-               charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
-  matrix.Concat(1.0f, 0, 0, 1.0f, 0, 0);
+  if (charpos.m_bGlyphAdjust) {
+    matrix =
+        CFX_Matrix(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
+                   charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
+  }
+  matrix.Concat(CFX_Matrix(1.0f, 0, 0, 1.0f, 0, 0));
   const CFX_PathData* pPathData = pFaceCache->LoadGlyphPath(
       pFont, charpos.m_GlyphIndex, charpos.m_FontCharWidth);
-  if (!pPathData) {
+  if (!pPathData)
     return;
-  }
+
   CFX_PathData TransformedPath(*pPathData);
-  if (charpos.m_bGlyphAdjust) {
+  if (charpos.m_bGlyphAdjust)
     TransformedPath.Transform(&matrix);
-  }
+
   CFX_ByteTextBuf buf;
   buf << "/X" << *ps_fontnum << " Ff/CharProcs get begin/" << glyphindex
       << "{n ";
-  for (int p = 0; p < TransformedPath.GetPointCount(); p++) {
-    FX_FLOAT x = TransformedPath.GetPointX(p), y = TransformedPath.GetPointY(p);
-    switch (TransformedPath.GetFlag(p) & FXPT_TYPE) {
-      case FXPT_MOVETO: {
-        buf << x << " " << y << " m\n";
+  for (size_t p = 0; p < TransformedPath.GetPoints().size(); p++) {
+    CFX_PointF point = TransformedPath.GetPoint(p);
+    switch (TransformedPath.GetType(p)) {
+      case FXPT_TYPE::MoveTo: {
+        buf << point.x << " " << point.y << " m\n";
         break;
       }
-      case FXPT_LINETO: {
-        buf << x << " " << y << " l\n";
+      case FXPT_TYPE::LineTo: {
+        buf << point.x << " " << point.y << " l\n";
         break;
       }
-      case FXPT_BEZIERTO: {
-        buf << x << " " << y << " " << TransformedPath.GetPointX(p + 1) << " "
-            << TransformedPath.GetPointY(p + 1) << " "
-            << TransformedPath.GetPointX(p + 2) << " "
-            << TransformedPath.GetPointY(p + 2) << " c\n";
+      case FXPT_TYPE::BezierTo: {
+        CFX_PointF point1 = TransformedPath.GetPoint(p + 1);
+        CFX_PointF point2 = TransformedPath.GetPoint(p + 2);
+        buf << point.x << " " << point.y << " " << point1.x << " " << point1.y
+            << " " << point2.x << " " << point2.y << " c\n";
         p += 2;
         break;
       }
@@ -656,7 +660,7 @@
       buf << "/X" << ps_fontnum << " Ff " << font_size << " Fs Sf ";
       last_fontnum = ps_fontnum;
     }
-    buf << pCharPos[i].m_OriginX << " " << pCharPos[i].m_OriginY << " m";
+    buf << pCharPos[i].m_Origin.x << " " << pCharPos[i].m_Origin.y << " m";
     CFX_ByteString hex;
     hex.Format("<%02X>", ps_glyphindex);
     buf << hex.AsStringC() << "Tj\n";
diff --git a/core/fxge/win32/cfx_psrenderer.h b/core/fxge/win32/cfx_psrenderer.h
index e941739..163c618 100644
--- a/core/fxge/win32/cfx_psrenderer.h
+++ b/core/fxge/win32/cfx_psrenderer.h
@@ -22,7 +22,7 @@
 class CFX_Matrix;
 class CFX_PathData;
 class CPSFont;
-struct FXTEXT_CHARPOS;
+class FXTEXT_CHARPOS;
 
 class CFX_PSRenderer {
  public:
diff --git a/core/fxge/win32/fx_win32_device.cpp b/core/fxge/win32/fx_win32_device.cpp
index c673a18..92e9b41 100644
--- a/core/fxge/win32/fx_win32_device.cpp
+++ b/core/fxge/win32/fx_win32_device.cpp
@@ -166,47 +166,45 @@
                  const CFX_PathData* pPathData,
                  const CFX_Matrix* pMatrix) {
   BeginPath(hDC);
-  int nPoints = pPathData->GetPointCount();
-  FX_PATHPOINT* pPoints = pPathData->GetPoints();
-  for (int i = 0; i < nPoints; i++) {
-    FX_FLOAT posx = pPoints[i].m_PointX, posy = pPoints[i].m_PointY;
-    if (pMatrix) {
-      pMatrix->Transform(posx, posy);
-    }
-    int screen_x = FXSYS_round(posx), screen_y = FXSYS_round(posy);
-    int point_type = pPoints[i].m_Flag & FXPT_TYPE;
-    if (point_type == PT_MOVETO) {
-      MoveToEx(hDC, screen_x, screen_y, nullptr);
-    } else if (point_type == PT_LINETO) {
-      if (pPoints[i].m_PointY == pPoints[i - 1].m_PointY &&
-          pPoints[i].m_PointX == pPoints[i - 1].m_PointX) {
-        screen_x++;
-      }
-      LineTo(hDC, screen_x, screen_y);
-    } else if (point_type == PT_BEZIERTO) {
+
+  const std::vector<FX_PATHPOINT>& pPoints = pPathData->GetPoints();
+  for (size_t i = 0; i < pPoints.size(); i++) {
+    CFX_PointF pos = pPoints[i].m_Point;
+    if (pMatrix)
+      pos = pMatrix->Transform(pos);
+
+    CFX_Point screen(FXSYS_round(pos.x), FXSYS_round(pos.y));
+    FXPT_TYPE point_type = pPoints[i].m_Type;
+    if (point_type == FXPT_TYPE::MoveTo) {
+      MoveToEx(hDC, screen.x, screen.y, nullptr);
+    } else if (point_type == FXPT_TYPE::LineTo) {
+      if (pPoints[i].m_Point == pPoints[i - 1].m_Point)
+        screen.x++;
+
+      LineTo(hDC, screen.x, screen.y);
+    } else if (point_type == FXPT_TYPE::BezierTo) {
       POINT lppt[3];
-      lppt[0].x = screen_x;
-      lppt[0].y = screen_y;
-      posx = pPoints[i + 1].m_PointX;
-      posy = pPoints[i + 1].m_PointY;
-      if (pMatrix) {
-        pMatrix->Transform(posx, posy);
-      }
-      lppt[1].x = FXSYS_round(posx);
-      lppt[1].y = FXSYS_round(posy);
-      posx = pPoints[i + 2].m_PointX;
-      posy = pPoints[i + 2].m_PointY;
-      if (pMatrix) {
-        pMatrix->Transform(posx, posy);
-      }
-      lppt[2].x = FXSYS_round(posx);
-      lppt[2].y = FXSYS_round(posy);
+      lppt[0].x = screen.x;
+      lppt[0].y = screen.y;
+
+      pos = pPoints[i + 1].m_Point;
+      if (pMatrix)
+        pos = pMatrix->Transform(pos);
+
+      lppt[1].x = FXSYS_round(pos.x);
+      lppt[1].y = FXSYS_round(pos.y);
+
+      pos = pPoints[i + 2].m_Point;
+      if (pMatrix)
+        pos = pMatrix->Transform(pos);
+
+      lppt[2].x = FXSYS_round(pos.x);
+      lppt[2].y = FXSYS_round(pos.y);
       PolyBezierTo(hDC, lppt, 3);
       i += 2;
     }
-    if (pPoints[i].m_Flag & PT_CLOSEFIGURE) {
+    if (pPoints[i].m_CloseFigure)
       CloseFigure(hDC);
-    }
   }
   EndPath(hDC);
 }
@@ -316,11 +314,6 @@
 }
 #endif  // _SKIA_SUPPORT_
 
-bool MatrixNoScaled(const CFX_Matrix* pMatrix) {
-  return pMatrix->GetA() == 1.0f && pMatrix->GetB() == 0 &&
-         pMatrix->GetC() == 0 && pMatrix->GetD() == 1.0f;
-}
-
 class CFX_Win32FallbackFontInfo final : public CFX_FolderFontInfo {
  public:
   CFX_Win32FallbackFontInfo() {}
@@ -996,9 +989,9 @@
   if (!(pGraphState || stroke_color == 0) &&
       !pPlatform->m_GdiplusExt.IsAvailable()) {
     CFX_FloatRect bbox_f = pPathData->GetBoundingBox();
-    if (pMatrix) {
-      bbox_f.Transform(pMatrix);
-    }
+    if (pMatrix)
+      pMatrix->TransformRect(bbox_f);
+
     FX_RECT bbox = bbox_f.GetInnerRect();
     if (bbox.Width() <= 0) {
       return DrawCosmeticLine(
@@ -1022,10 +1015,10 @@
     if (bDrawAlpha ||
         ((m_DeviceClass != FXDC_PRINTER && !(fill_mode & FXFILL_FULLCOVER)) ||
          (pGraphState && pGraphState->m_DashCount))) {
-      if (!((!pMatrix || MatrixNoScaled(pMatrix)) && pGraphState &&
+      if (!((!pMatrix || !pMatrix->WillScale()) && pGraphState &&
             pGraphState->m_LineWidth == 1.f &&
-            (pPathData->GetPointCount() == 5 ||
-             pPathData->GetPointCount() == 4) &&
+            (pPathData->GetPoints().size() == 5 ||
+             pPathData->GetPoints().size() == 4) &&
             pPathData->IsRect())) {
         if (pPlatform->m_GdiplusExt.DrawPath(m_hDC, pPathData, pMatrix,
                                              pGraphState, fill_color,
@@ -1049,17 +1042,15 @@
     hBrush = CreateBrush(fill_color);
     hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
   }
-  if (pPathData->GetPointCount() == 2 && pGraphState &&
+  if (pPathData->GetPoints().size() == 2 && pGraphState &&
       pGraphState->m_DashCount) {
-    FX_FLOAT x1 = pPathData->GetPointX(0);
-    FX_FLOAT y1 = pPathData->GetPointY(0);
-    FX_FLOAT x2 = pPathData->GetPointX(1);
-    FX_FLOAT y2 = pPathData->GetPointY(1);
+    CFX_PointF pos1 = pPathData->GetPoint(0);
+    CFX_PointF pos2 = pPathData->GetPoint(1);
     if (pMatrix) {
-      pMatrix->Transform(x1, y1);
-      pMatrix->Transform(x2, y2);
+      pos1 = pMatrix->Transform(pos1);
+      pos2 = pMatrix->Transform(pos2);
     }
-    DrawLine(x1, y1, x2, y2);
+    DrawLine(pos1.x, pos1.y, pos2.x, pos2.y);
   } else {
     SetPathToDC(m_hDC, pPathData, pMatrix);
     if (pGraphState && stroke_alpha) {
@@ -1113,7 +1104,7 @@
 bool CGdiDeviceDriver::SetClip_PathFill(const CFX_PathData* pPathData,
                                         const CFX_Matrix* pMatrix,
                                         int fill_mode) {
-  if (pPathData->GetPointCount() == 5) {
+  if (pPathData->GetPoints().size() == 5) {
     CFX_FloatRect rectf;
     if (pPathData->IsRect(pMatrix, &rectf)) {
       FX_RECT rect = rectf.GetOuterRect();
diff --git a/core/fxge/win32/fx_win32_gdipext.cpp b/core/fxge/win32/fx_win32_gdipext.cpp
index cd18525..1be2a54 100644
--- a/core/fxge/win32/fx_win32_gdipext.cpp
+++ b/core/fxge/win32/fx_win32_gdipext.cpp
@@ -1080,15 +1080,16 @@
   for (int i = 0; i < 3; i++) {
     int pair1 = pairs[i * 2];
     int pair2 = pairs[i * 2 + 1];
-    FX_FLOAT x1 = points[pair1].X, x2 = points[pair2].X;
-    FX_FLOAT y1 = points[pair1].Y, y2 = points[pair2].Y;
+
+    CFX_PointF p1(points[pair1].X, points[pair1].Y);
+    CFX_PointF p2(points[pair2].X, points[pair2].Y);
     if (pMatrix) {
-      pMatrix->Transform(x1, y1);
-      pMatrix->Transform(x2, y2);
+      p1 = pMatrix->Transform(p1);
+      p2 = pMatrix->Transform(p2);
     }
-    FX_FLOAT dx = x1 - x2;
-    FX_FLOAT dy = y1 - y2;
-    FX_FLOAT distance_square = (dx * dx) + (dy * dy);
+
+    CFX_PointF diff = p1 - p2;
+    FX_FLOAT distance_square = (diff.x * diff.x) + (diff.y * diff.y);
     if (distance_square < (1.0f * 2 + 1.0f / 4)) {
       v1 = i;
       v2 = pair1;
@@ -1104,11 +1105,10 @@
                            uint32_t fill_argb,
                            uint32_t stroke_argb,
                            int fill_mode) {
-  int nPoints = pPathData->GetPointCount();
-  if (nPoints == 0) {
+  auto& pPoints = pPathData->GetPoints();
+  if (pPoints.empty())
     return true;
-  }
-  FX_PATHPOINT* pPoints = pPathData->GetPoints();
+
   GpGraphics* pGraphics = nullptr;
   CGdiplusExt& GdiplusExt =
       ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
@@ -1122,45 +1122,41 @@
                                 pObject2Device->e, pObject2Device->f, &pMatrix);
     CallFunc(GdipSetWorldTransform)(pGraphics, pMatrix);
   }
-  PointF* points = FX_Alloc(PointF, nPoints);
-  BYTE* types = FX_Alloc(BYTE, nPoints);
+  PointF* points = FX_Alloc(PointF, pPoints.size());
+  BYTE* types = FX_Alloc(BYTE, pPoints.size());
   int nSubPathes = 0;
   bool bSubClose = false;
   int pos_subclose = 0;
   bool bSmooth = false;
   int startpoint = 0;
-  for (int i = 0; i < nPoints; i++) {
-    points[i].X = pPoints[i].m_PointX;
-    points[i].Y = pPoints[i].m_PointY;
-    FX_FLOAT x, y;
-    if (pObject2Device) {
-      pObject2Device->Transform(pPoints[i].m_PointX, pPoints[i].m_PointY, x, y);
-    } else {
-      x = pPoints[i].m_PointX;
-      y = pPoints[i].m_PointY;
-    }
-    if (x > 50000 * 1.0f) {
+  for (size_t i = 0; i < pPoints.size(); i++) {
+    points[i].X = pPoints[i].m_Point.x;
+    points[i].Y = pPoints[i].m_Point.y;
+
+    CFX_PointF pos = pPoints[i].m_Point;
+    if (pObject2Device)
+      pos = pObject2Device->Transform(pos);
+
+    if (pos.x > 50000 * 1.0f)
       points[i].X = 50000 * 1.0f;
-    }
-    if (x < -50000 * 1.0f) {
+    if (pos.x < -50000 * 1.0f)
       points[i].X = -50000 * 1.0f;
-    }
-    if (y > 50000 * 1.0f) {
+    if (pos.y > 50000 * 1.0f)
       points[i].Y = 50000 * 1.0f;
-    }
-    if (y < -50000 * 1.0f) {
+    if (pos.y < -50000 * 1.0f)
       points[i].Y = -50000 * 1.0f;
-    }
-    int point_type = pPoints[i].m_Flag & FXPT_TYPE;
-    if (point_type == FXPT_MOVETO) {
+
+    FXPT_TYPE point_type = pPoints[i].m_Type;
+    if (point_type == FXPT_TYPE::MoveTo) {
       types[i] = PathPointTypeStart;
       nSubPathes++;
       bSubClose = false;
       startpoint = i;
-    } else if (point_type == FXPT_LINETO) {
+    } else if (point_type == FXPT_TYPE::LineTo) {
       types[i] = PathPointTypeLine;
-      if (pPoints[i - 1].m_Flag == FXPT_MOVETO &&
-          (i == nPoints - 1 || pPoints[i + 1].m_Flag == FXPT_MOVETO) &&
+      if (pPoints[i - 1].IsTypeAndOpen(FXPT_TYPE::MoveTo) &&
+          (i == pPoints.size() - 1 ||
+           pPoints[i + 1].IsTypeAndOpen(FXPT_TYPE::MoveTo)) &&
           points[i].Y == points[i - 1].Y && points[i].X == points[i - 1].X) {
         points[i].X += 0.01f;
         continue;
@@ -1169,11 +1165,11 @@
           points[i].Y != points[i - 1].Y) {
         bSmooth = true;
       }
-    } else if (point_type == FXPT_BEZIERTO) {
+    } else if (point_type == FXPT_TYPE::BezierTo) {
       types[i] = PathPointTypeBezier;
       bSmooth = true;
     }
-    if (pPoints[i].m_Flag & FXPT_CLOSEFIGURE) {
+    if (pPoints[i].m_CloseFigure) {
       if (bSubClose) {
         types[pos_subclose] &= ~PathPointTypeCloseSubpath;
       } else {
@@ -1199,7 +1195,7 @@
     }
   }
   int new_fill_mode = fill_mode & 3;
-  if (nPoints == 4 && !pGraphState) {
+  if (pPoints.size() == 4 && !pGraphState) {
     int v1, v2;
     if (IsSmallTriangle(points, pObject2Device, v1, v2)) {
       GpPen* pPen = nullptr;
@@ -1212,12 +1208,12 @@
     }
   }
   GpPath* pGpPath = nullptr;
-  CallFunc(GdipCreatePath2)(points, types, nPoints,
+  CallFunc(GdipCreatePath2)(points, types, pPoints.size(),
                             GdiFillType2Gdip(new_fill_mode), &pGpPath);
   if (!pGpPath) {
-    if (pMatrix) {
+    if (pMatrix)
       CallFunc(GdipDeleteMatrix)(pMatrix);
-    }
+
     FX_Free(points);
     FX_Free(types);
     CallFunc(GdipDeleteGraphics)(pGraphics);
@@ -1236,8 +1232,8 @@
       CallFunc(GdipDrawPath)(pGraphics, pPen, pGpPath);
     } else {
       int iStart = 0;
-      for (int i = 0; i < nPoints; i++) {
-        if (i == nPoints - 1 || types[i + 1] == PathPointTypeStart) {
+      for (size_t i = 0; i < pPoints.size(); i++) {
+        if (i == pPoints.size() - 1 || types[i + 1] == PathPointTypeStart) {
           GpPath* pSubPath;
           CallFunc(GdipCreatePath2)(points + iStart, types + iStart,
                                     i - iStart + 1,
diff --git a/core/fxge/win32/fx_win32_print.cpp b/core/fxge/win32/fx_win32_print.cpp
index 94c415b..cda83eb 100644
--- a/core/fxge/win32/fx_win32_print.cpp
+++ b/core/fxge/win32/fx_win32_print.cpp
@@ -269,12 +269,12 @@
   // Transforms
   SetGraphicsMode(m_hDC, GM_ADVANCED);
   XFORM xform;
-  xform.eM11 = pObject2Device->GetA() / kScaleFactor;
-  xform.eM12 = pObject2Device->GetB() / kScaleFactor;
-  xform.eM21 = -pObject2Device->GetC() / kScaleFactor;
-  xform.eM22 = -pObject2Device->GetD() / kScaleFactor;
-  xform.eDx = pObject2Device->GetE();
-  xform.eDy = pObject2Device->GetF();
+  xform.eM11 = pObject2Device->a / kScaleFactor;
+  xform.eM12 = pObject2Device->b / kScaleFactor;
+  xform.eM21 = -pObject2Device->c / kScaleFactor;
+  xform.eM22 = -pObject2Device->d / kScaleFactor;
+  xform.eDx = pObject2Device->e;
+  xform.eDy = pObject2Device->f;
   ModifyWorldTransform(m_hDC, &xform, MWT_LEFTMULTIPLY);
 
   // Color
@@ -296,11 +296,11 @@
     ASSERT(charpos.m_AdjustMatrix[1] == 0);
     ASSERT(charpos.m_AdjustMatrix[2] == 0);
     ASSERT(charpos.m_AdjustMatrix[3] == 0);
-    ASSERT(charpos.m_OriginY == 0);
+    ASSERT(charpos.m_Origin.y == 0);
 
     // Round the spacing to the nearest integer, but keep track of the rounding
     // error for calculating the next spacing value.
-    FX_FLOAT fOriginX = charpos.m_OriginX * kScaleFactor;
+    FX_FLOAT fOriginX = charpos.m_Origin.x * kScaleFactor;
     FX_FLOAT fPixelSpacing = fOriginX - fPreviousOriginX;
     spacing[i] = FXSYS_round(fPixelSpacing);
     fPreviousOriginX = fOriginX - (fPixelSpacing - spacing[i]);
@@ -346,12 +346,13 @@
       ret = ::GetRegionData(hRgn, ret, pData);
       if (ret) {
         CFX_PathData path;
-        path.AllocPointCount(pData->rdh.nCount * 5);
         for (uint32_t i = 0; i < pData->rdh.nCount; i++) {
           RECT* pRect =
               reinterpret_cast<RECT*>(pData->Buffer + pData->rdh.nRgnSize * i);
-          path.AppendRect((FX_FLOAT)pRect->left, (FX_FLOAT)pRect->bottom,
-                          (FX_FLOAT)pRect->right, (FX_FLOAT)pRect->top);
+          path.AppendRect(static_cast<FX_FLOAT>(pRect->left),
+                          static_cast<FX_FLOAT>(pRect->bottom),
+                          static_cast<FX_FLOAT>(pRect->right),
+                          static_cast<FX_FLOAT>(pRect->top));
         }
         m_PSRenderer.SetClip_PathFill(&path, nullptr, FXFILL_WINDING);
       }
diff --git a/core/fxge/win32/win32_int.h b/core/fxge/win32/win32_int.h
index 974a120..f8eae87 100644
--- a/core/fxge/win32/win32_int.h
+++ b/core/fxge/win32/win32_int.h
@@ -17,7 +17,7 @@
 #include "core/fxge/win32/cpsoutput.h"
 #include "core/fxge/win32/dwrite_int.h"
 
-struct FXTEXT_CHARPOS;
+class FXTEXT_CHARPOS;
 struct WINDIB_Open_Args_;
 
 typedef HANDLE(__stdcall* FuncType_GdiAddFontMemResourceEx)(PVOID pbFont,
diff --git a/fpdfsdk/cfx_systemhandler.cpp b/fpdfsdk/cfx_systemhandler.cpp
index f38be4c..b6dc19d 100644
--- a/fpdfsdk/cfx_systemhandler.cpp
+++ b/fpdfsdk/cfx_systemhandler.cpp
@@ -46,19 +46,14 @@
   CFX_Matrix device2page;
   device2page.SetReverse(page2device);
 
-  FX_FLOAT left;
-  FX_FLOAT top;
-  FX_FLOAT right;
-  FX_FLOAT bottom;
-  device2page.Transform(static_cast<FX_FLOAT>(rect.left),
-                        static_cast<FX_FLOAT>(rect.top), left, top);
-  device2page.Transform(static_cast<FX_FLOAT>(rect.right),
-                        static_cast<FX_FLOAT>(rect.bottom), right, bottom);
-  CFX_FloatRect rcPDF(left, bottom, right, top);
-  rcPDF.Normalize();
+  CFX_PointF left_top = device2page.Transform(CFX_PointF(
+      static_cast<FX_FLOAT>(rect.left), static_cast<FX_FLOAT>(rect.top)));
+  CFX_PointF right_bottom = device2page.Transform(CFX_PointF(
+      static_cast<FX_FLOAT>(rect.right), static_cast<FX_FLOAT>(rect.bottom)));
 
-  m_pFormFillEnv->Invalidate(pPage, rcPDF.left, rcPDF.top, rcPDF.right,
-                             rcPDF.bottom);
+  CFX_FloatRect rcPDF(left_top.x, right_bottom.y, right_bottom.x, left_top.y);
+  rcPDF.Normalize();
+  m_pFormFillEnv->Invalidate(pPage, rcPDF.ToFxRect());
 }
 
 void CFX_SystemHandler::OutputSelectedRect(CFFL_FormFiller* pFormFiller,
@@ -66,16 +61,15 @@
   if (!pFormFiller)
     return;
 
-  CFX_FloatPoint leftbottom = CFX_FloatPoint(rect.left, rect.bottom);
-  CFX_FloatPoint righttop = CFX_FloatPoint(rect.right, rect.top);
-  CFX_FloatPoint ptA = pFormFiller->PWLtoFFL(leftbottom);
-  CFX_FloatPoint ptB = pFormFiller->PWLtoFFL(righttop);
+  CFX_PointF ptA = pFormFiller->PWLtoFFL(CFX_PointF(rect.left, rect.bottom));
+  CFX_PointF ptB = pFormFiller->PWLtoFFL(CFX_PointF(rect.right, rect.top));
 
   CPDFSDK_Annot* pAnnot = pFormFiller->GetSDKAnnot();
   UnderlyingPageType* pPage = pAnnot->GetUnderlyingPage();
   ASSERT(pPage);
 
-  m_pFormFillEnv->OutputSelectedRect(pPage, ptA.x, ptB.y, ptB.x, ptA.y);
+  m_pFormFillEnv->OutputSelectedRect(pPage,
+                                     CFX_FloatRect(ptA.x, ptA.y, ptB.x, ptB.y));
 }
 
 bool CFX_SystemHandler::IsSelectionImplemented() const {
diff --git a/fpdfsdk/cpdfsdk_annothandlermgr.cpp b/fpdfsdk/cpdfsdk_annothandlermgr.cpp
index 898b9cc..c499067 100644
--- a/fpdfsdk/cpdfsdk_annothandlermgr.cpp
+++ b/fpdfsdk/cpdfsdk_annothandlermgr.cpp
@@ -106,7 +106,7 @@
     CPDFSDK_PageView* pPageView,
     CPDFSDK_Annot::ObservedPtr* pAnnot,
     uint32_t nFlags,
-    const CFX_FloatPoint& point) {
+    const CFX_PointF& point) {
   ASSERT(*pAnnot);
   return GetAnnotHandler(pAnnot->Get())
       ->OnLButtonDown(pPageView, pAnnot, nFlags, point);
@@ -116,7 +116,7 @@
     CPDFSDK_PageView* pPageView,
     CPDFSDK_Annot::ObservedPtr* pAnnot,
     uint32_t nFlags,
-    const CFX_FloatPoint& point) {
+    const CFX_PointF& point) {
   ASSERT(*pAnnot);
   return GetAnnotHandler(pAnnot->Get())
       ->OnLButtonUp(pPageView, pAnnot, nFlags, point);
@@ -126,7 +126,7 @@
     CPDFSDK_PageView* pPageView,
     CPDFSDK_Annot::ObservedPtr* pAnnot,
     uint32_t nFlags,
-    const CFX_FloatPoint& point) {
+    const CFX_PointF& point) {
   ASSERT(*pAnnot);
   return GetAnnotHandler(pAnnot->Get())
       ->OnLButtonDblClk(pPageView, pAnnot, nFlags, point);
@@ -136,7 +136,7 @@
     CPDFSDK_PageView* pPageView,
     CPDFSDK_Annot::ObservedPtr* pAnnot,
     uint32_t nFlags,
-    const CFX_FloatPoint& point) {
+    const CFX_PointF& point) {
   ASSERT(*pAnnot);
   return GetAnnotHandler(pAnnot->Get())
       ->OnMouseMove(pPageView, pAnnot, nFlags, point);
@@ -147,7 +147,7 @@
     CPDFSDK_Annot::ObservedPtr* pAnnot,
     uint32_t nFlags,
     short zDelta,
-    const CFX_FloatPoint& point) {
+    const CFX_PointF& point) {
   ASSERT(*pAnnot);
   return GetAnnotHandler(pAnnot->Get())
       ->OnMouseWheel(pPageView, pAnnot, nFlags, zDelta, point);
@@ -157,7 +157,7 @@
     CPDFSDK_PageView* pPageView,
     CPDFSDK_Annot::ObservedPtr* pAnnot,
     uint32_t nFlags,
-    const CFX_FloatPoint& point) {
+    const CFX_PointF& point) {
   ASSERT(*pAnnot);
   return GetAnnotHandler(pAnnot->Get())
       ->OnRButtonDown(pPageView, pAnnot, nFlags, point);
@@ -167,7 +167,7 @@
     CPDFSDK_PageView* pPageView,
     CPDFSDK_Annot::ObservedPtr* pAnnot,
     uint32_t nFlags,
-    const CFX_FloatPoint& point) {
+    const CFX_PointF& point) {
   ASSERT(*pAnnot);
   return GetAnnotHandler(pAnnot->Get())
       ->OnRButtonUp(pPageView, pAnnot, nFlags, point);
@@ -263,7 +263,7 @@
 
 bool CPDFSDK_AnnotHandlerMgr::Annot_OnHitTest(CPDFSDK_PageView* pPageView,
                                               CPDFSDK_Annot* pAnnot,
-                                              const CFX_FloatPoint& point) {
+                                              const CFX_PointF& point) {
   ASSERT(pAnnot);
   IPDFSDK_AnnotHandler* pAnnotHandler = GetAnnotHandler(pAnnot);
   if (pAnnotHandler->CanAnswer(pAnnot))
diff --git a/fpdfsdk/cpdfsdk_annothandlermgr.h b/fpdfsdk/cpdfsdk_annothandlermgr.h
index 7742fd6..cbda02c 100644
--- a/fpdfsdk/cpdfsdk_annothandlermgr.h
+++ b/fpdfsdk/cpdfsdk_annothandlermgr.h
@@ -58,32 +58,32 @@
   bool Annot_OnLButtonDown(CPDFSDK_PageView* pPageView,
                            CPDFSDK_Annot::ObservedPtr* pAnnot,
                            uint32_t nFlags,
-                           const CFX_FloatPoint& point);
+                           const CFX_PointF& point);
   bool Annot_OnLButtonUp(CPDFSDK_PageView* pPageView,
                          CPDFSDK_Annot::ObservedPtr* pAnnot,
                          uint32_t nFlags,
-                         const CFX_FloatPoint& point);
+                         const CFX_PointF& point);
   bool Annot_OnLButtonDblClk(CPDFSDK_PageView* pPageView,
                              CPDFSDK_Annot::ObservedPtr* pAnnot,
                              uint32_t nFlags,
-                             const CFX_FloatPoint& point);
+                             const CFX_PointF& point);
   bool Annot_OnMouseMove(CPDFSDK_PageView* pPageView,
                          CPDFSDK_Annot::ObservedPtr* pAnnot,
                          uint32_t nFlags,
-                         const CFX_FloatPoint& point);
+                         const CFX_PointF& point);
   bool Annot_OnMouseWheel(CPDFSDK_PageView* pPageView,
                           CPDFSDK_Annot::ObservedPtr* pAnnot,
                           uint32_t nFlags,
                           short zDelta,
-                          const CFX_FloatPoint& point);
+                          const CFX_PointF& point);
   bool Annot_OnRButtonDown(CPDFSDK_PageView* pPageView,
                            CPDFSDK_Annot::ObservedPtr* pAnnot,
                            uint32_t nFlags,
-                           const CFX_FloatPoint& point);
+                           const CFX_PointF& point);
   bool Annot_OnRButtonUp(CPDFSDK_PageView* pPageView,
                          CPDFSDK_Annot::ObservedPtr* pAnnot,
                          uint32_t nFlags,
-                         const CFX_FloatPoint& point);
+                         const CFX_PointF& point);
   bool Annot_OnChar(CPDFSDK_Annot* pAnnot, uint32_t nChar, uint32_t nFlags);
   bool Annot_OnKeyDown(CPDFSDK_Annot* pAnnot, int nKeyCode, int nFlag);
   bool Annot_OnKeyUp(CPDFSDK_Annot* pAnnot, int nKeyCode, int nFlag);
@@ -100,7 +100,7 @@
                                     CPDFSDK_Annot* pAnnot);
   bool Annot_OnHitTest(CPDFSDK_PageView* pPageView,
                        CPDFSDK_Annot* pAnnot,
-                       const CFX_FloatPoint& point);
+                       const CFX_PointF& point);
 
  private:
   IPDFSDK_AnnotHandler* GetAnnotHandler(CPDF_Annot::Subtype nSubtype) const;
diff --git a/fpdfsdk/cpdfsdk_baannothandler.cpp b/fpdfsdk/cpdfsdk_baannothandler.cpp
index 617d88f..fa83932 100644
--- a/fpdfsdk/cpdfsdk_baannothandler.cpp
+++ b/fpdfsdk/cpdfsdk_baannothandler.cpp
@@ -96,28 +96,28 @@
 bool CPDFSDK_BAAnnotHandler::OnLButtonDown(CPDFSDK_PageView* pPageView,
                                            CPDFSDK_Annot::ObservedPtr* pAnnot,
                                            uint32_t nFlags,
-                                           const CFX_FloatPoint& point) {
+                                           const CFX_PointF& point) {
   return false;
 }
 
 bool CPDFSDK_BAAnnotHandler::OnLButtonUp(CPDFSDK_PageView* pPageView,
                                          CPDFSDK_Annot::ObservedPtr* pAnnot,
                                          uint32_t nFlags,
-                                         const CFX_FloatPoint& point) {
+                                         const CFX_PointF& point) {
   return false;
 }
 
 bool CPDFSDK_BAAnnotHandler::OnLButtonDblClk(CPDFSDK_PageView* pPageView,
                                              CPDFSDK_Annot::ObservedPtr* pAnnot,
                                              uint32_t nFlags,
-                                             const CFX_FloatPoint& point) {
+                                             const CFX_PointF& point) {
   return false;
 }
 
 bool CPDFSDK_BAAnnotHandler::OnMouseMove(CPDFSDK_PageView* pPageView,
                                          CPDFSDK_Annot::ObservedPtr* pAnnot,
                                          uint32_t nFlags,
-                                         const CFX_FloatPoint& point) {
+                                         const CFX_PointF& point) {
   return false;
 }
 
@@ -125,28 +125,28 @@
                                           CPDFSDK_Annot::ObservedPtr* pAnnot,
                                           uint32_t nFlags,
                                           short zDelta,
-                                          const CFX_FloatPoint& point) {
+                                          const CFX_PointF& point) {
   return false;
 }
 
 bool CPDFSDK_BAAnnotHandler::OnRButtonDown(CPDFSDK_PageView* pPageView,
                                            CPDFSDK_Annot::ObservedPtr* pAnnot,
                                            uint32_t nFlags,
-                                           const CFX_FloatPoint& point) {
+                                           const CFX_PointF& point) {
   return false;
 }
 
 bool CPDFSDK_BAAnnotHandler::OnRButtonUp(CPDFSDK_PageView* pPageView,
                                          CPDFSDK_Annot::ObservedPtr* pAnnot,
                                          uint32_t nFlags,
-                                         const CFX_FloatPoint& point) {
+                                         const CFX_PointF& point) {
   return false;
 }
 
 bool CPDFSDK_BAAnnotHandler::OnRButtonDblClk(CPDFSDK_PageView* pPageView,
                                              CPDFSDK_Annot::ObservedPtr* pAnnot,
                                              uint32_t nFlags,
-                                             const CFX_FloatPoint& point) {
+                                             const CFX_PointF& point) {
   return false;
 }
 
@@ -195,10 +195,8 @@
 
 bool CPDFSDK_BAAnnotHandler::HitTest(CPDFSDK_PageView* pPageView,
                                      CPDFSDK_Annot* pAnnot,
-                                     const CFX_FloatPoint& point) {
+                                     const CFX_PointF& point) {
   ASSERT(pPageView);
   ASSERT(pAnnot);
-
-  CFX_FloatRect rect = GetViewBBox(pPageView, pAnnot);
-  return rect.Contains(point.x, point.y);
+  return GetViewBBox(pPageView, pAnnot).Contains(point);
 }
diff --git a/fpdfsdk/cpdfsdk_baannothandler.h b/fpdfsdk/cpdfsdk_baannothandler.h
index 2efed0e..d5f170f 100644
--- a/fpdfsdk/cpdfsdk_baannothandler.h
+++ b/fpdfsdk/cpdfsdk_baannothandler.h
@@ -39,7 +39,7 @@
                             CPDFSDK_Annot* pAnnot) override;
   bool HitTest(CPDFSDK_PageView* pPageView,
                CPDFSDK_Annot* pAnnot,
-               const CFX_FloatPoint& point) override;
+               const CFX_PointF& point) override;
   void OnDraw(CPDFSDK_PageView* pPageView,
               CPDFSDK_Annot* pAnnot,
               CFX_RenderDevice* pDevice,
@@ -56,36 +56,36 @@
   bool OnLButtonDown(CPDFSDK_PageView* pPageView,
                      CPDFSDK_Annot::ObservedPtr* pAnnot,
                      uint32_t nFlags,
-                     const CFX_FloatPoint& point) override;
+                     const CFX_PointF& point) override;
   bool OnLButtonUp(CPDFSDK_PageView* pPageView,
                    CPDFSDK_Annot::ObservedPtr* pAnnot,
                    uint32_t nFlags,
-                   const CFX_FloatPoint& point) override;
+                   const CFX_PointF& point) override;
   bool OnLButtonDblClk(CPDFSDK_PageView* pPageView,
                        CPDFSDK_Annot::ObservedPtr* pAnnot,
                        uint32_t nFlags,
-                       const CFX_FloatPoint& point) override;
+                       const CFX_PointF& point) override;
   bool OnMouseMove(CPDFSDK_PageView* pPageView,
                    CPDFSDK_Annot::ObservedPtr* pAnnot,
                    uint32_t nFlags,
-                   const CFX_FloatPoint& point) override;
+                   const CFX_PointF& point) override;
   bool OnMouseWheel(CPDFSDK_PageView* pPageView,
                     CPDFSDK_Annot::ObservedPtr* pAnnot,
                     uint32_t nFlags,
                     short zDelta,
-                    const CFX_FloatPoint& point) override;
+                    const CFX_PointF& point) override;
   bool OnRButtonDown(CPDFSDK_PageView* pPageView,
                      CPDFSDK_Annot::ObservedPtr* pAnnot,
                      uint32_t nFlags,
-                     const CFX_FloatPoint& point) override;
+                     const CFX_PointF& point) override;
   bool OnRButtonUp(CPDFSDK_PageView* pPageView,
                    CPDFSDK_Annot::ObservedPtr* pAnnot,
                    uint32_t nFlags,
-                   const CFX_FloatPoint& point) override;
+                   const CFX_PointF& point) override;
   bool OnRButtonDblClk(CPDFSDK_PageView* pPageView,
                        CPDFSDK_Annot::ObservedPtr* pAnnot,
                        uint32_t nFlags,
-                       const CFX_FloatPoint& point) override;
+                       const CFX_PointF& point) override;
   bool OnChar(CPDFSDK_Annot* pAnnot, uint32_t nChar, uint32_t nFlags) override;
   bool OnKeyDown(CPDFSDK_Annot* pAnnot, int nKeyCode, int nFlag) override;
   bool OnKeyUp(CPDFSDK_Annot* pAnnot, int nKeyCode, int nFlag) override;
diff --git a/fpdfsdk/cpdfsdk_formfillenvironment.cpp b/fpdfsdk/cpdfsdk_formfillenvironment.cpp
index b91c978..4ef766d 100644
--- a/fpdfsdk/cpdfsdk_formfillenvironment.cpp
+++ b/fpdfsdk/cpdfsdk_formfillenvironment.cpp
@@ -233,21 +233,20 @@
 }
 
 void CPDFSDK_FormFillEnvironment::Invalidate(FPDF_PAGE page,
-                                             double left,
-                                             double top,
-                                             double right,
-                                             double bottom) {
-  if (m_pInfo && m_pInfo->FFI_Invalidate)
-    m_pInfo->FFI_Invalidate(m_pInfo, page, left, top, right, bottom);
+                                             const FX_RECT& rect) {
+  if (m_pInfo && m_pInfo->FFI_Invalidate) {
+    m_pInfo->FFI_Invalidate(m_pInfo, page, rect.left, rect.top, rect.right,
+                            rect.bottom);
+  }
 }
 
-void CPDFSDK_FormFillEnvironment::OutputSelectedRect(FPDF_PAGE page,
-                                                     double left,
-                                                     double top,
-                                                     double right,
-                                                     double bottom) {
-  if (m_pInfo && m_pInfo->FFI_OutputSelectedRect)
-    m_pInfo->FFI_OutputSelectedRect(m_pInfo, page, left, top, right, bottom);
+void CPDFSDK_FormFillEnvironment::OutputSelectedRect(
+    FPDF_PAGE page,
+    const CFX_FloatRect& rect) {
+  if (m_pInfo && m_pInfo->FFI_OutputSelectedRect) {
+    m_pInfo->FFI_OutputSelectedRect(m_pInfo, page, rect.left, rect.top,
+                                    rect.right, rect.bottom);
+  }
 }
 
 void CPDFSDK_FormFillEnvironment::SetCursor(int nCursorType) {
diff --git a/fpdfsdk/cpdfsdk_formfillenvironment.h b/fpdfsdk/cpdfsdk_formfillenvironment.h
index 8c2a8a3..eead873 100644
--- a/fpdfsdk/cpdfsdk_formfillenvironment.h
+++ b/fpdfsdk/cpdfsdk_formfillenvironment.h
@@ -68,16 +68,8 @@
   void ProcJavascriptFun();
   bool ProcOpenAction();
 
-  void Invalidate(FPDF_PAGE page,
-                  double left,
-                  double top,
-                  double right,
-                  double bottom);
-  void OutputSelectedRect(FPDF_PAGE page,
-                          double left,
-                          double top,
-                          double right,
-                          double bottom);
+  void Invalidate(FPDF_PAGE page, const FX_RECT& rect);
+  void OutputSelectedRect(FPDF_PAGE page, const CFX_FloatRect& rect);
 
   void SetCursor(int nCursorType);
   int SetTimer(int uElapse, TimerCallback lpTimerFunc);
diff --git a/fpdfsdk/cpdfsdk_interform.cpp b/fpdfsdk/cpdfsdk_interform.cpp
index 7b77180..4ebcf8a 100644
--- a/fpdfsdk/cpdfsdk_interform.cpp
+++ b/fpdfsdk/cpdfsdk_interform.cpp
@@ -30,7 +30,7 @@
 #include "fpdfsdk/fsdk_define.h"
 #include "fpdfsdk/fxedit/fxet_edit.h"
 #include "fpdfsdk/ipdfsdk_annothandler.h"
-#include "fpdfsdk/javascript/ijs_context.h"
+#include "fpdfsdk/javascript/ijs_event_context.h"
 #include "fpdfsdk/javascript/ijs_runtime.h"
 #include "fpdfsdk/pdfwindow/PWL_Utils.h"
 #include "third_party/base/stl_util.h"
@@ -253,7 +253,7 @@
     if (csJS.IsEmpty())
       continue;
 
-    IJS_Context* pContext = pRuntime->NewContext();
+    IJS_EventContext* pContext = pRuntime->NewEventContext();
     CFX_WideString sOldValue = pField->GetValue();
     CFX_WideString sValue = sOldValue;
     bool bRC = true;
@@ -261,12 +261,10 @@
 
     CFX_WideString sInfo;
     bool bRet = pContext->RunScript(csJS, &sInfo);
-    pRuntime->ReleaseContext(pContext);
-
+    pRuntime->ReleaseEventContext(pContext);
     if (bRet && bRC && sValue.Compare(sOldValue) != 0)
       pField->SetValue(sValue, true);
   }
-
   m_bBusy = false;
 }
 
@@ -296,12 +294,11 @@
       if (!script.IsEmpty()) {
         CFX_WideString Value = sValue;
 
-        IJS_Context* pContext = pRuntime->NewContext();
+        IJS_EventContext* pContext = pRuntime->NewEventContext();
         pContext->OnField_Format(pFormField, Value, true);
         CFX_WideString sInfo;
         bool bRet = pContext->RunScript(script, &sInfo);
-        pRuntime->ReleaseContext(pContext);
-
+        pRuntime->ReleaseEventContext(pContext);
         if (bRet) {
           sValue = Value;
           bFormatted = true;
@@ -309,7 +306,6 @@
       }
     }
   }
-
   return sValue;
 }
 
@@ -325,18 +321,16 @@
 }
 
 void CPDFSDK_InterForm::UpdateField(CPDF_FormField* pFormField) {
+  auto formfiller = m_pFormFillEnv->GetInteractiveFormFiller();
   for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
     CPDF_FormControl* pFormCtrl = pFormField->GetControl(i);
     ASSERT(pFormCtrl);
 
     if (CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl)) {
       UnderlyingPageType* pPage = pWidget->GetUnderlyingPage();
-      CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetPageView(pPage, false);
-      FX_RECT rcBBox = m_pFormFillEnv->GetInteractiveFormFiller()->GetViewBBox(
-          pPageView, pWidget);
-
-      m_pFormFillEnv->Invalidate(pPage, rcBBox.left, rcBBox.top, rcBBox.right,
-                                 rcBBox.bottom);
+      m_pFormFillEnv->Invalidate(
+          pPage, formfiller->GetViewBBox(
+                     m_pFormFillEnv->GetPageView(pPage, false), pWidget));
     }
   }
 }
@@ -427,13 +421,13 @@
     std::vector<CPDF_FormField*> fields = GetFieldFromObjects(fieldObjects);
     if (!fields.empty()) {
       bool bIncludeOrExclude = !(dwFlags & 0x01);
-      if (m_pInterForm->CheckRequiredFields(&fields, bIncludeOrExclude))
+      if (!m_pInterForm->CheckRequiredFields(&fields, bIncludeOrExclude))
         return false;
 
       return SubmitFields(sDestination, fields, bIncludeOrExclude, false);
     }
   }
-  if (m_pInterForm->CheckRequiredFields(nullptr, true))
+  if (!m_pInterForm->CheckRequiredFields(nullptr, true))
     return false;
 
   return SubmitForm(sDestination, false);
diff --git a/fpdfsdk/cpdfsdk_pageview.cpp b/fpdfsdk/cpdfsdk_pageview.cpp
index 416adff..c67948d 100644
--- a/fpdfsdk/cpdfsdk_pageview.cpp
+++ b/fpdfsdk/cpdfsdk_pageview.cpp
@@ -95,13 +95,11 @@
     return;
 
   if (pPage->GetContext()->GetDocType() == DOCTYPE_DYNAMIC_XFA) {
-    CFX_Graphics gs;
-    gs.Create(pDevice);
-    CFX_RectF rectClip;
-    rectClip.Set(static_cast<FX_FLOAT>(pClip.left),
-                 static_cast<FX_FLOAT>(pClip.top),
-                 static_cast<FX_FLOAT>(pClip.Width()),
-                 static_cast<FX_FLOAT>(pClip.Height()));
+    CFX_Graphics gs(pDevice);
+    CFX_RectF rectClip(static_cast<FX_FLOAT>(pClip.left),
+                       static_cast<FX_FLOAT>(pClip.top),
+                       static_cast<FX_FLOAT>(pClip.Width()),
+                       static_cast<FX_FLOAT>(pClip.Height()));
     gs.SetClipRect(rectClip);
     std::unique_ptr<CXFA_RenderContext> pRenderContext(new CXFA_RenderContext);
     CXFA_RenderOptions renderOptions;
@@ -131,22 +129,20 @@
   }
 }
 
-CPDFSDK_Annot* CPDFSDK_PageView::GetFXAnnotAtPoint(FX_FLOAT pageX,
-                                                   FX_FLOAT pageY) {
+CPDFSDK_Annot* CPDFSDK_PageView::GetFXAnnotAtPoint(const CFX_PointF& point) {
   CPDFSDK_AnnotHandlerMgr* pAnnotMgr = m_pFormFillEnv->GetAnnotHandlerMgr();
   CPDFSDK_AnnotIteration annotIteration(this, false);
   for (const auto& pSDKAnnot : annotIteration) {
     CFX_FloatRect rc = pAnnotMgr->Annot_OnGetViewBBox(this, pSDKAnnot.Get());
     if (pSDKAnnot->GetAnnotSubtype() == CPDF_Annot::Subtype::POPUP)
       continue;
-    if (rc.Contains(pageX, pageY))
+    if (rc.Contains(point))
       return pSDKAnnot.Get();
   }
   return nullptr;
 }
 
-CPDFSDK_Annot* CPDFSDK_PageView::GetFXWidgetAtPoint(FX_FLOAT pageX,
-                                                    FX_FLOAT pageY) {
+CPDFSDK_Annot* CPDFSDK_PageView::GetFXWidgetAtPoint(const CFX_PointF& point) {
   CPDFSDK_AnnotHandlerMgr* pAnnotMgr = m_pFormFillEnv->GetAnnotHandlerMgr();
   CPDFSDK_AnnotIteration annotIteration(this, false);
   for (const auto& pSDKAnnot : annotIteration) {
@@ -157,7 +153,6 @@
 #endif  // PDF_ENABLE_XFA
     if (bHitTest) {
       pAnnotMgr->Annot_OnGetViewBBox(this, pSDKAnnot.Get());
-      CFX_FloatPoint point(pageX, pageY);
       if (pAnnotMgr->Annot_OnHitTest(this, pSDKAnnot.Get(), point))
         return pSDKAnnot.Get();
     }
@@ -247,9 +242,8 @@
 }
 #endif  // PDF_ENABLE_XFA
 
-bool CPDFSDK_PageView::OnLButtonDown(const CFX_FloatPoint& point,
-                                     uint32_t nFlag) {
-  CPDFSDK_Annot::ObservedPtr pAnnot(GetFXWidgetAtPoint(point.x, point.y));
+bool CPDFSDK_PageView::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
+  CPDFSDK_Annot::ObservedPtr pAnnot(GetFXWidgetAtPoint(point));
   if (!pAnnot) {
     m_pFormFillEnv->KillFocusAnnot(nFlag);
     return false;
@@ -268,9 +262,8 @@
 }
 
 #ifdef PDF_ENABLE_XFA
-bool CPDFSDK_PageView::OnRButtonDown(const CFX_FloatPoint& point,
-                                     uint32_t nFlag) {
-  CPDFSDK_Annot::ObservedPtr pAnnot(GetFXWidgetAtPoint(point.x, point.y));
+bool CPDFSDK_PageView::OnRButtonDown(const CFX_PointF& point, uint32_t nFlag) {
+  CPDFSDK_Annot::ObservedPtr pAnnot(GetFXWidgetAtPoint(point));
   if (!pAnnot)
     return false;
 
@@ -286,11 +279,10 @@
   return true;
 }
 
-bool CPDFSDK_PageView::OnRButtonUp(const CFX_FloatPoint& point,
-                                   uint32_t nFlag) {
+bool CPDFSDK_PageView::OnRButtonUp(const CFX_PointF& point, uint32_t nFlag) {
   CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
       m_pFormFillEnv->GetAnnotHandlerMgr();
-  CPDFSDK_Annot::ObservedPtr pFXAnnot(GetFXWidgetAtPoint(point.x, point.y));
+  CPDFSDK_Annot::ObservedPtr pFXAnnot(GetFXWidgetAtPoint(point));
   if (!pFXAnnot)
     return false;
 
@@ -301,11 +293,10 @@
 }
 #endif  // PDF_ENABLE_XFA
 
-bool CPDFSDK_PageView::OnLButtonUp(const CFX_FloatPoint& point,
-                                   uint32_t nFlag) {
+bool CPDFSDK_PageView::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
   CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
       m_pFormFillEnv->GetAnnotHandlerMgr();
-  CPDFSDK_Annot::ObservedPtr pFXAnnot(GetFXWidgetAtPoint(point.x, point.y));
+  CPDFSDK_Annot::ObservedPtr pFXAnnot(GetFXWidgetAtPoint(point));
   CPDFSDK_Annot::ObservedPtr pFocusAnnot(GetFocusAnnot());
   if (pFocusAnnot && pFocusAnnot != pFXAnnot) {
     // Last focus Annot gets a chance to handle the event.
@@ -316,10 +307,10 @@
          pAnnotHandlerMgr->Annot_OnLButtonUp(this, &pFXAnnot, nFlag, point);
 }
 
-bool CPDFSDK_PageView::OnMouseMove(const CFX_FloatPoint& point, int nFlag) {
+bool CPDFSDK_PageView::OnMouseMove(const CFX_PointF& point, int nFlag) {
   CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
       m_pFormFillEnv->GetAnnotHandlerMgr();
-  CPDFSDK_Annot::ObservedPtr pFXAnnot(GetFXAnnotAtPoint(point.x, point.y));
+  CPDFSDK_Annot::ObservedPtr pFXAnnot(GetFXAnnotAtPoint(point));
   if (pFXAnnot) {
     if (m_pCaptureWidget && m_pCaptureWidget != pFXAnnot) {
       m_bExitWidget = true;
@@ -350,9 +341,9 @@
 
 bool CPDFSDK_PageView::OnMouseWheel(double deltaX,
                                     double deltaY,
-                                    const CFX_FloatPoint& point,
+                                    const CFX_PointF& point,
                                     int nFlag) {
-  CPDFSDK_Annot::ObservedPtr pAnnot(GetFXWidgetAtPoint(point.x, point.y));
+  CPDFSDK_Annot::ObservedPtr pAnnot(GetFXWidgetAtPoint(point));
   if (!pAnnot)
     return false;
 
@@ -441,13 +432,12 @@
 
 void CPDFSDK_PageView::UpdateRects(const std::vector<CFX_FloatRect>& rects) {
   for (const auto& rc : rects)
-    m_pFormFillEnv->Invalidate(m_page, rc.left, rc.top, rc.right, rc.bottom);
+    m_pFormFillEnv->Invalidate(m_page, rc.ToFxRect());
 }
 
 void CPDFSDK_PageView::UpdateView(CPDFSDK_Annot* pAnnot) {
   CFX_FloatRect rcWindow = pAnnot->GetRect();
-  m_pFormFillEnv->Invalidate(m_page, rcWindow.left, rcWindow.top,
-                             rcWindow.right, rcWindow.bottom);
+  m_pFormFillEnv->Invalidate(m_page, rcWindow.ToFxRect());
 }
 
 int CPDFSDK_PageView::GetPageIndex() const {
diff --git a/fpdfsdk/cpdfsdk_pageview.h b/fpdfsdk/cpdfsdk_pageview.h
index 9a3443b..bcd5177 100644
--- a/fpdfsdk/cpdfsdk_pageview.h
+++ b/fpdfsdk/cpdfsdk_pageview.h
@@ -35,9 +35,6 @@
                        CPDF_RenderOptions* pOptions);
 #endif  // PDF_ENABLE_XFA
 
-  CPDFSDK_Annot* GetFXAnnotAtPoint(FX_FLOAT pageX, FX_FLOAT pageY);
-  CPDFSDK_Annot* GetFXWidgetAtPoint(FX_FLOAT pageX, FX_FLOAT pageY);
-
   void LoadFXAnnots();
   CPDFSDK_Annot* GetFocusAnnot();
   bool IsValidAnnot(const CPDF_Annot* p) const;
@@ -59,20 +56,20 @@
   CPDF_Page* GetPDFPage() const;
   CPDF_Document* GetPDFDocument();
   CPDFSDK_FormFillEnvironment* GetFormFillEnv() const { return m_pFormFillEnv; }
-  bool OnLButtonDown(const CFX_FloatPoint& point, uint32_t nFlag);
-  bool OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag);
+  bool OnLButtonDown(const CFX_PointF& point, uint32_t nFlag);
+  bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag);
 #ifdef PDF_ENABLE_XFA
-  bool OnRButtonDown(const CFX_FloatPoint& point, uint32_t nFlag);
-  bool OnRButtonUp(const CFX_FloatPoint& point, uint32_t nFlag);
+  bool OnRButtonDown(const CFX_PointF& point, uint32_t nFlag);
+  bool OnRButtonUp(const CFX_PointF& point, uint32_t nFlag);
 #endif  // PDF_ENABLE_XFA
   bool OnChar(int nChar, uint32_t nFlag);
   bool OnKeyDown(int nKeyCode, int nFlag);
   bool OnKeyUp(int nKeyCode, int nFlag);
 
-  bool OnMouseMove(const CFX_FloatPoint& point, int nFlag);
+  bool OnMouseMove(const CFX_PointF& point, int nFlag);
   bool OnMouseWheel(double deltaX,
                     double deltaY,
-                    const CFX_FloatPoint& point,
+                    const CFX_PointF& point,
                     int nFlag);
 
   void GetCurrentMatrix(CFX_Matrix& matrix) { matrix = m_curMatrix; }
@@ -96,6 +93,9 @@
 #endif  // PDF_ENABLE_XFA
 
  private:
+  CPDFSDK_Annot* GetFXAnnotAtPoint(const CFX_PointF& point);
+  CPDFSDK_Annot* GetFXWidgetAtPoint(const CFX_PointF& point);
+
   int GetPageIndexForStaticPDF() const;
 
   CFX_Matrix m_curMatrix;
diff --git a/fpdfsdk/cpdfsdk_widget.cpp b/fpdfsdk/cpdfsdk_widget.cpp
index 1086906..cd86f7a 100644
--- a/fpdfsdk/cpdfsdk_widget.cpp
+++ b/fpdfsdk/cpdfsdk_widget.cpp
@@ -841,24 +841,24 @@
   if (!m_pInterForm->IsNeedHighLight(nFieldType))
     return;
 
-  CFX_FloatRect rc = GetRect();
-  FX_COLORREF color = m_pInterForm->GetHighlightColor(nFieldType);
-  uint8_t alpha = m_pInterForm->GetHighlightAlpha();
-
-  CFX_FloatRect rcDevice;
   CFX_Matrix page2device;
   pPageView->GetCurrentMatrix(page2device);
-  page2device.Transform(((FX_FLOAT)rc.left), ((FX_FLOAT)rc.bottom),
-                        rcDevice.left, rcDevice.bottom);
-  page2device.Transform(((FX_FLOAT)rc.right), ((FX_FLOAT)rc.top),
-                        rcDevice.right, rcDevice.top);
 
+  CFX_FloatRect rcDevice = GetRect();
+  CFX_PointF tmp =
+      page2device.Transform(CFX_PointF(rcDevice.left, rcDevice.bottom));
+  rcDevice.left = tmp.x;
+  rcDevice.bottom = tmp.y;
+
+  tmp = page2device.Transform(CFX_PointF(rcDevice.right, rcDevice.top));
+  rcDevice.right = tmp.x;
+  rcDevice.top = tmp.y;
   rcDevice.Normalize();
 
-  FX_ARGB argb = ArgbEncode((int)alpha, color);
-  FX_RECT rcDev((int)rcDevice.left, (int)rcDevice.top, (int)rcDevice.right,
-                (int)rcDevice.bottom);
-  pDevice->FillRect(&rcDev, argb);
+  FX_RECT rcDev = rcDevice.ToFxRect();
+  pDevice->FillRect(
+      &rcDev, ArgbEncode(static_cast<int>(m_pInterForm->GetHighlightAlpha()),
+                         m_pInterForm->GetHighlightColor(nFieldType)));
 }
 
 void CPDFSDK_Widget::ResetAppearance_PushButton() {
@@ -889,11 +889,10 @@
       break;
   }
 
-  CPWL_Color crBackground, crBorder;
-
+  CPWL_Color crBackground;
+  CPWL_Color crBorder;
   int iColorType;
   FX_FLOAT fc[4];
-
   pControl->GetOriginalBackgroundColor(iColorType, fc);
   if (iColorType > 0)
     crBackground = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
@@ -904,7 +903,8 @@
 
   FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth();
   CPWL_Dash dsBorder(3, 0, 0);
-  CPWL_Color crLeftTop, crRightBottom;
+  CPWL_Color crLeftTop;
+  CPWL_Color crRightBottom;
 
   BorderStyle nBorderStyle = GetBorderStyle();
   switch (nBorderStyle) {
@@ -914,7 +914,7 @@
     case BorderStyle::BEVELED:
       fBorderWidth *= 2;
       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1);
-      crRightBottom = CPWL_Utils::DevideColor(crBackground, 2);
+      crRightBottom = crBackground / 2.0f;
       break;
     case BorderStyle::INSET:
       fBorderWidth *= 2;
@@ -1050,8 +1050,7 @@
 
     font_map.SetAPType("D");
 
-    csAP = CPWL_Utils::GetRectFillAppStream(
-               rcWindow, CPWL_Utils::SubstractColor(crBackground, 0.25f)) +
+    csAP = CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
            CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
                                           crLeftTop, crRightBottom,
                                           nBorderStyle, dsBorder) +
@@ -1094,7 +1093,7 @@
     case BorderStyle::BEVELED:
       fBorderWidth *= 2;
       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1);
-      crRightBottom = CPWL_Utils::DevideColor(crBackground, 2);
+      crRightBottom = crBackground / 2.0f;
       break;
     case BorderStyle::INSET:
       fBorderWidth *= 2;
@@ -1107,7 +1106,6 @@
 
   CFX_FloatRect rcWindow = GetRotatedRect();
   CFX_FloatRect rcClient = CPWL_Utils::DeflateRect(rcWindow, fBorderWidth);
-
   CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
   if (da.HasColor()) {
     da.GetColor(iColorType, fc);
@@ -1115,7 +1113,6 @@
   }
 
   int32_t nStyle = 0;
-
   CFX_WideString csWCaption = pControl->GetNormalCaption();
   if (csWCaption.GetLength() > 0) {
     switch (csWCaption[0]) {
@@ -1167,8 +1164,7 @@
   }
 
   CFX_ByteString csAP_D_ON =
-      CPWL_Utils::GetRectFillAppStream(
-          rcWindow, CPWL_Utils::SubstractColor(crBackground, 0.25f)) +
+      CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
       CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
                                      crLeftTop, crRightBottom, nBorderStyle,
                                      dsBorder);
@@ -1207,8 +1203,8 @@
 
   FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth();
   CPWL_Dash dsBorder(3, 0, 0);
-  CPWL_Color crLeftTop, crRightBottom;
-
+  CPWL_Color crLeftTop;
+  CPWL_Color crRightBottom;
   BorderStyle nBorderStyle = GetBorderStyle();
   switch (nBorderStyle) {
     case BorderStyle::DASH:
@@ -1217,7 +1213,7 @@
     case BorderStyle::BEVELED:
       fBorderWidth *= 2;
       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1);
-      crRightBottom = CPWL_Utils::DevideColor(crBackground, 2);
+      crRightBottom = crBackground / 2.0f;
       break;
     case BorderStyle::INSET:
       fBorderWidth *= 2;
@@ -1238,7 +1234,6 @@
   }
 
   int32_t nStyle = 0;
-
   CFX_WideString csWCaption = pControl->GetNormalCaption();
   if (csWCaption.GetLength() > 0) {
     switch (csWCaption[0]) {
@@ -1273,7 +1268,7 @@
   if (nStyle == PCS_CIRCLE) {
     if (nBorderStyle == BorderStyle::BEVELED) {
       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1);
-      crRightBottom = CPWL_Utils::SubstractColor(crBackground, 0.25f);
+      crRightBottom = crBackground - 0.25f;
     } else if (nBorderStyle == BorderStyle::INSET) {
       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0.5f);
       crRightBottom = CPWL_Color(COLORTYPE_GRAY, 0.75f);
@@ -1311,9 +1306,9 @@
   CFX_ByteString csAP_D_ON;
 
   if (nStyle == PCS_CIRCLE) {
-    CPWL_Color crBK = CPWL_Utils::SubstractColor(crBackground, 0.25f);
+    CPWL_Color crBK = crBackground - 0.25f;
     if (nBorderStyle == BorderStyle::BEVELED) {
-      crLeftTop = CPWL_Utils::SubstractColor(crBackground, 0.25f);
+      crLeftTop = crBackground - 0.25f;
       crRightBottom = CPWL_Color(COLORTYPE_GRAY, 1);
       crBK = crBackground;
     } else if (nBorderStyle == BorderStyle::INSET) {
@@ -1326,11 +1321,11 @@
                     rcCenter, fBorderWidth, crBorder, crLeftTop, crRightBottom,
                     nBorderStyle, dsBorder);
   } else {
-    csAP_D_ON = CPWL_Utils::GetRectFillAppStream(
-                    rcWindow, CPWL_Utils::SubstractColor(crBackground, 0.25f)) +
-                CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
-                                               crLeftTop, crRightBottom,
-                                               nBorderStyle, dsBorder);
+    csAP_D_ON =
+        CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
+        CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
+                                       crLeftTop, crRightBottom, nBorderStyle,
+                                       dsBorder);
   }
 
   CFX_ByteString csAP_D_OFF = csAP_D_ON;
@@ -1395,7 +1390,7 @@
   CFX_FloatRect rcContent = pEdit->GetContentRect();
 
   CFX_ByteString sEdit =
-      CPWL_Utils::GetEditAppStream(pEdit.get(), CFX_FloatPoint());
+      CPWL_Utils::GetEditAppStream(pEdit.get(), CFX_PointF());
   if (sEdit.GetLength() > 0) {
     sBody << "/Tx BMC\n"
           << "q\n";
@@ -1475,15 +1470,13 @@
       sList << "BT\n"
             << CPWL_Utils::GetColorAppStream(CPWL_Color(COLORTYPE_GRAY, 1),
                                              true)
-            << CPWL_Utils::GetEditAppStream(pEdit.get(),
-                                            CFX_FloatPoint(0.0f, fy))
+            << CPWL_Utils::GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, fy))
             << "ET\n";
     } else {
       CPWL_Color crText = GetTextPWLColor();
       sList << "BT\n"
             << CPWL_Utils::GetColorAppStream(crText, true)
-            << CPWL_Utils::GetEditAppStream(pEdit.get(),
-                                            CFX_FloatPoint(0.0f, fy))
+            << CPWL_Utils::GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, fy))
             << "ET\n";
     }
 
@@ -1572,7 +1565,7 @@
 
   CFX_FloatRect rcContent = pEdit->GetContentRect();
   CFX_ByteString sEdit = CPWL_Utils::GetEditAppStream(
-      pEdit.get(), CFX_FloatPoint(), nullptr, !bCharArray, subWord);
+      pEdit.get(), CFX_PointF(), nullptr, !bCharArray, subWord);
 
   if (sEdit.GetLength() > 0) {
     sBody << "/Tx BMC\n"
@@ -1709,7 +1702,7 @@
     case BorderStyle::BEVELED:
       fBorderWidth *= 2;
       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1);
-      crRightBottom = CPWL_Utils::DevideColor(crBackground, 2);
+      crRightBottom = crBackground / 2.0f;
       break;
     case BorderStyle::INSET:
       fBorderWidth *= 2;
@@ -1915,18 +1908,3 @@
 int32_t CPDFSDK_Widget::GetValueAge() const {
   return m_nValueAge;
 }
-
-bool CPDFSDK_Widget::HitTest(FX_FLOAT pageX, FX_FLOAT pageY) {
-  CPDF_Annot* pAnnot = GetPDFAnnot();
-  CFX_FloatRect annotRect = pAnnot->GetRect();
-  if (!annotRect.Contains(pageX, pageY))
-    return false;
-
-  if (!IsVisible())
-    return false;
-
-  if ((GetFieldFlags() & FIELDFLAG_READONLY) == FIELDFLAG_READONLY)
-    return false;
-
-  return true;
-}
diff --git a/fpdfsdk/cpdfsdk_widget.h b/fpdfsdk/cpdfsdk_widget.h
index 69114d1..21e5169 100644
--- a/fpdfsdk/cpdfsdk_widget.h
+++ b/fpdfsdk/cpdfsdk_widget.h
@@ -138,8 +138,6 @@
                       CPDF_Annot::AppearanceMode mode,
                       const CPDF_RenderOptions* pOptions) override;
 
-  bool HitTest(FX_FLOAT pageX, FX_FLOAT pageY);
-
  private:
   void ResetAppearance_PushButton();
   void ResetAppearance_CheckBox();
diff --git a/fpdfsdk/cpdfsdk_widgethandler.cpp b/fpdfsdk/cpdfsdk_widgethandler.cpp
index 4105ae4..e85d24c 100644
--- a/fpdfsdk/cpdfsdk_widgethandler.cpp
+++ b/fpdfsdk/cpdfsdk_widgethandler.cpp
@@ -119,7 +119,7 @@
 bool CPDFSDK_WidgetHandler::OnLButtonDown(CPDFSDK_PageView* pPageView,
                                           CPDFSDK_Annot::ObservedPtr* pAnnot,
                                           uint32_t nFlags,
-                                          const CFX_FloatPoint& point) {
+                                          const CFX_PointF& point) {
   if (!(*pAnnot)->IsSignatureWidget() && m_pFormFiller)
     return m_pFormFiller->OnLButtonDown(pPageView, pAnnot, nFlags, point);
 
@@ -129,7 +129,7 @@
 bool CPDFSDK_WidgetHandler::OnLButtonUp(CPDFSDK_PageView* pPageView,
                                         CPDFSDK_Annot::ObservedPtr* pAnnot,
                                         uint32_t nFlags,
-                                        const CFX_FloatPoint& point) {
+                                        const CFX_PointF& point) {
   if (!(*pAnnot)->IsSignatureWidget() && m_pFormFiller)
     return m_pFormFiller->OnLButtonUp(pPageView, pAnnot, nFlags, point);
 
@@ -139,7 +139,7 @@
 bool CPDFSDK_WidgetHandler::OnLButtonDblClk(CPDFSDK_PageView* pPageView,
                                             CPDFSDK_Annot::ObservedPtr* pAnnot,
                                             uint32_t nFlags,
-                                            const CFX_FloatPoint& point) {
+                                            const CFX_PointF& point) {
   if (!(*pAnnot)->IsSignatureWidget() && m_pFormFiller)
     return m_pFormFiller->OnLButtonDblClk(pPageView, pAnnot, nFlags, point);
 
@@ -149,7 +149,7 @@
 bool CPDFSDK_WidgetHandler::OnMouseMove(CPDFSDK_PageView* pPageView,
                                         CPDFSDK_Annot::ObservedPtr* pAnnot,
                                         uint32_t nFlags,
-                                        const CFX_FloatPoint& point) {
+                                        const CFX_PointF& point) {
   if (!(*pAnnot)->IsSignatureWidget() && m_pFormFiller)
     return m_pFormFiller->OnMouseMove(pPageView, pAnnot, nFlags, point);
 
@@ -160,7 +160,7 @@
                                          CPDFSDK_Annot::ObservedPtr* pAnnot,
                                          uint32_t nFlags,
                                          short zDelta,
-                                         const CFX_FloatPoint& point) {
+                                         const CFX_PointF& point) {
   if (!(*pAnnot)->IsSignatureWidget() && m_pFormFiller)
     return m_pFormFiller->OnMouseWheel(pPageView, pAnnot, nFlags, zDelta,
                                        point);
@@ -171,7 +171,7 @@
 bool CPDFSDK_WidgetHandler::OnRButtonDown(CPDFSDK_PageView* pPageView,
                                           CPDFSDK_Annot::ObservedPtr* pAnnot,
                                           uint32_t nFlags,
-                                          const CFX_FloatPoint& point) {
+                                          const CFX_PointF& point) {
   if (!(*pAnnot)->IsSignatureWidget() && m_pFormFiller)
     return m_pFormFiller->OnRButtonDown(pPageView, pAnnot, nFlags, point);
 
@@ -181,7 +181,7 @@
 bool CPDFSDK_WidgetHandler::OnRButtonUp(CPDFSDK_PageView* pPageView,
                                         CPDFSDK_Annot::ObservedPtr* pAnnot,
                                         uint32_t nFlags,
-                                        const CFX_FloatPoint& point) {
+                                        const CFX_PointF& point) {
   if (!(*pAnnot)->IsSignatureWidget() && m_pFormFiller)
     return m_pFormFiller->OnRButtonUp(pPageView, pAnnot, nFlags, point);
 
@@ -191,7 +191,7 @@
 bool CPDFSDK_WidgetHandler::OnRButtonDblClk(CPDFSDK_PageView* pPageView,
                                             CPDFSDK_Annot::ObservedPtr* pAnnot,
                                             uint32_t nFlags,
-                                            const CFX_FloatPoint& point) {
+                                            const CFX_PointF& point) {
   return false;
 }
 
@@ -279,10 +279,8 @@
 
 bool CPDFSDK_WidgetHandler::HitTest(CPDFSDK_PageView* pPageView,
                                     CPDFSDK_Annot* pAnnot,
-                                    const CFX_FloatPoint& point) {
+                                    const CFX_PointF& point) {
   ASSERT(pPageView);
   ASSERT(pAnnot);
-
-  CFX_FloatRect rect = GetViewBBox(pPageView, pAnnot);
-  return rect.Contains(point.x, point.y);
+  return GetViewBBox(pPageView, pAnnot).Contains(point);
 }
diff --git a/fpdfsdk/cpdfsdk_widgethandler.h b/fpdfsdk/cpdfsdk_widgethandler.h
index 7154bda..6e4d50b 100644
--- a/fpdfsdk/cpdfsdk_widgethandler.h
+++ b/fpdfsdk/cpdfsdk_widgethandler.h
@@ -39,7 +39,7 @@
                             CPDFSDK_Annot* pAnnot) override;
   bool HitTest(CPDFSDK_PageView* pPageView,
                CPDFSDK_Annot* pAnnot,
-               const CFX_FloatPoint& point) override;
+               const CFX_PointF& point) override;
   void OnDraw(CPDFSDK_PageView* pPageView,
               CPDFSDK_Annot* pAnnot,
               CFX_RenderDevice* pDevice,
@@ -56,36 +56,36 @@
   bool OnLButtonDown(CPDFSDK_PageView* pPageView,
                      CPDFSDK_Annot::ObservedPtr* pAnnot,
                      uint32_t nFlags,
-                     const CFX_FloatPoint& point) override;
+                     const CFX_PointF& point) override;
   bool OnLButtonUp(CPDFSDK_PageView* pPageView,
                    CPDFSDK_Annot::ObservedPtr* pAnnot,
                    uint32_t nFlags,
-                   const CFX_FloatPoint& point) override;
+                   const CFX_PointF& point) override;
   bool OnLButtonDblClk(CPDFSDK_PageView* pPageView,
                        CPDFSDK_Annot::ObservedPtr* pAnnot,
                        uint32_t nFlags,
-                       const CFX_FloatPoint& point) override;
+                       const CFX_PointF& point) override;
   bool OnMouseMove(CPDFSDK_PageView* pPageView,
                    CPDFSDK_Annot::ObservedPtr* pAnnot,
                    uint32_t nFlags,
-                   const CFX_FloatPoint& point) override;
+                   const CFX_PointF& point) override;
   bool OnMouseWheel(CPDFSDK_PageView* pPageView,
                     CPDFSDK_Annot::ObservedPtr* pAnnot,
                     uint32_t nFlags,
                     short zDelta,
-                    const CFX_FloatPoint& point) override;
+                    const CFX_PointF& point) override;
   bool OnRButtonDown(CPDFSDK_PageView* pPageView,
                      CPDFSDK_Annot::ObservedPtr* pAnnot,
                      uint32_t nFlags,
-                     const CFX_FloatPoint& point) override;
+                     const CFX_PointF& point) override;
   bool OnRButtonUp(CPDFSDK_PageView* pPageView,
                    CPDFSDK_Annot::ObservedPtr* pAnnot,
                    uint32_t nFlags,
-                   const CFX_FloatPoint& point) override;
+                   const CFX_PointF& point) override;
   bool OnRButtonDblClk(CPDFSDK_PageView* pPageView,
                        CPDFSDK_Annot::ObservedPtr* pAnnot,
                        uint32_t nFlags,
-                       const CFX_FloatPoint& point) override;
+                       const CFX_PointF& point) override;
   bool OnChar(CPDFSDK_Annot* pAnnot, uint32_t nChar, uint32_t nFlags) override;
   bool OnKeyDown(CPDFSDK_Annot* pAnnot, int nKeyCode, int nFlag) override;
   bool OnKeyUp(CPDFSDK_Annot* pAnnot, int nKeyCode, int nFlag) override;
diff --git a/fpdfsdk/cpdfsdk_xfawidget.cpp b/fpdfsdk/cpdfsdk_xfawidget.cpp
index 67a8a17..b30e5f3 100644
--- a/fpdfsdk/cpdfsdk_xfawidget.cpp
+++ b/fpdfsdk/cpdfsdk_xfawidget.cpp
@@ -29,8 +29,7 @@
 }
 
 CFX_FloatRect CPDFSDK_XFAWidget::GetRect() const {
-  CFX_RectF rcBBox;
-  GetXFAWidget()->GetRect(rcBBox);
+  CFX_RectF rcBBox = GetXFAWidget()->GetRect(false);
   return CFX_FloatRect(rcBBox.left, rcBBox.top, rcBBox.left + rcBBox.width,
                        rcBBox.top + rcBBox.height);
 }
diff --git a/fpdfsdk/cpdfsdk_xfawidgethandler.cpp b/fpdfsdk/cpdfsdk_xfawidgethandler.cpp
index eff351b..653eb8a 100644
--- a/fpdfsdk/cpdfsdk_xfawidgethandler.cpp
+++ b/fpdfsdk/cpdfsdk_xfawidgethandler.cpp
@@ -53,12 +53,9 @@
   ASSERT(pPageView);
   ASSERT(pAnnot);
 
-  CFX_Graphics gs;
-  gs.Create(pDevice);
+  CFX_Graphics gs(pDevice);
 
-  CFX_Matrix mt;
-  mt = *pUser2Device;
-
+  CFX_Matrix mt = *pUser2Device;
   bool bIsHighlight = false;
   if (pPageView->GetFormFillEnv()->GetFocusAnnot() != pAnnot)
     bIsHighlight = true;
@@ -86,9 +83,9 @@
   CFX_RectF rcBBox;
   XFA_Element eType = pAnnot->GetXFAWidget()->GetDataAcc()->GetUIType();
   if (eType == XFA_Element::Signature)
-    pAnnot->GetXFAWidget()->GetBBox(rcBBox, XFA_WidgetStatus_Visible, true);
+    rcBBox = pAnnot->GetXFAWidget()->GetBBox(XFA_WidgetStatus_Visible, true);
   else
-    pAnnot->GetXFAWidget()->GetBBox(rcBBox, XFA_WidgetStatus_None);
+    rcBBox = pAnnot->GetXFAWidget()->GetBBox(XFA_WidgetStatus_None);
 
   CFX_FloatRect rcWidget(rcBBox.left, rcBBox.top, rcBBox.left + rcBBox.width,
                          rcBBox.top + rcBBox.height);
@@ -102,7 +99,7 @@
 
 bool CPDFSDK_XFAWidgetHandler::HitTest(CPDFSDK_PageView* pPageView,
                                        CPDFSDK_Annot* pAnnot,
-                                       const CFX_FloatPoint& point) {
+                                       const CFX_PointF& point) {
   if (!pPageView || !pAnnot)
     return false;
 
@@ -123,7 +120,7 @@
     return false;
 
   FWL_WidgetHit dwHitTest =
-      pWidgetHandler->OnHitTest(pAnnot->GetXFAWidget(), point.x, point.y);
+      pWidgetHandler->OnHitTest(pAnnot->GetXFAWidget(), point);
   return dwHitTest != FWL_WidgetHit::Unknown;
 }
 
@@ -149,100 +146,100 @@
 bool CPDFSDK_XFAWidgetHandler::OnLButtonDown(CPDFSDK_PageView* pPageView,
                                              CPDFSDK_Annot::ObservedPtr* pAnnot,
                                              uint32_t nFlags,
-                                             const CFX_FloatPoint& point) {
+                                             const CFX_PointF& point) {
   if (!pPageView || !(*pAnnot))
     return false;
 
   CXFA_FFWidgetHandler* pWidgetHandler = GetXFAWidgetHandler(pAnnot->Get());
   return pWidgetHandler->OnLButtonDown((*pAnnot)->GetXFAWidget(),
-                                       GetFWLFlags(nFlags), point.x, point.y);
+                                       GetFWLFlags(nFlags), point);
 }
 
 bool CPDFSDK_XFAWidgetHandler::OnLButtonUp(CPDFSDK_PageView* pPageView,
                                            CPDFSDK_Annot::ObservedPtr* pAnnot,
                                            uint32_t nFlags,
-                                           const CFX_FloatPoint& point) {
+                                           const CFX_PointF& point) {
   if (!pPageView || !(*pAnnot))
     return false;
 
   CXFA_FFWidgetHandler* pWidgetHandler = GetXFAWidgetHandler(pAnnot->Get());
   return pWidgetHandler->OnLButtonUp((*pAnnot)->GetXFAWidget(),
-                                     GetFWLFlags(nFlags), point.x, point.y);
+                                     GetFWLFlags(nFlags), point);
 }
 
 bool CPDFSDK_XFAWidgetHandler::OnLButtonDblClk(
     CPDFSDK_PageView* pPageView,
     CPDFSDK_Annot::ObservedPtr* pAnnot,
     uint32_t nFlags,
-    const CFX_FloatPoint& point) {
+    const CFX_PointF& point) {
   if (!pPageView || !(*pAnnot))
     return false;
 
   CXFA_FFWidgetHandler* pWidgetHandler = GetXFAWidgetHandler(pAnnot->Get());
   return pWidgetHandler->OnLButtonDblClk((*pAnnot)->GetXFAWidget(),
-                                         GetFWLFlags(nFlags), point.x, point.y);
+                                         GetFWLFlags(nFlags), point);
 }
 
 bool CPDFSDK_XFAWidgetHandler::OnMouseMove(CPDFSDK_PageView* pPageView,
                                            CPDFSDK_Annot::ObservedPtr* pAnnot,
                                            uint32_t nFlags,
-                                           const CFX_FloatPoint& point) {
+                                           const CFX_PointF& point) {
   if (!pPageView || !(*pAnnot))
     return false;
 
   CXFA_FFWidgetHandler* pWidgetHandler = GetXFAWidgetHandler(pAnnot->Get());
   return pWidgetHandler->OnMouseMove((*pAnnot)->GetXFAWidget(),
-                                     GetFWLFlags(nFlags), point.x, point.y);
+                                     GetFWLFlags(nFlags), point);
 }
 
 bool CPDFSDK_XFAWidgetHandler::OnMouseWheel(CPDFSDK_PageView* pPageView,
                                             CPDFSDK_Annot::ObservedPtr* pAnnot,
                                             uint32_t nFlags,
                                             short zDelta,
-                                            const CFX_FloatPoint& point) {
+                                            const CFX_PointF& point) {
   if (!pPageView || !(*pAnnot))
     return false;
 
   CXFA_FFWidgetHandler* pWidgetHandler = GetXFAWidgetHandler(pAnnot->Get());
-  return pWidgetHandler->OnMouseWheel(
-      (*pAnnot)->GetXFAWidget(), GetFWLFlags(nFlags), zDelta, point.x, point.y);
+  return pWidgetHandler->OnMouseWheel((*pAnnot)->GetXFAWidget(),
+                                      GetFWLFlags(nFlags), zDelta, point);
 }
 
 bool CPDFSDK_XFAWidgetHandler::OnRButtonDown(CPDFSDK_PageView* pPageView,
                                              CPDFSDK_Annot::ObservedPtr* pAnnot,
                                              uint32_t nFlags,
-                                             const CFX_FloatPoint& point) {
+                                             const CFX_PointF& point) {
   if (!pPageView || !(*pAnnot))
     return false;
 
   CXFA_FFWidgetHandler* pWidgetHandler = GetXFAWidgetHandler(pAnnot->Get());
   return pWidgetHandler->OnRButtonDown((*pAnnot)->GetXFAWidget(),
-                                       GetFWLFlags(nFlags), point.x, point.y);
+                                       GetFWLFlags(nFlags), point);
 }
 
 bool CPDFSDK_XFAWidgetHandler::OnRButtonUp(CPDFSDK_PageView* pPageView,
                                            CPDFSDK_Annot::ObservedPtr* pAnnot,
                                            uint32_t nFlags,
-                                           const CFX_FloatPoint& point) {
+                                           const CFX_PointF& point) {
   if (!pPageView || !(*pAnnot))
     return false;
 
   CXFA_FFWidgetHandler* pWidgetHandler = GetXFAWidgetHandler(pAnnot->Get());
   return pWidgetHandler->OnRButtonUp((*pAnnot)->GetXFAWidget(),
-                                     GetFWLFlags(nFlags), point.x, point.y);
+                                     GetFWLFlags(nFlags), point);
 }
 
 bool CPDFSDK_XFAWidgetHandler::OnRButtonDblClk(
     CPDFSDK_PageView* pPageView,
     CPDFSDK_Annot::ObservedPtr* pAnnot,
     uint32_t nFlags,
-    const CFX_FloatPoint& point) {
+    const CFX_PointF& point) {
   if (!pPageView || !(*pAnnot))
     return false;
 
   CXFA_FFWidgetHandler* pWidgetHandler = GetXFAWidgetHandler(pAnnot->Get());
   return pWidgetHandler->OnRButtonDblClk((*pAnnot)->GetXFAWidget(),
-                                         GetFWLFlags(nFlags), point.x, point.y);
+                                         GetFWLFlags(nFlags), point);
 }
 
 bool CPDFSDK_XFAWidgetHandler::OnChar(CPDFSDK_Annot* pAnnot,
diff --git a/fpdfsdk/cpdfsdk_xfawidgethandler.h b/fpdfsdk/cpdfsdk_xfawidgethandler.h
index 1a1a480..3903103 100644
--- a/fpdfsdk/cpdfsdk_xfawidgethandler.h
+++ b/fpdfsdk/cpdfsdk_xfawidgethandler.h
@@ -34,7 +34,7 @@
                             CPDFSDK_Annot* pAnnot) override;
   bool HitTest(CPDFSDK_PageView* pPageView,
                CPDFSDK_Annot* pAnnot,
-               const CFX_FloatPoint& point) override;
+               const CFX_PointF& point) override;
   void OnDraw(CPDFSDK_PageView* pPageView,
               CPDFSDK_Annot* pAnnot,
               CFX_RenderDevice* pDevice,
@@ -50,36 +50,36 @@
   bool OnLButtonDown(CPDFSDK_PageView* pPageView,
                      CPDFSDK_Annot::ObservedPtr* pAnnot,
                      uint32_t nFlags,
-                     const CFX_FloatPoint& point) override;
+                     const CFX_PointF& point) override;
   bool OnLButtonUp(CPDFSDK_PageView* pPageView,
                    CPDFSDK_Annot::ObservedPtr* pAnnot,
                    uint32_t nFlags,
-                   const CFX_FloatPoint& point) override;
+                   const CFX_PointF& point) override;
   bool OnLButtonDblClk(CPDFSDK_PageView* pPageView,
                        CPDFSDK_Annot::ObservedPtr* pAnnot,
                        uint32_t nFlags,
-                       const CFX_FloatPoint& point) override;
+                       const CFX_PointF& point) override;
   bool OnMouseMove(CPDFSDK_PageView* pPageView,
                    CPDFSDK_Annot::ObservedPtr* pAnnot,
                    uint32_t nFlags,
-                   const CFX_FloatPoint& point) override;
+                   const CFX_PointF& point) override;
   bool OnMouseWheel(CPDFSDK_PageView* pPageView,
                     CPDFSDK_Annot::ObservedPtr* pAnnot,
                     uint32_t nFlags,
                     short zDelta,
-                    const CFX_FloatPoint& point) override;
+                    const CFX_PointF& point) override;
   bool OnRButtonDown(CPDFSDK_PageView* pPageView,
                      CPDFSDK_Annot::ObservedPtr* pAnnot,
                      uint32_t nFlags,
-                     const CFX_FloatPoint& point) override;
+                     const CFX_PointF& point) override;
   bool OnRButtonUp(CPDFSDK_PageView* pPageView,
                    CPDFSDK_Annot::ObservedPtr* pAnnot,
                    uint32_t nFlags,
-                   const CFX_FloatPoint& point) override;
+                   const CFX_PointF& point) override;
   bool OnRButtonDblClk(CPDFSDK_PageView* pPageView,
                        CPDFSDK_Annot::ObservedPtr* pAnnot,
                        uint32_t nFlags,
-                       const CFX_FloatPoint& point) override;
+                       const CFX_PointF& point) override;
   bool OnChar(CPDFSDK_Annot* pAnnot, uint32_t nChar, uint32_t nFlags) override;
   bool OnKeyDown(CPDFSDK_Annot* pAnnot, int nKeyCode, int nFlag) override;
   bool OnKeyUp(CPDFSDK_Annot* pAnnot, int nKeyCode, int nFlag) override;
diff --git a/fpdfsdk/formfiller/cffl_checkbox.cpp b/fpdfsdk/formfiller/cffl_checkbox.cpp
index ffa3a03..c233c13 100644
--- a/fpdfsdk/formfiller/cffl_checkbox.cpp
+++ b/fpdfsdk/formfiller/cffl_checkbox.cpp
@@ -73,7 +73,7 @@
 bool CFFL_CheckBox::OnLButtonUp(CPDFSDK_PageView* pPageView,
                                 CPDFSDK_Annot* pAnnot,
                                 uint32_t nFlags,
-                                const CFX_FloatPoint& point) {
+                                const CFX_PointF& point) {
   CFFL_Button::OnLButtonUp(pPageView, pAnnot, nFlags, point);
 
   if (IsValid()) {
diff --git a/fpdfsdk/formfiller/cffl_checkbox.h b/fpdfsdk/formfiller/cffl_checkbox.h
index 65dba29..79ddc84 100644
--- a/fpdfsdk/formfiller/cffl_checkbox.h
+++ b/fpdfsdk/formfiller/cffl_checkbox.h
@@ -24,7 +24,7 @@
   bool OnLButtonUp(CPDFSDK_PageView* pPageView,
                    CPDFSDK_Annot* pAnnot,
                    uint32_t nFlags,
-                   const CFX_FloatPoint& point) override;
+                   const CFX_PointF& point) override;
   bool IsDataChanged(CPDFSDK_PageView* pPageView) override;
   void SaveData(CPDFSDK_PageView* pPageView) override;
 };
diff --git a/fpdfsdk/formfiller/cffl_formfiller.cpp b/fpdfsdk/formfiller/cffl_formfiller.cpp
index 281057a..da6f920 100644
--- a/fpdfsdk/formfiller/cffl_formfiller.cpp
+++ b/fpdfsdk/formfiller/cffl_formfiller.cpp
@@ -119,13 +119,12 @@
 bool CFFL_FormFiller::OnLButtonDown(CPDFSDK_PageView* pPageView,
                                     CPDFSDK_Annot* pAnnot,
                                     uint32_t nFlags,
-                                    const CFX_FloatPoint& point) {
+                                    const CFX_PointF& point) {
   if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, true)) {
     m_bValid = true;
     FX_RECT rect = GetViewBBox(pPageView, pAnnot);
-    InvalidateRect(rect.left, rect.top, rect.right, rect.bottom);
-
-    if (!rect.Contains((int)point.x, (int)point.y))
+    InvalidateRect(rect);
+    if (!rect.Contains(static_cast<int>(point.x), static_cast<int>(point.y)))
       return false;
 
     return pWnd->OnLButtonDown(WndtoPWL(pPageView, point), nFlags);
@@ -137,13 +136,12 @@
 bool CFFL_FormFiller::OnLButtonUp(CPDFSDK_PageView* pPageView,
                                   CPDFSDK_Annot* pAnnot,
                                   uint32_t nFlags,
-                                  const CFX_FloatPoint& point) {
+                                  const CFX_PointF& point) {
   CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false);
   if (!pWnd)
     return false;
 
-  FX_RECT rcFFL = GetViewBBox(pPageView, pAnnot);
-  InvalidateRect(rcFFL.left, rcFFL.top, rcFFL.right, rcFFL.bottom);
+  InvalidateRect(GetViewBBox(pPageView, pAnnot));
   pWnd->OnLButtonUp(WndtoPWL(pPageView, point), nFlags);
   return true;
 }
@@ -151,7 +149,7 @@
 bool CFFL_FormFiller::OnLButtonDblClk(CPDFSDK_PageView* pPageView,
                                       CPDFSDK_Annot* pAnnot,
                                       uint32_t nFlags,
-                                      const CFX_FloatPoint& point) {
+                                      const CFX_PointF& point) {
   CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false);
   if (!pWnd)
     return false;
@@ -163,7 +161,7 @@
 bool CFFL_FormFiller::OnMouseMove(CPDFSDK_PageView* pPageView,
                                   CPDFSDK_Annot* pAnnot,
                                   uint32_t nFlags,
-                                  const CFX_FloatPoint& point) {
+                                  const CFX_PointF& point) {
   if (m_ptOldPos != point)
     m_ptOldPos = point;
 
@@ -179,7 +177,7 @@
                                    CPDFSDK_Annot* pAnnot,
                                    uint32_t nFlags,
                                    short zDelta,
-                                   const CFX_FloatPoint& point) {
+                                   const CFX_PointF& point) {
   if (!IsValid())
     return false;
 
@@ -190,7 +188,7 @@
 bool CFFL_FormFiller::OnRButtonDown(CPDFSDK_PageView* pPageView,
                                     CPDFSDK_Annot* pAnnot,
                                     uint32_t nFlags,
-                                    const CFX_FloatPoint& point) {
+                                    const CFX_PointF& point) {
   CPWL_Wnd* pWnd = GetPDFWindow(pPageView, true);
   if (!pWnd)
     return false;
@@ -202,7 +200,7 @@
 bool CFFL_FormFiller::OnRButtonUp(CPDFSDK_PageView* pPageView,
                                   CPDFSDK_Annot* pAnnot,
                                   uint32_t nFlags,
-                                  const CFX_FloatPoint& point) {
+                                  const CFX_PointF& point) {
   CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false);
   if (!pWnd)
     return false;
@@ -249,8 +247,7 @@
     pWnd->SetFocus();
 
   m_bValid = true;
-  FX_RECT rcRect = GetViewBBox(pPageView, pAnnot);
-  InvalidateRect(rcRect.left, rcRect.top, rcRect.right, rcRect.bottom);
+  InvalidateRect(GetViewBBox(pPageView, pAnnot));
 }
 
 void CFFL_FormFiller::KillFocusForAnnot(CPDFSDK_Annot* pAnnot, uint32_t nFlag) {
@@ -395,6 +392,7 @@
     if (pPrivateData->pPageView) {
       CFX_Matrix mtPageView;
       pPrivateData->pPageView->GetCurrentMatrix(mtPageView);
+
       CFX_Matrix mt = GetCurMatrix();
       mt.Concat(mtPageView);
 
@@ -482,27 +480,18 @@
   return temp;
 }
 
-CFX_FloatPoint CFFL_FormFiller::FFLtoPWL(const CFX_FloatPoint& point) {
+CFX_PointF CFFL_FormFiller::FFLtoPWL(const CFX_PointF& point) {
   CFX_Matrix mt;
   mt.SetReverse(GetCurMatrix());
-
-  CFX_FloatPoint pt = point;
-  mt.Transform(pt.x, pt.y);
-
-  return pt;
+  return mt.Transform(point);
 }
 
-CFX_FloatPoint CFFL_FormFiller::PWLtoFFL(const CFX_FloatPoint& point) {
-  CFX_Matrix mt = GetCurMatrix();
-
-  CFX_FloatPoint pt = point;
-  mt.Transform(pt.x, pt.y);
-
-  return pt;
+CFX_PointF CFFL_FormFiller::PWLtoFFL(const CFX_PointF& point) {
+  return GetCurMatrix().Transform(point);
 }
 
-CFX_FloatPoint CFFL_FormFiller::WndtoPWL(CPDFSDK_PageView* pPageView,
-                                         const CFX_FloatPoint& pt) {
+CFX_PointF CFFL_FormFiller::WndtoPWL(CPDFSDK_PageView* pPageView,
+                                     const CFX_PointF& pt) {
   return FFLtoPWL(pt);
 }
 
@@ -593,19 +582,13 @@
                                    bool bDestroyPDFWindow) {
   m_bValid = false;
 
-  FX_RECT rcRect = GetViewBBox(pPageView, m_pWidget);
-  InvalidateRect(rcRect.left, rcRect.top, rcRect.right, rcRect.bottom);
-
+  InvalidateRect(GetViewBBox(pPageView, m_pWidget));
   if (bDestroyPDFWindow)
     DestroyPDFWindow(pPageView);
 }
 
-void CFFL_FormFiller::InvalidateRect(double left,
-                                     double top,
-                                     double right,
-                                     double bottom) {
-  UnderlyingPageType* pPage = m_pWidget->GetUnderlyingPage();
-  m_pFormFillEnv->Invalidate(pPage, left, top, right, bottom);
+void CFFL_FormFiller::InvalidateRect(const FX_RECT& rect) {
+  m_pFormFillEnv->Invalidate(m_pWidget->GetUnderlyingPage(), rect);
 }
 
 CFFL_Button::CFFL_Button(CPDFSDK_FormFillEnvironment* pApp,
@@ -617,16 +600,14 @@
 void CFFL_Button::OnMouseEnter(CPDFSDK_PageView* pPageView,
                                CPDFSDK_Annot* pAnnot) {
   m_bMouseIn = true;
-  FX_RECT rect = GetViewBBox(pPageView, pAnnot);
-  InvalidateRect(rect.left, rect.top, rect.right, rect.bottom);
+  InvalidateRect(GetViewBBox(pPageView, pAnnot));
 }
 
 void CFFL_Button::OnMouseExit(CPDFSDK_PageView* pPageView,
                               CPDFSDK_Annot* pAnnot) {
   m_bMouseIn = false;
 
-  FX_RECT rect = GetViewBBox(pPageView, pAnnot);
-  InvalidateRect(rect.left, rect.top, rect.right, rect.bottom);
+  InvalidateRect(GetViewBBox(pPageView, pAnnot));
   EndTimer();
   ASSERT(m_pWidget);
 }
@@ -634,40 +615,35 @@
 bool CFFL_Button::OnLButtonDown(CPDFSDK_PageView* pPageView,
                                 CPDFSDK_Annot* pAnnot,
                                 uint32_t nFlags,
-                                const CFX_FloatPoint& point) {
-  CFX_FloatRect rcAnnot = pAnnot->GetRect();
-  if (!rcAnnot.Contains(point.x, point.y))
+                                const CFX_PointF& point) {
+  if (!pAnnot->GetRect().Contains(point))
     return false;
 
   m_bMouseDown = true;
   m_bValid = true;
-  FX_RECT rect = GetViewBBox(pPageView, pAnnot);
-  InvalidateRect(rect.left, rect.top, rect.right, rect.bottom);
+  InvalidateRect(GetViewBBox(pPageView, pAnnot));
   return true;
 }
 
 bool CFFL_Button::OnLButtonUp(CPDFSDK_PageView* pPageView,
                               CPDFSDK_Annot* pAnnot,
                               uint32_t nFlags,
-                              const CFX_FloatPoint& point) {
-  CFX_FloatRect rcAnnot = pAnnot->GetRect();
-  if (!rcAnnot.Contains(point.x, point.y))
+                              const CFX_PointF& point) {
+  if (!pAnnot->GetRect().Contains(point))
     return false;
 
   m_bMouseDown = false;
   m_pWidget->GetPDFPage();
 
-  FX_RECT rect = GetViewBBox(pPageView, pAnnot);
-  InvalidateRect(rect.left, rect.top, rect.right, rect.bottom);
+  InvalidateRect(GetViewBBox(pPageView, pAnnot));
   return true;
 }
 
 bool CFFL_Button::OnMouseMove(CPDFSDK_PageView* pPageView,
                               CPDFSDK_Annot* pAnnot,
                               uint32_t nFlags,
-                              const CFX_FloatPoint& point) {
+                              const CFX_PointF& point) {
   ASSERT(m_pFormFillEnv);
-
   return true;
 }
 
diff --git a/fpdfsdk/formfiller/cffl_formfiller.h b/fpdfsdk/formfiller/cffl_formfiller.h
index cf1aaf7..c6b1e59 100644
--- a/fpdfsdk/formfiller/cffl_formfiller.h
+++ b/fpdfsdk/formfiller/cffl_formfiller.h
@@ -41,32 +41,32 @@
   virtual bool OnLButtonDown(CPDFSDK_PageView* pPageView,
                              CPDFSDK_Annot* pAnnot,
                              uint32_t nFlags,
-                             const CFX_FloatPoint& point);
+                             const CFX_PointF& point);
   virtual bool OnLButtonUp(CPDFSDK_PageView* pPageView,
                            CPDFSDK_Annot* pAnnot,
                            uint32_t nFlags,
-                           const CFX_FloatPoint& point);
+                           const CFX_PointF& point);
   virtual bool OnLButtonDblClk(CPDFSDK_PageView* pPageView,
                                CPDFSDK_Annot* pAnnot,
                                uint32_t nFlags,
-                               const CFX_FloatPoint& point);
+                               const CFX_PointF& point);
   virtual bool OnMouseMove(CPDFSDK_PageView* pPageView,
                            CPDFSDK_Annot* pAnnot,
                            uint32_t nFlags,
-                           const CFX_FloatPoint& point);
+                           const CFX_PointF& point);
   virtual bool OnMouseWheel(CPDFSDK_PageView* pPageView,
                             CPDFSDK_Annot* pAnnot,
                             uint32_t nFlags,
                             short zDelta,
-                            const CFX_FloatPoint& point);
+                            const CFX_PointF& point);
   virtual bool OnRButtonDown(CPDFSDK_PageView* pPageView,
                              CPDFSDK_Annot* pAnnot,
                              uint32_t nFlags,
-                             const CFX_FloatPoint& point);
+                             const CFX_PointF& point);
   virtual bool OnRButtonUp(CPDFSDK_PageView* pPageView,
                            CPDFSDK_Annot* pAnnot,
                            uint32_t nFlags,
-                           const CFX_FloatPoint& point);
+                           const CFX_PointF& point);
 
   virtual bool OnKeyDown(CPDFSDK_Annot* pAnnot,
                          uint32_t nKeyCode,
@@ -104,11 +104,10 @@
 
   CFX_FloatRect FFLtoPWL(const CFX_FloatRect& rect);
   CFX_FloatRect PWLtoFFL(const CFX_FloatRect& rect);
-  CFX_FloatPoint FFLtoPWL(const CFX_FloatPoint& point);
-  CFX_FloatPoint PWLtoFFL(const CFX_FloatPoint& point);
+  CFX_PointF FFLtoPWL(const CFX_PointF& point);
+  CFX_PointF PWLtoFFL(const CFX_PointF& point);
 
-  CFX_FloatPoint WndtoPWL(CPDFSDK_PageView* pPageView,
-                          const CFX_FloatPoint& pt);
+  CFX_PointF WndtoPWL(CPDFSDK_PageView* pPageView, const CFX_PointF& pt);
   CFX_FloatRect FFLtoWnd(CPDFSDK_PageView* pPageView,
                          const CFX_FloatRect& rect);
 
@@ -139,10 +138,7 @@
   CPDFSDK_PageView* GetCurPageView(bool renew);
   void SetChangeMark();
 
-  virtual void InvalidateRect(double left,
-                              double top,
-                              double right,
-                              double bottom);
+  virtual void InvalidateRect(const FX_RECT& rect);
   CPDFSDK_Annot* GetSDKAnnot() { return m_pAnnot; }
 
  protected:
@@ -159,10 +155,9 @@
   CPDFSDK_FormFillEnvironment* m_pFormFillEnv;
   CPDFSDK_Widget* m_pWidget;
   CPDFSDK_Annot* m_pAnnot;
-
   bool m_bValid;
   CFFL_PageView2PDFWindow m_Maps;
-  CFX_FloatPoint m_ptOldPos;
+  CFX_PointF m_ptOldPos;
 };
 
 class CFFL_Button : public CFFL_FormFiller {
@@ -178,15 +173,15 @@
   bool OnLButtonDown(CPDFSDK_PageView* pPageView,
                      CPDFSDK_Annot* pAnnot,
                      uint32_t nFlags,
-                     const CFX_FloatPoint& point) override;
+                     const CFX_PointF& point) override;
   bool OnLButtonUp(CPDFSDK_PageView* pPageView,
                    CPDFSDK_Annot* pAnnot,
                    uint32_t nFlags,
-                   const CFX_FloatPoint& point) override;
+                   const CFX_PointF& point) override;
   bool OnMouseMove(CPDFSDK_PageView* pPageView,
                    CPDFSDK_Annot* pAnnot,
                    uint32_t nFlags,
-                   const CFX_FloatPoint& point) override;
+                   const CFX_PointF& point) override;
   void OnDraw(CPDFSDK_PageView* pPageView,
               CPDFSDK_Annot* pAnnot,
               CFX_RenderDevice* pDevice,
diff --git a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
index 01009d2..a830d52 100644
--- a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
+++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
@@ -34,9 +34,8 @@
 
 bool CFFL_InteractiveFormFiller::Annot_HitTest(CPDFSDK_PageView* pPageView,
                                                CPDFSDK_Annot* pAnnot,
-                                               CFX_FloatPoint point) {
-  CFX_FloatRect rc = pAnnot->GetRect();
-  return rc.Contains(point.x, point.y);
+                                               const CFX_PointF& point) {
+  return pAnnot->GetRect().Contains(point);
 }
 
 FX_RECT CFFL_InteractiveFormFiller::GetViewBBox(CPDFSDK_PageView* pPageView,
@@ -70,12 +69,16 @@
         CFX_FloatRect rcFocus = pFormFiller->GetFocusBox(pPageView);
         if (!rcFocus.IsEmpty()) {
           CFX_PathData path;
-          path.SetPointCount(5);
-          path.SetPoint(0, rcFocus.left, rcFocus.top, FXPT_MOVETO);
-          path.SetPoint(1, rcFocus.left, rcFocus.bottom, FXPT_LINETO);
-          path.SetPoint(2, rcFocus.right, rcFocus.bottom, FXPT_LINETO);
-          path.SetPoint(3, rcFocus.right, rcFocus.top, FXPT_LINETO);
-          path.SetPoint(4, rcFocus.left, rcFocus.top, FXPT_LINETO);
+          path.AppendPoint(CFX_PointF(rcFocus.left, rcFocus.top),
+                           FXPT_TYPE::MoveTo, false);
+          path.AppendPoint(CFX_PointF(rcFocus.left, rcFocus.bottom),
+                           FXPT_TYPE::LineTo, false);
+          path.AppendPoint(CFX_PointF(rcFocus.right, rcFocus.bottom),
+                           FXPT_TYPE::LineTo, false);
+          path.AppendPoint(CFX_PointF(rcFocus.right, rcFocus.top),
+                           FXPT_TYPE::LineTo, false);
+          path.AppendPoint(CFX_PointF(rcFocus.left, rcFocus.top),
+                           FXPT_TYPE::LineTo, false);
 
           CFX_GraphStateData gsd;
           gsd.SetDashCount(1);
@@ -176,7 +179,7 @@
     CPDFSDK_PageView* pPageView,
     CPDFSDK_Annot::ObservedPtr* pAnnot,
     uint32_t nFlags,
-    const CFX_FloatPoint& point) {
+    const CFX_PointF& point) {
   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
   if (!m_bNotifying) {
     CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
@@ -217,7 +220,7 @@
 bool CFFL_InteractiveFormFiller::OnLButtonUp(CPDFSDK_PageView* pPageView,
                                              CPDFSDK_Annot::ObservedPtr* pAnnot,
                                              uint32_t nFlags,
-                                             const CFX_FloatPoint& point) {
+                                             const CFX_PointF& point) {
   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
   CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
 
@@ -291,7 +294,7 @@
     CPDFSDK_PageView* pPageView,
     CPDFSDK_Annot::ObservedPtr* pAnnot,
     uint32_t nFlags,
-    const CFX_FloatPoint& point) {
+    const CFX_PointF& point) {
   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false);
   return pFormFiller &&
@@ -301,7 +304,7 @@
 bool CFFL_InteractiveFormFiller::OnMouseMove(CPDFSDK_PageView* pPageView,
                                              CPDFSDK_Annot::ObservedPtr* pAnnot,
                                              uint32_t nFlags,
-                                             const CFX_FloatPoint& point) {
+                                             const CFX_PointF& point) {
   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), true);
   return pFormFiller &&
@@ -313,7 +316,7 @@
     CPDFSDK_Annot::ObservedPtr* pAnnot,
     uint32_t nFlags,
     short zDelta,
-    const CFX_FloatPoint& point) {
+    const CFX_PointF& point) {
   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false);
   return pFormFiller &&
@@ -325,7 +328,7 @@
     CPDFSDK_PageView* pPageView,
     CPDFSDK_Annot::ObservedPtr* pAnnot,
     uint32_t nFlags,
-    const CFX_FloatPoint& point) {
+    const CFX_PointF& point) {
   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false);
   return pFormFiller &&
@@ -335,7 +338,7 @@
 bool CFFL_InteractiveFormFiller::OnRButtonUp(CPDFSDK_PageView* pPageView,
                                              CPDFSDK_Annot::ObservedPtr* pAnnot,
                                              uint32_t nFlags,
-                                             const CFX_FloatPoint& point) {
+                                             const CFX_PointF& point) {
   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false);
   return pFormFiller &&
diff --git a/fpdfsdk/formfiller/cffl_interactiveformfiller.h b/fpdfsdk/formfiller/cffl_interactiveformfiller.h
index e81d3c8..90fd98c 100644
--- a/fpdfsdk/formfiller/cffl_interactiveformfiller.h
+++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.h
@@ -27,7 +27,7 @@
 
   bool Annot_HitTest(CPDFSDK_PageView* pPageView,
                      CPDFSDK_Annot* pAnnot,
-                     CFX_FloatPoint point);
+                     const CFX_PointF& point);
   FX_RECT GetViewBBox(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot);
   void OnDraw(CPDFSDK_PageView* pPageView,
               CPDFSDK_Annot* pAnnot,
@@ -45,32 +45,32 @@
   bool OnLButtonDown(CPDFSDK_PageView* pPageView,
                      CPDFSDK_Annot::ObservedPtr* pAnnot,
                      uint32_t nFlags,
-                     const CFX_FloatPoint& point);
+                     const CFX_PointF& point);
   bool OnLButtonUp(CPDFSDK_PageView* pPageView,
                    CPDFSDK_Annot::ObservedPtr* pAnnot,
                    uint32_t nFlags,
-                   const CFX_FloatPoint& point);
+                   const CFX_PointF& point);
   bool OnLButtonDblClk(CPDFSDK_PageView* pPageView,
                        CPDFSDK_Annot::ObservedPtr* pAnnot,
                        uint32_t nFlags,
-                       const CFX_FloatPoint& point);
+                       const CFX_PointF& point);
   bool OnMouseMove(CPDFSDK_PageView* pPageView,
                    CPDFSDK_Annot::ObservedPtr* pAnnot,
                    uint32_t nFlags,
-                   const CFX_FloatPoint& point);
+                   const CFX_PointF& point);
   bool OnMouseWheel(CPDFSDK_PageView* pPageView,
                     CPDFSDK_Annot::ObservedPtr* pAnnot,
                     uint32_t nFlags,
                     short zDelta,
-                    const CFX_FloatPoint& point);
+                    const CFX_PointF& point);
   bool OnRButtonDown(CPDFSDK_PageView* pPageView,
                      CPDFSDK_Annot::ObservedPtr* pAnnot,
                      uint32_t nFlags,
-                     const CFX_FloatPoint& point);
+                     const CFX_PointF& point);
   bool OnRButtonUp(CPDFSDK_PageView* pPageView,
                    CPDFSDK_Annot::ObservedPtr* pAnnot,
                    uint32_t nFlags,
-                   const CFX_FloatPoint& point);
+                   const CFX_PointF& point);
 
   bool OnKeyDown(CPDFSDK_Annot* pAnnot, uint32_t nKeyCode, uint32_t nFlags);
   bool OnChar(CPDFSDK_Annot* pAnnot, uint32_t nChar, uint32_t nFlags);
diff --git a/fpdfsdk/formfiller/cffl_listbox.cpp b/fpdfsdk/formfiller/cffl_listbox.cpp
index bc3bb6c..556e0e1 100644
--- a/fpdfsdk/formfiller/cffl_listbox.cpp
+++ b/fpdfsdk/formfiller/cffl_listbox.cpp
@@ -167,20 +167,25 @@
 void CFFL_ListBox::SaveState(CPDFSDK_PageView* pPageView) {
   ASSERT(pPageView);
 
-  if (CPWL_ListBox* pListBox = (CPWL_ListBox*)GetPDFWindow(pPageView, false)) {
-    for (int32_t i = 0, sz = pListBox->GetCount(); i < sz; i++) {
-      if (pListBox->IsItemSelected(i)) {
-        m_State.Add(i);
-      }
-    }
+  CPWL_ListBox* pListBox =
+      static_cast<CPWL_ListBox*>(GetPDFWindow(pPageView, false));
+  if (!pListBox)
+    return;
+
+  for (int32_t i = 0, sz = pListBox->GetCount(); i < sz; i++) {
+    if (pListBox->IsItemSelected(i))
+      m_State.push_back(i);
   }
 }
 
 void CFFL_ListBox::RestoreState(CPDFSDK_PageView* pPageView) {
-  if (CPWL_ListBox* pListBox = (CPWL_ListBox*)GetPDFWindow(pPageView, false)) {
-    for (int i = 0, sz = m_State.GetSize(); i < sz; i++)
-      pListBox->Select(m_State[i]);
-  }
+  CPWL_ListBox* pListBox =
+      static_cast<CPWL_ListBox*>(GetPDFWindow(pPageView, false));
+  if (!pListBox)
+    return;
+
+  for (const auto& item : m_State)
+    pListBox->Select(item);
 }
 
 CPWL_Wnd* CFFL_ListBox::ResetPDFWindow(CPDFSDK_PageView* pPageView,
diff --git a/fpdfsdk/formfiller/cffl_listbox.h b/fpdfsdk/formfiller/cffl_listbox.h
index e97ede0..609f2c4 100644
--- a/fpdfsdk/formfiller/cffl_listbox.h
+++ b/fpdfsdk/formfiller/cffl_listbox.h
@@ -9,6 +9,7 @@
 
 #include <memory>
 #include <set>
+#include <vector>
 
 #include "fpdfsdk/formfiller/cffl_formfiller.h"
 
@@ -37,7 +38,7 @@
  private:
   std::unique_ptr<CBA_FontMap> m_pFontMap;
   std::set<int> m_OriginSelections;
-  CFX_ArrayTemplate<int> m_State;
+  std::vector<int> m_State;
 };
 
 #endif  // FPDFSDK_FORMFILLER_CFFL_LISTBOX_H_
diff --git a/fpdfsdk/formfiller/cffl_radiobutton.cpp b/fpdfsdk/formfiller/cffl_radiobutton.cpp
index 70d4c0d..e78160e 100644
--- a/fpdfsdk/formfiller/cffl_radiobutton.cpp
+++ b/fpdfsdk/formfiller/cffl_radiobutton.cpp
@@ -72,7 +72,7 @@
 bool CFFL_RadioButton::OnLButtonUp(CPDFSDK_PageView* pPageView,
                                    CPDFSDK_Annot* pAnnot,
                                    uint32_t nFlags,
-                                   const CFX_FloatPoint& point) {
+                                   const CFX_PointF& point) {
   CFFL_Button::OnLButtonUp(pPageView, pAnnot, nFlags, point);
 
   if (IsValid()) {
diff --git a/fpdfsdk/formfiller/cffl_radiobutton.h b/fpdfsdk/formfiller/cffl_radiobutton.h
index 49a658f..10ac37d 100644
--- a/fpdfsdk/formfiller/cffl_radiobutton.h
+++ b/fpdfsdk/formfiller/cffl_radiobutton.h
@@ -24,7 +24,7 @@
   bool OnLButtonUp(CPDFSDK_PageView* pPageView,
                    CPDFSDK_Annot* pAnnot,
                    uint32_t nFlags,
-                   const CFX_FloatPoint& point) override;
+                   const CFX_PointF& point) override;
   bool IsDataChanged(CPDFSDK_PageView* pPageView) override;
   void SaveData(CPDFSDK_PageView* pPageView) override;
 };
diff --git a/fpdfsdk/formfiller/cffl_textfield.cpp b/fpdfsdk/formfiller/cffl_textfield.cpp
index c1cd786..91db095 100644
--- a/fpdfsdk/formfiller/cffl_textfield.cpp
+++ b/fpdfsdk/formfiller/cffl_textfield.cpp
@@ -114,9 +114,8 @@
         CPDFSDK_PageView* pPageView = GetCurPageView(true);
         ASSERT(pPageView);
         m_bValid = !m_bValid;
-        CFX_FloatRect rcAnnot = pAnnot->GetRect();
-        m_pFormFillEnv->Invalidate(pAnnot->GetUnderlyingPage(), rcAnnot.left,
-                                   rcAnnot.top, rcAnnot.right, rcAnnot.bottom);
+        m_pFormFillEnv->Invalidate(pAnnot->GetUnderlyingPage(),
+                                   pAnnot->GetRect().ToFxRect());
 
         if (m_bValid) {
           if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, true))
diff --git a/fpdfsdk/fpdf_structtree.cpp b/fpdfsdk/fpdf_structtree.cpp
index 9bc1df6..5a922a1 100644
--- a/fpdfsdk/fpdf_structtree.cpp
+++ b/fpdfsdk/fpdf_structtree.cpp
@@ -4,6 +4,8 @@
 
 #include "public/fpdf_structtree.h"
 
+#include <memory>
+
 #include "core/fpdfapi/page/cpdf_page.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfdoc/fpdf_tagged.h"
@@ -30,7 +32,7 @@
 }
 
 DLLEXPORT void STDCALL FPDF_StructTree_Close(FPDF_STRUCTTREE struct_tree) {
-  delete ToStructTree(struct_tree);
+  std::unique_ptr<IPDF_StructTree>(ToStructTree(struct_tree));
 }
 
 DLLEXPORT int STDCALL
@@ -83,7 +85,5 @@
   if (!elem || index < 0 || index >= elem->CountKids())
     return nullptr;
 
-  CPDF_StructKid kid = elem->GetKid(index);
-  return kid.m_Type == CPDF_StructKid::Element ? kid.m_Element.m_pElement
-                                               : nullptr;
+  return elem->GetKidIfElement(index);
 }
diff --git a/fpdfsdk/fpdf_transformpage.cpp b/fpdfsdk/fpdf_transformpage.cpp
index 13d9756..3427f4e 100644
--- a/fpdfsdk/fpdf_transformpage.cpp
+++ b/fpdfsdk/fpdf_transformpage.cpp
@@ -6,6 +6,8 @@
 
 #include "public/fpdf_transformpage.h"
 
+#include <vector>
+
 #include "core/fpdfapi/page/cpdf_clippath.h"
 #include "core/fpdfapi/page/cpdf_page.h"
 #include "core/fpdfapi/page/cpdf_pageobject.h"
@@ -235,35 +237,34 @@
   if (!pPathData)
     return;
 
-  FX_PATHPOINT* pPoints = pPathData->GetPoints();
-
+  const std::vector<FX_PATHPOINT>& pPoints = pPathData->GetPoints();
   if (path.IsRect()) {
-    buf << (pPoints[0].m_PointX) << " " << (pPoints[0].m_PointY) << " "
-        << (pPoints[2].m_PointX - pPoints[0].m_PointX) << " "
-        << (pPoints[2].m_PointY - pPoints[0].m_PointY) << " re\n";
+    CFX_PointF diff = pPoints[2].m_Point - pPoints[0].m_Point;
+    buf << pPoints[0].m_Point.x << " " << pPoints[0].m_Point.y << " " << diff.x
+        << " " << diff.y << " re\n";
     return;
   }
 
   CFX_ByteString temp;
-  for (int i = 0; i < pPathData->GetPointCount(); i++) {
-    buf << (pPoints[i].m_PointX) << " " << (pPoints[i].m_PointY);
-    int point_type = pPoints[i].m_Flag & FXPT_TYPE;
-    if (point_type == FXPT_MOVETO) {
+  for (size_t i = 0; i < pPoints.size(); i++) {
+    buf << pPoints[i].m_Point.x << " " << pPoints[i].m_Point.y;
+    FXPT_TYPE point_type = pPoints[i].m_Type;
+    if (point_type == FXPT_TYPE::MoveTo) {
       buf << " m\n";
-    } else if (point_type == FXPT_BEZIERTO) {
-      buf << " " << (pPoints[i + 1].m_PointX) << " "
-          << (pPoints[i + 1].m_PointY) << " " << (pPoints[i + 2].m_PointX)
-          << " " << (pPoints[i + 2].m_PointY);
-      if (pPoints[i + 2].m_Flag & FXPT_CLOSEFIGURE)
-        buf << " c h\n";
-      else
-        buf << " c\n";
+    } else if (point_type == FXPT_TYPE::BezierTo) {
+      buf << " " << pPoints[i + 1].m_Point.x << " " << pPoints[i + 1].m_Point.y
+          << " " << pPoints[i + 2].m_Point.x << " " << pPoints[i + 2].m_Point.y;
+      buf << " c";
+      if (pPoints[i + 2].m_CloseFigure)
+        buf << " h";
+      buf << "\n";
+
       i += 2;
-    } else if (point_type == FXPT_LINETO) {
-      if (pPoints[i].m_Flag & FXPT_CLOSEFIGURE)
-        buf << " l h\n";
-      else
-        buf << " l\n";
+    } else if (point_type == FXPT_TYPE::LineTo) {
+      buf << " l";
+      if (pPoints[i].m_CloseFigure)
+        buf << " h";
+      buf << "\n";
     }
   }
 }
@@ -288,7 +289,7 @@
   for (i = 0; i < pClipPath->GetPathCount(); i++) {
     CPDF_Path path = pClipPath->GetPath(i);
     int iClipType = pClipPath->GetClipType(i);
-    if (path.GetPointCount() == 0) {
+    if (path.GetPoints().empty()) {
       // Empty clipping (totally clipped out)
       strClip << "0 0 m W n ";
     } else {
diff --git a/fpdfsdk/fpdfdoc.cpp b/fpdfsdk/fpdfdoc.cpp
index 82b898a..f7d94c2 100644
--- a/fpdfsdk/fpdfdoc.cpp
+++ b/fpdfsdk/fpdfdoc.cpp
@@ -257,7 +257,10 @@
   if (!pLinkList)
     return nullptr;
 
-  return pLinkList->GetLinkAtPoint(pPage, (FX_FLOAT)x, (FX_FLOAT)y, nullptr)
+  return pLinkList
+      ->GetLinkAtPoint(
+          pPage, CFX_PointF(static_cast<FX_FLOAT>(x), static_cast<FX_FLOAT>(y)),
+          nullptr)
       .GetDict();
 }
 
@@ -273,7 +276,9 @@
     return -1;
 
   int z_order = -1;
-  pLinkList->GetLinkAtPoint(pPage, (FX_FLOAT)x, (FX_FLOAT)y, &z_order);
+  pLinkList->GetLinkAtPoint(
+      pPage, CFX_PointF(static_cast<FX_FLOAT>(x), static_cast<FX_FLOAT>(y)),
+      &z_order);
   return z_order;
 }
 
diff --git a/fpdfsdk/fpdfedit_embeddertest.cpp b/fpdfsdk/fpdfedit_embeddertest.cpp
index 40bed3a..53554a1 100644
--- a/fpdfsdk/fpdfedit_embeddertest.cpp
+++ b/fpdfsdk/fpdfedit_embeddertest.cpp
@@ -5,6 +5,13 @@
 #include <memory>
 #include <string>
 
+#include "core/fpdfapi/font/cpdf_font.h"
+#include "core/fpdfapi/page/cpdf_page.h"
+#include "core/fpdfapi/parser/cpdf_array.h"
+#include "core/fpdfapi/parser/cpdf_dictionary.h"
+#include "core/fpdfapi/parser/cpdf_stream.h"
+#include "core/fxcrt/fx_system.h"
+#include "fpdfsdk/fsdk_define.h"
 #include "public/fpdf_edit.h"
 #include "public/fpdfview.h"
 #include "testing/embedder_test.h"
@@ -140,16 +147,359 @@
     EXPECT_EQ(1, FPDF_GetPageCount(document_));
     FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
     EXPECT_NE(nullptr, new_page);
-    int width = static_cast<int>(FPDF_GetPageWidth(new_page));
-    int height = static_cast<int>(FPDF_GetPageHeight(new_page));
-    int alpha = FPDFPage_HasTransparency(new_page) ? 1 : 0;
-    FPDF_BITMAP new_bitmap = FPDFBitmap_Create(width, height, alpha);
-    FPDF_DWORD fill_color = alpha ? 0x00000000 : 0xFFFFFFFF;
-    FPDFBitmap_FillRect(new_bitmap, 0, 0, width, height, fill_color);
-    FPDF_RenderPageBitmap(new_bitmap, new_page, 0, 0, width, height, 0, 0);
+    FPDF_BITMAP new_bitmap = RenderPage(new_page);
     CompareBitmap(new_bitmap, 612, 792, kAllBlackMd5sum);
     FPDF_ClosePage(new_page);
     FPDF_CloseDocument(new_doc);
     FPDFBitmap_Destroy(new_bitmap);
   }
 }
+
+TEST_F(FPDFEditEmbeddertest, AddPaths) {
+  // Start with a blank page
+  FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
+  FPDF_PAGE page = FPDFPage_New(doc, 0, 612, 792);
+
+  // We will first add a red rectangle
+  FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
+  ASSERT_NE(nullptr, red_rect);
+  // Expect false when trying to set colors out of range
+  EXPECT_FALSE(FPDFPath_SetStrokeColor(red_rect, 100, 100, 100, 300));
+  EXPECT_FALSE(FPDFPath_SetFillColor(red_rect, 200, 256, 200, 0));
+
+  // Fill rectangle with red and insert to the page
+  EXPECT_TRUE(FPDFPath_SetFillColor(red_rect, 255, 0, 0, 255));
+  EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
+  FPDFPage_InsertObject(page, red_rect);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  FPDF_BITMAP page_bitmap = RenderPage(page);
+  CompareBitmap(page_bitmap, 612, 792, "66d02eaa6181e2c069ce2ea99beda497");
+  FPDFBitmap_Destroy(page_bitmap);
+
+  // Now add to that a green rectangle with some medium alpha
+  FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(100, 100, 40, 40);
+  EXPECT_TRUE(FPDFPath_SetFillColor(green_rect, 0, 255, 0, 128));
+  EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_WINDING, 0));
+  FPDFPage_InsertObject(page, green_rect);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  page_bitmap = RenderPage(page);
+  CompareBitmap(page_bitmap, 612, 792, "7b0b87604594e773add528fae567a558");
+  FPDFBitmap_Destroy(page_bitmap);
+
+  // Add a black triangle.
+  FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(400, 100);
+  EXPECT_TRUE(FPDFPath_SetFillColor(black_path, 0, 0, 0, 200));
+  EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
+  EXPECT_TRUE(FPDFPath_LineTo(black_path, 400, 200));
+  EXPECT_TRUE(FPDFPath_LineTo(black_path, 300, 100));
+  EXPECT_TRUE(FPDFPath_Close(black_path));
+  FPDFPage_InsertObject(page, black_path);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  page_bitmap = RenderPage(page);
+  CompareBitmap(page_bitmap, 612, 792, "eadc8020a14dfcf091da2688733d8806");
+  FPDFBitmap_Destroy(page_bitmap);
+
+  // Now add a more complex blue path.
+  FPDF_PAGEOBJECT blue_path = FPDFPageObj_CreateNewPath(200, 200);
+  EXPECT_TRUE(FPDFPath_SetFillColor(blue_path, 0, 0, 255, 255));
+  EXPECT_TRUE(FPDFPath_SetDrawMode(blue_path, FPDF_FILLMODE_WINDING, 0));
+  EXPECT_TRUE(FPDFPath_LineTo(blue_path, 230, 230));
+  EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 250, 250, 280, 280, 300, 300));
+  EXPECT_TRUE(FPDFPath_LineTo(blue_path, 325, 325));
+  EXPECT_TRUE(FPDFPath_LineTo(blue_path, 350, 325));
+  EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 375, 330, 390, 360, 400, 400));
+  EXPECT_TRUE(FPDFPath_Close(blue_path));
+  FPDFPage_InsertObject(page, blue_path);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  page_bitmap = RenderPage(page);
+  CompareBitmap(page_bitmap, 612, 792, "9823e1a21bd9b72b6a442ba4f12af946");
+  FPDFBitmap_Destroy(page_bitmap);
+
+  // Now save the result, closing the page and document
+  EXPECT_TRUE(FPDF_SaveAsCopy(doc, this, 0));
+  FPDF_ClosePage(page);
+  FPDF_CloseDocument(doc);
+  std::string new_file = GetString();
+
+  // Render the saved result
+  FPDF_FILEACCESS file_access;
+  memset(&file_access, 0, sizeof(file_access));
+  file_access.m_FileLen = new_file.size();
+  file_access.m_GetBlock = GetBlockFromString;
+  file_access.m_Param = &new_file;
+  FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
+  ASSERT_NE(nullptr, new_doc);
+  EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
+  FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
+  ASSERT_NE(nullptr, new_page);
+  FPDF_BITMAP new_bitmap = RenderPage(new_page);
+  CompareBitmap(new_bitmap, 612, 792, "9823e1a21bd9b72b6a442ba4f12af946");
+  FPDFBitmap_Destroy(new_bitmap);
+  FPDF_ClosePage(new_page);
+  FPDF_CloseDocument(new_doc);
+}
+
+TEST_F(FPDFEditEmbeddertest, PathOnTopOfText) {
+  // Load document with some text
+  EXPECT_TRUE(OpenDocument("hello_world.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  EXPECT_NE(nullptr, page);
+
+  // Add an opaque rectangle on top of some of the text.
+  FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
+  EXPECT_TRUE(FPDFPath_SetFillColor(red_rect, 255, 0, 0, 255));
+  EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
+  FPDFPage_InsertObject(page, red_rect);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+
+  // Add a transparent triangle on top of other part of the text.
+  FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(20, 50);
+  EXPECT_TRUE(FPDFPath_SetFillColor(black_path, 0, 0, 0, 100));
+  EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
+  EXPECT_TRUE(FPDFPath_LineTo(black_path, 30, 80));
+  EXPECT_TRUE(FPDFPath_LineTo(black_path, 40, 10));
+  EXPECT_TRUE(FPDFPath_Close(black_path));
+  FPDFPage_InsertObject(page, black_path);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+
+  // Render and check the result. Text is slightly different on Mac.
+  FPDF_BITMAP bitmap = RenderPage(page);
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
+  const char md5[] = "2f7c0deee10a9490538e195af64beb67";
+#else
+  const char md5[] = "17c942c76ff229200f2c98073bb60d85";
+#endif
+  CompareBitmap(bitmap, 200, 200, md5);
+  FPDFBitmap_Destroy(bitmap);
+  UnloadPage(page);
+}
+
+TEST_F(FPDFEditEmbeddertest, AddStrokedPaths) {
+  // Start with a blank page
+  FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
+  FPDF_PAGE page = FPDFPage_New(doc, 0, 612, 792);
+
+  // Add a large stroked rectangle (fill color should not affect it).
+  FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(20, 20, 200, 400);
+  EXPECT_TRUE(FPDFPath_SetFillColor(rect, 255, 0, 0, 255));
+  EXPECT_TRUE(FPDFPath_SetStrokeColor(rect, 0, 255, 0, 255));
+  EXPECT_TRUE(FPDFPath_SetStrokeWidth(rect, 15.0f));
+  EXPECT_TRUE(FPDFPath_SetDrawMode(rect, 0, 1));
+  FPDFPage_InsertObject(page, rect);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  FPDF_BITMAP page_bitmap = RenderPage(page);
+  CompareBitmap(page_bitmap, 612, 792, "64bd31f862a89e0a9e505a5af6efd506");
+  FPDFBitmap_Destroy(page_bitmap);
+
+  // Add crossed-checkmark
+  FPDF_PAGEOBJECT check = FPDFPageObj_CreateNewPath(300, 500);
+  EXPECT_TRUE(FPDFPath_LineTo(check, 400, 400));
+  EXPECT_TRUE(FPDFPath_LineTo(check, 600, 600));
+  EXPECT_TRUE(FPDFPath_MoveTo(check, 400, 600));
+  EXPECT_TRUE(FPDFPath_LineTo(check, 600, 400));
+  EXPECT_TRUE(FPDFPath_SetStrokeColor(check, 128, 128, 128, 180));
+  EXPECT_TRUE(FPDFPath_SetStrokeWidth(check, 8.35f));
+  EXPECT_TRUE(FPDFPath_SetDrawMode(check, 0, 1));
+  FPDFPage_InsertObject(page, check);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  page_bitmap = RenderPage(page);
+  CompareBitmap(page_bitmap, 612, 792, "4b6f3b9d25c4e194821217d5016c3724");
+  FPDFBitmap_Destroy(page_bitmap);
+
+  // Add stroked and filled oval-ish path.
+  FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(250, 100);
+  EXPECT_TRUE(FPDFPath_BezierTo(path, 180, 166, 180, 233, 250, 300));
+  EXPECT_TRUE(FPDFPath_LineTo(path, 255, 305));
+  EXPECT_TRUE(FPDFPath_BezierTo(path, 325, 233, 325, 166, 255, 105));
+  EXPECT_TRUE(FPDFPath_Close(path));
+  EXPECT_TRUE(FPDFPath_SetFillColor(path, 200, 128, 128, 100));
+  EXPECT_TRUE(FPDFPath_SetStrokeColor(path, 128, 200, 128, 150));
+  EXPECT_TRUE(FPDFPath_SetStrokeWidth(path, 10.5f));
+  EXPECT_TRUE(FPDFPath_SetDrawMode(path, FPDF_FILLMODE_ALTERNATE, 1));
+  FPDFPage_InsertObject(page, path);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  page_bitmap = RenderPage(page);
+  CompareBitmap(page_bitmap, 612, 792, "ff3e6a22326754944cc6e56609acd73b");
+  FPDFBitmap_Destroy(page_bitmap);
+  FPDF_ClosePage(page);
+  FPDF_CloseDocument(doc);
+}
+
+TEST_F(FPDFEditEmbeddertest, AddStandardFontText) {
+  // Start with a blank page
+  FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
+  FPDF_PAGE page = FPDFPage_New(doc, 0, 612, 792);
+
+  // Add some text to the page
+  FPDF_PAGEOBJECT text1 = FPDFPageObj_NewTextObj(doc, "Arial", 12.0f);
+  EXPECT_TRUE(text1);
+  EXPECT_TRUE(FPDFText_SetText(text1, "I'm at the bottom of the page"));
+  FPDFPageObj_Transform(text1, 1, 0, 0, 1, 20, 20);
+  FPDFPage_InsertObject(page, text1);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  FPDF_BITMAP page_bitmap = RenderPage(page);
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
+  const char md5[] = "e19c90395d73cb9f37a6c3b0e8b18a9e";
+#else
+  const char md5[] = "7c3a36ba7cec01688a16a14bfed9ecfc";
+#endif
+  CompareBitmap(page_bitmap, 612, 792, md5);
+  FPDFBitmap_Destroy(page_bitmap);
+
+  // Try another font
+  FPDF_PAGEOBJECT text2 =
+      FPDFPageObj_NewTextObj(doc, "TimesNewRomanBold", 15.0f);
+  EXPECT_TRUE(text2);
+  EXPECT_TRUE(FPDFText_SetText(text2, "Hi, I'm Bold. Times New Roman Bold."));
+  FPDFPageObj_Transform(text2, 1, 0, 0, 1, 100, 600);
+  FPDFPage_InsertObject(page, text2);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  page_bitmap = RenderPage(page);
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
+  const char md5_2[] = "8e1c43dca6be68d364dbc283f5521041";
+#else
+  const char md5_2[] = "e0e0873e3a2634a6394a431a51ce90ff";
+#endif
+  CompareBitmap(page_bitmap, 612, 792, md5_2);
+  FPDFBitmap_Destroy(page_bitmap);
+
+  // And some randomly transformed text
+  FPDF_PAGEOBJECT text3 = FPDFPageObj_NewTextObj(doc, "Courier-Bold", 20.0f);
+  EXPECT_TRUE(text3);
+  EXPECT_TRUE(FPDFText_SetText(text3, "Can you read me? <:)>"));
+  FPDFPageObj_Transform(text3, 1, 1.5, 2, 0.5, 200, 200);
+  FPDFPage_InsertObject(page, text3);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  page_bitmap = RenderPage(page);
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
+  const char md5_3[] = "c6e5df448428793c7e4b0c820bd8c85e";
+#else
+  const char md5_3[] = "903ee10b6a9f0be51ecad0a1a0eeb171";
+#endif
+  CompareBitmap(page_bitmap, 612, 792, md5_3);
+  FPDFBitmap_Destroy(page_bitmap);
+
+  // TODO(npm): Why are there issues with text rotated by 90 degrees?
+  // TODO(npm): FPDF_SaveAsCopy not giving the desired result after this.
+  FPDF_ClosePage(page);
+  FPDF_CloseDocument(doc);
+}
+
+TEST_F(FPDFEditEmbeddertest, DoubleGenerating) {
+  // Start with a blank page
+  FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
+  FPDF_PAGE page = FPDFPage_New(doc, 0, 612, 792);
+
+  // Add a red rectangle with some non-default alpha
+  FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
+  EXPECT_TRUE(FPDFPath_SetFillColor(rect, 255, 0, 0, 128));
+  EXPECT_TRUE(FPDFPath_SetDrawMode(rect, FPDF_FILLMODE_WINDING, 0));
+  FPDFPage_InsertObject(page, rect);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+
+  // Check the ExtGState
+  CPDF_Page* the_page = CPDFPageFromFPDFPage(page);
+  CPDF_Dictionary* graphics_dict =
+      the_page->m_pResources->GetDictFor("ExtGState");
+  ASSERT_TRUE(graphics_dict);
+  EXPECT_EQ(1, static_cast<int>(graphics_dict->GetCount()));
+
+  // Check the bitmap
+  FPDF_BITMAP page_bitmap = RenderPage(page);
+  CompareBitmap(page_bitmap, 612, 792, "5384da3406d62360ffb5cac4476fff1c");
+  FPDFBitmap_Destroy(page_bitmap);
+
+  // Never mind, my new favorite color is blue, increase alpha
+  EXPECT_TRUE(FPDFPath_SetFillColor(rect, 0, 0, 255, 180));
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
+
+  // Check that bitmap displays changed content
+  page_bitmap = RenderPage(page);
+  CompareBitmap(page_bitmap, 612, 792, "2e51656f5073b0bee611d9cd086aa09c");
+  FPDFBitmap_Destroy(page_bitmap);
+
+  // And now generate, without changes
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
+  page_bitmap = RenderPage(page);
+  CompareBitmap(page_bitmap, 612, 792, "2e51656f5073b0bee611d9cd086aa09c");
+  FPDFBitmap_Destroy(page_bitmap);
+
+  // Add some text to the page
+  FPDF_PAGEOBJECT text = FPDFPageObj_NewTextObj(doc, "Arial", 12.0f);
+  EXPECT_TRUE(FPDFText_SetText(text, "Something something #text# something"));
+  FPDFPageObj_Transform(text, 1, 0, 0, 1, 300, 300);
+  FPDFPage_InsertObject(page, text);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  CPDF_Dictionary* font_dict = the_page->m_pResources->GetDictFor("Font");
+  ASSERT_TRUE(font_dict);
+  EXPECT_EQ(1, static_cast<int>(font_dict->GetCount()));
+
+  // Generate yet again, check dicts are reasonably sized
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
+  EXPECT_EQ(1, static_cast<int>(font_dict->GetCount()));
+  FPDF_ClosePage(page);
+  FPDF_CloseDocument(doc);
+}
+
+TEST_F(FPDFEditEmbeddertest, Type1Font) {
+  // Create a new document
+  FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
+  CPDF_Document* document = reinterpret_cast<CPDF_Document*>(doc);
+
+  // Get Times New Roman Bold as a Type 1 font
+  CPDF_Font* times_bold = CPDF_Font::GetStockFont(document, "Times-Bold");
+  uint8_t* data = times_bold->m_Font.GetFontData();
+  uint32_t size = times_bold->m_Font.GetSize();
+  FPDF_FONT font = FPDFText_LoadType1Font(doc, data, size);
+  ASSERT_TRUE(font);
+  CPDF_Font* type1_font = reinterpret_cast<CPDF_Font*>(font);
+  EXPECT_TRUE(type1_font->IsType1Font());
+
+  // Check that the font dictionary has the required keys according to the spec
+  CPDF_Dictionary* font_dict = type1_font->GetFontDict();
+  EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
+  EXPECT_EQ("Type1", font_dict->GetStringFor("Subtype"));
+  EXPECT_EQ("Times New Roman Bold", font_dict->GetStringFor("BaseFont"));
+  ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
+  ASSERT_TRUE(font_dict->KeyExist("LastChar"));
+  EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
+  EXPECT_EQ(65532, font_dict->GetIntegerFor("LastChar"));
+  ASSERT_TRUE(font_dict->KeyExist("Widths"));
+  CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
+  EXPECT_EQ(65501U, widths_array->GetCount());
+  EXPECT_EQ(250, widths_array->GetNumberAt(0));
+  EXPECT_EQ(0, widths_array->GetNumberAt(8172));
+  EXPECT_EQ(1000, widths_array->GetNumberAt(65500));
+  ASSERT_TRUE(font_dict->KeyExist("FontDescriptor"));
+  CPDF_Dictionary* font_desc = font_dict->GetDictFor("FontDescriptor");
+  EXPECT_EQ("FontDescriptor", font_desc->GetStringFor("Type"));
+  EXPECT_EQ(font_dict->GetStringFor("BaseFont"),
+            font_desc->GetStringFor("FontName"));
+
+  // Check that the font descriptor has the required keys according to the spec
+  ASSERT_TRUE(font_desc->KeyExist("Flags"));
+  int font_flags = font_desc->GetIntegerFor("Flags");
+  EXPECT_TRUE(font_flags & FXFONT_BOLD);
+  EXPECT_TRUE(font_flags & FXFONT_NONSYMBOLIC);
+  ASSERT_TRUE(font_desc->KeyExist("FontBBox"));
+  EXPECT_EQ(4U, font_desc->GetArrayFor("FontBBox")->GetCount());
+  EXPECT_TRUE(font_desc->KeyExist("ItalicAngle"));
+  EXPECT_TRUE(font_desc->KeyExist("Ascent"));
+  EXPECT_TRUE(font_desc->KeyExist("Descent"));
+  EXPECT_TRUE(font_desc->KeyExist("CapHeight"));
+  EXPECT_TRUE(font_desc->KeyExist("StemV"));
+  ASSERT_TRUE(font_desc->KeyExist("FontFile"));
+
+  // Check that the font stream is the one that was provided
+  CPDF_Stream* font_stream = font_desc->GetStreamFor("FontFile");
+  ASSERT_EQ(size, font_stream->GetRawSize());
+  uint8_t* stream_data = font_stream->GetRawData();
+  for (size_t i = 0; i < size; i++)
+    EXPECT_EQ(data[i], stream_data[i]);
+
+  // Close document
+  FPDF_CloseDocument(doc);
+}
diff --git a/fpdfsdk/fpdfeditpage.cpp b/fpdfsdk/fpdfeditpage.cpp
index 18a1d61..63740ba 100644
--- a/fpdfsdk/fpdfeditpage.cpp
+++ b/fpdfsdk/fpdfeditpage.cpp
@@ -289,7 +289,7 @@
     CFX_FloatRect rect = pAnnot->GetRect();  // transformAnnots Rectangle
     CFX_Matrix matrix((FX_FLOAT)a, (FX_FLOAT)b, (FX_FLOAT)c, (FX_FLOAT)d,
                       (FX_FLOAT)e, (FX_FLOAT)f);
-    rect.Transform(&matrix);
+    matrix.TransformRect(rect);
 
     CPDF_Array* pRectArray = pAnnot->GetAnnotDict()->GetArrayFor("Rect");
     if (!pRectArray)
diff --git a/fpdfsdk/fpdfeditpath.cpp b/fpdfsdk/fpdfeditpath.cpp
new file mode 100644
index 0000000..074f083
--- /dev/null
+++ b/fpdfsdk/fpdfeditpath.cpp
@@ -0,0 +1,132 @@
+// 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 "public/fpdf_edit.h"
+
+#include "core/fpdfapi/page/cpdf_path.h"
+#include "core/fpdfapi/page/cpdf_pathobject.h"
+#include "core/fxcrt/fx_system.h"
+
+DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_CreateNewPath(float x, float y) {
+  CPDF_PathObject* pPathObj = new CPDF_PathObject;
+  pPathObj->m_Path.AppendPoint(CFX_PointF(x, y), FXPT_TYPE::MoveTo, false);
+  pPathObj->DefaultStates();
+  return pPathObj;
+}
+
+DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_CreateNewRect(float x,
+                                                            float y,
+                                                            float w,
+                                                            float h) {
+  CPDF_PathObject* pPathObj = new CPDF_PathObject;
+  pPathObj->m_Path.AppendRect(x, y, x + w, y + h);
+  pPathObj->DefaultStates();
+  return pPathObj;
+}
+
+DLLEXPORT FPDF_BOOL FPDFPath_SetStrokeColor(FPDF_PAGEOBJECT path,
+                                            unsigned int R,
+                                            unsigned int G,
+                                            unsigned int B,
+                                            unsigned int A) {
+  if (!path || R > 255 || G > 255 || B > 255 || A > 255)
+    return false;
+
+  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+  pPathObj->m_GeneralState.SetStrokeAlpha(A / 255.f);
+  FX_FLOAT rgb[3] = {R / 255.f, G / 255.f, B / 255.f};
+  pPathObj->m_ColorState.SetStrokeColor(
+      CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb, 3);
+  return true;
+}
+
+DLLEXPORT FPDF_BOOL FPDFPath_SetStrokeWidth(FPDF_PAGEOBJECT path, float width) {
+  if (!path || width < 0.0f)
+    return false;
+
+  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+  pPathObj->m_GraphState.SetLineWidth(width);
+  return true;
+}
+
+DLLEXPORT FPDF_BOOL FPDFPath_SetFillColor(FPDF_PAGEOBJECT path,
+                                          unsigned int R,
+                                          unsigned int G,
+                                          unsigned int B,
+                                          unsigned int A) {
+  if (!path || R > 255 || G > 255 || B > 255 || A > 255)
+    return false;
+
+  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+  pPathObj->m_GeneralState.SetFillAlpha(A / 255.f);
+  FX_FLOAT rgb[3] = {R / 255.f, G / 255.f, B / 255.f};
+  pPathObj->m_ColorState.SetFillColor(
+      CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb, 3);
+  return true;
+}
+
+DLLEXPORT FPDF_BOOL FPDFPath_MoveTo(FPDF_PAGEOBJECT path, float x, float y) {
+  if (!path)
+    return false;
+
+  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(x, y), FXPT_TYPE::MoveTo, false);
+  return true;
+}
+
+DLLEXPORT FPDF_BOOL FPDFPath_LineTo(FPDF_PAGEOBJECT path, float x, float y) {
+  if (!path)
+    return false;
+
+  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(x, y), FXPT_TYPE::LineTo, false);
+  return true;
+}
+
+DLLEXPORT FPDF_BOOL FPDFPath_BezierTo(FPDF_PAGEOBJECT path,
+                                      float x1,
+                                      float y1,
+                                      float x2,
+                                      float y2,
+                                      float x3,
+                                      float y3) {
+  if (!path)
+    return false;
+
+  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(x1, y1), FXPT_TYPE::BezierTo, false);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(x2, y2), FXPT_TYPE::BezierTo, false);
+  pPathObj->m_Path.AppendPoint(CFX_PointF(x3, y3), FXPT_TYPE::BezierTo, false);
+  return true;
+}
+
+DLLEXPORT FPDF_BOOL FPDFPath_Close(FPDF_PAGEOBJECT path) {
+  if (!path)
+    return false;
+
+  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+  if (pPathObj->m_Path.GetPoints().empty())
+    return false;
+
+  pPathObj->m_Path.ClosePath();
+  return true;
+}
+
+DLLEXPORT FPDF_BOOL FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path,
+                                         int fillmode,
+                                         FPDF_BOOL stroke) {
+  if (!path)
+    return false;
+
+  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+
+  if (fillmode == FPDF_FILLMODE_ALTERNATE)
+    pPathObj->m_FillType = FXFILL_ALTERNATE;
+  else if (fillmode == FPDF_FILLMODE_WINDING)
+    pPathObj->m_FillType = FXFILL_WINDING;
+  else
+    pPathObj->m_FillType = 0;
+  pPathObj->m_bStroke = stroke != 0;
+  return true;
+}
diff --git a/fpdfsdk/fpdfedittext.cpp b/fpdfsdk/fpdfedittext.cpp
new file mode 100644
index 0000000..8bf0a0a
--- /dev/null
+++ b/fpdfsdk/fpdfedittext.cpp
@@ -0,0 +1,132 @@
+// 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 <utility>
+
+#include "core/fpdfapi/cpdf_modulemgr.h"
+#include "core/fpdfapi/font/cpdf_font.h"
+#include "core/fpdfapi/font/cpdf_type1font.h"
+#include "core/fpdfapi/page/cpdf_textobject.h"
+#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/cpdf_name.h"
+#include "core/fpdfapi/parser/cpdf_number.h"
+#include "core/fpdfapi/parser/cpdf_reference.h"
+#include "core/fpdfapi/parser/cpdf_stream.h"
+#include "core/fxge/cfx_fontmgr.h"
+#include "core/fxge/fx_font.h"
+#include "fpdfsdk/fsdk_define.h"
+#include "public/fpdf_edit.h"
+
+DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_NewTextObj(FPDF_DOCUMENT document,
+                                                         FPDF_BYTESTRING font,
+                                                         float font_size) {
+  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+  if (!pDoc)
+    return nullptr;
+
+  CPDF_Font* pFont = CPDF_Font::GetStockFont(pDoc, CFX_ByteStringC(font));
+  if (!pFont)
+    return nullptr;
+
+  CPDF_TextObject* pTextObj = new CPDF_TextObject;
+  pTextObj->m_TextState.SetFont(pFont);
+  pTextObj->m_TextState.SetFontSize(font_size);
+  pTextObj->DefaultStates();
+  return pTextObj;
+}
+
+DLLEXPORT FPDF_BOOL STDCALL FPDFText_SetText(FPDF_PAGEOBJECT text_object,
+                                             FPDF_BYTESTRING text) {
+  if (!text_object)
+    return false;
+
+  auto pTextObj = reinterpret_cast<CPDF_TextObject*>(text_object);
+  pTextObj->SetText(CFX_ByteString(text));
+  return true;
+}
+
+DLLEXPORT FPDF_FONT STDCALL FPDFText_LoadType1Font(FPDF_DOCUMENT document,
+                                                   const uint8_t* data,
+                                                   uint32_t size) {
+  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+  if (!pDoc || !data || size == 0)
+    return nullptr;
+
+  auto pFont = pdfium::MakeUnique<CFX_Font>();
+
+  // TODO(npm): Maybe use FT_Get_X11_Font_Format to check format?
+  if (!pFont->LoadEmbedded(data, size))
+    return nullptr;
+
+  CPDF_Dictionary* fontDict = pDoc->NewIndirect<CPDF_Dictionary>();
+  fontDict->SetNewFor<CPDF_Name>("Type", "Font");
+  fontDict->SetNewFor<CPDF_Name>("Subtype", "Type1");
+  CFX_ByteString name = pFont->GetFaceName();
+  if (name.IsEmpty())
+    name = "Unnamed";
+  fontDict->SetNewFor<CPDF_Name>("BaseFont", name);
+
+  uint32_t glyphIndex;
+  int currentChar = FXFT_Get_First_Char(pFont->GetFace(), &glyphIndex);
+  fontDict->SetNewFor<CPDF_Number>("FirstChar", currentChar);
+  int nextChar;
+  CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
+  while (true) {
+    int width = pFont->GetGlyphWidth(glyphIndex);
+    widthsArray->AddNew<CPDF_Number>(width);
+    nextChar = FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
+    if (glyphIndex == 0)
+      break;
+    for (int i = currentChar + 1; i < nextChar; i++)
+      widthsArray->AddNew<CPDF_Number>(0);
+    currentChar = nextChar;
+  }
+  fontDict->SetNewFor<CPDF_Number>("LastChar", currentChar);
+  fontDict->SetNewFor<CPDF_Reference>("Widths", pDoc, widthsArray->GetObjNum());
+  CPDF_Dictionary* fontDesc = pDoc->NewIndirect<CPDF_Dictionary>();
+  fontDesc->SetNewFor<CPDF_Name>("Type", "FontDescriptor");
+  fontDesc->SetNewFor<CPDF_Name>("FontName", name);
+  int flags = 0;
+  if (FXFT_Is_Face_fixedwidth(pFont->GetFace()))
+    flags |= FXFONT_FIXED_PITCH;
+  if (name.Find("Serif") > -1)
+    flags |= FXFONT_SERIF;
+  if (FXFT_Is_Face_Italic(pFont->GetFace()))
+    flags |= FXFONT_ITALIC;
+  if (FXFT_Is_Face_Bold(pFont->GetFace()))
+    flags |= FXFONT_BOLD;
+
+  // TODO(npm): How do I know if a Type1 font is symbolic, script, allcap,
+  // smallcap
+  flags |= FXFONT_NONSYMBOLIC;
+
+  fontDesc->SetNewFor<CPDF_Number>("Flags", flags);
+  FX_RECT bbox;
+  pFont->GetBBox(bbox);
+  auto pBBox = pdfium::MakeUnique<CPDF_Array>();
+  pBBox->AddNew<CPDF_Number>(bbox.left);
+  pBBox->AddNew<CPDF_Number>(bbox.bottom);
+  pBBox->AddNew<CPDF_Number>(bbox.right);
+  pBBox->AddNew<CPDF_Number>(bbox.top);
+  fontDesc->SetFor("FontBBox", std::move(pBBox));
+
+  // TODO(npm): calculate italic angle correctly
+  fontDesc->SetNewFor<CPDF_Number>("ItalicAngle", pFont->IsItalic() ? -12 : 0);
+
+  fontDesc->SetNewFor<CPDF_Number>("Ascent", pFont->GetAscent());
+  fontDesc->SetNewFor<CPDF_Number>("Descent", pFont->GetDescent());
+
+  // TODO(npm): calculate the capheight, stemV correctly
+  fontDesc->SetNewFor<CPDF_Number>("CapHeight", pFont->GetAscent());
+  fontDesc->SetNewFor<CPDF_Number>("StemV", pFont->IsBold() ? 120 : 70);
+
+  CPDF_Stream* pStream = pDoc->NewIndirect<CPDF_Stream>();
+  pStream->SetData(data, size);
+  fontDesc->SetNewFor<CPDF_Reference>("FontFile", pDoc, pStream->GetObjNum());
+  fontDict->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
+                                      fontDesc->GetObjNum());
+  return pDoc->LoadFont(fontDict);
+}
diff --git a/fpdfsdk/fpdfformfill.cpp b/fpdfsdk/fpdfformfill.cpp
index 6b8cbaa..57ff6b6 100644
--- a/fpdfsdk/fpdfformfill.cpp
+++ b/fpdfsdk/fpdfformfill.cpp
@@ -98,9 +98,8 @@
     return;
 #endif  // PDF_ENABLE_XFA
 
-  CFX_Matrix matrix;
-  pPage->GetDisplayMatrix(matrix, start_x, start_y, size_x, size_y, rotate);
-
+  CFX_Matrix matrix =
+      pPage->GetDisplayMatrix(start_x, start_y, size_x, size_y, rotate);
   FX_RECT clip(start_x, start_y, start_x + size_x, start_y + size_y);
 
   std::unique_ptr<CFX_FxgeDevice> pDevice(new CFX_FxgeDevice);
@@ -127,12 +126,13 @@
   options.m_bDrawAnnots = flags & FPDF_ANNOT;
 
 #ifdef PDF_ENABLE_XFA
-  options.m_pOCContext = new CPDF_OCContext(pPDFDoc, CPDF_OCContext::View);
+  options.m_pOCContext =
+      pdfium::MakeRetain<CPDF_OCContext>(pPDFDoc, CPDF_OCContext::View);
   if (CPDFSDK_PageView* pPageView = pFormFillEnv->GetPageView(pPage, true))
     pPageView->PageView_OnDraw(pDevice.get(), &matrix, &options, clip);
 #else   // PDF_ENABLE_XFA
-  options.m_pOCContext =
-      new CPDF_OCContext(pPage->m_pDocument, CPDF_OCContext::View);
+  options.m_pOCContext = pdfium::MakeRetain<CPDF_OCContext>(
+      pPage->m_pDocument, CPDF_OCContext::View);
   if (CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, pPage))
     pPageView->PageView_OnDraw(pDevice.get(), &matrix, &options);
 #endif  // PDF_ENABLE_XFA
@@ -142,8 +142,6 @@
   pDevice->Flush();
   CFXBitmapFromFPDFBitmap(bitmap)->UnPreMultiply();
 #endif
-  delete options.m_pOCContext;
-  options.m_pOCContext = nullptr;
 }
 
 }  // namespace
@@ -157,9 +155,10 @@
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (pPage) {
     CPDF_InterForm interform(pPage->m_pDocument);
-    CPDF_FormControl* pFormCtrl =
-        interform.GetControlAtPoint(pPage, static_cast<FX_FLOAT>(page_x),
-                                    static_cast<FX_FLOAT>(page_y), nullptr);
+    CPDF_FormControl* pFormCtrl = interform.GetControlAtPoint(
+        pPage, CFX_PointF(static_cast<FX_FLOAT>(page_x),
+                          static_cast<FX_FLOAT>(page_y)),
+        nullptr);
     if (!pFormCtrl)
       return -1;
     CPDF_FormField* pFormField = pFormCtrl->GetField();
@@ -191,8 +190,7 @@
 
   CXFA_FFWidget* pXFAAnnot = pWidgetIterator->MoveToNext();
   while (pXFAAnnot) {
-    CFX_RectF rcBBox;
-    pXFAAnnot->GetBBox(rcBBox, 0);
+    CFX_RectF rcBBox = pXFAAnnot->GetBBox(0);
     CFX_FloatRect rcWidget(rcBBox.left, rcBBox.top, rcBBox.left + rcBBox.width,
                            rcBBox.top + rcBBox.height);
     rcWidget.left -= 1.0f;
@@ -200,8 +198,8 @@
     rcWidget.bottom -= 1.0f;
     rcWidget.top += 1.0f;
 
-    if (rcWidget.Contains(static_cast<FX_FLOAT>(page_x),
-                          static_cast<FX_FLOAT>(page_y))) {
+    if (rcWidget.Contains(CFX_PointF(static_cast<FX_FLOAT>(page_x),
+                                     static_cast<FX_FLOAT>(page_y)))) {
       return FPDF_FORMFIELD_XFA;
     }
     pXFAAnnot = pWidgetIterator->MoveToNext();
@@ -228,8 +226,10 @@
     return -1;
   CPDF_InterForm interform(pPage->m_pDocument);
   int z_order = -1;
-  (void)interform.GetControlAtPoint(pPage, (FX_FLOAT)page_x, (FX_FLOAT)page_y,
-                                    &z_order);
+  (void)interform.GetControlAtPoint(
+      pPage,
+      CFX_PointF(static_cast<FX_FLOAT>(page_x), static_cast<FX_FLOAT>(page_y)),
+      &z_order);
   return z_order;
 }
 
@@ -295,9 +295,7 @@
   CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
   if (!pPageView)
     return false;
-
-  CFX_FloatPoint pt((FX_FLOAT)page_x, (FX_FLOAT)page_y);
-  return pPageView->OnMouseMove(pt, modifier);
+  return pPageView->OnMouseMove(CFX_PointF(page_x, page_y), modifier);
 }
 
 DLLEXPORT FPDF_BOOL STDCALL FORM_OnLButtonDown(FPDF_FORMHANDLE hHandle,
@@ -308,9 +306,7 @@
   CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
   if (!pPageView)
     return false;
-
-  CFX_FloatPoint pt((FX_FLOAT)page_x, (FX_FLOAT)page_y);
-  return pPageView->OnLButtonDown(pt, modifier);
+  return pPageView->OnLButtonDown(CFX_PointF(page_x, page_y), modifier);
 }
 
 DLLEXPORT FPDF_BOOL STDCALL FORM_OnLButtonUp(FPDF_FORMHANDLE hHandle,
@@ -322,7 +318,7 @@
   if (!pPageView)
     return false;
 
-  CFX_FloatPoint pt((FX_FLOAT)page_x, (FX_FLOAT)page_y);
+  CFX_PointF pt((FX_FLOAT)page_x, (FX_FLOAT)page_y);
   return pPageView->OnLButtonUp(pt, modifier);
 }
 
@@ -335,9 +331,7 @@
   CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
   if (!pPageView)
     return false;
-
-  CFX_FloatPoint pt((FX_FLOAT)page_x, (FX_FLOAT)page_y);
-  return pPageView->OnRButtonDown(pt, modifier);
+  return pPageView->OnRButtonDown(CFX_PointF(page_x, page_y), modifier);
 }
 
 DLLEXPORT FPDF_BOOL STDCALL FORM_OnRButtonUp(FPDF_FORMHANDLE hHandle,
@@ -349,7 +343,7 @@
   if (!pPageView)
     return false;
 
-  CFX_FloatPoint pt((FX_FLOAT)page_x, (FX_FLOAT)page_y);
+  CFX_PointF pt((FX_FLOAT)page_x, (FX_FLOAT)page_y);
   return pPageView->OnRButtonUp(pt, modifier);
 }
 #endif  // PDF_ENABLE_XFA
diff --git a/fpdfsdk/fpdftext.cpp b/fpdfsdk/fpdftext.cpp
index 629e596..0432afd 100644
--- a/fpdfsdk/fpdftext.cpp
+++ b/fpdfsdk/fpdftext.cpp
@@ -133,8 +133,10 @@
     return -3;
 
   CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
-  return textpage->GetIndexAtPos((FX_FLOAT)x, (FX_FLOAT)y, (FX_FLOAT)xTolerance,
-                                 (FX_FLOAT)yTolerance);
+  return textpage->GetIndexAtPos(
+      CFX_PointF(static_cast<FX_FLOAT>(x), static_cast<FX_FLOAT>(y)),
+      CFX_SizeF(static_cast<FX_FLOAT>(xTolerance),
+                static_cast<FX_FLOAT>(yTolerance)));
 }
 
 DLLEXPORT int STDCALL FPDFText_GetText(FPDF_TEXTPAGE text_page,
diff --git a/fpdfsdk/fpdfview.cpp b/fpdfsdk/fpdfview.cpp
index ff4d46e..1e7a651 100644
--- a/fpdfsdk/fpdfview.cpp
+++ b/fpdfsdk/fpdfview.cpp
@@ -44,6 +44,22 @@
 #include "xfa/fxbarcode/BC_Library.h"
 #endif  // PDF_ENABLE_XFA
 
+#ifdef PDF_ENABLE_XFA_BMP
+#include "core/fxcodec/codec/ccodec_bmpmodule.h"
+#endif
+
+#ifdef PDF_ENABLE_XFA_GIF
+#include "core/fxcodec/codec/ccodec_gifmodule.h"
+#endif
+
+#ifdef PDF_ENABLE_XFA_PNG
+#include "core/fxcodec/codec/ccodec_pngmodule.h"
+#endif
+
+#ifdef PDF_ENABLE_XFA_TIFF
+#include "core/fxcodec/codec/ccodec_tiffmodule.h"
+#endif
+
 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
 #include "core/fxge/cfx_windowsdevice.h"
 #endif
@@ -94,7 +110,7 @@
       (flags & FPDF_PRINTING) ? CPDF_OCContext::Print : CPDF_OCContext::View;
   pContext->m_pOptions->m_AddFlags = flags >> 8;
   pContext->m_pOptions->m_pOCContext =
-      new CPDF_OCContext(pPage->m_pDocument, usage);
+      pdfium::MakeRetain<CPDF_OCContext>(pPage->m_pDocument, usage);
 
   pContext->m_pDevice->SaveState();
   pContext->m_pDevice->SetClip_Rect(clipping_rect);
@@ -364,6 +380,26 @@
   pModuleMgr->LoadEmbeddedCNS1CMaps();
   pModuleMgr->LoadEmbeddedKorea1CMaps();
 
+#ifdef PDF_ENABLE_XFA_BMP
+  pModuleMgr->GetCodecModule()->SetBmpModule(
+      pdfium::MakeUnique<CCodec_BmpModule>());
+#endif
+
+#ifdef PDF_ENABLE_XFA_GIF
+  pModuleMgr->GetCodecModule()->SetGifModule(
+      pdfium::MakeUnique<CCodec_GifModule>());
+#endif
+
+#ifdef PDF_ENABLE_XFA_PNG
+  pModuleMgr->GetCodecModule()->SetPngModule(
+      pdfium::MakeUnique<CCodec_PngModule>());
+#endif
+
+#ifdef PDF_ENABLE_XFA_TIFF
+  pModuleMgr->GetCodecModule()->SetTiffModule(
+      pdfium::MakeUnique<CCodec_TiffModule>());
+#endif
+
 #ifdef PDF_ENABLE_XFA
   FXJSE_Initialize();
   BC_Library_Init();
@@ -756,14 +792,8 @@
 
   CFX_Matrix transform_matrix = pPage->GetPageMatrix();
   if (matrix) {
-    CFX_Matrix cmatrix;
-    cmatrix.a = matrix->a;
-    cmatrix.b = matrix->b;
-    cmatrix.c = matrix->c;
-    cmatrix.d = matrix->d;
-    cmatrix.e = matrix->e;
-    cmatrix.f = matrix->f;
-    transform_matrix.Concat(cmatrix);
+    transform_matrix.Concat(CFX_Matrix(matrix->a, matrix->b, matrix->c,
+                                       matrix->d, matrix->e, matrix->f));
   }
 
   CFX_FloatRect clipping_rect;
@@ -856,16 +886,16 @@
   pPage->DeviceToPage(start_x, start_y, size_x, size_y, rotate, device_x,
                       device_y, page_x, page_y);
 #else   // PDF_ENABLE_XFA
-  CFX_Matrix page2device;
-  pPage->GetDisplayMatrix(page2device, start_x, start_y, size_x, size_y,
-                          rotate);
+  CFX_Matrix page2device =
+      pPage->GetDisplayMatrix(start_x, start_y, size_x, size_y, rotate);
   CFX_Matrix device2page;
   device2page.SetReverse(page2device);
-  FX_FLOAT page_x_f, page_y_f;
-  device2page.Transform((FX_FLOAT)(device_x), (FX_FLOAT)(device_y), page_x_f,
-                        page_y_f);
-  *page_x = (page_x_f);
-  *page_y = (page_y_f);
+
+  CFX_PointF pos = device2page.Transform(CFX_PointF(
+      static_cast<FX_FLOAT>(device_x), static_cast<FX_FLOAT>(device_y)));
+
+  *page_x = pos.x;
+  *page_y = pos.y;
 #endif  // PDF_ENABLE_XFA
 }
 
@@ -888,14 +918,13 @@
   pPage->PageToDevice(start_x, start_y, size_x, size_y, rotate, page_x, page_y,
                       device_x, device_y);
 #else   // PDF_ENABLE_XFA
-  CFX_Matrix page2device;
-  pPage->GetDisplayMatrix(page2device, start_x, start_y, size_x, size_y,
-                          rotate);
-  FX_FLOAT device_x_f, device_y_f;
-  page2device.Transform(((FX_FLOAT)page_x), ((FX_FLOAT)page_y), device_x_f,
-                        device_y_f);
-  *device_x = FXSYS_round(device_x_f);
-  *device_y = FXSYS_round(device_y_f);
+  CFX_Matrix page2device =
+      pPage->GetDisplayMatrix(start_x, start_y, size_x, size_y, rotate);
+  CFX_PointF pos = page2device.Transform(
+      CFX_PointF(static_cast<FX_FLOAT>(page_x), static_cast<FX_FLOAT>(page_y)));
+
+  *device_x = FXSYS_round(pos.x);
+  *device_y = FXSYS_round(pos.y);
 #endif  // PDF_ENABLE_XFA
 }
 
@@ -988,10 +1017,10 @@
   if (!pPage)
     return;
 
-  CFX_Matrix matrix;
-  pPage->GetDisplayMatrix(matrix, start_x, start_y, size_x, size_y, rotate);
-  FX_RECT rect(start_x, start_y, start_x + size_x, start_y + size_y);
-  RenderPageImpl(pContext, pPage, matrix, rect, flags, bNeedToRestore, pause);
+  RenderPageImpl(pContext, pPage, pPage->GetDisplayMatrix(
+                                      start_x, start_y, size_x, size_y, rotate),
+                 FX_RECT(start_x, start_y, start_x + size_x, start_y + size_y),
+                 flags, bNeedToRestore, pause);
 }
 
 DLLEXPORT int STDCALL FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,
diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c
index 98478f0..54a3325 100644
--- a/fpdfsdk/fpdfview_c_api_test.c
+++ b/fpdfsdk/fpdfview_c_api_test.c
@@ -83,8 +83,22 @@
     CHK(FPDFPage_TransformAnnots);
     CHK(FPDFPageObj_NewImgeObj);
     CHK(FPDFImageObj_LoadJpegFile);
+    CHK(FPDFImageObj_LoadJpegFileInline);
     CHK(FPDFImageObj_SetMatrix);
     CHK(FPDFImageObj_SetBitmap);
+    CHK(FPDFPageObj_CreateNewPath);
+    CHK(FPDFPageObj_CreateNewRect);
+    CHK(FPDFPath_SetStrokeColor);
+    CHK(FPDFPath_SetStrokeWidth);
+    CHK(FPDFPath_SetFillColor);
+    CHK(FPDFPath_MoveTo);
+    CHK(FPDFPath_LineTo);
+    CHK(FPDFPath_BezierTo);
+    CHK(FPDFPath_Close);
+    CHK(FPDFPath_SetDrawMode);
+    CHK(FPDFPageObj_NewTextObj);
+    CHK(FPDFText_SetText);
+    CHK(FPDFText_LoadType1Font);
 
     // fpdf_ext.h
     CHK(FSDK_SetUnSpObjProcessHandler);
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_context.cpp b/fpdfsdk/fpdfxfa/cpdfxfa_context.cpp
index 113a74e..88c88a1 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_context.cpp
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_context.cpp
@@ -19,6 +19,7 @@
 #include "fpdfsdk/javascript/ijs_runtime.h"
 #include "public/fpdf_formfill.h"
 #include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
 #include "xfa/fxfa/cxfa_eventparam.h"
 #include "xfa/fxfa/xfa_ffapp.h"
 #include "xfa/fxfa/xfa_ffdoc.h"
@@ -82,11 +83,10 @@
 
 bool CPDFXFA_Context::LoadXFADoc() {
   m_nLoadStatus = FXFA_LOADSTATUS_LOADING;
-
   if (!m_pPDFDoc)
     return false;
 
-  m_XFAPageList.RemoveAll();
+  m_XFAPageList.clear();
 
   CXFA_FFApp* pApp = GetXFAApp();
   if (!pApp)
@@ -155,24 +155,27 @@
     return nullptr;
 
   CPDFXFA_Page* pPage = nullptr;
-  int nCount = m_XFAPageList.GetSize();
+  int nCount = pdfium::CollectionSize<int>(m_XFAPageList);
   if (nCount > 0 && page_index < nCount) {
-    pPage = m_XFAPageList.GetAt(page_index);
-    if (pPage)
+    pPage = m_XFAPageList[page_index];
+    if (pPage) {
       pPage->Retain();
+      return pPage;
+    }
   } else {
     m_nPageCount = GetPageCount();
-    m_XFAPageList.SetSize(m_nPageCount);
+    m_XFAPageList.resize(m_nPageCount);
   }
-  if (pPage)
-    return pPage;
 
   pPage = new CPDFXFA_Page(this, page_index);
   if (!pPage->LoadPage()) {
     pPage->Release();
     return nullptr;
   }
-  m_XFAPageList.SetAt(page_index, pPage);
+  if (page_index >= 0 &&
+      page_index < pdfium::CollectionSize<int>(m_XFAPageList)) {
+    m_XFAPageList[page_index] = pPage;
+  }
   return pPage;
 }
 
@@ -186,15 +189,10 @@
   if (m_iDocType != DOCTYPE_DYNAMIC_XFA)
     return nullptr;
 
-  int nSize = m_XFAPageList.GetSize();
-  for (int i = 0; i < nSize; i++) {
-    CPDFXFA_Page* pTempPage = m_XFAPageList.GetAt(i);
-    if (!pTempPage)
-      continue;
-    if (pTempPage->GetXFAPageView() && pTempPage->GetXFAPageView() == pPage)
+  for (CPDFXFA_Page* pTempPage : m_XFAPageList) {
+    if (pTempPage && pTempPage->GetXFAPageView() == pPage)
       return pTempPage;
   }
-
   return nullptr;
 }
 
@@ -205,15 +203,20 @@
   if (m_pPDFDoc)
     m_pPDFDoc->DeletePage(page_index);
 
-  if (page_index < 0 || page_index >= m_XFAPageList.GetSize())
+  if (page_index < 0 ||
+      page_index >= pdfium::CollectionSize<int>(m_XFAPageList)) {
     return;
-
-  if (CPDFXFA_Page* pPage = m_XFAPageList.GetAt(page_index))
+  }
+  if (CPDFXFA_Page* pPage = m_XFAPageList[page_index])
     pPage->Release();
 }
 
 void CPDFXFA_Context::RemovePage(CPDFXFA_Page* page) {
-  m_XFAPageList.SetAt(page->GetPageIndex(), nullptr);
+  int page_index = page->GetPageIndex();
+  if (page_index >= 0 &&
+      page_index < pdfium::CollectionSize<int>(m_XFAPageList)) {
+    m_XFAPageList[page_index] = nullptr;
+  }
 }
 
 void CPDFXFA_Context::ClearChangeMark() {
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_context.h b/fpdfsdk/fpdfxfa/cpdfxfa_context.h
index de3f39c..9a2a517 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_context.h
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_context.h
@@ -8,6 +8,7 @@
 #define FPDFSDK_FPDFXFA_CPDFXFA_CONTEXT_H_
 
 #include <memory>
+#include <vector>
 
 #include "fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.h"
 #include "xfa/fxfa/xfa_ffdoc.h"
@@ -16,8 +17,8 @@
 class CPDFSDK_FormFillEnvironment;
 class CPDFXFA_Page;
 class CXFA_FFDocHandler;
+class IJS_EventContext;
 class IJS_Runtime;
-class IJS_Context;
 
 enum LoadStatus {
   FXFA_LOADSTATUS_PRELOAD = 0,
@@ -88,12 +89,11 @@
   int GetOriginalPageCount() const { return m_nPageCount; }
   void SetOriginalPageCount(int count) {
     m_nPageCount = count;
-    m_XFAPageList.SetSize(count);
+    m_XFAPageList.resize(count);
   }
 
   LoadStatus GetLoadStatus() const { return m_nLoadStatus; }
-
-  CFX_ArrayTemplate<CPDFXFA_Page*>* GetXFAPageList() { return &m_XFAPageList; }
+  std::vector<CPDFXFA_Page*>* GetXFAPageList() { return &m_XFAPageList; }
 
  private:
   void CloseXFADoc();
@@ -106,7 +106,7 @@
   CXFA_FFDocView* m_pXFADocView;                // not owned.
   std::unique_ptr<CXFA_FFApp> m_pXFAApp;
   std::unique_ptr<CJS_Runtime> m_pRuntime;
-  CFX_ArrayTemplate<CPDFXFA_Page*> m_XFAPageList;
+  std::vector<CPDFXFA_Page*> m_XFAPageList;
   LoadStatus m_nLoadStatus;
   int m_nPageCount;
 
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp b/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp
index 2b3368b..731b0cc 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp
@@ -38,13 +38,15 @@
 #define FXFA_XFA_ALL 0x01111111
 
 CPDFXFA_DocEnvironment::CPDFXFA_DocEnvironment(CPDFXFA_Context* pContext)
-    : m_pContext(pContext), m_pJSContext(nullptr) {
+    : m_pContext(pContext), m_pJSEventContext(nullptr) {
   ASSERT(m_pContext);
 }
 
 CPDFXFA_DocEnvironment::~CPDFXFA_DocEnvironment() {
-  if (m_pJSContext && m_pContext->GetFormFillEnv())
-    m_pContext->GetFormFillEnv()->GetJSRuntime()->ReleaseContext(m_pJSContext);
+  if (m_pJSEventContext && m_pContext->GetFormFillEnv()) {
+    m_pContext->GetFormFillEnv()->GetJSRuntime()->ReleaseEventContext(
+        m_pJSEventContext);
+  }
 }
 
 void CPDFXFA_DocEnvironment::SetChangeMark(CXFA_FFDoc* hDoc) {
@@ -69,9 +71,8 @@
   if (!pFormFillEnv)
     return;
 
-  CFX_FloatRect rcPage = CFX_FloatRect::FromCFXRectF(rt);
-  pFormFillEnv->Invalidate((FPDF_PAGE)pPage, rcPage.left, rcPage.bottom,
-                           rcPage.right, rcPage.top);
+  pFormFillEnv->Invalidate(static_cast<FPDF_PAGE>(pPage),
+                           CFX_FloatRect::FromCFXRectF(rt).ToFxRect());
 }
 
 void CPDFXFA_DocEnvironment::DisplayCaret(CXFA_FFWidget* hWidget,
@@ -277,7 +278,7 @@
 
   for (int iPageIter = 0; iPageIter < m_pContext->GetOriginalPageCount();
        iPageIter++) {
-    CPDFXFA_Page* pPage = m_pContext->GetXFAPageList()->GetAt(iPageIter);
+    CPDFXFA_Page* pPage = (*m_pContext->GetXFAPageList())[iPageIter];
     if (!pPage)
       continue;
 
@@ -1023,8 +1024,8 @@
   }
 
   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
-  if (!m_pJSContext)
-    m_pJSContext = pFormFillEnv->GetJSRuntime()->NewContext();
+  if (!m_pJSEventContext)
+    m_pJSEventContext = pFormFillEnv->GetJSRuntime()->NewEventContext();
 
   return pFormFillEnv->GetJSRuntime()->GetValueByName(szPropName, pValue);
 }
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.h b/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.h
index d7cb169..dc18d9a 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.h
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.h
@@ -12,7 +12,7 @@
 #include "xfa/fxfa/fxfa.h"
 
 class CPDFXFA_Context;
-class IJS_Context;
+class IJS_EventContext;
 
 class CPDFXFA_DocEnvironment : public IXFA_DocEnvironment {
  public:
@@ -107,8 +107,8 @@
                         FPDF_DWORD flag);
   void ToXFAContentFlags(CFX_WideString csSrcContent, FPDF_DWORD& flag);
 
-  CPDFXFA_Context* const m_pContext;  // Not owned;
-  IJS_Context* m_pJSContext;
+  CPDFXFA_Context* const m_pContext;    // Not owned.
+  IJS_EventContext* m_pJSEventContext;  // Not owned.
 };
 
 #endif  // FPDFSDK_FPDFXFA_CPDFXFA_DOCENVIRONMENT_H_
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_page.cpp b/fpdfsdk/fpdfxfa/cpdfxfa_page.cpp
index 8cc3250..8b5bb3d 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_page.cpp
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_page.cpp
@@ -101,17 +101,16 @@
   int nDocType = m_pContext->GetDocType();
   switch (nDocType) {
     case DOCTYPE_DYNAMIC_XFA: {
-      if (m_pXFAPageView) {
-        CFX_RectF rect;
-        m_pXFAPageView->GetPageViewRect(rect);
-        return rect.width;
-      }
-    } break;
+      if (m_pXFAPageView)
+        return m_pXFAPageView->GetPageViewRect().width;
+      break;
+    }
     case DOCTYPE_STATIC_XFA:
     case DOCTYPE_PDF: {
       if (m_pPDFPage)
         return m_pPDFPage->GetPageWidth();
-    } break;
+      break;
+    }
     default:
       return 0.0f;
   }
@@ -129,14 +128,13 @@
     case DOCTYPE_STATIC_XFA: {
       if (m_pPDFPage)
         return m_pPDFPage->GetPageHeight();
-    } break;
+      break;
+    }
     case DOCTYPE_DYNAMIC_XFA: {
-      if (m_pXFAPageView) {
-        CFX_RectF rect;
-        m_pXFAPageView->GetPageViewRect(rect);
-        return rect.height;
-      }
-    } break;
+      if (m_pXFAPageView)
+        return m_pXFAPageView->GetPageViewRect().height;
+      break;
+    }
     default:
       return 0.0f;
   }
@@ -156,18 +154,15 @@
   if (!m_pPDFPage && !m_pXFAPageView)
     return;
 
-  CFX_Matrix page2device;
   CFX_Matrix device2page;
-  FX_FLOAT page_x_f, page_y_f;
+  device2page.SetReverse(
+      GetDisplayMatrix(start_x, start_y, size_x, size_y, rotate));
 
-  GetDisplayMatrix(page2device, start_x, start_y, size_x, size_y, rotate);
+  CFX_PointF pos = device2page.Transform(CFX_PointF(
+      static_cast<FX_FLOAT>(device_x), static_cast<FX_FLOAT>(device_y)));
 
-  device2page.SetReverse(page2device);
-  device2page.Transform((FX_FLOAT)(device_x), (FX_FLOAT)(device_y), page_x_f,
-                        page_y_f);
-
-  *page_x = (page_x_f);
-  *page_y = (page_y_f);
+  *page_x = pos.x;
+  *page_y = pos.y;
 }
 
 void CPDFXFA_Page::PageToDevice(int start_x,
@@ -182,43 +177,41 @@
   if (!m_pPDFPage && !m_pXFAPageView)
     return;
 
-  CFX_Matrix page2device;
-  FX_FLOAT device_x_f, device_y_f;
+  CFX_Matrix page2device =
+      GetDisplayMatrix(start_x, start_y, size_x, size_y, rotate);
 
-  GetDisplayMatrix(page2device, start_x, start_y, size_x, size_y, rotate);
+  CFX_PointF pos = page2device.Transform(
+      CFX_PointF(static_cast<FX_FLOAT>(page_x), static_cast<FX_FLOAT>(page_y)));
 
-  page2device.Transform(((FX_FLOAT)page_x), ((FX_FLOAT)page_y), device_x_f,
-                        device_y_f);
-
-  *device_x = FXSYS_round(device_x_f);
-  *device_y = FXSYS_round(device_y_f);
+  *device_x = FXSYS_round(pos.x);
+  *device_y = FXSYS_round(pos.y);
 }
 
-void CPDFXFA_Page::GetDisplayMatrix(CFX_Matrix& matrix,
-                                    int xPos,
-                                    int yPos,
-                                    int xSize,
-                                    int ySize,
-                                    int iRotate) const {
+CFX_Matrix CPDFXFA_Page::GetDisplayMatrix(int xPos,
+                                          int yPos,
+                                          int xSize,
+                                          int ySize,
+                                          int iRotate) const {
   if (!m_pPDFPage && !m_pXFAPageView)
-    return;
+    return CFX_Matrix();
 
   int nDocType = m_pContext->GetDocType();
   switch (nDocType) {
     case DOCTYPE_DYNAMIC_XFA: {
       if (m_pXFAPageView) {
-        CFX_Rect rect;
-        rect.Set(xPos, yPos, xSize, ySize);
-        m_pXFAPageView->GetDisplayMatrix(matrix, rect, iRotate);
+        return m_pXFAPageView->GetDisplayMatrix(
+            CFX_Rect(xPos, yPos, xSize, ySize), iRotate);
       }
-    } break;
+      break;
+    }
     case DOCTYPE_PDF:
     case DOCTYPE_STATIC_XFA: {
-      if (m_pPDFPage) {
-        m_pPDFPage->GetDisplayMatrix(matrix, xPos, yPos, xSize, ySize, iRotate);
-      }
-    } break;
+      if (m_pPDFPage)
+        return m_pPDFPage->GetDisplayMatrix(xPos, yPos, xSize, ySize, iRotate);
+      break;
+    }
     default:
-      return;
+      return CFX_Matrix();
   }
+  return CFX_Matrix();
 }
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_page.h b/fpdfsdk/fpdfxfa/cpdfxfa_page.h
index 79158f4..993885d 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_page.h
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_page.h
@@ -60,12 +60,11 @@
                     int* device_x,
                     int* device_y);
 
-  void GetDisplayMatrix(CFX_Matrix& matrix,
-                        int xPos,
-                        int yPos,
-                        int xSize,
-                        int ySize,
-                        int iRotate) const;
+  CFX_Matrix GetDisplayMatrix(int xPos,
+                              int yPos,
+                              int xSize,
+                              int ySize,
+                              int iRotate) const;
 
  protected:
   // Refcounted class.
diff --git a/fpdfsdk/fsdk_actionhandler.cpp b/fpdfsdk/fsdk_actionhandler.cpp
index 61d2a52..dc99f32 100644
--- a/fpdfsdk/fsdk_actionhandler.cpp
+++ b/fpdfsdk/fsdk_actionhandler.cpp
@@ -14,7 +14,7 @@
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 #include "fpdfsdk/cpdfsdk_interform.h"
 #include "fpdfsdk/fsdk_define.h"
-#include "fpdfsdk/javascript/ijs_context.h"
+#include "fpdfsdk/javascript/ijs_event_context.h"
 #include "fpdfsdk/javascript/ijs_runtime.h"
 #include "third_party/base/stl_util.h"
 
@@ -157,16 +157,15 @@
       CFX_WideString swJS = action.GetJavaScript();
       if (!swJS.IsEmpty()) {
         IJS_Runtime* pRuntime = pFormFillEnv->GetJSRuntime();
-        IJS_Context* pContext = pRuntime->NewContext();
+        IJS_EventContext* pContext = pRuntime->NewEventContext();
         pContext->OnLink_MouseUp(pFormFillEnv);
 
         CFX_WideString csInfo;
         bool bRet = pContext->RunScript(swJS, &csInfo);
+        pRuntime->ReleaseEventContext(pContext);
         if (!bRet) {
           // FIXME: return error.
         }
-
-        pRuntime->ReleaseContext(pContext);
       }
     }
   } else {
@@ -282,14 +281,13 @@
       CFX_WideString swJS = action.GetJavaScript();
       if (!swJS.IsEmpty()) {
         IJS_Runtime* pRuntime = pFormFillEnv->GetJSRuntime();
-        IJS_Context* pContext = pRuntime->NewContext();
+        IJS_EventContext* pContext = pRuntime->NewEventContext();
         CFX_WideString csInfo;
         bool bRet = pContext->RunScript(swJS, &csInfo);
+        pRuntime->ReleaseEventContext(pContext);
         if (!bRet) {
           // FIXME: return error.
         }
-
-        pRuntime->ReleaseContext(pContext);
       }
     }
   } else {
@@ -322,16 +320,15 @@
       CFX_WideString swJS = action.GetJavaScript();
       if (!swJS.IsEmpty()) {
         IJS_Runtime* pRuntime = pFormFillEnv->GetJSRuntime();
-        IJS_Context* pContext = pRuntime->NewContext();
+        IJS_EventContext* pContext = pRuntime->NewEventContext();
         pContext->OnBookmark_MouseUp(pBookmark);
 
         CFX_WideString csInfo;
         bool bRet = pContext->RunScript(swJS, &csInfo);
+        pRuntime->ReleaseEventContext(pContext);
         if (!bRet) {
           // FIXME: return error.
         }
-
-        pRuntime->ReleaseContext(pContext);
       }
     }
   } else {
@@ -478,7 +475,7 @@
   ASSERT(type != CPDF_AAction::Format);
 
   IJS_Runtime* pRuntime = pFormFillEnv->GetJSRuntime();
-  IJS_Context* pContext = pRuntime->NewContext();
+  IJS_EventContext* pContext = pRuntime->NewEventContext();
   switch (type) {
     case CPDF_AAction::CursorEnter:
       pContext->OnField_MouseEnter(data.bModifier, data.bShift, pFormField);
@@ -518,11 +515,10 @@
 
   CFX_WideString csInfo;
   bool bRet = pContext->RunScript(script, &csInfo);
+  pRuntime->ReleaseEventContext(pContext);
   if (!bRet) {
     // FIXME: return error.
   }
-
-  pRuntime->ReleaseContext(pContext);
 }
 
 void CPDFSDK_ActionHandler::RunDocumentOpenJavaScript(
@@ -530,16 +526,15 @@
     const CFX_WideString& sScriptName,
     const CFX_WideString& script) {
   IJS_Runtime* pRuntime = pFormFillEnv->GetJSRuntime();
-  IJS_Context* pContext = pRuntime->NewContext();
+  IJS_EventContext* pContext = pRuntime->NewEventContext();
   pContext->OnDoc_Open(pFormFillEnv, sScriptName);
 
   CFX_WideString csInfo;
   bool bRet = pContext->RunScript(script, &csInfo);
+  pRuntime->ReleaseEventContext(pContext);
   if (!bRet) {
     // FIXME: return error.
   }
-
-  pRuntime->ReleaseContext(pContext);
 }
 
 void CPDFSDK_ActionHandler::RunDocumentPageJavaScript(
@@ -547,7 +542,7 @@
     CPDF_AAction::AActionType type,
     const CFX_WideString& script) {
   IJS_Runtime* pRuntime = pFormFillEnv->GetJSRuntime();
-  IJS_Context* pContext = pRuntime->NewContext();
+  IJS_EventContext* pContext = pRuntime->NewEventContext();
   switch (type) {
     case CPDF_AAction::OpenPage:
       pContext->OnPage_Open(pFormFillEnv);
@@ -583,11 +578,10 @@
 
   CFX_WideString csInfo;
   bool bRet = pContext->RunScript(script, &csInfo);
+  pRuntime->ReleaseEventContext(pContext);
   if (!bRet) {
     // FIXME: return error.
   }
-
-  pRuntime->ReleaseContext(pContext);
 }
 
 bool CPDFSDK_ActionHandler::DoAction_Hide(
diff --git a/fpdfsdk/fxedit/fxet_edit.cpp b/fpdfsdk/fxedit/fxet_edit.cpp
index aa77e9f..1acc577 100644
--- a/fpdfsdk/fxedit/fxet_edit.cpp
+++ b/fpdfsdk/fxedit/fxet_edit.cpp
@@ -29,6 +29,7 @@
 #include "fpdfsdk/pdfwindow/PWL_Edit.h"
 #include "fpdfsdk/pdfwindow/PWL_EditCtrl.h"
 #include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
 
 namespace {
 
@@ -56,16 +57,14 @@
 }
 
 void DrawTextString(CFX_RenderDevice* pDevice,
-                    const CFX_FloatPoint& pt,
+                    const CFX_PointF& pt,
                     CPDF_Font* pFont,
                     FX_FLOAT fFontSize,
                     CFX_Matrix* pUser2Device,
                     const CFX_ByteString& str,
                     FX_ARGB crTextFill,
-                    FX_ARGB crTextStroke,
                     int32_t nHorzScale) {
-  FX_FLOAT x = pt.x, y = pt.y;
-  pUser2Device->Transform(x, y);
+  CFX_PointF pos = pUser2Device->Transform(pt);
 
   if (pFont) {
     if (nHorzScale != 100) {
@@ -76,86 +75,20 @@
       ro.m_Flags = RENDER_CLEARTYPE;
       ro.m_ColorMode = RENDER_COLOR_NORMAL;
 
-      if (crTextStroke != 0) {
-        CFX_FloatPoint pt1;
-        CFX_FloatPoint pt2;
-        pUser2Device->Transform(pt1.x, pt1.y);
-        pUser2Device->Transform(pt2.x, pt2.y);
-        CFX_GraphStateData gsd;
-        gsd.m_LineWidth =
-            (FX_FLOAT)FXSYS_fabs((pt2.x + pt2.y) - (pt1.x + pt1.y));
-
-        CPDF_TextRenderer::DrawTextString(pDevice, x, y, pFont, fFontSize, &mt,
-                                          str, crTextFill, crTextStroke, &gsd,
-                                          &ro);
-      } else {
-        CPDF_TextRenderer::DrawTextString(pDevice, x, y, pFont, fFontSize, &mt,
-                                          str, crTextFill, 0, nullptr, &ro);
-      }
+      CPDF_TextRenderer::DrawTextString(pDevice, pos.x, pos.y, pFont, fFontSize,
+                                        &mt, str, crTextFill, nullptr, &ro);
     } else {
       CPDF_RenderOptions ro;
       ro.m_Flags = RENDER_CLEARTYPE;
       ro.m_ColorMode = RENDER_COLOR_NORMAL;
 
-      if (crTextStroke != 0) {
-        CFX_FloatPoint pt1;
-        CFX_FloatPoint pt2;
-        pUser2Device->Transform(pt1.x, pt1.y);
-        pUser2Device->Transform(pt2.x, pt2.y);
-        CFX_GraphStateData gsd;
-        gsd.m_LineWidth =
-            (FX_FLOAT)FXSYS_fabs((pt2.x + pt2.y) - (pt1.x + pt1.y));
-
-        CPDF_TextRenderer::DrawTextString(pDevice, x, y, pFont, fFontSize,
-                                          pUser2Device, str, crTextFill,
-                                          crTextStroke, &gsd, &ro);
-      } else {
-        CPDF_TextRenderer::DrawTextString(pDevice, x, y, pFont, fFontSize,
-                                          pUser2Device, str, crTextFill, 0,
-                                          nullptr, &ro);
-      }
+      CPDF_TextRenderer::DrawTextString(pDevice, pos.x, pos.y, pFont, fFontSize,
+                                        pUser2Device, str, crTextFill, nullptr,
+                                        &ro);
     }
   }
 }
 
-CPDF_TextObject* AddTextObjToPageObjects(CPDF_PageObjectHolder* pObjectHolder,
-                                         FX_COLORREF crText,
-                                         CPDF_Font* pFont,
-                                         FX_FLOAT fFontSize,
-                                         FX_FLOAT fCharSpace,
-                                         int32_t nHorzScale,
-                                         const CFX_FloatPoint& point,
-                                         const CFX_ByteString& text) {
-  std::unique_ptr<CPDF_TextObject> pTxtObj(new CPDF_TextObject);
-  pTxtObj->m_TextState.SetFont(pFont);
-  pTxtObj->m_TextState.SetFontSize(fFontSize);
-  pTxtObj->m_TextState.SetCharSpace(fCharSpace);
-  pTxtObj->m_TextState.SetWordSpace(0);
-  pTxtObj->m_TextState.SetTextMode(TextRenderingMode::MODE_FILL);
-
-  FX_FLOAT* matrix = pTxtObj->m_TextState.GetMutableMatrix();
-  matrix[0] = nHorzScale / 100.0f;
-  matrix[1] = 0;
-  matrix[2] = 0;
-  matrix[3] = 1;
-
-  FX_FLOAT rgb[3];
-  rgb[0] = FXARGB_R(crText) / 255.0f;
-  rgb[1] = FXARGB_G(crText) / 255.0f;
-  rgb[2] = FXARGB_B(crText) / 255.0f;
-  pTxtObj->m_ColorState.SetFillColor(
-      CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb, 3);
-  pTxtObj->m_ColorState.SetStrokeColor(
-      CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb, 3);
-
-  pTxtObj->SetPosition(point.x, point.y);
-  pTxtObj->SetText(text);
-
-  CPDF_TextObject* pRet = pTxtObj.get();
-  pObjectHolder->GetPageObjectList()->push_back(std::move(pTxtObj));
-  return pRet;
-}
-
 }  // namespace
 
 CFX_Edit_Iterator::CFX_Edit_Iterator(CFX_Edit* pEdit,
@@ -274,8 +207,8 @@
 CFX_Edit_Refresh::~CFX_Edit_Refresh() {}
 
 void CFX_Edit_Refresh::BeginRefresh() {
-  m_RefreshRects.Empty();
-  m_OldLineRects = m_NewLineRects;
+  m_RefreshRects.Clear();
+  m_OldLineRects = std::move(m_NewLineRects);
 }
 
 void CFX_Edit_Refresh::Push(const CPVT_WordRange& linerange,
@@ -306,7 +239,7 @@
 }
 
 void CFX_Edit_Refresh::EndRefresh() {
-  m_RefreshRects.Empty();
+  m_RefreshRects.Clear();
 }
 
 CFX_Edit_Undo::CFX_Edit_Undo(int32_t nBufsize)
@@ -326,55 +259,43 @@
 
 void CFX_Edit_Undo::Undo() {
   m_bWorking = true;
-
   if (m_nCurUndoPos > 0) {
-    IFX_Edit_UndoItem* pItem = m_UndoItemStack.GetAt(m_nCurUndoPos - 1);
-    pItem->Undo();
-
+    m_UndoItemStack[m_nCurUndoPos - 1]->Undo();
     m_nCurUndoPos--;
     m_bModified = (m_nCurUndoPos != 0);
   }
-
   m_bWorking = false;
 }
 
 bool CFX_Edit_Undo::CanRedo() const {
-  return m_nCurUndoPos < m_UndoItemStack.GetSize();
+  return m_nCurUndoPos < m_UndoItemStack.size();
 }
 
 void CFX_Edit_Undo::Redo() {
   m_bWorking = true;
-
-  int32_t nStackSize = m_UndoItemStack.GetSize();
-
-  if (m_nCurUndoPos < nStackSize) {
-    IFX_Edit_UndoItem* pItem = m_UndoItemStack.GetAt(m_nCurUndoPos);
-    pItem->Redo();
-
+  if (m_nCurUndoPos < m_UndoItemStack.size()) {
+    m_UndoItemStack[m_nCurUndoPos]->Redo();
     m_nCurUndoPos++;
-    m_bModified = (m_nCurUndoPos != 0);
+    m_bModified = true;
   }
-
   m_bWorking = false;
 }
 
-void CFX_Edit_Undo::AddItem(IFX_Edit_UndoItem* pItem) {
+void CFX_Edit_Undo::AddItem(std::unique_ptr<IFX_Edit_UndoItem> pItem) {
   ASSERT(!m_bWorking);
   ASSERT(pItem);
   ASSERT(m_nBufSize > 1);
-
-  if (m_nCurUndoPos < m_UndoItemStack.GetSize())
+  if (m_nCurUndoPos < m_UndoItemStack.size())
     RemoveTails();
 
-  if (m_UndoItemStack.GetSize() >= m_nBufSize) {
+  if (m_UndoItemStack.size() >= m_nBufSize) {
     RemoveHeads();
     m_bVirgin = false;
   }
 
-  m_UndoItemStack.Add(pItem);
-  m_nCurUndoPos = m_UndoItemStack.GetSize();
-
-  m_bModified = (m_nCurUndoPos != 0);
+  m_UndoItemStack.push_back(std::move(pItem));
+  m_nCurUndoPos = m_UndoItemStack.size();
+  m_bModified = true;
 }
 
 bool CFX_Edit_Undo::IsModified() const {
@@ -382,33 +303,26 @@
 }
 
 void CFX_Edit_Undo::RemoveHeads() {
-  ASSERT(m_UndoItemStack.GetSize() > 1);
-
-  delete m_UndoItemStack.GetAt(0);
-  m_UndoItemStack.RemoveAt(0);
+  ASSERT(m_UndoItemStack.size() > 1);
+  m_UndoItemStack.pop_front();
 }
 
 void CFX_Edit_Undo::RemoveTails() {
-  for (int32_t i = m_UndoItemStack.GetSize() - 1; i >= m_nCurUndoPos; i--) {
-    delete m_UndoItemStack.GetAt(i);
-    m_UndoItemStack.RemoveAt(i);
-  }
+  while (m_UndoItemStack.size() > m_nCurUndoPos)
+    m_UndoItemStack.pop_back();
 }
 
 void CFX_Edit_Undo::Reset() {
-  for (int32_t i = 0, sz = m_UndoItemStack.GetSize(); i < sz; i++) {
-    delete m_UndoItemStack.GetAt(i);
-  }
+  m_UndoItemStack.clear();
   m_nCurUndoPos = 0;
-  m_UndoItemStack.RemoveAll();
 }
 
 CFX_Edit_UndoItem::CFX_Edit_UndoItem() : m_bFirst(true), m_bLast(true) {}
 
 CFX_Edit_UndoItem::~CFX_Edit_UndoItem() {}
 
-CFX_WideString CFX_Edit_UndoItem::GetUndoTitle() {
-  return L"";
+CFX_WideString CFX_Edit_UndoItem::GetUndoTitle() const {
+  return CFX_WideString();
 }
 
 void CFX_Edit_UndoItem::SetFirst(bool bFirst) {
@@ -426,49 +340,36 @@
 CFX_Edit_GroupUndoItem::CFX_Edit_GroupUndoItem(const CFX_WideString& sTitle)
     : m_sTitle(sTitle) {}
 
-CFX_Edit_GroupUndoItem::~CFX_Edit_GroupUndoItem() {
-  for (int i = 0, sz = m_Items.GetSize(); i < sz; i++) {
-    delete m_Items[i];
-  }
+CFX_Edit_GroupUndoItem::~CFX_Edit_GroupUndoItem() {}
 
-  m_Items.RemoveAll();
-}
-
-void CFX_Edit_GroupUndoItem::AddUndoItem(CFX_Edit_UndoItem* pUndoItem) {
+void CFX_Edit_GroupUndoItem::AddUndoItem(
+    std::unique_ptr<CFX_Edit_UndoItem> pUndoItem) {
   pUndoItem->SetFirst(false);
   pUndoItem->SetLast(false);
-
-  m_Items.Add(pUndoItem);
-
   if (m_sTitle.IsEmpty())
     m_sTitle = pUndoItem->GetUndoTitle();
+
+  m_Items.push_back(std::move(pUndoItem));
 }
 
 void CFX_Edit_GroupUndoItem::UpdateItems() {
-  if (m_Items.GetSize() > 0) {
-    CFX_Edit_UndoItem* pFirstItem = m_Items[0];
-    pFirstItem->SetFirst(true);
-
-    CFX_Edit_UndoItem* pLastItem = m_Items[m_Items.GetSize() - 1];
-    pLastItem->SetLast(true);
+  if (!m_Items.empty()) {
+    m_Items.front()->SetFirst(true);
+    m_Items.back()->SetLast(true);
   }
 }
 
 void CFX_Edit_GroupUndoItem::Undo() {
-  for (int i = m_Items.GetSize() - 1; i >= 0; i--) {
-    CFX_Edit_UndoItem* pUndoItem = m_Items[i];
-    pUndoItem->Undo();
-  }
+  for (auto iter = m_Items.rbegin(); iter != m_Items.rend(); ++iter)
+    (*iter)->Undo();
 }
 
 void CFX_Edit_GroupUndoItem::Redo() {
-  for (int i = 0, sz = m_Items.GetSize(); i < sz; i++) {
-    CFX_Edit_UndoItem* pUndoItem = m_Items[i];
-    pUndoItem->Redo();
-  }
+  for (auto iter = m_Items.begin(); iter != m_Items.end(); ++iter)
+    (*iter)->Redo();
 }
 
-CFX_WideString CFX_Edit_GroupUndoItem::GetUndoTitle() {
+CFX_WideString CFX_Edit_GroupUndoItem::GetUndoTitle() const {
   return m_sTitle;
 }
 
@@ -671,7 +572,7 @@
 
 // static
 CFX_ByteString CFX_Edit::GetEditAppearanceStream(CFX_Edit* pEdit,
-                                                 const CFX_FloatPoint& ptOffset,
+                                                 const CFX_PointF& ptOffset,
                                                  const CPVT_WordRange* pRange,
                                                  bool bContinuous,
                                                  uint16_t SubWord) {
@@ -684,8 +585,8 @@
   CFX_ByteTextBuf sEditStream;
   CFX_ByteTextBuf sWords;
   int32_t nCurFontIndex = -1;
-  CFX_FloatPoint ptOld;
-  CFX_FloatPoint ptNew;
+  CFX_PointF ptOld;
+  CFX_PointF ptNew;
   CPVT_WordPlace oldplace;
 
   while (pIterator->NextWord()) {
@@ -702,13 +603,13 @@
 
         CPVT_Word word;
         if (pIterator->GetWord(word)) {
-          ptNew = CFX_FloatPoint(word.ptWord.x + ptOffset.x,
-                                 word.ptWord.y + ptOffset.y);
+          ptNew = CFX_PointF(word.ptWord.x + ptOffset.x,
+                             word.ptWord.y + ptOffset.y);
         } else {
           CPVT_Line line;
           pIterator->GetLine(line);
-          ptNew = CFX_FloatPoint(line.ptLine.x + ptOffset.x,
-                                 line.ptLine.y + ptOffset.y);
+          ptNew = CFX_PointF(line.ptLine.x + ptOffset.x,
+                             line.ptLine.y + ptOffset.y);
         }
 
         if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
@@ -739,8 +640,8 @@
     } else {
       CPVT_Word word;
       if (pIterator->GetWord(word)) {
-        ptNew = CFX_FloatPoint(word.ptWord.x + ptOffset.x,
-                               word.ptWord.y + ptOffset.y);
+        ptNew =
+            CFX_PointF(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y);
 
         if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
           sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
@@ -786,7 +687,7 @@
 // static
 CFX_ByteString CFX_Edit::GetSelectAppearanceStream(
     CFX_Edit* pEdit,
-    const CFX_FloatPoint& ptOffset,
+    const CFX_PointF& ptOffset,
     const CPVT_WordRange* pRange) {
   if (!pRange || !pRange->IsExist())
     return CFX_ByteString();
@@ -817,9 +718,8 @@
                         CFX_Matrix* pUser2Device,
                         CFX_Edit* pEdit,
                         FX_COLORREF crTextFill,
-                        FX_COLORREF crTextStroke,
                         const CFX_FloatRect& rcClip,
-                        const CFX_FloatPoint& ptOffset,
+                        const CFX_PointF& ptOffset,
                         const CPVT_WordRange* pRange,
                         CFX_SystemHandler* pSystemHandler,
                         CFFL_FormFiller* pFFLData) {
@@ -839,7 +739,7 @@
 
   CFX_ByteTextBuf sTextBuf;
   int32_t nFontIndex = -1;
-  CFX_FloatPoint ptBT;
+  CFX_PointF ptBT;
   pDevice->SaveState();
   if (!rcClip.IsEmpty()) {
     CFX_FloatRect rcTemp = rcClip;
@@ -897,10 +797,9 @@
               crOldFill != crCurFill) {
             if (sTextBuf.GetLength() > 0) {
               DrawTextString(
-                  pDevice,
-                  CFX_FloatPoint(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
+                  pDevice, CFX_PointF(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
                   pFontMap->GetPDFFont(nFontIndex), fFontSize, pUser2Device,
-                  sTextBuf.MakeString(), crOldFill, crTextStroke, nHorzScale);
+                  sTextBuf.MakeString(), crOldFill, nHorzScale);
 
               sTextBuf.Clear();
             }
@@ -914,85 +813,27 @@
                           .AsStringC();
         } else {
           DrawTextString(
-              pDevice, CFX_FloatPoint(word.ptWord.x + ptOffset.x,
-                                      word.ptWord.y + ptOffset.y),
+              pDevice, CFX_PointF(word.ptWord.x + ptOffset.x,
+                                  word.ptWord.y + ptOffset.y),
               pFontMap->GetPDFFont(word.nFontIndex), fFontSize, pUser2Device,
               GetPDFWordString(pFontMap, word.nFontIndex, word.Word, SubWord),
-              crCurFill, crTextStroke, nHorzScale);
+              crCurFill, nHorzScale);
         }
         oldplace = place;
       }
     }
 
     if (sTextBuf.GetLength() > 0) {
-      DrawTextString(
-          pDevice, CFX_FloatPoint(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
-          pFontMap->GetPDFFont(nFontIndex), fFontSize, pUser2Device,
-          sTextBuf.MakeString(), crOldFill, crTextStroke, nHorzScale);
+      DrawTextString(pDevice,
+                     CFX_PointF(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
+                     pFontMap->GetPDFFont(nFontIndex), fFontSize, pUser2Device,
+                     sTextBuf.MakeString(), crOldFill, nHorzScale);
     }
   }
 
   pDevice->RestoreState(false);
 }
 
-// static
-void CFX_Edit::GeneratePageObjects(CPDF_PageObjectHolder* pObjectHolder,
-                                   CFX_Edit* pEdit,
-                                   const CFX_FloatPoint& ptOffset,
-                                   const CPVT_WordRange* pRange,
-                                   FX_COLORREF crText,
-                                   std::vector<CPDF_TextObject*>* ObjArray) {
-  ObjArray->clear();
-
-  IPVT_FontMap* pFontMap = pEdit->GetFontMap();
-  if (!pFontMap)
-    return;
-
-  FX_FLOAT fFontSize = pEdit->GetFontSize();
-  int32_t nOldFontIndex = -1;
-  CFX_ByteTextBuf sTextBuf;
-  CPVT_WordPlace oldplace;
-  CFX_FloatPoint ptBT(0.0f, 0.0f);
-  CFX_Edit_Iterator* pIterator = pEdit->GetIterator();
-  if (pRange)
-    pIterator->SetAt(pRange->BeginPos);
-  else
-    pIterator->SetAt(0);
-
-  while (pIterator->NextWord()) {
-    CPVT_WordPlace place = pIterator->GetAt();
-    if (pRange && place.WordCmp(pRange->EndPos) > 0)
-      break;
-
-    CPVT_Word word;
-    if (!pIterator->GetWord(word))
-      continue;
-
-    if (place.LineCmp(oldplace) != 0 || nOldFontIndex != word.nFontIndex) {
-      if (sTextBuf.GetLength() > 0) {
-        ObjArray->push_back(AddTextObjToPageObjects(
-            pObjectHolder, crText, pFontMap->GetPDFFont(nOldFontIndex),
-            fFontSize, 0.0f, 100,
-            CFX_FloatPoint(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
-            sTextBuf.MakeString()));
-
-        sTextBuf.Clear();
-      }
-      ptBT = word.ptWord;
-      nOldFontIndex = word.nFontIndex;
-    }
-    sTextBuf << GetPDFWordString(pFontMap, word.nFontIndex, word.Word, 0)
-                    .AsStringC();
-    oldplace = place;
-  }
-  if (sTextBuf.GetLength() > 0) {
-    ObjArray->push_back(AddTextObjToPageObjects(
-        pObjectHolder, crText, pFontMap->GetPDFFont(nOldFontIndex), fFontSize,
-        0.0f, 100, CFX_FloatPoint(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
-        sTextBuf.MakeString()));
-  }
-}
-
 CFX_Edit::CFX_Edit()
     : m_pVT(new CPDF_VariableText),
       m_pNotify(nullptr),
@@ -1048,7 +889,7 @@
 
 void CFX_Edit::SetPlateRect(const CFX_FloatRect& rect) {
   m_pVT->SetPlateRect(rect);
-  m_ptScrollPos = CFX_FloatPoint(rect.left, rect.top);
+  m_ptScrollPos = CFX_PointF(rect.left, rect.top);
   Paint();
 }
 
@@ -1336,10 +1177,10 @@
   if (m_pVT->IsValid()) {
     CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
 
-    CPVT_WordPlace place1 = m_pVT->SearchWordPlace(
-        EditToVT(CFX_FloatPoint(rcPlate.left, rcPlate.top)));
+    CPVT_WordPlace place1 =
+        m_pVT->SearchWordPlace(EditToVT(CFX_PointF(rcPlate.left, rcPlate.top)));
     CPVT_WordPlace place2 = m_pVT->SearchWordPlace(
-        EditToVT(CFX_FloatPoint(rcPlate.right, rcPlate.bottom)));
+        EditToVT(CFX_PointF(rcPlate.right, rcPlate.bottom)));
 
     return CPVT_WordRange(place1, place2);
   }
@@ -1347,7 +1188,7 @@
   return CPVT_WordRange();
 }
 
-CPVT_WordPlace CFX_Edit::SearchWordPlace(const CFX_FloatPoint& point) const {
+CPVT_WordPlace CFX_Edit::SearchWordPlace(const CFX_PointF& point) const {
   if (m_pVT->IsValid()) {
     return m_pVT->SearchWordPlace(EditToVT(point));
   }
@@ -1424,7 +1265,7 @@
   return m_SelState.IsExist();
 }
 
-CFX_FloatPoint CFX_Edit::VTToEdit(const CFX_FloatPoint& point) const {
+CFX_PointF CFX_Edit::VTToEdit(const CFX_PointF& point) const {
   CFX_FloatRect rcContent = m_pVT->GetContentRect();
   CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
 
@@ -1442,11 +1283,11 @@
       break;
   }
 
-  return CFX_FloatPoint(point.x - (m_ptScrollPos.x - rcPlate.left),
-                        point.y - (m_ptScrollPos.y + fPadding - rcPlate.top));
+  return CFX_PointF(point.x - (m_ptScrollPos.x - rcPlate.left),
+                    point.y - (m_ptScrollPos.y + fPadding - rcPlate.top));
 }
 
-CFX_FloatPoint CFX_Edit::EditToVT(const CFX_FloatPoint& point) const {
+CFX_PointF CFX_Edit::EditToVT(const CFX_PointF& point) const {
   CFX_FloatRect rcContent = m_pVT->GetContentRect();
   CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
 
@@ -1464,14 +1305,13 @@
       break;
   }
 
-  return CFX_FloatPoint(point.x + (m_ptScrollPos.x - rcPlate.left),
-                        point.y + (m_ptScrollPos.y + fPadding - rcPlate.top));
+  return CFX_PointF(point.x + (m_ptScrollPos.x - rcPlate.left),
+                    point.y + (m_ptScrollPos.y + fPadding - rcPlate.top));
 }
 
 CFX_FloatRect CFX_Edit::VTToEdit(const CFX_FloatRect& rect) const {
-  CFX_FloatPoint ptLeftBottom =
-      VTToEdit(CFX_FloatPoint(rect.left, rect.bottom));
-  CFX_FloatPoint ptRightTop = VTToEdit(CFX_FloatPoint(rect.right, rect.top));
+  CFX_PointF ptLeftBottom = VTToEdit(CFX_PointF(rect.left, rect.bottom));
+  CFX_PointF ptRightTop = VTToEdit(CFX_PointF(rect.right, rect.top));
 
   return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x,
                        ptRightTop.y);
@@ -1524,14 +1364,14 @@
   }
 }
 
-void CFX_Edit::SetScrollPos(const CFX_FloatPoint& point) {
+void CFX_Edit::SetScrollPos(const CFX_PointF& point) {
   SetScrollPosX(point.x);
   SetScrollPosY(point.y);
   SetScrollLimit();
   SetCaretInfo();
 }
 
-CFX_FloatPoint CFX_Edit::GetScrollPos() const {
+CFX_PointF CFX_Edit::GetScrollPos() const {
   return m_ptScrollPos;
 }
 
@@ -1573,8 +1413,8 @@
   CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
   pIterator->SetAt(m_wpCaret);
 
-  CFX_FloatPoint ptHead;
-  CFX_FloatPoint ptFoot;
+  CFX_PointF ptHead;
+  CFX_PointF ptFoot;
   CPVT_Word word;
   CPVT_Line line;
   if (pIterator->GetWord(word)) {
@@ -1589,8 +1429,8 @@
     ptFoot.y = line.ptLine.y + line.fLineDescent;
   }
 
-  CFX_FloatPoint ptHeadEdit = VTToEdit(ptHead);
-  CFX_FloatPoint ptFootEdit = VTToEdit(ptFoot);
+  CFX_PointF ptHeadEdit = VTToEdit(ptHead);
+  CFX_PointF ptFootEdit = VTToEdit(ptFoot);
   CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
   if (!IsFloatEqual(rcPlate.left, rcPlate.right)) {
     if (IsFloatSmaller(ptHeadEdit.x, rcPlate.left) ||
@@ -1732,8 +1572,8 @@
       CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
       pIterator->SetAt(m_wpCaret);
 
-      CFX_FloatPoint ptHead;
-      CFX_FloatPoint ptFoot;
+      CFX_PointF ptHead;
+      CFX_PointF ptFoot;
       CPVT_Word word;
       CPVT_Line line;
       if (pIterator->GetWord(word)) {
@@ -1768,9 +1608,7 @@
   }
 }
 
-void CFX_Edit::OnMouseDown(const CFX_FloatPoint& point,
-                           bool bShift,
-                           bool bCtrl) {
+void CFX_Edit::OnMouseDown(const CFX_PointF& point, bool bShift, bool bCtrl) {
   if (m_pVT->IsValid()) {
     SelectNone();
     SetCaret(m_pVT->SearchWordPlace(EditToVT(point)));
@@ -1782,9 +1620,7 @@
   }
 }
 
-void CFX_Edit::OnMouseMove(const CFX_FloatPoint& point,
-                           bool bShift,
-                           bool bCtrl) {
+void CFX_Edit::OnMouseMove(const CFX_PointF& point, bool bShift, bool bCtrl) {
   if (m_pVT->IsValid()) {
     SetCaret(m_pVT->SearchWordPlace(EditToVT(point)));
 
@@ -2020,167 +1856,139 @@
                           const CPVT_WordProps* pWordProps,
                           bool bAddUndo,
                           bool bPaint) {
-  if (IsTextOverflow())
+  if (IsTextOverflow() || !m_pVT->IsValid())
     return false;
 
-  if (m_pVT->IsValid()) {
-    m_pVT->UpdateWordPlace(m_wpCaret);
+  m_pVT->UpdateWordPlace(m_wpCaret);
+  SetCaret(m_pVT->InsertWord(m_wpCaret, word,
+                             GetCharSetFromUnicode(word, charset), pWordProps));
+  m_SelState.Set(m_wpCaret, m_wpCaret);
+  if (m_wpCaret == m_wpOldCaret)
+    return false;
 
-    SetCaret(m_pVT->InsertWord(
-        m_wpCaret, word, GetCharSetFromUnicode(word, charset), pWordProps));
-    m_SelState.Set(m_wpCaret, m_wpCaret);
-
-    if (m_wpCaret != m_wpOldCaret) {
-      if (bAddUndo && m_bEnableUndo) {
-        AddEditUndoItem(new CFXEU_InsertWord(this, m_wpOldCaret, m_wpCaret,
-                                             word, charset, pWordProps));
-      }
-
-      if (bPaint)
-        PaintInsertText(m_wpOldCaret, m_wpCaret);
-
-      if (m_bOprNotify && m_pOprNotify)
-        m_pOprNotify->OnInsertWord(m_wpCaret, m_wpOldCaret);
-
-      return true;
-    }
+  if (bAddUndo && m_bEnableUndo) {
+    AddEditUndoItem(pdfium::MakeUnique<CFXEU_InsertWord>(
+        this, m_wpOldCaret, m_wpCaret, word, charset, pWordProps));
   }
+  if (bPaint)
+    PaintInsertText(m_wpOldCaret, m_wpCaret);
 
-  return false;
+  if (m_bOprNotify && m_pOprNotify)
+    m_pOprNotify->OnInsertWord(m_wpCaret, m_wpOldCaret);
+
+  return true;
 }
 
 bool CFX_Edit::InsertReturn(const CPVT_SecProps* pSecProps,
                             const CPVT_WordProps* pWordProps,
                             bool bAddUndo,
                             bool bPaint) {
-  if (IsTextOverflow())
+  if (IsTextOverflow() || !m_pVT->IsValid())
     return false;
 
-  if (m_pVT->IsValid()) {
-    m_pVT->UpdateWordPlace(m_wpCaret);
-    SetCaret(m_pVT->InsertSection(m_wpCaret, pSecProps, pWordProps));
-    m_SelState.Set(m_wpCaret, m_wpCaret);
+  m_pVT->UpdateWordPlace(m_wpCaret);
+  SetCaret(m_pVT->InsertSection(m_wpCaret, pSecProps, pWordProps));
+  m_SelState.Set(m_wpCaret, m_wpCaret);
+  if (m_wpCaret == m_wpOldCaret)
+    return false;
 
-    if (m_wpCaret != m_wpOldCaret) {
-      if (bAddUndo && m_bEnableUndo) {
-        AddEditUndoItem(new CFXEU_InsertReturn(this, m_wpOldCaret, m_wpCaret,
-                                               pSecProps, pWordProps));
-      }
-
-      if (bPaint) {
-        RearrangePart(CPVT_WordRange(m_wpOldCaret, m_wpCaret));
-        ScrollToCaret();
-        Refresh();
-        SetCaretOrigin();
-        SetCaretInfo();
-      }
-
-      if (m_bOprNotify && m_pOprNotify)
-        m_pOprNotify->OnInsertReturn(m_wpCaret, m_wpOldCaret);
-
-      return true;
-    }
+  if (bAddUndo && m_bEnableUndo) {
+    AddEditUndoItem(pdfium::MakeUnique<CFXEU_InsertReturn>(
+        this, m_wpOldCaret, m_wpCaret, pSecProps, pWordProps));
   }
+  if (bPaint) {
+    RearrangePart(CPVT_WordRange(m_wpOldCaret, m_wpCaret));
+    ScrollToCaret();
+    Refresh();
+    SetCaretOrigin();
+    SetCaretInfo();
+  }
+  if (m_bOprNotify && m_pOprNotify)
+    m_pOprNotify->OnInsertReturn(m_wpCaret, m_wpOldCaret);
 
-  return false;
+  return true;
 }
 
 bool CFX_Edit::Backspace(bool bAddUndo, bool bPaint) {
-  if (m_pVT->IsValid()) {
-    if (m_wpCaret == m_pVT->GetBeginWordPlace())
-      return false;
+  if (!m_pVT->IsValid() || m_wpCaret == m_pVT->GetBeginWordPlace())
+    return false;
 
-    CPVT_Section section;
-    CPVT_Word word;
+  CPVT_Section section;
+  CPVT_Word word;
+  if (bAddUndo) {
+    CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
+    pIterator->SetAt(m_wpCaret);
+    pIterator->GetSection(section);
+    pIterator->GetWord(word);
+  }
+  m_pVT->UpdateWordPlace(m_wpCaret);
+  SetCaret(m_pVT->BackSpaceWord(m_wpCaret));
+  m_SelState.Set(m_wpCaret, m_wpCaret);
+  if (m_wpCaret == m_wpOldCaret)
+    return false;
 
-    if (bAddUndo) {
-      CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
-      pIterator->SetAt(m_wpCaret);
-      pIterator->GetSection(section);
-      pIterator->GetWord(word);
-    }
-
-    m_pVT->UpdateWordPlace(m_wpCaret);
-    SetCaret(m_pVT->BackSpaceWord(m_wpCaret));
-    m_SelState.Set(m_wpCaret, m_wpCaret);
-
-    if (m_wpCaret != m_wpOldCaret) {
-      if (bAddUndo && m_bEnableUndo) {
-        if (m_wpCaret.SecCmp(m_wpOldCaret) != 0)
-          AddEditUndoItem(new CFXEU_Backspace(
-              this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset,
-              section.SecProps, section.WordProps));
-        else
-          AddEditUndoItem(new CFXEU_Backspace(
-              this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset,
-              section.SecProps, word.WordProps));
-      }
-
-      if (bPaint) {
-        RearrangePart(CPVT_WordRange(m_wpCaret, m_wpOldCaret));
-        ScrollToCaret();
-        Refresh();
-        SetCaretOrigin();
-        SetCaretInfo();
-      }
-
-      if (m_bOprNotify && m_pOprNotify)
-        m_pOprNotify->OnBackSpace(m_wpCaret, m_wpOldCaret);
-
-      return true;
+  if (bAddUndo && m_bEnableUndo) {
+    if (m_wpCaret.SecCmp(m_wpOldCaret) != 0) {
+      AddEditUndoItem(pdfium::MakeUnique<CFXEU_Backspace>(
+          this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset,
+          section.SecProps, section.WordProps));
+    } else {
+      AddEditUndoItem(pdfium::MakeUnique<CFXEU_Backspace>(
+          this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset,
+          section.SecProps, word.WordProps));
     }
   }
+  if (bPaint) {
+    RearrangePart(CPVT_WordRange(m_wpCaret, m_wpOldCaret));
+    ScrollToCaret();
+    Refresh();
+    SetCaretOrigin();
+    SetCaretInfo();
+  }
+  if (m_bOprNotify && m_pOprNotify)
+    m_pOprNotify->OnBackSpace(m_wpCaret, m_wpOldCaret);
 
-  return false;
+  return true;
 }
 
 bool CFX_Edit::Delete(bool bAddUndo, bool bPaint) {
-  if (m_pVT->IsValid()) {
-    if (m_wpCaret == m_pVT->GetEndWordPlace())
-      return false;
+  if (!m_pVT->IsValid() || m_wpCaret == m_pVT->GetEndWordPlace())
+    return false;
 
-    CPVT_Section section;
-    CPVT_Word word;
-
-    if (bAddUndo) {
-      CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
-      pIterator->SetAt(m_pVT->GetNextWordPlace(m_wpCaret));
-      pIterator->GetSection(section);
-      pIterator->GetWord(word);
-    }
-
-    m_pVT->UpdateWordPlace(m_wpCaret);
-    bool bSecEnd = (m_wpCaret == m_pVT->GetSectionEndPlace(m_wpCaret));
-
-    SetCaret(m_pVT->DeleteWord(m_wpCaret));
-    m_SelState.Set(m_wpCaret, m_wpCaret);
-
-    if (bAddUndo && m_bEnableUndo) {
-      if (bSecEnd)
-        AddEditUndoItem(new CFXEU_Delete(
-            this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset,
-            section.SecProps, section.WordProps, bSecEnd));
-      else
-        AddEditUndoItem(new CFXEU_Delete(
-            this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset,
-            section.SecProps, word.WordProps, bSecEnd));
-    }
-
-    if (bPaint) {
-      RearrangePart(CPVT_WordRange(m_wpOldCaret, m_wpCaret));
-      ScrollToCaret();
-      Refresh();
-      SetCaretOrigin();
-      SetCaretInfo();
-    }
-
-    if (m_bOprNotify && m_pOprNotify)
-      m_pOprNotify->OnDelete(m_wpCaret, m_wpOldCaret);
-
-    return true;
+  CPVT_Section section;
+  CPVT_Word word;
+  if (bAddUndo) {
+    CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
+    pIterator->SetAt(m_pVT->GetNextWordPlace(m_wpCaret));
+    pIterator->GetSection(section);
+    pIterator->GetWord(word);
   }
+  m_pVT->UpdateWordPlace(m_wpCaret);
+  bool bSecEnd = (m_wpCaret == m_pVT->GetSectionEndPlace(m_wpCaret));
+  SetCaret(m_pVT->DeleteWord(m_wpCaret));
+  m_SelState.Set(m_wpCaret, m_wpCaret);
+  if (bAddUndo && m_bEnableUndo) {
+    if (bSecEnd) {
+      AddEditUndoItem(pdfium::MakeUnique<CFXEU_Delete>(
+          this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset,
+          section.SecProps, section.WordProps, bSecEnd));
+    } else {
+      AddEditUndoItem(pdfium::MakeUnique<CFXEU_Delete>(
+          this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset,
+          section.SecProps, word.WordProps, bSecEnd));
+    }
+  }
+  if (bPaint) {
+    RearrangePart(CPVT_WordRange(m_wpOldCaret, m_wpCaret));
+    ScrollToCaret();
+    Refresh();
+    SetCaretOrigin();
+    SetCaretInfo();
+  }
+  if (m_bOprNotify && m_pOprNotify)
+    m_pOprNotify->OnDelete(m_wpCaret, m_wpOldCaret);
 
-  return false;
+  return true;
 }
 
 bool CFX_Edit::Empty() {
@@ -2195,21 +2003,16 @@
 }
 
 bool CFX_Edit::Clear(bool bAddUndo, bool bPaint) {
-  if (!m_pVT->IsValid())
-    return false;
-
-  if (!m_SelState.IsExist())
+  if (!m_pVT->IsValid() || !m_SelState.IsExist())
     return false;
 
   CPVT_WordRange range = m_SelState.ConvertToWordRange();
-
   if (bAddUndo && m_bEnableUndo)
-    AddEditUndoItem(new CFXEU_Clear(this, range, GetSelText()));
+    AddEditUndoItem(pdfium::MakeUnique<CFXEU_Clear>(this, range, GetSelText()));
 
   SelectNone();
   SetCaret(m_pVT->DeleteWords(range));
   m_SelState.Set(m_wpCaret, m_wpCaret);
-
   if (bPaint) {
     RearrangePart(range);
     ScrollToCaret();
@@ -2217,7 +2020,6 @@
     SetCaretOrigin();
     SetCaretInfo();
   }
-
   if (m_bOprNotify && m_pOprNotify)
     m_pOprNotify->OnClear(m_wpCaret, m_wpOldCaret);
 
@@ -2238,10 +2040,9 @@
     return false;
 
   if (bAddUndo && m_bEnableUndo) {
-    AddEditUndoItem(
-        new CFXEU_InsertText(this, m_wpOldCaret, m_wpCaret, sText, charset));
+    AddEditUndoItem(pdfium::MakeUnique<CFXEU_InsertText>(
+        this, m_wpOldCaret, m_wpCaret, sText, charset));
   }
-
   if (bPaint)
     PaintInsertText(m_wpOldCaret, m_wpCaret);
 
@@ -2407,53 +2208,36 @@
   return nOldCharset;
 }
 
-void CFX_Edit::AddEditUndoItem(CFX_Edit_UndoItem* pEditUndoItem) {
-  if (m_pGroupUndoItem) {
-    m_pGroupUndoItem->AddUndoItem(pEditUndoItem);
-  } else {
-    m_Undo.AddItem(pEditUndoItem);
-  }
+void CFX_Edit::AddEditUndoItem(
+    std::unique_ptr<CFX_Edit_UndoItem> pEditUndoItem) {
+  if (m_pGroupUndoItem)
+    m_pGroupUndoItem->AddUndoItem(std::move(pEditUndoItem));
+  else
+    m_Undo.AddItem(std::move(pEditUndoItem));
 }
 
 CFX_Edit_LineRectArray::CFX_Edit_LineRectArray() {}
 
-CFX_Edit_LineRectArray::~CFX_Edit_LineRectArray() {
-  Empty();
-}
+CFX_Edit_LineRectArray::~CFX_Edit_LineRectArray() {}
 
-void CFX_Edit_LineRectArray::Empty() {
-  for (int32_t i = 0, sz = m_LineRects.GetSize(); i < sz; i++)
-    delete m_LineRects.GetAt(i);
-
-  m_LineRects.RemoveAll();
-}
-
-void CFX_Edit_LineRectArray::RemoveAll() {
-  m_LineRects.RemoveAll();
-}
-
-void CFX_Edit_LineRectArray::operator=(CFX_Edit_LineRectArray& rects) {
-  Empty();
-  for (int32_t i = 0, sz = rects.GetSize(); i < sz; i++)
-    m_LineRects.Add(rects.GetAt(i));
-
-  rects.RemoveAll();
+void CFX_Edit_LineRectArray::operator=(CFX_Edit_LineRectArray&& that) {
+  m_LineRects = std::move(that.m_LineRects);
 }
 
 void CFX_Edit_LineRectArray::Add(const CPVT_WordRange& wrLine,
                                  const CFX_FloatRect& rcLine) {
-  m_LineRects.Add(new CFX_Edit_LineRect(wrLine, rcLine));
+  m_LineRects.push_back(pdfium::MakeUnique<CFX_Edit_LineRect>(wrLine, rcLine));
 }
 
 int32_t CFX_Edit_LineRectArray::GetSize() const {
-  return m_LineRects.GetSize();
+  return pdfium::CollectionSize<int32_t>(m_LineRects);
 }
 
 CFX_Edit_LineRect* CFX_Edit_LineRectArray::GetAt(int32_t nIndex) const {
-  if (nIndex < 0 || nIndex >= m_LineRects.GetSize())
+  if (nIndex < 0 || nIndex >= GetSize())
     return nullptr;
 
-  return m_LineRects.GetAt(nIndex);
+  return m_LineRects[nIndex].get();
 }
 
 CFX_Edit_Select::CFX_Edit_Select() {}
@@ -2496,35 +2280,28 @@
 
 CFX_Edit_RectArray::CFX_Edit_RectArray() {}
 
-CFX_Edit_RectArray::~CFX_Edit_RectArray() {
-  Empty();
-}
+CFX_Edit_RectArray::~CFX_Edit_RectArray() {}
 
-void CFX_Edit_RectArray::Empty() {
-  for (int32_t i = 0, sz = m_Rects.GetSize(); i < sz; i++)
-    delete m_Rects.GetAt(i);
-
-  m_Rects.RemoveAll();
+void CFX_Edit_RectArray::Clear() {
+  m_Rects.clear();
 }
 
 void CFX_Edit_RectArray::Add(const CFX_FloatRect& rect) {
   // check for overlapped area
-  for (int32_t i = 0, sz = m_Rects.GetSize(); i < sz; i++) {
-    CFX_FloatRect* pRect = m_Rects.GetAt(i);
+  for (const auto& pRect : m_Rects) {
     if (pRect && pRect->Contains(rect))
       return;
   }
-
-  m_Rects.Add(new CFX_FloatRect(rect));
+  m_Rects.push_back(pdfium::MakeUnique<CFX_FloatRect>(rect));
 }
 
 int32_t CFX_Edit_RectArray::GetSize() const {
-  return m_Rects.GetSize();
+  return pdfium::CollectionSize<int32_t>(m_Rects);
 }
 
 CFX_FloatRect* CFX_Edit_RectArray::GetAt(int32_t nIndex) const {
-  if (nIndex < 0 || nIndex >= m_Rects.GetSize())
+  if (nIndex < 0 || nIndex >= GetSize())
     return nullptr;
 
-  return m_Rects.GetAt(nIndex);
+  return m_Rects[nIndex].get();
 }
diff --git a/fpdfsdk/fxedit/fxet_edit.h b/fpdfsdk/fxedit/fxet_edit.h
index 2ab27d3..ab83af2 100644
--- a/fpdfsdk/fxedit/fxet_edit.h
+++ b/fpdfsdk/fxedit/fxet_edit.h
@@ -7,6 +7,7 @@
 #ifndef FPDFSDK_FXEDIT_FXET_EDIT_H_
 #define FPDFSDK_FXEDIT_FXET_EDIT_H_
 
+#include <deque>
 #include <memory>
 #include <vector>
 
@@ -40,16 +41,14 @@
   CFX_Edit_LineRectArray();
   virtual ~CFX_Edit_LineRectArray();
 
-  void Empty();
-  void RemoveAll();
-  void operator=(CFX_Edit_LineRectArray& rects);
+  void operator=(CFX_Edit_LineRectArray&& rects);
   void Add(const CPVT_WordRange& wrLine, const CFX_FloatRect& rcLine);
 
   int32_t GetSize() const;
   CFX_Edit_LineRect* GetAt(int32_t nIndex) const;
 
  private:
-  CFX_ArrayTemplate<CFX_Edit_LineRect*> m_LineRects;
+  std::vector<std::unique_ptr<CFX_Edit_LineRect>> m_LineRects;
 };
 
 class CFX_Edit_RectArray {
@@ -57,14 +56,14 @@
   CFX_Edit_RectArray();
   virtual ~CFX_Edit_RectArray();
 
-  void Empty();
+  void Clear();
   void Add(const CFX_FloatRect& rect);
 
   int32_t GetSize() const;
   CFX_FloatRect* GetAt(int32_t nIndex) const;
 
  private:
-  CFX_ArrayTemplate<CFX_FloatRect*> m_Rects;
+  std::vector<std::unique_ptr<CFX_FloatRect>> m_Rects;
 };
 
 class CFX_Edit_Refresh {
@@ -99,7 +98,8 @@
   CPVT_WordRange ConvertToWordRange() const;
   bool IsExist() const;
 
-  CPVT_WordPlace BeginPos, EndPos;
+  CPVT_WordPlace BeginPos;
+  CPVT_WordPlace EndPos;
 };
 
 class CFX_Edit_Undo {
@@ -107,26 +107,21 @@
   explicit CFX_Edit_Undo(int32_t nBufsize);
   virtual ~CFX_Edit_Undo();
 
+  void AddItem(std::unique_ptr<IFX_Edit_UndoItem> pItem);
   void Undo();
   void Redo();
-
-  void AddItem(IFX_Edit_UndoItem* pItem);
-
   bool CanUndo() const;
   bool CanRedo() const;
   bool IsModified() const;
-
   void Reset();
 
  private:
   void RemoveHeads();
   void RemoveTails();
 
- private:
-  CFX_ArrayTemplate<IFX_Edit_UndoItem*> m_UndoItemStack;
-
-  int32_t m_nCurUndoPos;
-  int32_t m_nBufSize;
+  std::deque<std::unique_ptr<IFX_Edit_UndoItem>> m_UndoItemStack;
+  size_t m_nCurUndoPos;
+  size_t m_nBufSize;
   bool m_bModified;
   bool m_bVirgin;
   bool m_bWorking;
@@ -138,7 +133,7 @@
 
   virtual void Undo() = 0;
   virtual void Redo() = 0;
-  virtual CFX_WideString GetUndoTitle() = 0;
+  virtual CFX_WideString GetUndoTitle() const = 0;
 };
 
 class CFX_Edit_UndoItem : public IFX_Edit_UndoItem {
@@ -146,7 +141,7 @@
   CFX_Edit_UndoItem();
   ~CFX_Edit_UndoItem() override;
 
-  CFX_WideString GetUndoTitle() override;
+  CFX_WideString GetUndoTitle() const override;
 
   void SetFirst(bool bFirst);
   void SetLast(bool bLast);
@@ -165,14 +160,14 @@
   // IFX_Edit_UndoItem
   void Undo() override;
   void Redo() override;
-  CFX_WideString GetUndoTitle() override;
+  CFX_WideString GetUndoTitle() const override;
 
-  void AddUndoItem(CFX_Edit_UndoItem* pUndoItem);
+  void AddUndoItem(std::unique_ptr<CFX_Edit_UndoItem> pUndoItem);
   void UpdateItems();
 
  private:
   CFX_WideString m_sTitle;
-  CFX_ArrayTemplate<CFX_Edit_UndoItem*> m_Items;
+  std::vector<std::unique_ptr<CFX_Edit_UndoItem>> m_Items;
 };
 
 class CFXEU_InsertWord : public CFX_Edit_UndoItem {
@@ -318,30 +313,22 @@
 class CFX_Edit {
  public:
   static CFX_ByteString GetEditAppearanceStream(CFX_Edit* pEdit,
-                                                const CFX_FloatPoint& ptOffset,
+                                                const CFX_PointF& ptOffset,
                                                 const CPVT_WordRange* pRange,
                                                 bool bContinuous,
                                                 uint16_t SubWord);
-  static CFX_ByteString GetSelectAppearanceStream(
-      CFX_Edit* pEdit,
-      const CFX_FloatPoint& ptOffset,
-      const CPVT_WordRange* pRange);
+  static CFX_ByteString GetSelectAppearanceStream(CFX_Edit* pEdit,
+                                                  const CFX_PointF& ptOffset,
+                                                  const CPVT_WordRange* pRange);
   static void DrawEdit(CFX_RenderDevice* pDevice,
                        CFX_Matrix* pUser2Device,
                        CFX_Edit* pEdit,
                        FX_COLORREF crTextFill,
-                       FX_COLORREF crTextStroke,
                        const CFX_FloatRect& rcClip,
-                       const CFX_FloatPoint& ptOffset,
+                       const CFX_PointF& ptOffset,
                        const CPVT_WordRange* pRange,
                        CFX_SystemHandler* pSystemHandler,
                        CFFL_FormFiller* pFFLData);
-  static void GeneratePageObjects(CPDF_PageObjectHolder* pObjectHolder,
-                                  CFX_Edit* pEdit,
-                                  const CFX_FloatPoint& ptOffset,
-                                  const CPVT_WordRange* pRange,
-                                  FX_COLORREF crText,
-                                  std::vector<CPDF_TextObject*>* ObjArray);
 
   CFX_Edit();
   ~CFX_Edit();
@@ -357,7 +344,7 @@
 
   // Set the bounding box of the text area.
   void SetPlateRect(const CFX_FloatRect& rect);
-  void SetScrollPos(const CFX_FloatPoint& point);
+  void SetScrollPos(const CFX_PointF& point);
 
   // Set the horizontal text alignment. (nFormat [0:left, 1:middle, 2:right])
   void SetAlignmentH(int32_t nFormat, bool bPaint);
@@ -377,8 +364,8 @@
   void SetAutoScroll(bool bAuto, bool bPaint);
   void SetFontSize(FX_FLOAT fFontSize);
   void SetTextOverflow(bool bAllowed, bool bPaint);
-  void OnMouseDown(const CFX_FloatPoint& point, bool bShift, bool bCtrl);
-  void OnMouseMove(const CFX_FloatPoint& point, bool bShift, bool bCtrl);
+  void OnMouseDown(const CFX_PointF& point, bool bShift, bool bCtrl);
+  void OnMouseMove(const CFX_PointF& point, bool bShift, bool bCtrl);
   void OnVK_UP(bool bShift, bool bCtrl);
   void OnVK_DOWN(bool bShift, bool bCtrl);
   void OnVK_LEFT(bool bShift, bool bCtrl);
@@ -396,14 +383,14 @@
   bool Undo();
   int32_t WordPlaceToWordIndex(const CPVT_WordPlace& place) const;
   CPVT_WordPlace WordIndexToWordPlace(int32_t index) const;
-  CPVT_WordPlace SearchWordPlace(const CFX_FloatPoint& point) const;
+  CPVT_WordPlace SearchWordPlace(const CFX_PointF& point) const;
   int32_t GetCaret() const;
   CPVT_WordPlace GetCaretWordPlace() const;
   CFX_WideString GetSelText() const;
   CFX_WideString GetText() const;
   FX_FLOAT GetFontSize() const;
   uint16_t GetPasswordChar() const;
-  CFX_FloatPoint GetScrollPos() const;
+  CFX_PointF GetScrollPos() const;
   int32_t GetCharArray() const;
   CFX_FloatRect GetContentRect() const;
   CFX_WideString GetRangeText(const CPVT_WordRange& range) const;
@@ -477,8 +464,8 @@
   void PaintInsertText(const CPVT_WordPlace& wpOld,
                        const CPVT_WordPlace& wpNew);
 
-  inline CFX_FloatPoint VTToEdit(const CFX_FloatPoint& point) const;
-  inline CFX_FloatPoint EditToVT(const CFX_FloatPoint& point) const;
+  inline CFX_PointF VTToEdit(const CFX_PointF& point) const;
+  inline CFX_PointF EditToVT(const CFX_PointF& point) const;
   inline CFX_FloatRect VTToEdit(const CFX_FloatRect& rect) const;
 
   void Refresh();
@@ -488,24 +475,22 @@
   void SetCaretInfo();
   void SetCaretOrigin();
 
-  void AddEditUndoItem(CFX_Edit_UndoItem* pEditUndoItem);
+  void AddEditUndoItem(std::unique_ptr<CFX_Edit_UndoItem> pEditUndoItem);
 
  private:
   std::unique_ptr<CPDF_VariableText> m_pVT;
   CPWL_EditCtrl* m_pNotify;
   CPWL_Edit* m_pOprNotify;
   std::unique_ptr<CFX_Edit_Provider> m_pVTProvider;
-
   CPVT_WordPlace m_wpCaret;
   CPVT_WordPlace m_wpOldCaret;
   CFX_Edit_Select m_SelState;
-
-  CFX_FloatPoint m_ptScrollPos;
-  CFX_FloatPoint m_ptRefreshScrollPos;
+  CFX_PointF m_ptScrollPos;
+  CFX_PointF m_ptRefreshScrollPos;
   bool m_bEnableScroll;
   std::unique_ptr<CFX_Edit_Iterator> m_pIterator;
   CFX_Edit_Refresh m_Refresh;
-  CFX_FloatPoint m_ptCaret;
+  CFX_PointF m_ptCaret;
   CFX_Edit_Undo m_Undo;
   int32_t m_nAlignment;
   bool m_bNotifyFlag;
diff --git a/fpdfsdk/fxedit/fxet_list.cpp b/fpdfsdk/fxedit/fxet_list.cpp
index cf718b9..39877c9 100644
--- a/fpdfsdk/fxedit/fxet_list.cpp
+++ b/fpdfsdk/fxedit/fxet_list.cpp
@@ -207,37 +207,33 @@
   m_pNotify = pNotify;
 }
 
-CFX_FloatPoint CFX_ListCtrl::InToOut(const CFX_FloatPoint& point) const {
+CFX_PointF CFX_ListCtrl::InToOut(const CFX_PointF& point) const {
   CFX_FloatRect rcPlate = GetPlateRect();
-
-  return CFX_FloatPoint(point.x - (m_ptScrollPos.x - rcPlate.left),
-                        point.y - (m_ptScrollPos.y - rcPlate.top));
+  return CFX_PointF(point.x - (m_ptScrollPos.x - rcPlate.left),
+                    point.y - (m_ptScrollPos.y - rcPlate.top));
 }
 
-CFX_FloatPoint CFX_ListCtrl::OutToIn(const CFX_FloatPoint& point) const {
+CFX_PointF CFX_ListCtrl::OutToIn(const CFX_PointF& point) const {
   CFX_FloatRect rcPlate = GetPlateRect();
-
-  return CFX_FloatPoint(point.x + (m_ptScrollPos.x - rcPlate.left),
-                        point.y + (m_ptScrollPos.y - rcPlate.top));
+  return CFX_PointF(point.x + (m_ptScrollPos.x - rcPlate.left),
+                    point.y + (m_ptScrollPos.y - rcPlate.top));
 }
 
 CFX_FloatRect CFX_ListCtrl::InToOut(const CFX_FloatRect& rect) const {
-  CFX_FloatPoint ptLeftBottom = InToOut(CFX_FloatPoint(rect.left, rect.bottom));
-  CFX_FloatPoint ptRightTop = InToOut(CFX_FloatPoint(rect.right, rect.top));
-
+  CFX_PointF ptLeftBottom = InToOut(CFX_PointF(rect.left, rect.bottom));
+  CFX_PointF ptRightTop = InToOut(CFX_PointF(rect.right, rect.top));
   return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x,
                        ptRightTop.y);
 }
 
 CFX_FloatRect CFX_ListCtrl::OutToIn(const CFX_FloatRect& rect) const {
-  CFX_FloatPoint ptLeftBottom = OutToIn(CFX_FloatPoint(rect.left, rect.bottom));
-  CFX_FloatPoint ptRightTop = OutToIn(CFX_FloatPoint(rect.right, rect.top));
-
+  CFX_PointF ptLeftBottom = OutToIn(CFX_PointF(rect.left, rect.bottom));
+  CFX_PointF ptRightTop = OutToIn(CFX_PointF(rect.right, rect.top));
   return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x,
                        ptRightTop.y);
 }
 
-void CFX_ListCtrl::OnMouseDown(const CFX_FloatPoint& point,
+void CFX_ListCtrl::OnMouseDown(const CFX_PointF& point,
                                bool bShift,
                                bool bCtrl) {
   int32_t nHitIndex = GetItemIndex(point);
@@ -276,7 +272,7 @@
     ScrollToListItem(nHitIndex);
 }
 
-void CFX_ListCtrl::OnMouseMove(const CFX_FloatPoint& point,
+void CFX_ListCtrl::OnMouseMove(const CFX_PointF& point,
                                bool bShift,
                                bool bCtrl) {
   int32_t nHitIndex = GetItemIndex(point);
@@ -367,7 +363,7 @@
 void CFX_ListCtrl::SetPlateRect(const CFX_FloatRect& rect) {
   CFX_ListContainer::SetPlateRect(rect);
   m_ptScrollPos.x = rect.left;
-  SetScrollPos(CFX_FloatPoint(rect.left, rect.top));
+  SetScrollPos(CFX_PointF(rect.left, rect.top));
   ReArrange(0);
   InvalidateItem(-1);
 }
@@ -542,7 +538,7 @@
   }
 }
 
-void CFX_ListCtrl::SetScrollPos(const CFX_FloatPoint& point) {
+void CFX_ListCtrl::SetScrollPos(const CFX_PointF& point) {
   SetScrollPosY(point.y);
 }
 
@@ -630,8 +626,8 @@
   m_aSelItems.DeselectAll();
 }
 
-int32_t CFX_ListCtrl::GetItemIndex(const CFX_FloatPoint& point) const {
-  CFX_FloatPoint pt = OuterToInner(OutToIn(point));
+int32_t CFX_ListCtrl::GetItemIndex(const CFX_PointF& point) const {
+  CFX_PointF pt = OuterToInner(OutToIn(point));
 
   bool bFirst = true;
   bool bLast = true;
diff --git a/fpdfsdk/fxedit/fxet_list.h b/fpdfsdk/fxedit/fxet_list.h
index 38d1957..01e18bc 100644
--- a/fpdfsdk/fxedit/fxet_list.h
+++ b/fpdfsdk/fxedit/fxet_list.h
@@ -64,11 +64,11 @@
     return bottom - top;
   }
 
-  CFX_FloatPoint LeftTop() const { return CFX_FloatPoint(left, top); }
+  CFX_PointF LeftTop() const { return CFX_PointF(left, top); }
 
-  CFX_FloatPoint RightBottom() const { return CFX_FloatPoint(right, bottom); }
+  CFX_PointF RightBottom() const { return CFX_PointF(right, bottom); }
 
-  const CLST_Rect operator+=(const CFX_FloatPoint& point) {
+  const CLST_Rect operator+=(const CFX_PointF& point) {
     left += point.x;
     right += point.x;
     top += point.y;
@@ -77,7 +77,7 @@
     return *this;
   }
 
-  const CLST_Rect operator-=(const CFX_FloatPoint& point) {
+  const CLST_Rect operator-=(const CFX_PointF& point) {
     left -= point.x;
     right -= point.x;
     top -= point.y;
@@ -86,12 +86,12 @@
     return *this;
   }
 
-  CLST_Rect operator+(const CFX_FloatPoint& point) const {
+  CLST_Rect operator+(const CFX_PointF& point) const {
     return CLST_Rect(left + point.x, top + point.y, right + point.x,
                      bottom + point.y);
   }
 
-  CLST_Rect operator-(const CFX_FloatPoint& point) const {
+  CLST_Rect operator-(const CFX_PointF& point) const {
     return CLST_Rect(left - point.x, top - point.y, right - point.x,
                      bottom - point.y);
   }
@@ -134,33 +134,31 @@
   CFX_FloatRect GetPlateRect() const { return m_rcPlate; }
   void SetContentRect(const CLST_Rect& rect) { m_rcContent = rect; }
   CLST_Rect GetContentRect() const { return m_rcContent; }
-  CFX_FloatPoint GetBTPoint() const {
-    return CFX_FloatPoint(m_rcPlate.left, m_rcPlate.top);
+  CFX_PointF GetBTPoint() const {
+    return CFX_PointF(m_rcPlate.left, m_rcPlate.top);
   }
-  CFX_FloatPoint GetETPoint() const {
-    return CFX_FloatPoint(m_rcPlate.right, m_rcPlate.bottom);
+  CFX_PointF GetETPoint() const {
+    return CFX_PointF(m_rcPlate.right, m_rcPlate.bottom);
   }
 
  public:
-  CFX_FloatPoint InnerToOuter(const CFX_FloatPoint& point) const {
-    return CFX_FloatPoint(point.x + GetBTPoint().x, GetBTPoint().y - point.y);
+  CFX_PointF InnerToOuter(const CFX_PointF& point) const {
+    return CFX_PointF(point.x + GetBTPoint().x, GetBTPoint().y - point.y);
   }
-  CFX_FloatPoint OuterToInner(const CFX_FloatPoint& point) const {
-    return CFX_FloatPoint(point.x - GetBTPoint().x, GetBTPoint().y - point.y);
+  CFX_PointF OuterToInner(const CFX_PointF& point) const {
+    return CFX_PointF(point.x - GetBTPoint().x, GetBTPoint().y - point.y);
   }
   CFX_FloatRect InnerToOuter(const CLST_Rect& rect) const {
-    CFX_FloatPoint ptLeftTop =
-        InnerToOuter(CFX_FloatPoint(rect.left, rect.top));
-    CFX_FloatPoint ptRightBottom =
-        InnerToOuter(CFX_FloatPoint(rect.right, rect.bottom));
+    CFX_PointF ptLeftTop = InnerToOuter(CFX_PointF(rect.left, rect.top));
+    CFX_PointF ptRightBottom =
+        InnerToOuter(CFX_PointF(rect.right, rect.bottom));
     return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x,
                          ptLeftTop.y);
   }
   CLST_Rect OuterToInner(const CFX_FloatRect& rect) const {
-    CFX_FloatPoint ptLeftTop =
-        OuterToInner(CFX_FloatPoint(rect.left, rect.top));
-    CFX_FloatPoint ptRightBottom =
-        OuterToInner(CFX_FloatPoint(rect.right, rect.bottom));
+    CFX_PointF ptLeftTop = OuterToInner(CFX_PointF(rect.left, rect.top));
+    CFX_PointF ptRightBottom =
+        OuterToInner(CFX_PointF(rect.right, rect.bottom));
     return CLST_Rect(ptLeftTop.x, ptLeftTop.y, ptRightBottom.x,
                      ptRightBottom.y);
   }
@@ -226,8 +224,8 @@
   void SetPlateRect(const CFX_FloatRect& rect) override;
 
   void SetNotify(CPWL_List_Notify* pNotify);
-  void OnMouseDown(const CFX_FloatPoint& point, bool bShift, bool bCtrl);
-  void OnMouseMove(const CFX_FloatPoint& point, bool bShift, bool bCtrl);
+  void OnMouseDown(const CFX_PointF& point, bool bShift, bool bCtrl);
+  void OnMouseMove(const CFX_PointF& point, bool bShift, bool bCtrl);
   void OnVK_UP(bool bShift, bool bCtrl);
   void OnVK_DOWN(bool bShift, bool bCtrl);
   void OnVK_LEFT(bool bShift, bool bCtrl);
@@ -237,14 +235,14 @@
   void OnVK(int32_t nItemIndex, bool bShift, bool bCtrl);
   bool OnChar(uint16_t nChar, bool bShift, bool bCtrl);
 
-  void SetScrollPos(const CFX_FloatPoint& point);
+  void SetScrollPos(const CFX_PointF& point);
   void ScrollToListItem(int32_t nItemIndex);
   CFX_FloatRect GetItemRect(int32_t nIndex) const;
   int32_t GetCaret() const;
   int32_t GetSelect() const;
   int32_t GetTopItem() const;
   CFX_FloatRect GetContentRect() const;
-  int32_t GetItemIndex(const CFX_FloatPoint& point) const;
+  int32_t GetItemIndex(const CFX_PointF& point) const;
   void AddString(const CFX_WideString& str);
   void SetTopItem(int32_t nIndex);
   void Select(int32_t nItemIndex);
@@ -267,8 +265,8 @@
   int32_t FindNext(int32_t nIndex, FX_WCHAR nChar) const;
   int32_t GetFirstSelected() const;
 
-  CFX_FloatPoint InToOut(const CFX_FloatPoint& point) const;
-  CFX_FloatPoint OutToIn(const CFX_FloatPoint& point) const;
+  CFX_PointF InToOut(const CFX_PointF& point) const;
+  CFX_PointF OutToIn(const CFX_PointF& point) const;
   CFX_FloatRect InToOut(const CFX_FloatRect& rect) const;
   CFX_FloatRect OutToIn(const CFX_FloatRect& rect) const;
 
@@ -291,7 +289,7 @@
 
   CPWL_List_Notify* m_pNotify;
   bool m_bNotifyFlag;
-  CFX_FloatPoint m_ptScrollPos;
+  CFX_PointF m_ptScrollPos;
   CPLST_Select m_aSelItems;  // for multiple
   int32_t m_nSelItem;        // for single
   int32_t m_nFootIndex;      // for multiple
diff --git a/fpdfsdk/ipdfsdk_annothandler.h b/fpdfsdk/ipdfsdk_annothandler.h
index 408dcce..636d161 100644
--- a/fpdfsdk/ipdfsdk_annothandler.h
+++ b/fpdfsdk/ipdfsdk_annothandler.h
@@ -38,7 +38,7 @@
                                     CPDFSDK_Annot* pAnnot) = 0;
   virtual bool HitTest(CPDFSDK_PageView* pPageView,
                        CPDFSDK_Annot* pAnnot,
-                       const CFX_FloatPoint& point) = 0;
+                       const CFX_PointF& point) = 0;
   virtual void OnDraw(CPDFSDK_PageView* pPageView,
                       CPDFSDK_Annot* pAnnot,
                       CFX_RenderDevice* pDevice,
@@ -55,36 +55,36 @@
   virtual bool OnLButtonDown(CPDFSDK_PageView* pPageView,
                              CPDFSDK_Annot::ObservedPtr* pAnnot,
                              uint32_t nFlags,
-                             const CFX_FloatPoint& point) = 0;
+                             const CFX_PointF& point) = 0;
   virtual bool OnLButtonUp(CPDFSDK_PageView* pPageView,
                            CPDFSDK_Annot::ObservedPtr* pAnnot,
                            uint32_t nFlags,
-                           const CFX_FloatPoint& point) = 0;
+                           const CFX_PointF& point) = 0;
   virtual bool OnLButtonDblClk(CPDFSDK_PageView* pPageView,
                                CPDFSDK_Annot::ObservedPtr* pAnnot,
                                uint32_t nFlags,
-                               const CFX_FloatPoint& point) = 0;
+                               const CFX_PointF& point) = 0;
   virtual bool OnMouseMove(CPDFSDK_PageView* pPageView,
                            CPDFSDK_Annot::ObservedPtr* pAnnot,
                            uint32_t nFlags,
-                           const CFX_FloatPoint& point) = 0;
+                           const CFX_PointF& point) = 0;
   virtual bool OnMouseWheel(CPDFSDK_PageView* pPageView,
                             CPDFSDK_Annot::ObservedPtr* pAnnot,
                             uint32_t nFlags,
                             short zDelta,
-                            const CFX_FloatPoint& point) = 0;
+                            const CFX_PointF& point) = 0;
   virtual bool OnRButtonDown(CPDFSDK_PageView* pPageView,
                              CPDFSDK_Annot::ObservedPtr* pAnnot,
                              uint32_t nFlags,
-                             const CFX_FloatPoint& point) = 0;
+                             const CFX_PointF& point) = 0;
   virtual bool OnRButtonUp(CPDFSDK_PageView* pPageView,
                            CPDFSDK_Annot::ObservedPtr* pAnnot,
                            uint32_t nFlags,
-                           const CFX_FloatPoint& point) = 0;
+                           const CFX_PointF& point) = 0;
   virtual bool OnRButtonDblClk(CPDFSDK_PageView* pPageView,
                                CPDFSDK_Annot::ObservedPtr* pAnnot,
                                uint32_t nFlags,
-                               const CFX_FloatPoint& point) = 0;
+                               const CFX_PointF& point) = 0;
   virtual bool OnChar(CPDFSDK_Annot* pAnnot,
                       uint32_t nChar,
                       uint32_t nFlags) = 0;
diff --git a/fpdfsdk/javascript/Annot.cpp b/fpdfsdk/javascript/Annot.cpp
index 1aef463..41c71ec 100644
--- a/fpdfsdk/javascript/Annot.cpp
+++ b/fpdfsdk/javascript/Annot.cpp
@@ -9,7 +9,7 @@
 #include "fpdfsdk/javascript/JS_Define.h"
 #include "fpdfsdk/javascript/JS_Object.h"
 #include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/cjs_context.h"
+#include "fpdfsdk/javascript/cjs_event_context.h"
 
 namespace {
 
@@ -19,17 +19,15 @@
 
 }  // namespace
 
-BEGIN_JS_STATIC_CONST(CJS_Annot)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Annot::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
 
-BEGIN_JS_STATIC_PROP(CJS_Annot)
-JS_STATIC_PROP_ENTRY(hidden)
-JS_STATIC_PROP_ENTRY(name)
-JS_STATIC_PROP_ENTRY(type)
-END_JS_STATIC_PROP()
+JSPropertySpec CJS_Annot::PropertySpecs[] = {
+    {"hidden", get_hidden_static, set_hidden_static},
+    {"name", get_name_static, set_name_static},
+    {"type", get_type_static, set_type_static},
+    {0, 0, 0}};
 
-BEGIN_JS_STATIC_METHOD(CJS_Annot)
-END_JS_STATIC_METHOD()
+JSMethodSpec CJS_Annot::MethodSpecs[] = {{0, 0}};
 
 IMPLEMENT_JS_CLASS(CJS_Annot, Annot)
 
@@ -37,7 +35,9 @@
 
 Annot::~Annot() {}
 
-bool Annot::hidden(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool Annot::hidden(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError) {
   if (vp.IsGetting()) {
     if (!m_pAnnot) {
       sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
@@ -71,7 +71,9 @@
   return true;
 }
 
-bool Annot::name(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool Annot::name(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError) {
   if (vp.IsGetting()) {
     if (!m_pAnnot) {
       sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
@@ -92,7 +94,9 @@
   return true;
 }
 
-bool Annot::type(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool Annot::type(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError) {
   if (vp.IsSetting()) {
     sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
     return false;
diff --git a/fpdfsdk/javascript/Annot.h b/fpdfsdk/javascript/Annot.h
index 39073e6..d9757fa 100644
--- a/fpdfsdk/javascript/Annot.h
+++ b/fpdfsdk/javascript/Annot.h
@@ -17,9 +17,9 @@
   explicit Annot(CJS_Object* pJSObject);
   ~Annot() override;
 
-  bool hidden(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool name(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool type(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
+  bool hidden(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool name(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool type(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
 
   void SetSDKAnnot(CPDFSDK_BAAnnot* annot);
 
diff --git a/fpdfsdk/javascript/Consts.cpp b/fpdfsdk/javascript/Consts.cpp
index c224ad0..82f9b4c 100644
--- a/fpdfsdk/javascript/Consts.cpp
+++ b/fpdfsdk/javascript/Consts.cpp
@@ -10,93 +10,92 @@
 #include "fpdfsdk/javascript/JS_Object.h"
 #include "fpdfsdk/javascript/JS_Value.h"
 
-BEGIN_JS_STATIC_CONST(CJS_Border)
-JS_STATIC_CONST_ENTRY_STRING(L"s", L"solid")
-JS_STATIC_CONST_ENTRY_STRING(L"b", L"beveled")
-JS_STATIC_CONST_ENTRY_STRING(L"d", L"dashed")
-JS_STATIC_CONST_ENTRY_STRING(L"i", L"inset")
-JS_STATIC_CONST_ENTRY_STRING(L"u", L"underline")
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Border::ConstSpecs[] = {
+    {"s", JSConstSpec::String, 0, "solid"},
+    {"b", JSConstSpec::String, 0, "beveled"},
+    {"d", JSConstSpec::String, 0, "dashed"},
+    {"i", JSConstSpec::String, 0, "inset"},
+    {"u", JSConstSpec::String, 0, "underline"},
+    {0, JSConstSpec::Number, 0, 0}};
 IMPLEMENT_JS_CLASS_CONST(CJS_Border, border)
 
-BEGIN_JS_STATIC_CONST(CJS_Display)
-JS_STATIC_CONST_ENTRY_NUMBER(L"visible", 0)
-JS_STATIC_CONST_ENTRY_NUMBER(L"hidden", 1)
-JS_STATIC_CONST_ENTRY_NUMBER(L"noPrint", 2)
-JS_STATIC_CONST_ENTRY_NUMBER(L"noView", 3)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Display::ConstSpecs[] = {{"visible", JSConstSpec::Number, 0, 0},
+                                         {"hidden", JSConstSpec::Number, 1, 0},
+                                         {"noPrint", JSConstSpec::Number, 2, 0},
+                                         {"noView", JSConstSpec::Number, 3, 0},
+                                         {0, JSConstSpec::Number, 0, 0}};
 IMPLEMENT_JS_CLASS_CONST(CJS_Display, display)
 
-BEGIN_JS_STATIC_CONST(CJS_Font)
-JS_STATIC_CONST_ENTRY_STRING(L"Times", L"Times-Roman")
-JS_STATIC_CONST_ENTRY_STRING(L"TimesB", L"Times-Bold")
-JS_STATIC_CONST_ENTRY_STRING(L"TimesI", L"Times-Italic")
-JS_STATIC_CONST_ENTRY_STRING(L"TimesBI", L"Times-BoldItalic")
-JS_STATIC_CONST_ENTRY_STRING(L"Helv", L"Helvetica")
-JS_STATIC_CONST_ENTRY_STRING(L"HelvB", L"Helvetica-Bold")
-JS_STATIC_CONST_ENTRY_STRING(L"HelvI", L"Helvetica-Oblique")
-JS_STATIC_CONST_ENTRY_STRING(L"HelvBI", L"Helvetica-BoldOblique")
-JS_STATIC_CONST_ENTRY_STRING(L"Cour", L"Courier")
-JS_STATIC_CONST_ENTRY_STRING(L"CourB", L"Courier-Bold")
-JS_STATIC_CONST_ENTRY_STRING(L"CourI", L"Courier-Oblique")
-JS_STATIC_CONST_ENTRY_STRING(L"CourBI", L"Courier-BoldOblique")
-JS_STATIC_CONST_ENTRY_STRING(L"Symbol", L"Symbol")
-JS_STATIC_CONST_ENTRY_STRING(L"ZapfD", L"ZapfDingbats")
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Font::ConstSpecs[] = {
+    {"Times", JSConstSpec::String, 0, "Times-Roman"},
+    {"TimesB", JSConstSpec::String, 0, "Times-Bold"},
+    {"TimesI", JSConstSpec::String, 0, "Times-Italic"},
+    {"TimesBI", JSConstSpec::String, 0, "Times-BoldItalic"},
+    {"Helv", JSConstSpec::String, 0, "Helvetica"},
+    {"HelvB", JSConstSpec::String, 0, "Helvetica-Bold"},
+    {"HelvI", JSConstSpec::String, 0, "Helvetica-Oblique"},
+    {"HelvBI", JSConstSpec::String, 0, "Helvetica-BoldOblique"},
+    {"Cour", JSConstSpec::String, 0, "Courier"},
+    {"CourB", JSConstSpec::String, 0, "Courier-Bold"},
+    {"CourI", JSConstSpec::String, 0, "Courier-Oblique"},
+    {"CourBI", JSConstSpec::String, 0, "Courier-BoldOblique"},
+    {"Symbol", JSConstSpec::String, 0, "Symbol"},
+    {"ZapfD", JSConstSpec::String, 0, "ZapfDingbats"},
+    {0, JSConstSpec::Number, 0, 0}};
 IMPLEMENT_JS_CLASS_CONST(CJS_Font, font)
 
-BEGIN_JS_STATIC_CONST(CJS_Highlight)
-JS_STATIC_CONST_ENTRY_STRING(L"n", L"none")
-JS_STATIC_CONST_ENTRY_STRING(L"i", L"invert")
-JS_STATIC_CONST_ENTRY_STRING(L"p", L"push")
-JS_STATIC_CONST_ENTRY_STRING(L"o", L"outline")
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Highlight::ConstSpecs[] = {
+    {"n", JSConstSpec::String, 0, "none"},
+    {"i", JSConstSpec::String, 0, "invert"},
+    {"p", JSConstSpec::String, 0, "push"},
+    {"o", JSConstSpec::String, 0, "outline"},
+    {0, JSConstSpec::Number, 0, 0}};
 IMPLEMENT_JS_CLASS_CONST(CJS_Highlight, highlight)
 
-BEGIN_JS_STATIC_CONST(CJS_Position)
-JS_STATIC_CONST_ENTRY_NUMBER(L"textOnly", 0)
-JS_STATIC_CONST_ENTRY_NUMBER(L"iconOnly", 1)
-JS_STATIC_CONST_ENTRY_NUMBER(L"iconTextV", 2)
-JS_STATIC_CONST_ENTRY_NUMBER(L"textIconV", 3)
-JS_STATIC_CONST_ENTRY_NUMBER(L"iconTextH", 4)
-JS_STATIC_CONST_ENTRY_NUMBER(L"textIconH", 5)
-JS_STATIC_CONST_ENTRY_NUMBER(L"overlay", 6)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Position::ConstSpecs[] = {
+    {"textOnly", JSConstSpec::Number, 0, 0},
+    {"iconOnly", JSConstSpec::Number, 1, 0},
+    {"iconTextV", JSConstSpec::Number, 2, 0},
+    {"textIconV", JSConstSpec::Number, 3, 0},
+    {"iconTextH", JSConstSpec::Number, 4, 0},
+    {"textIconH", JSConstSpec::Number, 5, 0},
+    {"overlay", JSConstSpec::Number, 6, 0},
+    {0, JSConstSpec::Number, 0, 0}};
 IMPLEMENT_JS_CLASS_CONST(CJS_Position, position)
 
-BEGIN_JS_STATIC_CONST(CJS_ScaleHow)
-JS_STATIC_CONST_ENTRY_NUMBER(L"proportional", 0)
-JS_STATIC_CONST_ENTRY_NUMBER(L"anamorphic", 1)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_ScaleHow::ConstSpecs[] = {
+    {"proportional", JSConstSpec::Number, 0, 0},
+    {"anamorphic", JSConstSpec::Number, 1, 0},
+    {0, JSConstSpec::Number, 0, 0}};
 IMPLEMENT_JS_CLASS_CONST(CJS_ScaleHow, scaleHow)
 
-BEGIN_JS_STATIC_CONST(CJS_ScaleWhen)
-JS_STATIC_CONST_ENTRY_NUMBER(L"always", 0)
-JS_STATIC_CONST_ENTRY_NUMBER(L"never", 1)
-JS_STATIC_CONST_ENTRY_NUMBER(L"tooBig", 2)
-JS_STATIC_CONST_ENTRY_NUMBER(L"tooSmall", 3)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_ScaleWhen::ConstSpecs[] = {
+    {"always", JSConstSpec::Number, 0, 0},
+    {"never", JSConstSpec::Number, 1, 0},
+    {"tooBig", JSConstSpec::Number, 2, 0},
+    {"tooSmall", JSConstSpec::Number, 3, 0},
+    {0, JSConstSpec::Number, 0, 0}};
 IMPLEMENT_JS_CLASS_CONST(CJS_ScaleWhen, scaleWhen)
 
-BEGIN_JS_STATIC_CONST(CJS_Style)
-JS_STATIC_CONST_ENTRY_STRING(L"ch", L"check")
-JS_STATIC_CONST_ENTRY_STRING(L"cr", L"cross")
-JS_STATIC_CONST_ENTRY_STRING(L"di", L"diamond")
-JS_STATIC_CONST_ENTRY_STRING(L"ci", L"circle")
-JS_STATIC_CONST_ENTRY_STRING(L"st", L"star")
-JS_STATIC_CONST_ENTRY_STRING(L"sq", L"square")
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Style::ConstSpecs[] = {
+    {"ch", JSConstSpec::String, 0, "check"},
+    {"cr", JSConstSpec::String, 0, "cross"},
+    {"di", JSConstSpec::String, 0, "diamond"},
+    {"ci", JSConstSpec::String, 0, "circle"},
+    {"st", JSConstSpec::String, 0, "star"},
+    {"sq", JSConstSpec::String, 0, "square"},
+    {0, JSConstSpec::Number, 0, 0}};
 IMPLEMENT_JS_CLASS_CONST(CJS_Style, style)
 
-BEGIN_JS_STATIC_CONST(CJS_Zoomtype)
-JS_STATIC_CONST_ENTRY_STRING(L"none", L"NoVary")
-JS_STATIC_CONST_ENTRY_STRING(L"fitP", L"FitPage")
-JS_STATIC_CONST_ENTRY_STRING(L"fitW", L"FitWidth")
-JS_STATIC_CONST_ENTRY_STRING(L"fitH", L"FitHeight")
-JS_STATIC_CONST_ENTRY_STRING(L"fitV", L"FitVisibleWidth")
-JS_STATIC_CONST_ENTRY_STRING(L"pref", L"Preferred")
-JS_STATIC_CONST_ENTRY_STRING(L"refW", L"ReflowWidth")
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Zoomtype::ConstSpecs[] = {
+    {"none", JSConstSpec::String, 0, "NoVary"},
+    {"fitP", JSConstSpec::String, 0, "FitPage"},
+    {"fitW", JSConstSpec::String, 0, "FitWidth"},
+    {"fitH", JSConstSpec::String, 0, "FitHeight"},
+    {"fitV", JSConstSpec::String, 0, "FitVisibleWidth"},
+    {"pref", JSConstSpec::String, 0, "Preferred"},
+    {"refW", JSConstSpec::String, 0, "ReflowWidth"},
+    {0, JSConstSpec::Number, 0, 0}};
 IMPLEMENT_JS_CLASS_CONST(CJS_Zoomtype, zoomtype)
 
 #define GLOBAL_STRING(rt, name, value)                                \
diff --git a/fpdfsdk/javascript/Document.cpp b/fpdfsdk/javascript/Document.cpp
index 4bf1afd..a45b8b9 100644
--- a/fpdfsdk/javascript/Document.cpp
+++ b/fpdfsdk/javascript/Document.cpp
@@ -6,6 +6,7 @@
 
 #include "fpdfsdk/javascript/Document.h"
 
+#include <algorithm>
 #include <utility>
 #include <vector>
 
@@ -30,20 +31,17 @@
 #include "fpdfsdk/javascript/JS_Object.h"
 #include "fpdfsdk/javascript/JS_Value.h"
 #include "fpdfsdk/javascript/app.h"
-#include "fpdfsdk/javascript/cjs_context.h"
+#include "fpdfsdk/javascript/cjs_event_context.h"
 #include "fpdfsdk/javascript/cjs_runtime.h"
 #include "fpdfsdk/javascript/resource.h"
 #include "third_party/base/numerics/safe_math.h"
 #include "third_party/base/ptr_util.h"
 
-BEGIN_JS_STATIC_CONST(CJS_PrintParamsObj)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_PrintParamsObj::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
 
-BEGIN_JS_STATIC_PROP(CJS_PrintParamsObj)
-END_JS_STATIC_PROP()
+JSPropertySpec CJS_PrintParamsObj::PropertySpecs[] = {{0, 0, 0}};
 
-BEGIN_JS_STATIC_METHOD(CJS_PrintParamsObj)
-END_JS_STATIC_METHOD()
+JSMethodSpec CJS_PrintParamsObj::MethodSpecs[] = {{0, 0}};
 
 IMPLEMENT_JS_CLASS(CJS_PrintParamsObj, PrintParamsObj)
 
@@ -62,88 +60,88 @@
 #define MINWIDTH 5.0f
 #define MINHEIGHT 5.0f
 
-BEGIN_JS_STATIC_CONST(CJS_Document)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Document::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
 
-BEGIN_JS_STATIC_PROP(CJS_Document)
-JS_STATIC_PROP_ENTRY(ADBE)
-JS_STATIC_PROP_ENTRY(author)
-JS_STATIC_PROP_ENTRY(baseURL)
-JS_STATIC_PROP_ENTRY(bookmarkRoot)
-JS_STATIC_PROP_ENTRY(calculate)
-JS_STATIC_PROP_ENTRY(Collab)
-JS_STATIC_PROP_ENTRY(creationDate)
-JS_STATIC_PROP_ENTRY(creator)
-JS_STATIC_PROP_ENTRY(delay)
-JS_STATIC_PROP_ENTRY(dirty)
-JS_STATIC_PROP_ENTRY(documentFileName)
-JS_STATIC_PROP_ENTRY(external)
-JS_STATIC_PROP_ENTRY(filesize)
-JS_STATIC_PROP_ENTRY(icons)
-JS_STATIC_PROP_ENTRY(info)
-JS_STATIC_PROP_ENTRY(keywords)
-JS_STATIC_PROP_ENTRY(layout)
-JS_STATIC_PROP_ENTRY(media)
-JS_STATIC_PROP_ENTRY(modDate)
-JS_STATIC_PROP_ENTRY(mouseX)
-JS_STATIC_PROP_ENTRY(mouseY)
-JS_STATIC_PROP_ENTRY(numFields)
-JS_STATIC_PROP_ENTRY(numPages)
-JS_STATIC_PROP_ENTRY(pageNum)
-JS_STATIC_PROP_ENTRY(pageWindowRect)
-JS_STATIC_PROP_ENTRY(path)
-JS_STATIC_PROP_ENTRY(producer)
-JS_STATIC_PROP_ENTRY(subject)
-JS_STATIC_PROP_ENTRY(title)
-JS_STATIC_PROP_ENTRY(URL)
-JS_STATIC_PROP_ENTRY(zoom)
-JS_STATIC_PROP_ENTRY(zoomType)
-END_JS_STATIC_PROP()
+JSPropertySpec CJS_Document::PropertySpecs[] = {
+    {"ADBE", get_ADBE_static, set_ADBE_static},
+    {"author", get_author_static, set_author_static},
+    {"baseURL", get_baseURL_static, set_baseURL_static},
+    {"bookmarkRoot", get_bookmarkRoot_static, set_bookmarkRoot_static},
+    {"calculate", get_calculate_static, set_calculate_static},
+    {"Collab", get_Collab_static, set_Collab_static},
+    {"creationDate", get_creationDate_static, set_creationDate_static},
+    {"creator", get_creator_static, set_creator_static},
+    {"delay", get_delay_static, set_delay_static},
+    {"dirty", get_dirty_static, set_dirty_static},
+    {"documentFileName", get_documentFileName_static,
+     set_documentFileName_static},
+    {"external", get_external_static, set_external_static},
+    {"filesize", get_filesize_static, set_filesize_static},
+    {"icons", get_icons_static, set_icons_static},
+    {"info", get_info_static, set_info_static},
+    {"keywords", get_keywords_static, set_keywords_static},
+    {"layout", get_layout_static, set_layout_static},
+    {"media", get_media_static, set_media_static},
+    {"modDate", get_modDate_static, set_modDate_static},
+    {"mouseX", get_mouseX_static, set_mouseX_static},
+    {"mouseY", get_mouseY_static, set_mouseY_static},
+    {"numFields", get_numFields_static, set_numFields_static},
+    {"numPages", get_numPages_static, set_numPages_static},
+    {"pageNum", get_pageNum_static, set_pageNum_static},
+    {"pageWindowRect", get_pageWindowRect_static, set_pageWindowRect_static},
+    {"path", get_path_static, set_path_static},
+    {"producer", get_producer_static, set_producer_static},
+    {"subject", get_subject_static, set_subject_static},
+    {"title", get_title_static, set_title_static},
+    {"URL", get_URL_static, set_URL_static},
+    {"zoom", get_zoom_static, set_zoom_static},
+    {"zoomType", get_zoomType_static, set_zoomType_static},
+    {0, 0, 0}};
 
-BEGIN_JS_STATIC_METHOD(CJS_Document)
-JS_STATIC_METHOD_ENTRY(addAnnot)
-JS_STATIC_METHOD_ENTRY(addField)
-JS_STATIC_METHOD_ENTRY(addLink)
-JS_STATIC_METHOD_ENTRY(addIcon)
-JS_STATIC_METHOD_ENTRY(calculateNow)
-JS_STATIC_METHOD_ENTRY(closeDoc)
-JS_STATIC_METHOD_ENTRY(createDataObject)
-JS_STATIC_METHOD_ENTRY(deletePages)
-JS_STATIC_METHOD_ENTRY(exportAsText)
-JS_STATIC_METHOD_ENTRY(exportAsFDF)
-JS_STATIC_METHOD_ENTRY(exportAsXFDF)
-JS_STATIC_METHOD_ENTRY(extractPages)
-JS_STATIC_METHOD_ENTRY(getAnnot)
-JS_STATIC_METHOD_ENTRY(getAnnots)
-JS_STATIC_METHOD_ENTRY(getAnnot3D)
-JS_STATIC_METHOD_ENTRY(getAnnots3D)
-JS_STATIC_METHOD_ENTRY(getField)
-JS_STATIC_METHOD_ENTRY(getIcon)
-JS_STATIC_METHOD_ENTRY(getLinks)
-JS_STATIC_METHOD_ENTRY(getNthFieldName)
-JS_STATIC_METHOD_ENTRY(getOCGs)
-JS_STATIC_METHOD_ENTRY(getPageBox)
-JS_STATIC_METHOD_ENTRY(getPageNthWord)
-JS_STATIC_METHOD_ENTRY(getPageNthWordQuads)
-JS_STATIC_METHOD_ENTRY(getPageNumWords)
-JS_STATIC_METHOD_ENTRY(getPrintParams)
-JS_STATIC_METHOD_ENTRY(getURL)
-JS_STATIC_METHOD_ENTRY(gotoNamedDest)
-JS_STATIC_METHOD_ENTRY(importAnFDF)
-JS_STATIC_METHOD_ENTRY(importAnXFDF)
-JS_STATIC_METHOD_ENTRY(importTextData)
-JS_STATIC_METHOD_ENTRY(insertPages)
-JS_STATIC_METHOD_ENTRY(mailForm)
-JS_STATIC_METHOD_ENTRY(print)
-JS_STATIC_METHOD_ENTRY(removeField)
-JS_STATIC_METHOD_ENTRY(replacePages)
-JS_STATIC_METHOD_ENTRY(resetForm)
-JS_STATIC_METHOD_ENTRY(removeIcon)
-JS_STATIC_METHOD_ENTRY(saveAs)
-JS_STATIC_METHOD_ENTRY(submitForm)
-JS_STATIC_METHOD_ENTRY(syncAnnotScan)
-JS_STATIC_METHOD_ENTRY(mailDoc)
-END_JS_STATIC_METHOD()
+JSMethodSpec CJS_Document::MethodSpecs[] = {
+    {"addAnnot", addAnnot_static},
+    {"addField", addField_static},
+    {"addLink", addLink_static},
+    {"addIcon", addIcon_static},
+    {"calculateNow", calculateNow_static},
+    {"closeDoc", closeDoc_static},
+    {"createDataObject", createDataObject_static},
+    {"deletePages", deletePages_static},
+    {"exportAsText", exportAsText_static},
+    {"exportAsFDF", exportAsFDF_static},
+    {"exportAsXFDF", exportAsXFDF_static},
+    {"extractPages", extractPages_static},
+    {"getAnnot", getAnnot_static},
+    {"getAnnots", getAnnots_static},
+    {"getAnnot3D", getAnnot3D_static},
+    {"getAnnots3D", getAnnots3D_static},
+    {"getField", getField_static},
+    {"getIcon", getIcon_static},
+    {"getLinks", getLinks_static},
+    {"getNthFieldName", getNthFieldName_static},
+    {"getOCGs", getOCGs_static},
+    {"getPageBox", getPageBox_static},
+    {"getPageNthWord", getPageNthWord_static},
+    {"getPageNthWordQuads", getPageNthWordQuads_static},
+    {"getPageNumWords", getPageNumWords_static},
+    {"getPrintParams", getPrintParams_static},
+    {"getURL", getURL_static},
+    {"gotoNamedDest", gotoNamedDest_static},
+    {"importAnFDF", importAnFDF_static},
+    {"importAnXFDF", importAnXFDF_static},
+    {"importTextData", importTextData_static},
+    {"insertPages", insertPages_static},
+    {"mailForm", mailForm_static},
+    {"print", print_static},
+    {"removeField", removeField_static},
+    {"replacePages", replacePages_static},
+    {"resetForm", resetForm_static},
+    {"removeIcon", removeIcon_static},
+    {"saveAs", saveAs_static},
+    {"submitForm", submitForm_static},
+    {"syncAnnotScan", syncAnnotScan_static},
+    {"mailDoc", mailDoc_static},
+    {0, 0}};
 
 IMPLEMENT_JS_CLASS(CJS_Document, Document)
 
@@ -163,7 +161,7 @@
 }
 
 // the total number of fileds in document.
-bool Document::numFields(IJS_Context* cc,
+bool Document::numFields(CJS_Runtime* pRuntime,
                          CJS_PropValue& vp,
                          CFX_WideString& sError) {
   if (vp.IsSetting()) {
@@ -180,7 +178,7 @@
   return true;
 }
 
-bool Document::dirty(IJS_Context* cc,
+bool Document::dirty(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   if (!m_pFormFillEnv) {
@@ -189,28 +187,28 @@
   }
   if (vp.IsGetting()) {
     vp << !!m_pFormFillEnv->GetChangeMark();
-  } else {
-    bool bChanged = false;
-    vp >> bChanged;
-
-    if (bChanged)
-      m_pFormFillEnv->SetChangeMark();
-    else
-      m_pFormFillEnv->ClearChangeMark();
+    return true;
   }
+  bool bChanged = false;
+  vp >> bChanged;
+  if (bChanged)
+    m_pFormFillEnv->SetChangeMark();
+  else
+    m_pFormFillEnv->ClearChangeMark();
+
   return true;
 }
 
-bool Document::ADBE(IJS_Context* cc,
+bool Document::ADBE(CJS_Runtime* pRuntime,
                     CJS_PropValue& vp,
                     CFX_WideString& sError) {
   if (vp.IsGetting())
-    vp.GetJSValue()->SetNull(CJS_Runtime::FromContext(cc));
+    vp.GetJSValue()->SetNull(pRuntime);
 
   return true;
 }
 
-bool Document::pageNum(IJS_Context* cc,
+bool Document::pageNum(CJS_Runtime* pRuntime,
                        CJS_PropValue& vp,
                        CFX_WideString& sError) {
   if (!m_pFormFillEnv) {
@@ -218,27 +216,24 @@
     return false;
   }
   if (vp.IsGetting()) {
-    if (CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetCurrentView()) {
+    if (CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetCurrentView())
       vp << pPageView->GetPageIndex();
-    }
-  } else {
-    int iPageCount = m_pFormFillEnv->GetPageCount();
-    int iPageNum = 0;
-    vp >> iPageNum;
-
-    if (iPageNum >= 0 && iPageNum < iPageCount) {
-      m_pFormFillEnv->JS_docgotoPage(iPageNum);
-    } else if (iPageNum >= iPageCount) {
-      m_pFormFillEnv->JS_docgotoPage(iPageCount - 1);
-    } else if (iPageNum < 0) {
-      m_pFormFillEnv->JS_docgotoPage(0);
-    }
+    return true;
   }
+  int iPageCount = m_pFormFillEnv->GetPageCount();
+  int iPageNum = 0;
+  vp >> iPageNum;
+  if (iPageNum >= 0 && iPageNum < iPageCount)
+    m_pFormFillEnv->JS_docgotoPage(iPageNum);
+  else if (iPageNum >= iPageCount)
+    m_pFormFillEnv->JS_docgotoPage(iPageCount - 1);
+  else if (iPageNum < 0)
+    m_pFormFillEnv->JS_docgotoPage(0);
 
   return true;
 }
 
-bool Document::addAnnot(IJS_Context* cc,
+bool Document::addAnnot(CJS_Runtime* pRuntime,
                         const std::vector<CJS_Value>& params,
                         CJS_Value& vRet,
                         CFX_WideString& sError) {
@@ -246,7 +241,7 @@
   return true;
 }
 
-bool Document::addField(IJS_Context* cc,
+bool Document::addField(CJS_Runtime* pRuntime,
                         const std::vector<CJS_Value>& params,
                         CJS_Value& vRet,
                         CFX_WideString& sError) {
@@ -254,7 +249,7 @@
   return true;
 }
 
-bool Document::exportAsText(IJS_Context* cc,
+bool Document::exportAsText(CJS_Runtime* pRuntime,
                             const std::vector<CJS_Value>& params,
                             CJS_Value& vRet,
                             CFX_WideString& sError) {
@@ -262,7 +257,7 @@
   return true;
 }
 
-bool Document::exportAsFDF(IJS_Context* cc,
+bool Document::exportAsFDF(CJS_Runtime* pRuntime,
                            const std::vector<CJS_Value>& params,
                            CJS_Value& vRet,
                            CFX_WideString& sError) {
@@ -270,7 +265,7 @@
   return true;
 }
 
-bool Document::exportAsXFDF(IJS_Context* cc,
+bool Document::exportAsXFDF(CJS_Runtime* pRuntime,
                             const std::vector<CJS_Value>& params,
                             CJS_Value& vRet,
                             CFX_WideString& sError) {
@@ -283,7 +278,7 @@
 // note: the paremter cName, this is clue how to treat if the cName is not a
 // valiable filed name in this document
 
-bool Document::getField(IJS_Context* cc,
+bool Document::getField(CJS_Runtime* pRuntime,
                         const std::vector<CJS_Value>& params,
                         CJS_Value& vRet,
                         CFX_WideString& sError) {
@@ -295,8 +290,6 @@
     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
     return false;
   }
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
   CFX_WideString wideName = params[0].ToCFXWideString(pRuntime);
   CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
   CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
@@ -307,17 +300,19 @@
 
   v8::Local<v8::Object> pFieldObj =
       pRuntime->NewFxDynamicObj(CJS_Field::g_nObjDefnID);
+  if (pFieldObj.IsEmpty())
+    return false;
+
   CJS_Field* pJSField =
       static_cast<CJS_Field*>(pRuntime->GetObjectPrivate(pFieldObj));
   Field* pField = static_cast<Field*>(pJSField->GetEmbedObject());
   pField->AttachField(this, wideName);
-
   vRet = CJS_Value(pRuntime, pJSField);
   return true;
 }
 
 // Gets the name of the nth field in the document
-bool Document::getNthFieldName(IJS_Context* cc,
+bool Document::getNthFieldName(CJS_Runtime* pRuntime,
                                const std::vector<CJS_Value>& params,
                                CJS_Value& vRet,
                                CFX_WideString& sError) {
@@ -329,8 +324,6 @@
     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
     return false;
   }
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
   int nIndex = params[0].ToInt(pRuntime);
   if (nIndex < 0) {
     sError = JSGetStringFromID(IDS_STRING_JSVALUEERROR);
@@ -346,7 +339,7 @@
   return true;
 }
 
-bool Document::importAnFDF(IJS_Context* cc,
+bool Document::importAnFDF(CJS_Runtime* pRuntime,
                            const std::vector<CJS_Value>& params,
                            CJS_Value& vRet,
                            CFX_WideString& sError) {
@@ -354,7 +347,7 @@
   return true;
 }
 
-bool Document::importAnXFDF(IJS_Context* cc,
+bool Document::importAnXFDF(CJS_Runtime* pRuntime,
                             const std::vector<CJS_Value>& params,
                             CJS_Value& vRet,
                             CFX_WideString& sError) {
@@ -362,7 +355,7 @@
   return true;
 }
 
-bool Document::importTextData(IJS_Context* cc,
+bool Document::importTextData(CJS_Runtime* pRuntime,
                               const std::vector<CJS_Value>& params,
                               CJS_Value& vRet,
                               CFX_WideString& sError) {
@@ -373,7 +366,7 @@
 // exports the form data and mails the resulting fdf file as an attachment to
 // all recipients.
 // comment: need reader supports
-bool Document::mailForm(IJS_Context* cc,
+bool Document::mailForm(CJS_Runtime* pRuntime,
                         const std::vector<CJS_Value>& params,
                         CJS_Value& vRet,
                         CFX_WideString& sError) {
@@ -385,10 +378,6 @@
     sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
     return false;
   }
-
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-
   int iLength = params.size();
   bool bUI = iLength > 0 ? params[0].ToBool(pRuntime) : true;
   CFX_WideString cTo = iLength > 1 ? params[1].ToCFXWideString(pRuntime) : L"";
@@ -397,14 +386,13 @@
   CFX_WideString cSubject =
       iLength > 4 ? params[4].ToCFXWideString(pRuntime) : L"";
   CFX_WideString cMsg = iLength > 5 ? params[5].ToCFXWideString(pRuntime) : L"";
-
   CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
   CFX_ByteTextBuf textBuf;
   if (!pInterForm->ExportFormToFDFTextBuf(textBuf))
     return false;
 
   pRuntime->BeginBlock();
-  CPDFSDK_FormFillEnvironment* pFormFillEnv = pContext->GetFormFillEnv();
+  CPDFSDK_FormFillEnvironment* pFormFillEnv = pRuntime->GetFormFillEnv();
   pFormFillEnv->JS_docmailForm(textBuf.GetBuffer(), textBuf.GetLength(), bUI,
                                cTo.c_str(), cSubject.c_str(), cCc.c_str(),
                                cBcc.c_str(), cMsg.c_str());
@@ -412,7 +400,7 @@
   return true;
 }
 
-bool Document::print(IJS_Context* cc,
+bool Document::print(CJS_Runtime* pRuntime,
                      const std::vector<CJS_Value>& params,
                      CJS_Value& vRet,
                      CFX_WideString& sError) {
@@ -420,10 +408,6 @@
     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
     return false;
   }
-
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-
   bool bUI = true;
   int nStart = 0;
   int nEnd = 0;
@@ -432,7 +416,6 @@
   bool bPrintAsImage = false;
   bool bReverse = false;
   bool bAnnotations = false;
-
   int nlength = params.size();
   if (nlength == 9) {
     if (params[8].GetType() == CJS_Value::VT_object) {
@@ -485,7 +468,7 @@
 // comment:
 // note: if the filed name is not rational, adobe is dumb for it.
 
-bool Document::removeField(IJS_Context* cc,
+bool Document::removeField(CJS_Runtime* pRuntime,
                            const std::vector<CJS_Value>& params,
                            CJS_Value& vRet,
                            CFX_WideString& sError) {
@@ -502,8 +485,6 @@
     sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
     return false;
   }
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
   CFX_WideString sFieldName = params[0].ToCFXWideString(pRuntime);
   CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
   std::vector<CPDFSDK_Annot::ObservedPtr> widgets;
@@ -546,7 +527,7 @@
 // comment:
 // note: if the fields names r not rational, aodbe is dumb for it.
 
-bool Document::resetForm(IJS_Context* cc,
+bool Document::resetForm(CJS_Runtime* pRuntime,
                          const std::vector<CJS_Value>& params,
                          CJS_Value& vRet,
                          CFX_WideString& sError) {
@@ -571,9 +552,6 @@
     return true;
   }
 
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-
   switch (params[0].GetType()) {
     default:
       aName.Attach(params[0].ToV8Array(pRuntime));
@@ -600,7 +578,7 @@
   return true;
 }
 
-bool Document::saveAs(IJS_Context* cc,
+bool Document::saveAs(CJS_Runtime* pRuntime,
                       const std::vector<CJS_Value>& params,
                       CJS_Value& vRet,
                       CFX_WideString& sError) {
@@ -608,14 +586,14 @@
   return true;
 }
 
-bool Document::syncAnnotScan(IJS_Context* cc,
+bool Document::syncAnnotScan(CJS_Runtime* pRuntime,
                              const std::vector<CJS_Value>& params,
                              CJS_Value& vRet,
                              CFX_WideString& sError) {
   return true;
 }
 
-bool Document::submitForm(IJS_Context* cc,
+bool Document::submitForm(CJS_Runtime* pRuntime,
                           const std::vector<CJS_Value>& params,
                           CJS_Value& vRet,
                           CFX_WideString& sError) {
@@ -628,8 +606,7 @@
     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
     return false;
   }
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
+
   CJS_Array aFields;
   CFX_WideString strURL;
   bool bFDF = true;
@@ -698,20 +675,17 @@
   m_pFormFillEnv.Reset(pFormFillEnv);
 }
 
-bool Document::bookmarkRoot(IJS_Context* cc,
+bool Document::bookmarkRoot(CJS_Runtime* pRuntime,
                             CJS_PropValue& vp,
                             CFX_WideString& sError) {
   return true;
 }
 
-bool Document::mailDoc(IJS_Context* cc,
+bool Document::mailDoc(CJS_Runtime* pRuntime,
                        const std::vector<CJS_Value>& params,
                        CJS_Value& vRet,
                        CFX_WideString& sError) {
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-
   // TODO(tsepez): Check maximum number of allowed params.
-
   bool bUI = true;
   CFX_WideString cTo = L"";
   CFX_WideString cCc = L"";
@@ -719,8 +693,6 @@
   CFX_WideString cSubject = L"";
   CFX_WideString cMsg = L"";
 
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-
   if (params.size() >= 1)
     bUI = params[0].ToBool(pRuntime);
   if (params.size() >= 2)
@@ -761,17 +733,16 @@
   pFormFillEnv->JS_docmailForm(nullptr, 0, bUI, cTo.c_str(), cSubject.c_str(),
                                cCc.c_str(), cBcc.c_str(), cMsg.c_str());
   pRuntime->EndBlock();
-
   return true;
 }
 
-bool Document::author(IJS_Context* cc,
+bool Document::author(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
-  return getPropertyInternal(cc, vp, "Author", sError);
+  return getPropertyInternal(pRuntime, vp, "Author", sError);
 }
 
-bool Document::info(IJS_Context* cc,
+bool Document::info(CJS_Runtime* pRuntime,
                     CJS_PropValue& vp,
                     CFX_WideString& sError) {
   if (vp.IsSetting()) {
@@ -797,22 +768,25 @@
   CFX_WideString cwModDate = pDictionary->GetUnicodeTextFor("ModDate");
   CFX_WideString cwTrapped = pDictionary->GetUnicodeTextFor("Trapped");
 
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-
   v8::Local<v8::Object> pObj = pRuntime->NewFxDynamicObj(-1);
-  pRuntime->PutObjectProperty(pObj, L"Author", pRuntime->NewString(cwAuthor));
-  pRuntime->PutObjectProperty(pObj, L"Title", pRuntime->NewString(cwTitle));
-  pRuntime->PutObjectProperty(pObj, L"Subject", pRuntime->NewString(cwSubject));
+  pRuntime->PutObjectProperty(pObj, L"Author",
+                              pRuntime->NewString(cwAuthor.AsStringC()));
+  pRuntime->PutObjectProperty(pObj, L"Title",
+                              pRuntime->NewString(cwTitle.AsStringC()));
+  pRuntime->PutObjectProperty(pObj, L"Subject",
+                              pRuntime->NewString(cwSubject.AsStringC()));
   pRuntime->PutObjectProperty(pObj, L"Keywords",
-                              pRuntime->NewString(cwKeywords));
-  pRuntime->PutObjectProperty(pObj, L"Creator", pRuntime->NewString(cwCreator));
+                              pRuntime->NewString(cwKeywords.AsStringC()));
+  pRuntime->PutObjectProperty(pObj, L"Creator",
+                              pRuntime->NewString(cwCreator.AsStringC()));
   pRuntime->PutObjectProperty(pObj, L"Producer",
-                              pRuntime->NewString(cwProducer));
+                              pRuntime->NewString(cwProducer.AsStringC()));
   pRuntime->PutObjectProperty(pObj, L"CreationDate",
-                              pRuntime->NewString(cwCreationDate));
-  pRuntime->PutObjectProperty(pObj, L"ModDate", pRuntime->NewString(cwModDate));
-  pRuntime->PutObjectProperty(pObj, L"Trapped", pRuntime->NewString(cwTrapped));
+                              pRuntime->NewString(cwCreationDate.AsStringC()));
+  pRuntime->PutObjectProperty(pObj, L"ModDate",
+                              pRuntime->NewString(cwModDate.AsStringC()));
+  pRuntime->PutObjectProperty(pObj, L"Trapped",
+                              pRuntime->NewString(cwTrapped.AsStringC()));
 
   // It's to be compatible to non-standard info dictionary.
   for (const auto& it : *pDictionary) {
@@ -821,7 +795,8 @@
     CFX_WideString wsKey = CFX_WideString::FromUTF8(bsKey.AsStringC());
     if (pValueObj->IsString() || pValueObj->IsName()) {
       pRuntime->PutObjectProperty(
-          pObj, wsKey, pRuntime->NewString(pValueObj->GetUnicodeText()));
+          pObj, wsKey,
+          pRuntime->NewString(pValueObj->GetUnicodeText().AsStringC()));
     } else if (pValueObj->IsNumber()) {
       pRuntime->PutObjectProperty(pObj, wsKey,
                                   pRuntime->NewNumber(pValueObj->GetNumber()));
@@ -834,7 +809,7 @@
   return true;
 }
 
-bool Document::getPropertyInternal(IJS_Context* cc,
+bool Document::getPropertyInternal(CJS_Runtime* pRuntime,
                                    CJS_PropValue& vp,
                                    const CFX_ByteString& propName,
                                    CFX_WideString& sError) {
@@ -862,19 +837,19 @@
   return true;
 }
 
-bool Document::creationDate(IJS_Context* cc,
+bool Document::creationDate(CJS_Runtime* pRuntime,
                             CJS_PropValue& vp,
                             CFX_WideString& sError) {
-  return getPropertyInternal(cc, vp, "CreationDate", sError);
+  return getPropertyInternal(pRuntime, vp, "CreationDate", sError);
 }
 
-bool Document::creator(IJS_Context* cc,
+bool Document::creator(CJS_Runtime* pRuntime,
                        CJS_PropValue& vp,
                        CFX_WideString& sError) {
-  return getPropertyInternal(cc, vp, "Creator", sError);
+  return getPropertyInternal(pRuntime, vp, "Creator", sError);
 }
 
-bool Document::delay(IJS_Context* cc,
+bool Document::delay(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   if (!m_pFormFillEnv) {
@@ -883,59 +858,60 @@
   }
   if (vp.IsGetting()) {
     vp << m_bDelay;
-  } else {
-    if (!m_pFormFillEnv->GetPermissions(FPDFPERM_MODIFY)) {
-      sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
-      return false;
-    }
-    vp >> m_bDelay;
-    if (m_bDelay) {
-      m_DelayData.clear();
-    } else {
-      std::list<std::unique_ptr<CJS_DelayData>> DelayDataToProcess;
-      DelayDataToProcess.swap(m_DelayData);
-      for (const auto& pData : DelayDataToProcess)
-        Field::DoDelay(m_pFormFillEnv.Get(), pData.get());
-    }
+    return true;
   }
+  if (!m_pFormFillEnv->GetPermissions(FPDFPERM_MODIFY)) {
+    sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
+    return false;
+  }
+  vp >> m_bDelay;
+  if (m_bDelay) {
+    m_DelayData.clear();
+    return true;
+  }
+  std::list<std::unique_ptr<CJS_DelayData>> DelayDataToProcess;
+  DelayDataToProcess.swap(m_DelayData);
+  for (const auto& pData : DelayDataToProcess)
+    Field::DoDelay(m_pFormFillEnv.Get(), pData.get());
+
   return true;
 }
 
-bool Document::keywords(IJS_Context* cc,
+bool Document::keywords(CJS_Runtime* pRuntime,
                         CJS_PropValue& vp,
                         CFX_WideString& sError) {
-  return getPropertyInternal(cc, vp, "Keywords", sError);
+  return getPropertyInternal(pRuntime, vp, "Keywords", sError);
 }
 
-bool Document::modDate(IJS_Context* cc,
+bool Document::modDate(CJS_Runtime* pRuntime,
                        CJS_PropValue& vp,
                        CFX_WideString& sError) {
-  return getPropertyInternal(cc, vp, "ModDate", sError);
+  return getPropertyInternal(pRuntime, vp, "ModDate", sError);
 }
 
-bool Document::producer(IJS_Context* cc,
+bool Document::producer(CJS_Runtime* pRuntime,
                         CJS_PropValue& vp,
                         CFX_WideString& sError) {
-  return getPropertyInternal(cc, vp, "Producer", sError);
+  return getPropertyInternal(pRuntime, vp, "Producer", sError);
 }
 
-bool Document::subject(IJS_Context* cc,
+bool Document::subject(CJS_Runtime* pRuntime,
                        CJS_PropValue& vp,
                        CFX_WideString& sError) {
-  return getPropertyInternal(cc, vp, "Subject", sError);
+  return getPropertyInternal(pRuntime, vp, "Subject", sError);
 }
 
-bool Document::title(IJS_Context* cc,
+bool Document::title(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   if (!m_pFormFillEnv || !m_pFormFillEnv->GetUnderlyingDocument()) {
     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
     return false;
   }
-  return getPropertyInternal(cc, vp, "Title", sError);
+  return getPropertyInternal(pRuntime, vp, "Title", sError);
 }
 
-bool Document::numPages(IJS_Context* cc,
+bool Document::numPages(CJS_Runtime* pRuntime,
                         CJS_PropValue& vp,
                         CFX_WideString& sError) {
   if (vp.IsSetting()) {
@@ -950,7 +926,7 @@
   return true;
 }
 
-bool Document::external(IJS_Context* cc,
+bool Document::external(CJS_Runtime* pRuntime,
                         CJS_PropValue& vp,
                         CFX_WideString& sError) {
   // In Chrome case, should always return true.
@@ -960,7 +936,7 @@
   return true;
 }
 
-bool Document::filesize(IJS_Context* cc,
+bool Document::filesize(CJS_Runtime* pRuntime,
                         CJS_PropValue& vp,
                         CFX_WideString& sError) {
   if (vp.IsSetting()) {
@@ -971,19 +947,21 @@
   return true;
 }
 
-bool Document::mouseX(IJS_Context* cc,
+bool Document::mouseX(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
   return true;
 }
 
-bool Document::mouseY(IJS_Context* cc,
+bool Document::mouseY(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
   return true;
 }
 
-bool Document::URL(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool Document::URL(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError) {
   if (vp.IsSetting()) {
     sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
     return false;
@@ -996,7 +974,7 @@
   return true;
 }
 
-bool Document::baseURL(IJS_Context* cc,
+bool Document::baseURL(CJS_Runtime* pRuntime,
                        CJS_PropValue& vp,
                        CFX_WideString& sError) {
   if (vp.IsGetting()) {
@@ -1007,7 +985,7 @@
   return true;
 }
 
-bool Document::calculate(IJS_Context* cc,
+bool Document::calculate(CJS_Runtime* pRuntime,
                          CJS_PropValue& vp,
                          CFX_WideString& sError) {
   if (!m_pFormFillEnv) {
@@ -1017,15 +995,15 @@
   CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
   if (vp.IsGetting()) {
     vp << !!pInterForm->IsCalculateEnabled();
-  } else {
-    bool bCalculate;
-    vp >> bCalculate;
-    pInterForm->EnableCalculate(bCalculate);
+    return true;
   }
+  bool bCalculate;
+  vp >> bCalculate;
+  pInterForm->EnableCalculate(bCalculate);
   return true;
 }
 
-bool Document::documentFileName(IJS_Context* cc,
+bool Document::documentFileName(CJS_Runtime* pRuntime,
                                 CJS_PropValue& vp,
                                 CFX_WideString& sError) {
   if (vp.IsSetting()) {
@@ -1050,7 +1028,7 @@
   return true;
 }
 
-bool Document::path(IJS_Context* cc,
+bool Document::path(CJS_Runtime* pRuntime,
                     CJS_PropValue& vp,
                     CFX_WideString& sError) {
   if (vp.IsSetting()) {
@@ -1065,40 +1043,40 @@
   return true;
 }
 
-bool Document::pageWindowRect(IJS_Context* cc,
+bool Document::pageWindowRect(CJS_Runtime* pRuntime,
                               CJS_PropValue& vp,
                               CFX_WideString& sError) {
   return true;
 }
 
-bool Document::layout(IJS_Context* cc,
+bool Document::layout(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
   return true;
 }
 
-bool Document::addLink(IJS_Context* cc,
+bool Document::addLink(CJS_Runtime* pRuntime,
                        const std::vector<CJS_Value>& params,
                        CJS_Value& vRet,
                        CFX_WideString& sError) {
   return true;
 }
 
-bool Document::closeDoc(IJS_Context* cc,
+bool Document::closeDoc(CJS_Runtime* pRuntime,
                         const std::vector<CJS_Value>& params,
                         CJS_Value& vRet,
                         CFX_WideString& sError) {
   return true;
 }
 
-bool Document::getPageBox(IJS_Context* cc,
+bool Document::getPageBox(CJS_Runtime* pRuntime,
                           const std::vector<CJS_Value>& params,
                           CJS_Value& vRet,
                           CFX_WideString& sError) {
   return true;
 }
 
-bool Document::getAnnot(IJS_Context* cc,
+bool Document::getAnnot(CJS_Runtime* pRuntime,
                         const std::vector<CJS_Value>& params,
                         CJS_Value& vRet,
                         CFX_WideString& sError) {
@@ -1110,8 +1088,6 @@
     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
     return false;
   }
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
   int nPageNo = params[0].ToInt(pRuntime);
   CFX_WideString swAnnotName = params[1].ToCFXWideString(pRuntime);
   CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetPageView(nPageNo);
@@ -1138,19 +1114,13 @@
 
   CJS_Annot* pJS_Annot =
       static_cast<CJS_Annot*>(pRuntime->GetObjectPrivate(pObj));
-  if (!pJS_Annot)
-    return false;
-
   Annot* pAnnot = static_cast<Annot*>(pJS_Annot->GetEmbedObject());
-  if (!pAnnot)
-    return false;
-
   pAnnot->SetSDKAnnot(pSDKBAAnnot);
   vRet = CJS_Value(pRuntime, pJS_Annot);
   return true;
 }
 
-bool Document::getAnnots(IJS_Context* cc,
+bool Document::getAnnots(CJS_Runtime* pRuntime,
                          const std::vector<CJS_Value>& params,
                          CJS_Value& vRet,
                          CFX_WideString& sError) {
@@ -1158,9 +1128,6 @@
     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
     return false;
   }
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-
   // TODO(tonikitoo): Add support supported parameters as per
   // the PDF spec.
 
@@ -1185,13 +1152,7 @@
 
       CJS_Annot* pJS_Annot =
           static_cast<CJS_Annot*>(pRuntime->GetObjectPrivate(pObj));
-      if (!pJS_Annot)
-        return false;
-
       Annot* pAnnot = static_cast<Annot*>(pJS_Annot->GetEmbedObject());
-      if (!pAnnot)
-        return false;
-
       pAnnot->SetSDKAnnot(static_cast<CPDFSDK_BAAnnot*>(pSDKAnnotCur.Get()));
       annots.SetElement(pRuntime, i, CJS_Value(pRuntime, pJS_Annot));
     }
@@ -1200,29 +1161,29 @@
   return true;
 }
 
-bool Document::getAnnot3D(IJS_Context* cc,
+bool Document::getAnnot3D(CJS_Runtime* pRuntime,
                           const std::vector<CJS_Value>& params,
                           CJS_Value& vRet,
                           CFX_WideString& sError) {
-  vRet.SetNull(CJS_Runtime::FromContext(cc));
+  vRet.SetNull(pRuntime);
   return true;
 }
 
-bool Document::getAnnots3D(IJS_Context* cc,
+bool Document::getAnnots3D(CJS_Runtime* pRuntime,
                            const std::vector<CJS_Value>& params,
                            CJS_Value& vRet,
                            CFX_WideString& sError) {
   return true;
 }
 
-bool Document::getOCGs(IJS_Context* cc,
+bool Document::getOCGs(CJS_Runtime* pRuntime,
                        const std::vector<CJS_Value>& params,
                        CJS_Value& vRet,
                        CFX_WideString& sError) {
   return true;
 }
 
-bool Document::getLinks(IJS_Context* cc,
+bool Document::getLinks(CJS_Runtime* pRuntime,
                         const std::vector<CJS_Value>& params,
                         CJS_Value& vRet,
                         CFX_WideString& sError) {
@@ -1234,7 +1195,7 @@
           rect.right >= LinkRect.right && rect.bottom >= LinkRect.bottom);
 }
 
-bool Document::addIcon(IJS_Context* cc,
+bool Document::addIcon(CJS_Runtime* pRuntime,
                        const std::vector<CJS_Value>& params,
                        CJS_Value& vRet,
                        CFX_WideString& sError) {
@@ -1243,10 +1204,7 @@
     return false;
   }
 
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
   CFX_WideString swIconName = params[0].ToCFXWideString(pRuntime);
-
   if (params[1].GetType() != CJS_Value::VT_object) {
     sError = JSGetStringFromID(IDS_STRING_JSTYPEERROR);
     return false;
@@ -1258,35 +1216,30 @@
     return false;
   }
 
-  CJS_EmbedObj* pEmbedObj = params[1].ToCJSObject(pRuntime)->GetEmbedObject();
-  if (!pEmbedObj) {
+  if (!params[1].ToCJSObject(pRuntime)->GetEmbedObject()) {
     sError = JSGetStringFromID(IDS_STRING_JSTYPEERROR);
     return false;
   }
 
-  m_Icons.push_back(pdfium::MakeUnique<IconElement>(
-      swIconName, static_cast<Icon*>(pEmbedObj)));
+  m_IconNames.push_back(swIconName);
   return true;
 }
 
-bool Document::icons(IJS_Context* cc,
+bool Document::icons(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   if (vp.IsSetting()) {
     sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
     return false;
   }
-
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-  if (m_Icons.empty()) {
+  if (m_IconNames.empty()) {
     vp.GetJSValue()->SetNull(pRuntime);
     return true;
   }
 
   CJS_Array Icons;
-
   int i = 0;
-  for (const auto& pIconElement : m_Icons) {
+  for (const auto& name : m_IconNames) {
     v8::Local<v8::Object> pObj =
         pRuntime->NewFxDynamicObj(CJS_Icon::g_nObjDefnID);
     if (pObj.IsEmpty())
@@ -1294,15 +1247,8 @@
 
     CJS_Icon* pJS_Icon =
         static_cast<CJS_Icon*>(pRuntime->GetObjectPrivate(pObj));
-    if (!pJS_Icon)
-      return false;
-
     Icon* pIcon = static_cast<Icon*>(pJS_Icon->GetEmbedObject());
-    if (!pIcon)
-      return false;
-
-    pIcon->SetStream(pIconElement->IconStream->GetStream());
-    pIcon->SetIconName(pIconElement->IconName);
+    pIcon->SetIconName(name);
     Icons.SetElement(pRuntime, i++, CJS_Value(pRuntime, pJS_Icon));
   }
 
@@ -1310,7 +1256,7 @@
   return true;
 }
 
-bool Document::getIcon(IJS_Context* cc,
+bool Document::getIcon(CJS_Runtime* pRuntime,
                        const std::vector<CJS_Value>& params,
                        CJS_Value& vRet,
                        CFX_WideString& sError) {
@@ -1319,41 +1265,24 @@
     return false;
   }
 
-  if (m_Icons.empty())
+  CFX_WideString swIconName = params[0].ToCFXWideString(pRuntime);
+  auto it = std::find(m_IconNames.begin(), m_IconNames.end(), swIconName);
+  if (it == m_IconNames.end())
     return false;
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-  CFX_WideString swIconName = params[0].ToCFXWideString(pRuntime);
+  v8::Local<v8::Object> pObj =
+      pRuntime->NewFxDynamicObj(CJS_Icon::g_nObjDefnID);
+  if (pObj.IsEmpty())
+    return false;
 
-  for (const auto& pIconElement : m_Icons) {
-    if (pIconElement->IconName != swIconName)
-      continue;
-
-    v8::Local<v8::Object> pObj =
-        pRuntime->NewFxDynamicObj(CJS_Icon::g_nObjDefnID);
-    if (pObj.IsEmpty())
-      return false;
-
-    CJS_Icon* pJS_Icon =
-        static_cast<CJS_Icon*>(pRuntime->GetObjectPrivate(pObj));
-    if (!pJS_Icon)
-      return false;
-
-    Icon* pIcon = (Icon*)pJS_Icon->GetEmbedObject();
-    if (!pIcon)
-      return false;
-
-    pIcon->SetIconName(swIconName);
-    pIcon->SetStream(pIconElement->IconStream->GetStream());
-
-    vRet = CJS_Value(pRuntime, pJS_Icon);
-    return true;
-  }
-
-  return false;
+  CJS_Icon* pJS_Icon = static_cast<CJS_Icon*>(pRuntime->GetObjectPrivate(pObj));
+  Icon* pIcon = static_cast<Icon*>(pJS_Icon->GetEmbedObject());
+  pIcon->SetIconName(*it);
+  vRet = CJS_Value(pRuntime, pJS_Icon);
+  return true;
 }
 
-bool Document::removeIcon(IJS_Context* cc,
+bool Document::removeIcon(CJS_Runtime* pRuntime,
                           const std::vector<CJS_Value>& params,
                           CJS_Value& vRet,
                           CFX_WideString& sError) {
@@ -1361,7 +1290,7 @@
   return true;
 }
 
-bool Document::createDataObject(IJS_Context* cc,
+bool Document::createDataObject(CJS_Runtime* pRuntime,
                                 const std::vector<CJS_Value>& params,
                                 CJS_Value& vRet,
                                 CFX_WideString& sError) {
@@ -1369,13 +1298,13 @@
   return true;
 }
 
-bool Document::media(IJS_Context* cc,
+bool Document::media(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   return true;
 }
 
-bool Document::calculateNow(IJS_Context* cc,
+bool Document::calculateNow(CJS_Runtime* pRuntime,
                             const std::vector<CJS_Value>& params,
                             CJS_Value& vRet,
                             CFX_WideString& sError) {
@@ -1393,13 +1322,13 @@
   return true;
 }
 
-bool Document::Collab(IJS_Context* cc,
+bool Document::Collab(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
   return true;
 }
 
-bool Document::getPageNthWord(IJS_Context* cc,
+bool Document::getPageNthWord(CJS_Runtime* pRuntime,
                               const std::vector<CJS_Value>& params,
                               CJS_Value& vRet,
                               CFX_WideString& sError) {
@@ -1411,7 +1340,6 @@
     sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
     return false;
   }
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
 
   // TODO(tsepez): check maximum allowable params.
 
@@ -1458,7 +1386,7 @@
   return true;
 }
 
-bool Document::getPageNthWordQuads(IJS_Context* cc,
+bool Document::getPageNthWordQuads(CJS_Runtime* pRuntime,
                                    const std::vector<CJS_Value>& params,
                                    CJS_Value& vRet,
                                    CFX_WideString& sError) {
@@ -1473,7 +1401,7 @@
   return false;
 }
 
-bool Document::getPageNumWords(IJS_Context* cc,
+bool Document::getPageNumWords(CJS_Runtime* pRuntime,
                                const std::vector<CJS_Value>& params,
                                CJS_Value& vRet,
                                CFX_WideString& sError) {
@@ -1485,7 +1413,6 @@
     sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
     return false;
   }
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   int nPageNo = params.size() > 0 ? params[0].ToInt(pRuntime) : 0;
   CPDF_Document* pDocument = m_pFormFillEnv->GetPDFDocument();
   if (nPageNo < 0 || nPageNo >= pDocument->GetPageCount()) {
@@ -1510,14 +1437,14 @@
   return true;
 }
 
-bool Document::getPrintParams(IJS_Context* cc,
+bool Document::getPrintParams(CJS_Runtime* pRuntime,
                               const std::vector<CJS_Value>& params,
                               CJS_Value& vRet,
                               CFX_WideString& sError) {
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
   v8::Local<v8::Object> pRetObj =
       pRuntime->NewFxDynamicObj(CJS_PrintParamsObj::g_nObjDefnID);
+  if (pRetObj.IsEmpty())
+    return false;
 
   // Not implemented yet.
 
@@ -1543,7 +1470,7 @@
     uint32_t charcode = CPDF_Font::kInvalidCharCode;
     FX_FLOAT kerning;
 
-    pTextObj->GetCharInfo(i, charcode, kerning);
+    pTextObj->GetCharInfo(i, &charcode, &kerning);
     CFX_WideString swUnicode = pFont->UnicodeFromCharCode(charcode);
 
     uint16_t unicode = 0;
@@ -1576,7 +1503,7 @@
     uint32_t charcode = CPDF_Font::kInvalidCharCode;
     FX_FLOAT kerning;
 
-    pTextObj->GetCharInfo(i, charcode, kerning);
+    pTextObj->GetCharInfo(i, &charcode, &kerning);
     CFX_WideString swUnicode = pFont->UnicodeFromCharCode(charcode);
 
     uint16_t unicode = 0;
@@ -1597,7 +1524,7 @@
   return swRet;
 }
 
-bool Document::zoom(IJS_Context* cc,
+bool Document::zoom(CJS_Runtime* pRuntime,
                     CJS_PropValue& vp,
                     CFX_WideString& sError) {
   return true;
@@ -1613,13 +1540,13 @@
 (refW,  ReflowWidth)
 */
 
-bool Document::zoomType(IJS_Context* cc,
+bool Document::zoomType(CJS_Runtime* pRuntime,
                         CJS_PropValue& vp,
                         CFX_WideString& sError) {
   return true;
 }
 
-bool Document::deletePages(IJS_Context* cc,
+bool Document::deletePages(CJS_Runtime* pRuntime,
                            const std::vector<CJS_Value>& params,
                            CJS_Value& vRet,
                            CFX_WideString& sError) {
@@ -1627,7 +1554,7 @@
   return true;
 }
 
-bool Document::extractPages(IJS_Context* cc,
+bool Document::extractPages(CJS_Runtime* pRuntime,
                             const std::vector<CJS_Value>& params,
                             CJS_Value& vRet,
                             CFX_WideString& sError) {
@@ -1635,7 +1562,7 @@
   return true;
 }
 
-bool Document::insertPages(IJS_Context* cc,
+bool Document::insertPages(CJS_Runtime* pRuntime,
                            const std::vector<CJS_Value>& params,
                            CJS_Value& vRet,
                            CFX_WideString& sError) {
@@ -1643,7 +1570,7 @@
   return true;
 }
 
-bool Document::replacePages(IJS_Context* cc,
+bool Document::replacePages(CJS_Runtime* pRuntime,
                             const std::vector<CJS_Value>& params,
                             CJS_Value& vRet,
                             CFX_WideString& sError) {
@@ -1651,7 +1578,7 @@
   return true;
 }
 
-bool Document::getURL(IJS_Context* cc,
+bool Document::getURL(CJS_Runtime* pRuntime,
                       const std::vector<CJS_Value>& params,
                       CJS_Value& vRet,
                       CFX_WideString& sError) {
@@ -1659,7 +1586,7 @@
   return true;
 }
 
-bool Document::gotoNamedDest(IJS_Context* cc,
+bool Document::gotoNamedDest(CJS_Runtime* pRuntime,
                              const std::vector<CJS_Value>& params,
                              CJS_Value& vRet,
                              CFX_WideString& sError) {
@@ -1671,7 +1598,6 @@
     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
     return false;
   }
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CFX_WideString wideName = params[0].ToCFXWideString(pRuntime);
   CFX_ByteString utf8Name = wideName.UTF8Encode();
   CPDF_Document* pDocument = m_pFormFillEnv->GetPDFDocument();
diff --git a/fpdfsdk/javascript/Document.h b/fpdfsdk/javascript/Document.h
index 227c428..91ca778 100644
--- a/fpdfsdk/javascript/Document.h
+++ b/fpdfsdk/javascript/Document.h
@@ -41,231 +41,250 @@
   DECLARE_JS_CLASS();
 };
 
-class Icon;
-class Field;
-
-struct IconElement {
-  IconElement(const CFX_WideString& name, Icon* stream)
-      : IconName(name), IconStream(stream) {}
-
-  const CFX_WideString IconName;
-  Icon* const IconStream;
-};
-
-struct CJS_DelayData;
-struct CJS_DelayAnnot;
 struct CJS_AnnotObj;
+struct CJS_DelayAnnot;
+struct CJS_DelayData;
 
 class Document : public CJS_EmbedObj {
  public:
   explicit Document(CJS_Object* pJSObject);
   ~Document() override;
 
-  bool ADBE(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool author(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool baseURL(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool bookmarkRoot(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool calculate(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool Collab(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool creationDate(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool creator(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool delay(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool dirty(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool documentFileName(IJS_Context* cc,
+  bool ADBE(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool author(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool baseURL(CJS_Runtime* pRuntime,
+               CJS_PropValue& vp,
+               CFX_WideString& sError);
+  bool bookmarkRoot(CJS_Runtime* pRuntime,
+                    CJS_PropValue& vp,
+                    CFX_WideString& sError);
+  bool calculate(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError);
+  bool Collab(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool creationDate(CJS_Runtime* pRuntime,
+                    CJS_PropValue& vp,
+                    CFX_WideString& sError);
+  bool creator(CJS_Runtime* pRuntime,
+               CJS_PropValue& vp,
+               CFX_WideString& sError);
+  bool delay(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool dirty(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool documentFileName(CJS_Runtime* pRuntime,
                         CJS_PropValue& vp,
                         CFX_WideString& sError);
-  bool external(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool filesize(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool icons(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool info(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool keywords(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool layout(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool media(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool modDate(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool mouseX(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool mouseY(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool numFields(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool numPages(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool pageNum(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool pageWindowRect(IJS_Context* cc,
+  bool external(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool filesize(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool icons(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool info(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool keywords(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool layout(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool media(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool modDate(CJS_Runtime* pRuntime,
+               CJS_PropValue& vp,
+               CFX_WideString& sError);
+  bool mouseX(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool mouseY(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool numFields(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError);
+  bool numPages(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool pageNum(CJS_Runtime* pRuntime,
+               CJS_PropValue& vp,
+               CFX_WideString& sError);
+  bool pageWindowRect(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError);
-  bool path(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool producer(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool subject(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool title(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool zoom(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool zoomType(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
+  bool path(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool producer(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool subject(CJS_Runtime* pRuntime,
+               CJS_PropValue& vp,
+               CFX_WideString& sError);
+  bool title(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool zoom(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool zoomType(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
 
-  bool addAnnot(IJS_Context* cc,
+  bool addAnnot(CJS_Runtime* pRuntime,
                 const std::vector<CJS_Value>& params,
                 CJS_Value& vRet,
                 CFX_WideString& sError);
-  bool addField(IJS_Context* cc,
+  bool addField(CJS_Runtime* pRuntime,
                 const std::vector<CJS_Value>& params,
                 CJS_Value& vRet,
                 CFX_WideString& sError);
-  bool addLink(IJS_Context* cc,
+  bool addLink(CJS_Runtime* pRuntime,
                const std::vector<CJS_Value>& params,
                CJS_Value& vRet,
                CFX_WideString& sError);
-  bool addIcon(IJS_Context* cc,
+  bool addIcon(CJS_Runtime* pRuntime,
                const std::vector<CJS_Value>& params,
                CJS_Value& vRet,
                CFX_WideString& sError);
-  bool calculateNow(IJS_Context* cc,
+  bool calculateNow(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError);
-  bool closeDoc(IJS_Context* cc,
+  bool closeDoc(CJS_Runtime* pRuntime,
                 const std::vector<CJS_Value>& params,
                 CJS_Value& vRet,
                 CFX_WideString& sError);
-  bool createDataObject(IJS_Context* cc,
+  bool createDataObject(CJS_Runtime* pRuntime,
                         const std::vector<CJS_Value>& params,
                         CJS_Value& vRet,
                         CFX_WideString& sError);
-  bool deletePages(IJS_Context* cc,
+  bool deletePages(CJS_Runtime* pRuntime,
                    const std::vector<CJS_Value>& params,
                    CJS_Value& vRet,
                    CFX_WideString& sError);
-  bool exportAsText(IJS_Context* cc,
+  bool exportAsText(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError);
-  bool exportAsFDF(IJS_Context* cc,
+  bool exportAsFDF(CJS_Runtime* pRuntime,
                    const std::vector<CJS_Value>& params,
                    CJS_Value& vRet,
                    CFX_WideString& sError);
-  bool exportAsXFDF(IJS_Context* cc,
+  bool exportAsXFDF(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError);
-  bool extractPages(IJS_Context* cc,
+  bool extractPages(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError);
-  bool getAnnot(IJS_Context* cc,
+  bool getAnnot(CJS_Runtime* pRuntime,
                 const std::vector<CJS_Value>& params,
                 CJS_Value& vRet,
                 CFX_WideString& sError);
-  bool getAnnots(IJS_Context* cc,
+  bool getAnnots(CJS_Runtime* pRuntime,
                  const std::vector<CJS_Value>& params,
                  CJS_Value& vRet,
                  CFX_WideString& sError);
-  bool getAnnot3D(IJS_Context* cc,
+  bool getAnnot3D(CJS_Runtime* pRuntime,
                   const std::vector<CJS_Value>& params,
                   CJS_Value& vRet,
                   CFX_WideString& sError);
-  bool getAnnots3D(IJS_Context* cc,
+  bool getAnnots3D(CJS_Runtime* pRuntime,
                    const std::vector<CJS_Value>& params,
                    CJS_Value& vRet,
                    CFX_WideString& sError);
-  bool getField(IJS_Context* cc,
+  bool getField(CJS_Runtime* pRuntime,
                 const std::vector<CJS_Value>& params,
                 CJS_Value& vRet,
                 CFX_WideString& sError);
-  bool getIcon(IJS_Context* cc,
+  bool getIcon(CJS_Runtime* pRuntime,
                const std::vector<CJS_Value>& params,
                CJS_Value& vRet,
                CFX_WideString& sError);
-  bool getLinks(IJS_Context* cc,
+  bool getLinks(CJS_Runtime* pRuntime,
                 const std::vector<CJS_Value>& params,
                 CJS_Value& vRet,
                 CFX_WideString& sError);
-  bool getNthFieldName(IJS_Context* cc,
+  bool getNthFieldName(CJS_Runtime* pRuntime,
                        const std::vector<CJS_Value>& params,
                        CJS_Value& vRet,
                        CFX_WideString& sError);
-  bool getOCGs(IJS_Context* cc,
+  bool getOCGs(CJS_Runtime* pRuntime,
                const std::vector<CJS_Value>& params,
                CJS_Value& vRet,
                CFX_WideString& sError);
-  bool getPageBox(IJS_Context* cc,
+  bool getPageBox(CJS_Runtime* pRuntime,
                   const std::vector<CJS_Value>& params,
                   CJS_Value& vRet,
                   CFX_WideString& sError);
-  bool getPageNthWord(IJS_Context* cc,
+  bool getPageNthWord(CJS_Runtime* pRuntime,
                       const std::vector<CJS_Value>& params,
                       CJS_Value& vRet,
                       CFX_WideString& sError);
-  bool getPageNthWordQuads(IJS_Context* cc,
+  bool getPageNthWordQuads(CJS_Runtime* pRuntime,
                            const std::vector<CJS_Value>& params,
                            CJS_Value& vRet,
                            CFX_WideString& sError);
-  bool getPageNumWords(IJS_Context* cc,
+  bool getPageNumWords(CJS_Runtime* pRuntime,
                        const std::vector<CJS_Value>& params,
                        CJS_Value& vRet,
                        CFX_WideString& sError);
-  bool getPrintParams(IJS_Context* cc,
+  bool getPrintParams(CJS_Runtime* pRuntime,
                       const std::vector<CJS_Value>& params,
                       CJS_Value& vRet,
                       CFX_WideString& sError);
-  bool getURL(IJS_Context* cc,
+  bool getURL(CJS_Runtime* pRuntime,
               const std::vector<CJS_Value>& params,
               CJS_Value& vRet,
               CFX_WideString& sError);
-  bool gotoNamedDest(IJS_Context* cc,
+  bool gotoNamedDest(CJS_Runtime* pRuntime,
                      const std::vector<CJS_Value>& params,
                      CJS_Value& vRet,
                      CFX_WideString& sError);
-  bool importAnFDF(IJS_Context* cc,
+  bool importAnFDF(CJS_Runtime* pRuntime,
                    const std::vector<CJS_Value>& params,
                    CJS_Value& vRet,
                    CFX_WideString& sError);
-  bool importAnXFDF(IJS_Context* cc,
+  bool importAnXFDF(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError);
-  bool importTextData(IJS_Context* cc,
+  bool importTextData(CJS_Runtime* pRuntime,
                       const std::vector<CJS_Value>& params,
                       CJS_Value& vRet,
                       CFX_WideString& sError);
-  bool insertPages(IJS_Context* cc,
+  bool insertPages(CJS_Runtime* pRuntime,
                    const std::vector<CJS_Value>& params,
                    CJS_Value& vRet,
                    CFX_WideString& sError);
-  bool mailForm(IJS_Context* cc,
+  bool mailForm(CJS_Runtime* pRuntime,
                 const std::vector<CJS_Value>& params,
                 CJS_Value& vRet,
                 CFX_WideString& sError);
-  bool print(IJS_Context* cc,
+  bool print(CJS_Runtime* pRuntime,
              const std::vector<CJS_Value>& params,
              CJS_Value& vRet,
              CFX_WideString& sError);
-  bool removeField(IJS_Context* cc,
+  bool removeField(CJS_Runtime* pRuntime,
                    const std::vector<CJS_Value>& params,
                    CJS_Value& vRet,
                    CFX_WideString& sError);
-  bool replacePages(IJS_Context* cc,
+  bool replacePages(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError);
-  bool resetForm(IJS_Context* cc,
+  bool resetForm(CJS_Runtime* pRuntime,
                  const std::vector<CJS_Value>& params,
                  CJS_Value& vRet,
                  CFX_WideString& sError);
-  bool saveAs(IJS_Context* cc,
+  bool saveAs(CJS_Runtime* pRuntime,
               const std::vector<CJS_Value>& params,
               CJS_Value& vRet,
               CFX_WideString& sError);
-  bool submitForm(IJS_Context* cc,
+  bool submitForm(CJS_Runtime* pRuntime,
                   const std::vector<CJS_Value>& params,
                   CJS_Value& vRet,
                   CFX_WideString& sError);
-  bool syncAnnotScan(IJS_Context* cc,
+  bool syncAnnotScan(CJS_Runtime* pRuntime,
                      const std::vector<CJS_Value>& params,
                      CJS_Value& vRet,
                      CFX_WideString& sError);
-  bool mailDoc(IJS_Context* cc,
+  bool mailDoc(CJS_Runtime* pRuntime,
                const std::vector<CJS_Value>& params,
                CJS_Value& vRet,
                CFX_WideString& sError);
-  bool removeIcon(IJS_Context* cc,
+  bool removeIcon(CJS_Runtime* pRuntime,
                   const std::vector<CJS_Value>& params,
                   CJS_Value& vRet,
                   CFX_WideString& sError);
-  bool URL(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
+  bool URL(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
 
   void SetFormFillEnv(CPDFSDK_FormFillEnvironment* pFormFillEnv);
   CPDFSDK_FormFillEnvironment* GetFormFillEnv() const {
@@ -280,7 +299,7 @@
   int CountWords(CPDF_TextObject* pTextObj);
   CFX_WideString GetObjWordStr(CPDF_TextObject* pTextObj, int nWordIndex);
 
-  bool getPropertyInternal(IJS_Context* cc,
+  bool getPropertyInternal(CJS_Runtime* pRuntime,
                            CJS_PropValue& vp,
                            const CFX_ByteString& propName,
                            CFX_WideString& sError);
@@ -288,7 +307,8 @@
   CPDFSDK_FormFillEnvironment::ObservedPtr m_pFormFillEnv;
   CFX_WideString m_cwBaseURL;
   std::list<std::unique_ptr<CJS_DelayData>> m_DelayData;
-  std::vector<std::unique_ptr<IconElement>> m_Icons;
+  // Needs to be a std::list for iterator stability.
+  std::list<CFX_WideString> m_IconNames;
   bool m_bDelay;
 };
 
diff --git a/fpdfsdk/javascript/Field.cpp b/fpdfsdk/javascript/Field.cpp
index e04cbd6..f37b3d4 100644
--- a/fpdfsdk/javascript/Field.cpp
+++ b/fpdfsdk/javascript/Field.cpp
@@ -26,7 +26,7 @@
 #include "fpdfsdk/javascript/JS_Object.h"
 #include "fpdfsdk/javascript/JS_Value.h"
 #include "fpdfsdk/javascript/PublicMethods.h"
-#include "fpdfsdk/javascript/cjs_context.h"
+#include "fpdfsdk/javascript/cjs_event_context.h"
 #include "fpdfsdk/javascript/cjs_runtime.h"
 #include "fpdfsdk/javascript/color.h"
 
@@ -72,92 +72,94 @@
 
 }  // namespace
 
-BEGIN_JS_STATIC_CONST(CJS_Field)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Field::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
 
-BEGIN_JS_STATIC_PROP(CJS_Field)
-JS_STATIC_PROP_ENTRY(alignment)
-JS_STATIC_PROP_ENTRY(borderStyle)
-JS_STATIC_PROP_ENTRY(buttonAlignX)
-JS_STATIC_PROP_ENTRY(buttonAlignY)
-JS_STATIC_PROP_ENTRY(buttonFitBounds)
-JS_STATIC_PROP_ENTRY(buttonPosition)
-JS_STATIC_PROP_ENTRY(buttonScaleHow)
-JS_STATIC_PROP_ENTRY(buttonScaleWhen)
-JS_STATIC_PROP_ENTRY(calcOrderIndex)
-JS_STATIC_PROP_ENTRY(charLimit)
-JS_STATIC_PROP_ENTRY(comb)
-JS_STATIC_PROP_ENTRY(commitOnSelChange)
-JS_STATIC_PROP_ENTRY(currentValueIndices)
-JS_STATIC_PROP_ENTRY(defaultStyle)
-JS_STATIC_PROP_ENTRY(defaultValue)
-JS_STATIC_PROP_ENTRY(doNotScroll)
-JS_STATIC_PROP_ENTRY(doNotSpellCheck)
-JS_STATIC_PROP_ENTRY(delay)
-JS_STATIC_PROP_ENTRY(display)
-JS_STATIC_PROP_ENTRY(doc)
-JS_STATIC_PROP_ENTRY(editable)
-JS_STATIC_PROP_ENTRY(exportValues)
-JS_STATIC_PROP_ENTRY(hidden)
-JS_STATIC_PROP_ENTRY(fileSelect)
-JS_STATIC_PROP_ENTRY(fillColor)
-JS_STATIC_PROP_ENTRY(lineWidth)
-JS_STATIC_PROP_ENTRY(highlight)
-JS_STATIC_PROP_ENTRY(multiline)
-JS_STATIC_PROP_ENTRY(multipleSelection)
-JS_STATIC_PROP_ENTRY(name)
-JS_STATIC_PROP_ENTRY(numItems)
-JS_STATIC_PROP_ENTRY(page)
-JS_STATIC_PROP_ENTRY(password)
-JS_STATIC_PROP_ENTRY(print)
-JS_STATIC_PROP_ENTRY(radiosInUnison)
-JS_STATIC_PROP_ENTRY(readonly)
-JS_STATIC_PROP_ENTRY(rect)
-JS_STATIC_PROP_ENTRY(required)
-JS_STATIC_PROP_ENTRY(richText)
-JS_STATIC_PROP_ENTRY(richValue)
-JS_STATIC_PROP_ENTRY(rotation)
-JS_STATIC_PROP_ENTRY(strokeColor)
-JS_STATIC_PROP_ENTRY(style)
-JS_STATIC_PROP_ENTRY(submitName)
-JS_STATIC_PROP_ENTRY(textColor)
-JS_STATIC_PROP_ENTRY(textFont)
-JS_STATIC_PROP_ENTRY(textSize)
-JS_STATIC_PROP_ENTRY(type)
-JS_STATIC_PROP_ENTRY(userName)
-JS_STATIC_PROP_ENTRY(value)
-JS_STATIC_PROP_ENTRY(valueAsString)
-JS_STATIC_PROP_ENTRY(source)
-END_JS_STATIC_PROP()
+JSPropertySpec CJS_Field::PropertySpecs[] = {
+    {"alignment", get_alignment_static, set_alignment_static},
+    {"borderStyle", get_borderStyle_static, set_borderStyle_static},
+    {"buttonAlignX", get_buttonAlignX_static, set_buttonAlignX_static},
+    {"buttonAlignY", get_buttonAlignY_static, set_buttonAlignY_static},
+    {"buttonFitBounds", get_buttonFitBounds_static, set_buttonFitBounds_static},
+    {"buttonPosition", get_buttonPosition_static, set_buttonPosition_static},
+    {"buttonScaleHow", get_buttonScaleHow_static, set_buttonScaleHow_static},
+    {"buttonScaleWhen", get_buttonScaleWhen_static, set_buttonScaleWhen_static},
+    {"calcOrderIndex", get_calcOrderIndex_static, set_calcOrderIndex_static},
+    {"charLimit", get_charLimit_static, set_charLimit_static},
+    {"comb", get_comb_static, set_comb_static},
+    {"commitOnSelChange", get_commitOnSelChange_static,
+     set_commitOnSelChange_static},
+    {"currentValueIndices", get_currentValueIndices_static,
+     set_currentValueIndices_static},
+    {"defaultStyle", get_defaultStyle_static, set_defaultStyle_static},
+    {"defaultValue", get_defaultValue_static, set_defaultValue_static},
+    {"doNotScroll", get_doNotScroll_static, set_doNotScroll_static},
+    {"doNotSpellCheck", get_doNotSpellCheck_static, set_doNotSpellCheck_static},
+    {"delay", get_delay_static, set_delay_static},
+    {"display", get_display_static, set_display_static},
+    {"doc", get_doc_static, set_doc_static},
+    {"editable", get_editable_static, set_editable_static},
+    {"exportValues", get_exportValues_static, set_exportValues_static},
+    {"hidden", get_hidden_static, set_hidden_static},
+    {"fileSelect", get_fileSelect_static, set_fileSelect_static},
+    {"fillColor", get_fillColor_static, set_fillColor_static},
+    {"lineWidth", get_lineWidth_static, set_lineWidth_static},
+    {"highlight", get_highlight_static, set_highlight_static},
+    {"multiline", get_multiline_static, set_multiline_static},
+    {"multipleSelection", get_multipleSelection_static,
+     set_multipleSelection_static},
+    {"name", get_name_static, set_name_static},
+    {"numItems", get_numItems_static, set_numItems_static},
+    {"page", get_page_static, set_page_static},
+    {"password", get_password_static, set_password_static},
+    {"print", get_print_static, set_print_static},
+    {"radiosInUnison", get_radiosInUnison_static, set_radiosInUnison_static},
+    {"readonly", get_readonly_static, set_readonly_static},
+    {"rect", get_rect_static, set_rect_static},
+    {"required", get_required_static, set_required_static},
+    {"richText", get_richText_static, set_richText_static},
+    {"richValue", get_richValue_static, set_richValue_static},
+    {"rotation", get_rotation_static, set_rotation_static},
+    {"strokeColor", get_strokeColor_static, set_strokeColor_static},
+    {"style", get_style_static, set_style_static},
+    {"submitName", get_submitName_static, set_submitName_static},
+    {"textColor", get_textColor_static, set_textColor_static},
+    {"textFont", get_textFont_static, set_textFont_static},
+    {"textSize", get_textSize_static, set_textSize_static},
+    {"type", get_type_static, set_type_static},
+    {"userName", get_userName_static, set_userName_static},
+    {"value", get_value_static, set_value_static},
+    {"valueAsString", get_valueAsString_static, set_valueAsString_static},
+    {"source", get_source_static, set_source_static},
+    {0, 0, 0}};
 
-BEGIN_JS_STATIC_METHOD(CJS_Field)
-JS_STATIC_METHOD_ENTRY(browseForFileToSubmit)
-JS_STATIC_METHOD_ENTRY(buttonGetCaption)
-JS_STATIC_METHOD_ENTRY(buttonGetIcon)
-JS_STATIC_METHOD_ENTRY(buttonImportIcon)
-JS_STATIC_METHOD_ENTRY(buttonSetCaption)
-JS_STATIC_METHOD_ENTRY(buttonSetIcon)
-JS_STATIC_METHOD_ENTRY(checkThisBox)
-JS_STATIC_METHOD_ENTRY(clearItems)
-JS_STATIC_METHOD_ENTRY(defaultIsChecked)
-JS_STATIC_METHOD_ENTRY(deleteItemAt)
-JS_STATIC_METHOD_ENTRY(getArray)
-JS_STATIC_METHOD_ENTRY(getItemAt)
-JS_STATIC_METHOD_ENTRY(getLock)
-JS_STATIC_METHOD_ENTRY(insertItemAt)
-JS_STATIC_METHOD_ENTRY(isBoxChecked)
-JS_STATIC_METHOD_ENTRY(isDefaultChecked)
-JS_STATIC_METHOD_ENTRY(setAction)
-JS_STATIC_METHOD_ENTRY(setFocus)
-JS_STATIC_METHOD_ENTRY(setItems)
-JS_STATIC_METHOD_ENTRY(setLock)
-JS_STATIC_METHOD_ENTRY(signatureGetModifications)
-JS_STATIC_METHOD_ENTRY(signatureGetSeedValue)
-JS_STATIC_METHOD_ENTRY(signatureInfo)
-JS_STATIC_METHOD_ENTRY(signatureSetSeedValue)
-JS_STATIC_METHOD_ENTRY(signatureSign)
-JS_STATIC_METHOD_ENTRY(signatureValidate)
-END_JS_STATIC_METHOD()
+JSMethodSpec CJS_Field::MethodSpecs[] = {
+    {"browseForFileToSubmit", browseForFileToSubmit_static},
+    {"buttonGetCaption", buttonGetCaption_static},
+    {"buttonGetIcon", buttonGetIcon_static},
+    {"buttonImportIcon", buttonImportIcon_static},
+    {"buttonSetCaption", buttonSetCaption_static},
+    {"buttonSetIcon", buttonSetIcon_static},
+    {"checkThisBox", checkThisBox_static},
+    {"clearItems", clearItems_static},
+    {"defaultIsChecked", defaultIsChecked_static},
+    {"deleteItemAt", deleteItemAt_static},
+    {"getArray", getArray_static},
+    {"getItemAt", getItemAt_static},
+    {"getLock", getLock_static},
+    {"insertItemAt", insertItemAt_static},
+    {"isBoxChecked", isBoxChecked_static},
+    {"isDefaultChecked", isDefaultChecked_static},
+    {"setAction", setAction_static},
+    {"setFocus", setFocus_static},
+    {"setItems", setItems_static},
+    {"setLock", setLock_static},
+    {"signatureGetModifications", signatureGetModifications_static},
+    {"signatureGetSeedValue", signatureGetSeedValue_static},
+    {"signatureInfo", signatureInfo_static},
+    {"signatureSetSeedValue", signatureSetSeedValue_static},
+    {"signatureSign", signatureSign_static},
+    {"signatureValidate", signatureValidate_static},
+    {0, 0}};
 
 IMPLEMENT_JS_CLASS(CJS_Field, Field)
 
@@ -375,7 +377,7 @@
   return pFormField->GetControl(m_nFormControlIndex);
 }
 
-bool Field::alignment(IJS_Context* cc,
+bool Field::alignment(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -431,7 +433,7 @@
   // Not supported.
 }
 
-bool Field::borderStyle(IJS_Context* cc,
+bool Field::borderStyle(CJS_Runtime* pRuntime,
                         CJS_PropValue& vp,
                         CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -540,7 +542,7 @@
   }
 }
 
-bool Field::buttonAlignX(IJS_Context* cc,
+bool Field::buttonAlignX(CJS_Runtime* pRuntime,
                          CJS_PropValue& vp,
                          CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -589,7 +591,7 @@
   // Not supported.
 }
 
-bool Field::buttonAlignY(IJS_Context* cc,
+bool Field::buttonAlignY(CJS_Runtime* pRuntime,
                          CJS_PropValue& vp,
                          CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -638,7 +640,7 @@
   // Not supported.
 }
 
-bool Field::buttonFitBounds(IJS_Context* cc,
+bool Field::buttonFitBounds(CJS_Runtime* pRuntime,
                             CJS_PropValue& vp,
                             CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -682,7 +684,7 @@
   // Not supported.
 }
 
-bool Field::buttonPosition(IJS_Context* cc,
+bool Field::buttonPosition(CJS_Runtime* pRuntime,
                            CJS_PropValue& vp,
                            CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -725,7 +727,7 @@
   // Not supported.
 }
 
-bool Field::buttonScaleHow(IJS_Context* cc,
+bool Field::buttonScaleHow(CJS_Runtime* pRuntime,
                            CJS_PropValue& vp,
                            CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -773,7 +775,7 @@
   // Not supported.
 }
 
-bool Field::buttonScaleWhen(IJS_Context* cc,
+bool Field::buttonScaleWhen(CJS_Runtime* pRuntime,
                             CJS_PropValue& vp,
                             CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -832,7 +834,7 @@
   // Not supported.
 }
 
-bool Field::calcOrderIndex(IJS_Context* cc,
+bool Field::calcOrderIndex(CJS_Runtime* pRuntime,
                            CJS_PropValue& vp,
                            CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -876,7 +878,7 @@
   // Not supported.
 }
 
-bool Field::charLimit(IJS_Context* cc,
+bool Field::charLimit(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -915,7 +917,9 @@
   // Not supported.
 }
 
-bool Field::comb(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool Field::comb(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
 
   if (vp.IsSetting()) {
@@ -956,7 +960,7 @@
   // Not supported.
 }
 
-bool Field::commitOnSelChange(IJS_Context* cc,
+bool Field::commitOnSelChange(CJS_Runtime* pRuntime,
                               CJS_PropValue& vp,
                               CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -1001,11 +1005,9 @@
   // Not supported.
 }
 
-bool Field::currentValueIndices(IJS_Context* cc,
+bool Field::currentValueIndices(CJS_Runtime* pRuntime,
                                 CJS_PropValue& vp,
                                 CFX_WideString& sError) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-
   if (vp.IsSetting()) {
     if (!m_bCanSet)
       return false;
@@ -1087,7 +1089,7 @@
   }
 }
 
-bool Field::defaultStyle(IJS_Context* cc,
+bool Field::defaultStyle(CJS_Runtime* pRuntime,
                          CJS_PropValue& vp,
                          CFX_WideString& sError) {
   return false;
@@ -1099,7 +1101,7 @@
   // Not supported.
 }
 
-bool Field::defaultValue(IJS_Context* cc,
+bool Field::defaultValue(CJS_Runtime* pRuntime,
                          CJS_PropValue& vp,
                          CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -1140,7 +1142,7 @@
   // Not supported.
 }
 
-bool Field::doNotScroll(IJS_Context* cc,
+bool Field::doNotScroll(CJS_Runtime* pRuntime,
                         CJS_PropValue& vp,
                         CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -1183,7 +1185,7 @@
   // Not supported.
 }
 
-bool Field::doNotSpellCheck(IJS_Context* cc,
+bool Field::doNotSpellCheck(CJS_Runtime* pRuntime,
                             CJS_PropValue& vp,
                             CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -1223,22 +1225,23 @@
   }
 }
 
-bool Field::delay(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    bool bVP;
-    vp >> bVP;
-
-    SetDelay(bVP);
-  } else {
+bool Field::delay(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError) {
+  if (!vp.IsSetting()) {
     vp << m_bDelay;
+    return true;
   }
+  if (!m_bCanSet)
+    return false;
+
+  bool bVP;
+  vp >> bVP;
+  SetDelay(bVP);
   return true;
 }
 
-bool Field::display(IJS_Context* cc,
+bool Field::display(CJS_Runtime* pRuntime,
                     CJS_PropValue& vp,
                     CFX_WideString& sError) {
   if (vp.IsSetting()) {
@@ -1247,43 +1250,40 @@
 
     int nVP;
     vp >> nVP;
-
     if (m_bDelay) {
       AddDelay_Int(FP_DISPLAY, nVP);
     } else {
       Field::SetDisplay(m_pFormFillEnv.Get(), m_FieldName, m_nFormControlIndex,
                         nVP);
     }
+    return true;
+  }
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
+
+  CPDF_FormField* pFormField = FieldArray[0];
+  ASSERT(pFormField);
+  CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
+  CPDFSDK_Widget* pWidget =
+      pInterForm->GetWidget(GetSmartFieldControl(pFormField));
+  if (!pWidget)
+    return false;
+
+  uint32_t dwFlag = pWidget->GetFlags();
+  if (ANNOTFLAG_INVISIBLE & dwFlag || ANNOTFLAG_HIDDEN & dwFlag) {
+    vp << (int32_t)1;
   } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    ASSERT(pFormField);
-    CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
-    CPDFSDK_Widget* pWidget =
-        pInterForm->GetWidget(GetSmartFieldControl(pFormField));
-    if (!pWidget)
-      return false;
-
-    uint32_t dwFlag = pWidget->GetFlags();
-
-    if (ANNOTFLAG_INVISIBLE & dwFlag || ANNOTFLAG_HIDDEN & dwFlag) {
-      vp << (int32_t)1;
-    } else {
-      if (ANNOTFLAG_PRINT & dwFlag) {
-        if (ANNOTFLAG_NOVIEW & dwFlag) {
-          vp << (int32_t)3;
-        } else {
-          vp << (int32_t)0;
-        }
+    if (ANNOTFLAG_PRINT & dwFlag) {
+      if (ANNOTFLAG_NOVIEW & dwFlag) {
+        vp << (int32_t)3;
       } else {
-        vp << (int32_t)2;
+        vp << (int32_t)0;
       }
+    } else {
+      vp << (int32_t)2;
     }
   }
-
   return true;
 }
 
@@ -1323,15 +1323,17 @@
   }
 }
 
-bool Field::doc(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
-  if (!vp.IsGetting()) {
+bool Field::doc(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError) {
+  if (!vp.IsGetting())
     return false;
-  }
+
   vp << m_pJSDoc->GetCJSDoc();
   return true;
 }
 
-bool Field::editable(IJS_Context* cc,
+bool Field::editable(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   if (vp.IsSetting()) {
@@ -1340,25 +1342,21 @@
 
     bool bVP;
     vp >> bVP;
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    if (pFormField->GetFieldType() != FIELDTYPE_COMBOBOX)
-      return false;
-
-    if (pFormField->GetFieldFlags() & FIELDFLAG_EDIT)
-      vp << true;
-    else
-      vp << false;
+    return true;
   }
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
 
+  CPDF_FormField* pFormField = FieldArray[0];
+  if (pFormField->GetFieldType() != FIELDTYPE_COMBOBOX)
+    return false;
+
+  vp << !!(pFormField->GetFieldFlags() & FIELDFLAG_EDIT);
   return true;
 }
 
-bool Field::exportValues(IJS_Context* cc,
+bool Field::exportValues(CJS_Runtime* pRuntime,
                          CJS_PropValue& vp,
                          CFX_WideString& sError) {
   std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
@@ -1370,42 +1368,35 @@
       pFormField->GetFieldType() != FIELDTYPE_RADIOBUTTON) {
     return false;
   }
+  if (vp.IsSetting())
+    return m_bCanSet && vp.GetJSValue()->IsArrayObject();
 
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    if (!vp.GetJSValue()->IsArrayObject())
-      return false;
-  } else {
-    CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-    CJS_Array ExportValusArray;
-    if (m_nFormControlIndex < 0) {
-      for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
-        CPDF_FormControl* pFormControl = pFormField->GetControl(i);
-        ExportValusArray.SetElement(
-            pRuntime, i,
-            CJS_Value(pRuntime, pFormControl->GetExportValue().c_str()));
-      }
-    } else {
-      if (m_nFormControlIndex >= pFormField->CountControls())
-        return false;
-
-      CPDF_FormControl* pFormControl =
-          pFormField->GetControl(m_nFormControlIndex);
-      if (!pFormControl)
-        return false;
-
+  CJS_Array ExportValusArray;
+  if (m_nFormControlIndex < 0) {
+    for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
+      CPDF_FormControl* pFormControl = pFormField->GetControl(i);
       ExportValusArray.SetElement(
-          pRuntime, 0,
+          pRuntime, i,
           CJS_Value(pRuntime, pFormControl->GetExportValue().c_str()));
     }
-    vp << ExportValusArray;
+  } else {
+    if (m_nFormControlIndex >= pFormField->CountControls())
+      return false;
+
+    CPDF_FormControl* pFormControl =
+        pFormField->GetControl(m_nFormControlIndex);
+    if (!pFormControl)
+      return false;
+
+    ExportValusArray.SetElement(
+        pRuntime, 0,
+        CJS_Value(pRuntime, pFormControl->GetExportValue().c_str()));
   }
+  vp << ExportValusArray;
   return true;
 }
 
-bool Field::fileSelect(IJS_Context* cc,
+bool Field::fileSelect(CJS_Runtime* pRuntime,
                        CJS_PropValue& vp,
                        CFX_WideString& sError) {
   std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
@@ -1422,19 +1413,15 @@
 
     bool bVP;
     vp >> bVP;
-  } else {
-    if (pFormField->GetFieldFlags() & FIELDFLAG_FILESELECT)
-      vp << true;
-    else
-      vp << false;
+    return true;
   }
+  vp << !!(pFormField->GetFieldFlags() & FIELDFLAG_FILESELECT);
   return true;
 }
 
-bool Field::fillColor(IJS_Context* cc,
+bool Field::fillColor(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CJS_Array crArray;
   std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
   if (FieldArray.empty())
@@ -1457,41 +1444,39 @@
       Field::SetFillColor(m_pFormFillEnv.Get(), m_FieldName,
                           m_nFormControlIndex, color);
     }
-  } else {
-    CPDF_FormField* pFormField = FieldArray[0];
-    ASSERT(pFormField);
-    CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-    if (!pFormControl)
-      return false;
-
-    int iColorType;
-    pFormControl->GetBackgroundColor(iColorType);
-
-    CPWL_Color color;
-    if (iColorType == COLORTYPE_TRANSPARENT) {
-      color = CPWL_Color(COLORTYPE_TRANSPARENT);
-    } else if (iColorType == COLORTYPE_GRAY) {
-      color = CPWL_Color(COLORTYPE_GRAY,
-                         pFormControl->GetOriginalBackgroundColor(0));
-    } else if (iColorType == COLORTYPE_RGB) {
-      color =
-          CPWL_Color(COLORTYPE_RGB, pFormControl->GetOriginalBackgroundColor(0),
-                     pFormControl->GetOriginalBackgroundColor(1),
-                     pFormControl->GetOriginalBackgroundColor(2));
-    } else if (iColorType == COLORTYPE_CMYK) {
-      color = CPWL_Color(COLORTYPE_CMYK,
-                         pFormControl->GetOriginalBackgroundColor(0),
-                         pFormControl->GetOriginalBackgroundColor(1),
-                         pFormControl->GetOriginalBackgroundColor(2),
-                         pFormControl->GetOriginalBackgroundColor(3));
-    } else {
-      return false;
-    }
-
-    color::ConvertPWLColorToArray(pRuntime, color, &crArray);
-    vp << crArray;
+    return true;
   }
+  CPDF_FormField* pFormField = FieldArray[0];
+  ASSERT(pFormField);
+  CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
+  if (!pFormControl)
+    return false;
 
+  int iColorType;
+  pFormControl->GetBackgroundColor(iColorType);
+
+  CPWL_Color color;
+  if (iColorType == COLORTYPE_TRANSPARENT) {
+    color = CPWL_Color(COLORTYPE_TRANSPARENT);
+  } else if (iColorType == COLORTYPE_GRAY) {
+    color =
+        CPWL_Color(COLORTYPE_GRAY, pFormControl->GetOriginalBackgroundColor(0));
+  } else if (iColorType == COLORTYPE_RGB) {
+    color =
+        CPWL_Color(COLORTYPE_RGB, pFormControl->GetOriginalBackgroundColor(0),
+                   pFormControl->GetOriginalBackgroundColor(1),
+                   pFormControl->GetOriginalBackgroundColor(2));
+  } else if (iColorType == COLORTYPE_CMYK) {
+    color =
+        CPWL_Color(COLORTYPE_CMYK, pFormControl->GetOriginalBackgroundColor(0),
+                   pFormControl->GetOriginalBackgroundColor(1),
+                   pFormControl->GetOriginalBackgroundColor(2),
+                   pFormControl->GetOriginalBackgroundColor(3));
+  } else {
+    return false;
+  }
+  color::ConvertPWLColorToArray(pRuntime, color, &crArray);
+  vp << crArray;
   return true;
 }
 
@@ -1502,40 +1487,40 @@
   // Not supported.
 }
 
-bool Field::hidden(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool Field::hidden(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError) {
   if (vp.IsSetting()) {
     if (!m_bCanSet)
       return false;
 
     bool bVP;
     vp >> bVP;
-
     if (m_bDelay) {
       AddDelay_Bool(FP_HIDDEN, bVP);
     } else {
       Field::SetHidden(m_pFormFillEnv.Get(), m_FieldName, m_nFormControlIndex,
                        bVP);
     }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    ASSERT(pFormField);
-    CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
-    CPDFSDK_Widget* pWidget =
-        pInterForm->GetWidget(GetSmartFieldControl(pFormField));
-    if (!pWidget)
-      return false;
-
-    uint32_t dwFlags = pWidget->GetFlags();
-
-    if (ANNOTFLAG_INVISIBLE & dwFlags || ANNOTFLAG_HIDDEN & dwFlags)
-      vp << true;
-    else
-      vp << false;
+    return true;
   }
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
+
+  CPDF_FormField* pFormField = FieldArray[0];
+  ASSERT(pFormField);
+  CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
+  CPDFSDK_Widget* pWidget =
+      pInterForm->GetWidget(GetSmartFieldControl(pFormField));
+  if (!pWidget)
+    return false;
+
+  uint32_t dwFlags = pWidget->GetFlags();
+  if (ANNOTFLAG_INVISIBLE & dwFlags || ANNOTFLAG_HIDDEN & dwFlags)
+    vp << true;
+  else
+    vp << false;
 
   return true;
 }
@@ -1548,11 +1533,10 @@
   SetDisplay(pFormFillEnv, swFieldName, nControlIndex, display);
 }
 
-bool Field::highlight(IJS_Context* cc,
+bool Field::highlight(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
-
   if (vp.IsSetting()) {
     if (!m_bCanSet)
       return false;
@@ -1566,39 +1550,38 @@
       Field::SetHighlight(m_pFormFillEnv.Get(), m_FieldName,
                           m_nFormControlIndex, strMode);
     }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON)
-      return false;
-
-    CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-    if (!pFormControl)
-      return false;
-
-    int eHM = pFormControl->GetHighlightingMode();
-    switch (eHM) {
-      case CPDF_FormControl::None:
-        vp << L"none";
-        break;
-      case CPDF_FormControl::Push:
-        vp << L"push";
-        break;
-      case CPDF_FormControl::Invert:
-        vp << L"invert";
-        break;
-      case CPDF_FormControl::Outline:
-        vp << L"outline";
-        break;
-      case CPDF_FormControl::Toggle:
-        vp << L"toggle";
-        break;
-    }
+    return true;
   }
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
 
+  CPDF_FormField* pFormField = FieldArray[0];
+  if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON)
+    return false;
+
+  CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
+  if (!pFormControl)
+    return false;
+
+  int eHM = pFormControl->GetHighlightingMode();
+  switch (eHM) {
+    case CPDF_FormControl::None:
+      vp << L"none";
+      break;
+    case CPDF_FormControl::Push:
+      vp << L"push";
+      break;
+    case CPDF_FormControl::Invert:
+      vp << L"invert";
+      break;
+    case CPDF_FormControl::Outline:
+      vp << L"outline";
+      break;
+    case CPDF_FormControl::Toggle:
+      vp << L"toggle";
+      break;
+  }
   return true;
 }
 
@@ -1609,7 +1592,7 @@
   // Not supported.
 }
 
-bool Field::lineWidth(IJS_Context* cc,
+bool Field::lineWidth(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
   if (vp.IsSetting()) {
@@ -1625,28 +1608,27 @@
       Field::SetLineWidth(m_pFormFillEnv.Get(), m_FieldName,
                           m_nFormControlIndex, iWidth);
     }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    ASSERT(pFormField);
-    CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-    if (!pFormControl)
-      return false;
-
-    CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
-    if (!pFormField->CountControls())
-      return false;
-
-    CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormField->GetControl(0));
-    if (!pWidget)
-      return false;
-
-    vp << (int32_t)pWidget->GetBorderWidth();
+    return true;
   }
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
 
+  CPDF_FormField* pFormField = FieldArray[0];
+  ASSERT(pFormField);
+  CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
+  if (!pFormControl)
+    return false;
+
+  CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
+  if (!pFormField->CountControls())
+    return false;
+
+  CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormField->GetControl(0));
+  if (!pWidget)
+    return false;
+
+  vp << (int32_t)pWidget->GetBorderWidth();
   return true;
 }
 
@@ -1689,7 +1671,7 @@
   }
 }
 
-bool Field::multiline(IJS_Context* cc,
+bool Field::multiline(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -1707,20 +1689,20 @@
       Field::SetMultiline(m_pFormFillEnv.Get(), m_FieldName,
                           m_nFormControlIndex, bVP);
     }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    if (pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD)
-      return false;
-
-    if (pFormField->GetFieldFlags() & FIELDFLAG_MULTILINE)
-      vp << true;
-    else
-      vp << false;
+    return true;
   }
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
+
+  CPDF_FormField* pFormField = FieldArray[0];
+  if (pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD)
+    return false;
+
+  if (pFormField->GetFieldFlags() & FIELDFLAG_MULTILINE)
+    vp << true;
+  else
+    vp << false;
 
   return true;
 }
@@ -1732,39 +1714,33 @@
   // Not supported.
 }
 
-bool Field::multipleSelection(IJS_Context* cc,
+bool Field::multipleSelection(CJS_Runtime* pRuntime,
                               CJS_PropValue& vp,
                               CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
-
   if (vp.IsSetting()) {
     if (!m_bCanSet)
       return false;
 
     bool bVP;
     vp >> bVP;
-
     if (m_bDelay) {
       AddDelay_Bool(FP_MULTIPLESELECTION, bVP);
     } else {
       Field::SetMultipleSelection(m_pFormFillEnv.Get(), m_FieldName,
                                   m_nFormControlIndex, bVP);
     }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    if (pFormField->GetFieldType() != FIELDTYPE_LISTBOX)
-      return false;
-
-    if (pFormField->GetFieldFlags() & FIELDFLAG_MULTISELECT)
-      vp << true;
-    else
-      vp << false;
+    return true;
   }
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
 
+  CPDF_FormField* pFormField = FieldArray[0];
+  if (pFormField->GetFieldType() != FIELDTYPE_LISTBOX)
+    return false;
+
+  vp << !!(pFormField->GetFieldFlags() & FIELDFLAG_MULTISELECT);
   return true;
 }
 
@@ -1775,7 +1751,9 @@
   // Not supported.
 }
 
-bool Field::name(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool Field::name(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 
@@ -1784,11 +1762,10 @@
     return false;
 
   vp << m_FieldName;
-
   return true;
 }
 
-bool Field::numItems(IJS_Context* cc,
+bool Field::numItems(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   if (!vp.IsGetting())
@@ -1808,7 +1785,9 @@
   return true;
 }
 
-bool Field::page(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool Field::page(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError) {
   if (!vp.IsGetting()) {
     sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
     return false;
@@ -1829,7 +1808,6 @@
     return true;
   }
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CJS_Array PageArray;
   int i = 0;
   for (const auto& pObserved : widgets) {
@@ -1852,7 +1830,7 @@
   return true;
 }
 
-bool Field::password(IJS_Context* cc,
+bool Field::password(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -1863,28 +1841,24 @@
 
     bool bVP;
     vp >> bVP;
-
     if (m_bDelay) {
       AddDelay_Bool(FP_PASSWORD, bVP);
     } else {
       Field::SetPassword(m_pFormFillEnv.Get(), m_FieldName, m_nFormControlIndex,
                          bVP);
     }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    if (pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD)
-      return false;
-
-    if (pFormField->GetFieldFlags() & FIELDFLAG_PASSWORD)
-      vp << true;
-    else
-      vp << false;
+    return true;
   }
 
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
+
+  CPDF_FormField* pFormField = FieldArray[0];
+  if (pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD)
+    return false;
+
+  vp << !!(pFormField->GetFieldFlags() & FIELDFLAG_PASSWORD);
   return true;
 }
 
@@ -1895,7 +1869,9 @@
   // Not supported.
 }
 
-bool Field::print(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool Field::print(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError) {
   CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
   std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
   if (FieldArray.empty())
@@ -1951,23 +1927,20 @@
         }
       }
     }
-  } else {
-    CPDF_FormField* pFormField = FieldArray[0];
-    CPDFSDK_Widget* pWidget =
-        pInterForm->GetWidget(GetSmartFieldControl(pFormField));
-    if (!pWidget)
-      return false;
-
-    if (pWidget->GetFlags() & ANNOTFLAG_PRINT)
-      vp << true;
-    else
-      vp << false;
+    return true;
   }
 
+  CPDF_FormField* pFormField = FieldArray[0];
+  CPDFSDK_Widget* pWidget =
+      pInterForm->GetWidget(GetSmartFieldControl(pFormField));
+  if (!pWidget)
+    return false;
+
+  vp << !!(pWidget->GetFlags() & ANNOTFLAG_PRINT);
   return true;
 }
 
-bool Field::radiosInUnison(IJS_Context* cc,
+bool Field::radiosInUnison(CJS_Runtime* pRuntime,
                            CJS_PropValue& vp,
                            CFX_WideString& sError) {
   std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
@@ -1980,22 +1953,17 @@
 
     bool bVP;
     vp >> bVP;
-
-  } else {
-    CPDF_FormField* pFormField = FieldArray[0];
-    if (pFormField->GetFieldType() != FIELDTYPE_RADIOBUTTON)
-      return false;
-
-    if (pFormField->GetFieldFlags() & FIELDFLAG_RADIOSINUNISON)
-      vp << true;
-    else
-      vp << false;
+    return true;
   }
+  CPDF_FormField* pFormField = FieldArray[0];
+  if (pFormField->GetFieldType() != FIELDTYPE_RADIOBUTTON)
+    return false;
 
+  vp << !!(pFormField->GetFieldFlags() & FIELDFLAG_RADIOSINUNISON);
   return true;
 }
 
-bool Field::readonly(IJS_Context* cc,
+bool Field::readonly(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
@@ -2008,20 +1976,15 @@
 
     bool bVP;
     vp >> bVP;
-
-  } else {
-    CPDF_FormField* pFormField = FieldArray[0];
-    if (pFormField->GetFieldFlags() & FIELDFLAG_READONLY)
-      vp << true;
-    else
-      vp << false;
+    return true;
   }
-
+  vp << !!(FieldArray[0]->GetFieldFlags() & FIELDFLAG_READONLY);
   return true;
 }
 
-bool Field::rect(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
+bool Field::rect(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError) {
   CJS_Value Upper_Leftx(pRuntime);
   CJS_Value Upper_Lefty(pRuntime);
   CJS_Value Lower_Rightx(pRuntime);
@@ -2053,31 +2016,31 @@
       Field::SetRect(m_pFormFillEnv.Get(), m_FieldName, m_nFormControlIndex,
                      crRect);
     }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
-    CPDFSDK_Widget* pWidget =
-        pInterForm->GetWidget(GetSmartFieldControl(pFormField));
-    if (!pWidget)
-      return false;
-
-    CFX_FloatRect crRect = pWidget->GetRect();
-    Upper_Leftx = CJS_Value(pRuntime, static_cast<int32_t>(crRect.left));
-    Upper_Lefty = CJS_Value(pRuntime, static_cast<int32_t>(crRect.top));
-    Lower_Rightx = CJS_Value(pRuntime, static_cast<int32_t>(crRect.right));
-    Lower_Righty = CJS_Value(pRuntime, static_cast<int32_t>(crRect.bottom));
-
-    CJS_Array rcArray;
-    rcArray.SetElement(pRuntime, 0, Upper_Leftx);
-    rcArray.SetElement(pRuntime, 1, Upper_Lefty);
-    rcArray.SetElement(pRuntime, 2, Lower_Rightx);
-    rcArray.SetElement(pRuntime, 3, Lower_Righty);
-    vp << rcArray;
+    return true;
   }
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
+
+  CPDF_FormField* pFormField = FieldArray[0];
+  CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
+  CPDFSDK_Widget* pWidget =
+      pInterForm->GetWidget(GetSmartFieldControl(pFormField));
+  if (!pWidget)
+    return false;
+
+  CFX_FloatRect crRect = pWidget->GetRect();
+  Upper_Leftx = CJS_Value(pRuntime, static_cast<int32_t>(crRect.left));
+  Upper_Lefty = CJS_Value(pRuntime, static_cast<int32_t>(crRect.top));
+  Lower_Rightx = CJS_Value(pRuntime, static_cast<int32_t>(crRect.right));
+  Lower_Righty = CJS_Value(pRuntime, static_cast<int32_t>(crRect.bottom));
+
+  CJS_Array rcArray;
+  rcArray.SetElement(pRuntime, 0, Upper_Leftx);
+  rcArray.SetElement(pRuntime, 1, Upper_Lefty);
+  rcArray.SetElement(pRuntime, 2, Lower_Rightx);
+  rcArray.SetElement(pRuntime, 3, Lower_Righty);
+  vp << rcArray;
   return true;
 }
 
@@ -2139,7 +2102,7 @@
   }
 }
 
-bool Field::required(IJS_Context* cc,
+bool Field::required(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
@@ -2152,22 +2115,17 @@
 
     bool bVP;
     vp >> bVP;
-
-  } else {
-    CPDF_FormField* pFormField = FieldArray[0];
-    if (pFormField->GetFieldType() == FIELDTYPE_PUSHBUTTON)
-      return false;
-
-    if (pFormField->GetFieldFlags() & FIELDFLAG_REQUIRED)
-      vp << true;
-    else
-      vp << false;
+    return true;
   }
+  CPDF_FormField* pFormField = FieldArray[0];
+  if (pFormField->GetFieldType() == FIELDTYPE_PUSHBUTTON)
+    return false;
 
+  vp << !!(pFormField->GetFieldFlags() & FIELDFLAG_REQUIRED);
   return true;
 }
 
-bool Field::richText(IJS_Context* cc,
+bool Field::richText(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -2178,35 +2136,31 @@
 
     bool bVP;
     vp >> bVP;
-
-    if (m_bDelay) {
+    if (m_bDelay)
       AddDelay_Bool(FP_RICHTEXT, bVP);
-    }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
 
-    CPDF_FormField* pFormField = FieldArray[0];
-    if (pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD)
-      return false;
-
-    if (pFormField->GetFieldFlags() & FIELDFLAG_RICHTEXT)
-      vp << true;
-    else
-      vp << false;
+    return true;
   }
 
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
+
+  CPDF_FormField* pFormField = FieldArray[0];
+  if (pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD)
+    return false;
+
+  vp << !!(pFormField->GetFieldFlags() & FIELDFLAG_RICHTEXT);
   return true;
 }
 
-bool Field::richValue(IJS_Context* cc,
+bool Field::richValue(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
   return true;
 }
 
-bool Field::rotation(IJS_Context* cc,
+bool Field::rotation(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -2217,26 +2171,24 @@
 
     int nVP;
     vp >> nVP;
-
     if (m_bDelay) {
       AddDelay_Int(FP_ROTATION, nVP);
     } else {
       Field::SetRotation(m_pFormFillEnv.Get(), m_FieldName, m_nFormControlIndex,
                          nVP);
     }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-    if (!pFormControl)
-      return false;
-
-    vp << (int32_t)pFormControl->GetRotation();
+    return true;
   }
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
 
+  CPDF_FormField* pFormField = FieldArray[0];
+  CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
+  if (!pFormControl)
+    return false;
+
+  vp << (int32_t)pFormControl->GetRotation();
   return true;
 }
 
@@ -2247,10 +2199,9 @@
   // Not supported.
 }
 
-bool Field::strokeColor(IJS_Context* cc,
+bool Field::strokeColor(CJS_Runtime* pRuntime,
                         CJS_PropValue& vp,
                         CFX_WideString& sError) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CJS_Array crArray;
 
   if (vp.IsSetting()) {
@@ -2264,49 +2215,46 @@
 
     CPWL_Color color;
     color::ConvertArrayToPWLColor(pRuntime, crArray, &color);
-
     if (m_bDelay) {
       AddDelay_Color(FP_STROKECOLOR, color);
     } else {
       Field::SetStrokeColor(m_pFormFillEnv.Get(), m_FieldName,
                             m_nFormControlIndex, color);
     }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-    if (!pFormControl)
-      return false;
-
-    int iColorType;
-    pFormControl->GetBorderColor(iColorType);
-
-    CPWL_Color color;
-    if (iColorType == COLORTYPE_TRANSPARENT) {
-      color = CPWL_Color(COLORTYPE_TRANSPARENT);
-    } else if (iColorType == COLORTYPE_GRAY) {
-      color =
-          CPWL_Color(COLORTYPE_GRAY, pFormControl->GetOriginalBorderColor(0));
-    } else if (iColorType == COLORTYPE_RGB) {
-      color = CPWL_Color(COLORTYPE_RGB, pFormControl->GetOriginalBorderColor(0),
-                         pFormControl->GetOriginalBorderColor(1),
-                         pFormControl->GetOriginalBorderColor(2));
-    } else if (iColorType == COLORTYPE_CMYK) {
-      color =
-          CPWL_Color(COLORTYPE_CMYK, pFormControl->GetOriginalBorderColor(0),
-                     pFormControl->GetOriginalBorderColor(1),
-                     pFormControl->GetOriginalBorderColor(2),
-                     pFormControl->GetOriginalBorderColor(3));
-    } else {
-      return false;
-    }
-
-    color::ConvertPWLColorToArray(pRuntime, color, &crArray);
-    vp << crArray;
+    return true;
   }
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
+
+  CPDF_FormField* pFormField = FieldArray[0];
+  CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
+  if (!pFormControl)
+    return false;
+
+  int iColorType;
+  pFormControl->GetBorderColor(iColorType);
+
+  CPWL_Color color;
+  if (iColorType == COLORTYPE_TRANSPARENT) {
+    color = CPWL_Color(COLORTYPE_TRANSPARENT);
+  } else if (iColorType == COLORTYPE_GRAY) {
+    color = CPWL_Color(COLORTYPE_GRAY, pFormControl->GetOriginalBorderColor(0));
+  } else if (iColorType == COLORTYPE_RGB) {
+    color = CPWL_Color(COLORTYPE_RGB, pFormControl->GetOriginalBorderColor(0),
+                       pFormControl->GetOriginalBorderColor(1),
+                       pFormControl->GetOriginalBorderColor(2));
+  } else if (iColorType == COLORTYPE_CMYK) {
+    color = CPWL_Color(COLORTYPE_CMYK, pFormControl->GetOriginalBorderColor(0),
+                       pFormControl->GetOriginalBorderColor(1),
+                       pFormControl->GetOriginalBorderColor(2),
+                       pFormControl->GetOriginalBorderColor(3));
+  } else {
+    return false;
+  }
+
+  color::ConvertPWLColorToArray(pRuntime, color, &crArray);
+  vp << crArray;
   return true;
 }
 
@@ -2317,7 +2265,9 @@
   // Not supported.
 }
 
-bool Field::style(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool Field::style(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
 
   if (vp.IsSetting()) {
@@ -2333,47 +2283,46 @@
       Field::SetStyle(m_pFormFillEnv.Get(), m_FieldName, m_nFormControlIndex,
                       csBCaption);
     }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
+    return true;
+  }
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
 
-    CPDF_FormField* pFormField = FieldArray[0];
-    if (pFormField->GetFieldType() != FIELDTYPE_RADIOBUTTON &&
-        pFormField->GetFieldType() != FIELDTYPE_CHECKBOX) {
-      return false;
-    }
-
-    CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-    if (!pFormControl)
-      return false;
-
-    CFX_WideString csWCaption = pFormControl->GetNormalCaption();
-    CFX_ByteString csBCaption;
-
-    switch (csWCaption[0]) {
-      case L'l':
-        csBCaption = "circle";
-        break;
-      case L'8':
-        csBCaption = "cross";
-        break;
-      case L'u':
-        csBCaption = "diamond";
-        break;
-      case L'n':
-        csBCaption = "square";
-        break;
-      case L'H':
-        csBCaption = "star";
-        break;
-      default:  // L'4'
-        csBCaption = "check";
-        break;
-    }
-    vp << csBCaption;
+  CPDF_FormField* pFormField = FieldArray[0];
+  if (pFormField->GetFieldType() != FIELDTYPE_RADIOBUTTON &&
+      pFormField->GetFieldType() != FIELDTYPE_CHECKBOX) {
+    return false;
   }
 
+  CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
+  if (!pFormControl)
+    return false;
+
+  CFX_WideString csWCaption = pFormControl->GetNormalCaption();
+  CFX_ByteString csBCaption;
+
+  switch (csWCaption[0]) {
+    case L'l':
+      csBCaption = "circle";
+      break;
+    case L'8':
+      csBCaption = "cross";
+      break;
+    case L'u':
+      csBCaption = "diamond";
+      break;
+    case L'n':
+      csBCaption = "square";
+      break;
+    case L'H':
+      csBCaption = "star";
+      break;
+    default:  // L'4'
+      csBCaption = "check";
+      break;
+  }
+  vp << csBCaption;
   return true;
 }
 
@@ -2384,16 +2333,15 @@
   // Not supported.
 }
 
-bool Field::submitName(IJS_Context* cc,
+bool Field::submitName(CJS_Runtime* pRuntime,
                        CJS_PropValue& vp,
                        CFX_WideString& sError) {
   return true;
 }
 
-bool Field::textColor(IJS_Context* cc,
+bool Field::textColor(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CJS_Array crArray;
 
   if (vp.IsSetting()) {
@@ -2407,40 +2355,42 @@
 
     CPWL_Color color;
     color::ConvertArrayToPWLColor(pRuntime, crArray, &color);
-
     if (m_bDelay) {
       AddDelay_Color(FP_TEXTCOLOR, color);
     } else {
       Field::SetTextColor(m_pFormFillEnv.Get(), m_FieldName,
                           m_nFormControlIndex, color);
     }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-    if (!pFormControl)
-      return false;
-
-    int iColorType;
-    FX_ARGB color;
-    CPDF_DefaultAppearance FieldAppearance =
-        pFormControl->GetDefaultAppearance();
-    FieldAppearance.GetColor(color, iColorType);
-    int32_t a, r, g, b;
-    ArgbDecode(color, a, r, g, b);
-
-    CPWL_Color crRet =
-        CPWL_Color(COLORTYPE_RGB, r / 255.0f, g / 255.0f, b / 255.0f);
-
-    if (iColorType == COLORTYPE_TRANSPARENT)
-      crRet = CPWL_Color(COLORTYPE_TRANSPARENT);
-
-    color::ConvertPWLColorToArray(pRuntime, crRet, &crArray);
-    vp << crArray;
+    return true;
   }
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
+
+  CPDF_FormField* pFormField = FieldArray[0];
+  CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
+  if (!pFormControl)
+    return false;
+
+  int iColorType;
+  FX_ARGB color;
+  CPDF_DefaultAppearance FieldAppearance = pFormControl->GetDefaultAppearance();
+  FieldAppearance.GetColor(color, iColorType);
+
+  int32_t a;
+  int32_t r;
+  int32_t g;
+  int32_t b;
+  ArgbDecode(color, a, r, g, b);
+
+  CPWL_Color crRet =
+      CPWL_Color(COLORTYPE_RGB, r / 255.0f, g / 255.0f, b / 255.0f);
+
+  if (iColorType == COLORTYPE_TRANSPARENT)
+    crRet = CPWL_Color(COLORTYPE_TRANSPARENT);
+
+  color::ConvertPWLColorToArray(pRuntime, crRet, &crArray);
+  vp << crArray;
   return true;
 }
 
@@ -2451,7 +2401,7 @@
   // Not supported.
 }
 
-bool Field::textFont(IJS_Context* cc,
+bool Field::textFont(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -2471,32 +2421,28 @@
       Field::SetTextFont(m_pFormFillEnv.Get(), m_FieldName, m_nFormControlIndex,
                          csFontName);
     }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    ASSERT(pFormField);
-    CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-    if (!pFormControl)
-      return false;
-
-    int nFieldType = pFormField->GetFieldType();
-
-    if (nFieldType == FIELDTYPE_PUSHBUTTON ||
-        nFieldType == FIELDTYPE_COMBOBOX || nFieldType == FIELDTYPE_LISTBOX ||
-        nFieldType == FIELDTYPE_TEXTFIELD) {
-      CPDF_Font* pFont = pFormControl->GetDefaultControlFont();
-      if (!pFont)
-        return false;
-
-      vp << pFont->GetBaseFont();
-    } else {
-      return false;
-    }
+    return true;
   }
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
 
+  CPDF_FormField* pFormField = FieldArray[0];
+  ASSERT(pFormField);
+  CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
+  if (!pFormControl)
+    return false;
+
+  int nFieldType = pFormField->GetFieldType();
+  if (nFieldType != FIELDTYPE_PUSHBUTTON && nFieldType != FIELDTYPE_COMBOBOX &&
+      nFieldType != FIELDTYPE_LISTBOX && nFieldType != FIELDTYPE_TEXTFIELD) {
+    return false;
+  }
+  CPDF_Font* pFont = pFormControl->GetDefaultControlFont();
+  if (!pFont)
+    return false;
+
+  vp << pFont->GetBaseFont();
   return true;
 }
 
@@ -2507,7 +2453,7 @@
   // Not supported.
 }
 
-bool Field::textSize(IJS_Context* cc,
+bool Field::textSize(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -2518,34 +2464,30 @@
 
     int nVP;
     vp >> nVP;
-
     if (m_bDelay) {
       AddDelay_Int(FP_TEXTSIZE, nVP);
     } else {
       Field::SetTextSize(m_pFormFillEnv.Get(), m_FieldName, m_nFormControlIndex,
                          nVP);
     }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    ASSERT(pFormField);
-    CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-    if (!pFormControl)
-      return false;
-
-    CPDF_DefaultAppearance FieldAppearance =
-        pFormControl->GetDefaultAppearance();
-
-    CFX_ByteString csFontNameTag;
-    FX_FLOAT fFontSize;
-    FieldAppearance.GetFont(csFontNameTag, fFontSize);
-
-    vp << (int)fFontSize;
+    return true;
   }
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
 
+  CPDF_FormField* pFormField = FieldArray[0];
+  ASSERT(pFormField);
+  CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
+  if (!pFormControl)
+    return false;
+
+  CPDF_DefaultAppearance FieldAppearance = pFormControl->GetDefaultAppearance();
+
+  CFX_ByteString csFontNameTag;
+  FX_FLOAT fFontSize;
+  FieldAppearance.GetFont(csFontNameTag, fFontSize);
+  vp << (int)fFontSize;
   return true;
 }
 
@@ -2556,7 +2498,9 @@
   // Not supported.
 }
 
-bool Field::type(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool Field::type(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 
@@ -2594,11 +2538,10 @@
       vp << L"unknown";
       break;
   }
-
   return true;
 }
 
-bool Field::userName(IJS_Context* cc,
+bool Field::userName(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   ASSERT(m_pFormFillEnv);
@@ -2616,15 +2559,13 @@
       Field::SetUserName(m_pFormFillEnv.Get(), m_FieldName, m_nFormControlIndex,
                          swName);
     }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    vp << (CFX_WideString)pFormField->GetAlternateName();
+    return true;
   }
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
 
+  vp << FieldArray[0]->GetAlternateName();
   return true;
 }
 
@@ -2635,9 +2576,9 @@
   // Not supported.
 }
 
-bool Field::value(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-
+bool Field::value(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError) {
   if (vp.IsSetting()) {
     if (!m_bCanSet)
       return false;
@@ -2663,57 +2604,58 @@
       Field::SetValue(m_pFormFillEnv.Get(), m_FieldName, m_nFormControlIndex,
                       strArray);
     }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
+    return true;
+  }
 
-    CPDF_FormField* pFormField = FieldArray[0];
-    switch (pFormField->GetFieldType()) {
-      case FIELDTYPE_PUSHBUTTON:
-        return false;
-      case FIELDTYPE_COMBOBOX:
-      case FIELDTYPE_TEXTFIELD: {
-        vp << pFormField->GetValue();
-      } break;
-      case FIELDTYPE_LISTBOX: {
-        if (pFormField->CountSelectedItems() > 1) {
-          CJS_Array ValueArray;
-          CJS_Value ElementValue(pRuntime);
-          int iIndex;
-          for (int i = 0, sz = pFormField->CountSelectedItems(); i < sz; i++) {
-            iIndex = pFormField->GetSelectedIndex(i);
+  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
+  if (FieldArray.empty())
+    return false;
+
+  CPDF_FormField* pFormField = FieldArray[0];
+  switch (pFormField->GetFieldType()) {
+    case FIELDTYPE_PUSHBUTTON:
+      return false;
+    case FIELDTYPE_COMBOBOX:
+    case FIELDTYPE_TEXTFIELD: {
+      vp << pFormField->GetValue();
+    } break;
+    case FIELDTYPE_LISTBOX: {
+      if (pFormField->CountSelectedItems() > 1) {
+        CJS_Array ValueArray;
+        CJS_Value ElementValue(pRuntime);
+        int iIndex;
+        for (int i = 0, sz = pFormField->CountSelectedItems(); i < sz; i++) {
+          iIndex = pFormField->GetSelectedIndex(i);
+          ElementValue =
+              CJS_Value(pRuntime, pFormField->GetOptionValue(iIndex).c_str());
+          if (FXSYS_wcslen(ElementValue.ToCFXWideString(pRuntime).c_str()) ==
+              0) {
             ElementValue =
-                CJS_Value(pRuntime, pFormField->GetOptionValue(iIndex).c_str());
-            if (FXSYS_wcslen(ElementValue.ToCFXWideString(pRuntime).c_str()) ==
-                0) {
-              ElementValue = CJS_Value(
-                  pRuntime, pFormField->GetOptionLabel(iIndex).c_str());
-            }
-            ValueArray.SetElement(pRuntime, i, ElementValue);
+                CJS_Value(pRuntime, pFormField->GetOptionLabel(iIndex).c_str());
           }
-          vp << ValueArray;
-        } else {
-          vp << pFormField->GetValue();
+          ValueArray.SetElement(pRuntime, i, ElementValue);
         }
-      } break;
-      case FIELDTYPE_CHECKBOX:
-      case FIELDTYPE_RADIOBUTTON: {
-        bool bFind = false;
-        for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
-          if (pFormField->GetControl(i)->IsChecked()) {
-            vp << pFormField->GetControl(i)->GetExportValue();
-            bFind = true;
-            break;
-          }
-        }
-        if (!bFind)
-          vp << L"Off";
-      } break;
-      default:
+        vp << ValueArray;
+      } else {
         vp << pFormField->GetValue();
-        break;
-    }
+      }
+    } break;
+    case FIELDTYPE_CHECKBOX:
+    case FIELDTYPE_RADIOBUTTON: {
+      bool bFind = false;
+      for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
+        if (pFormField->GetControl(i)->IsChecked()) {
+          vp << pFormField->GetControl(i)->GetExportValue();
+          bFind = true;
+          break;
+        }
+      }
+      if (!bFind)
+        vp << L"Off";
+    } break;
+    default:
+      vp << pFormField->GetValue();
+      break;
   }
   vp.GetJSValue()->MaybeCoerceToNumber(pRuntime);
   return true;
@@ -2773,7 +2715,7 @@
   }
 }
 
-bool Field::valueAsString(IJS_Context* cc,
+bool Field::valueAsString(CJS_Runtime* pRuntime,
                           CJS_PropValue& vp,
                           CFX_WideString& sError) {
   if (!vp.IsGetting())
@@ -2815,7 +2757,7 @@
   return true;
 }
 
-bool Field::browseForFileToSubmit(IJS_Context* cc,
+bool Field::browseForFileToSubmit(CJS_Runtime* pRuntime,
                                   const std::vector<CJS_Value>& params,
                                   CJS_Value& vRet,
                                   CFX_WideString& sError) {
@@ -2836,12 +2778,10 @@
   return false;
 }
 
-bool Field::buttonGetCaption(IJS_Context* cc,
+bool Field::buttonGetCaption(CJS_Runtime* pRuntime,
                              const std::vector<CJS_Value>& params,
                              CJS_Value& vRet,
                              CFX_WideString& sError) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-
   int nface = 0;
   int iSize = params.size();
   if (iSize >= 1)
@@ -2871,17 +2811,15 @@
   return true;
 }
 
-bool Field::buttonGetIcon(IJS_Context* cc,
+bool Field::buttonGetIcon(CJS_Runtime* pRuntime,
                           const std::vector<CJS_Value>& params,
                           CJS_Value& vRet,
                           CFX_WideString& sError) {
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-
-  int nface = 0;
-  int iSize = params.size();
-  if (iSize >= 1)
-    nface = params[0].ToInt(pRuntime);
+  if (params.size() >= 1) {
+    int nFace = params[0].ToInt(pRuntime);
+    if (nFace < 0 || nFace > 2)
+      return false;
+  }
 
   std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
   if (FieldArray.empty())
@@ -2897,48 +2835,36 @@
 
   v8::Local<v8::Object> pObj =
       pRuntime->NewFxDynamicObj(CJS_Icon::g_nObjDefnID);
-  ASSERT(pObj.IsEmpty() == false);
-
-  CJS_Icon* pJS_Icon = static_cast<CJS_Icon*>(pRuntime->GetObjectPrivate(pObj));
-  Icon* pIcon = (Icon*)pJS_Icon->GetEmbedObject();
-
-  CPDF_Stream* pIconStream = nullptr;
-  if (nface == 0)
-    pIconStream = pFormControl->GetNormalIcon();
-  else if (nface == 1)
-    pIconStream = pFormControl->GetDownIcon();
-  else if (nface == 2)
-    pIconStream = pFormControl->GetRolloverIcon();
-  else
+  if (pObj.IsEmpty())
     return false;
 
-  pIcon->SetStream(pIconStream);
+  CJS_Icon* pJS_Icon = static_cast<CJS_Icon*>(pRuntime->GetObjectPrivate(pObj));
   vRet = CJS_Value(pRuntime, pJS_Icon);
   return true;
 }
 
-bool Field::buttonImportIcon(IJS_Context* cc,
+bool Field::buttonImportIcon(CJS_Runtime* pRuntime,
                              const std::vector<CJS_Value>& params,
                              CJS_Value& vRet,
                              CFX_WideString& sError) {
   return true;
 }
 
-bool Field::buttonSetCaption(IJS_Context* cc,
+bool Field::buttonSetCaption(CJS_Runtime* pRuntime,
                              const std::vector<CJS_Value>& params,
                              CJS_Value& vRet,
                              CFX_WideString& sError) {
   return false;
 }
 
-bool Field::buttonSetIcon(IJS_Context* cc,
+bool Field::buttonSetIcon(CJS_Runtime* pRuntime,
                           const std::vector<CJS_Value>& params,
                           CJS_Value& vRet,
                           CFX_WideString& sError) {
   return false;
 }
 
-bool Field::checkThisBox(IJS_Context* cc,
+bool Field::checkThisBox(CJS_Runtime* pRuntime,
                          const std::vector<CJS_Value>& params,
                          CJS_Value& vRet,
                          CFX_WideString& sError) {
@@ -2949,9 +2875,7 @@
   if (!m_bCanSet)
     return false;
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   int nWidget = params[0].ToInt(pRuntime);
-
   bool bCheckit = true;
   if (iSize >= 2)
     bCheckit = params[1].ToBool(pRuntime);
@@ -2977,14 +2901,14 @@
   return true;
 }
 
-bool Field::clearItems(IJS_Context* cc,
+bool Field::clearItems(CJS_Runtime* pRuntime,
                        const std::vector<CJS_Value>& params,
                        CJS_Value& vRet,
                        CFX_WideString& sError) {
   return true;
 }
 
-bool Field::defaultIsChecked(IJS_Context* cc,
+bool Field::defaultIsChecked(CJS_Runtime* pRuntime,
                              const std::vector<CJS_Value>& params,
                              CJS_Value& vRet,
                              CFX_WideString& sError) {
@@ -2995,9 +2919,7 @@
   if (iSize < 1)
     return false;
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   int nWidget = params[0].ToInt(pRuntime);
-
   std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
   if (FieldArray.empty())
     return false;
@@ -3013,14 +2935,14 @@
   return true;
 }
 
-bool Field::deleteItemAt(IJS_Context* cc,
+bool Field::deleteItemAt(CJS_Runtime* pRuntime,
                          const std::vector<CJS_Value>& params,
                          CJS_Value& vRet,
                          CFX_WideString& sError) {
   return true;
 }
 
-bool Field::getArray(IJS_Context* cc,
+bool Field::getArray(CJS_Runtime* pRuntime,
                      const std::vector<CJS_Value>& params,
                      CJS_Value& vRet,
                      CFX_WideString& sError) {
@@ -3039,15 +2961,14 @@
       [](const std::unique_ptr<CFX_WideString>& p1,
          const std::unique_ptr<CFX_WideString>& p2) { return *p1 < *p2; });
 
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
   CJS_Array FormFieldArray;
 
   int j = 0;
   for (const auto& pStr : swSort) {
     v8::Local<v8::Object> pObj =
         pRuntime->NewFxDynamicObj(CJS_Field::g_nObjDefnID);
-    ASSERT(!pObj.IsEmpty());
+    if (pObj.IsEmpty())
+      return false;
 
     CJS_Field* pJSField =
         static_cast<CJS_Field*>(pRuntime->GetObjectPrivate(pObj));
@@ -3060,12 +2981,10 @@
   return true;
 }
 
-bool Field::getItemAt(IJS_Context* cc,
+bool Field::getItemAt(CJS_Runtime* pRuntime,
                       const std::vector<CJS_Value>& params,
                       CJS_Value& vRet,
                       CFX_WideString& sError) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-
   int iSize = params.size();
   int nIdx = -1;
   if (iSize >= 1)
@@ -3100,26 +3019,24 @@
   return true;
 }
 
-bool Field::getLock(IJS_Context* cc,
+bool Field::getLock(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError) {
   return false;
 }
 
-bool Field::insertItemAt(IJS_Context* cc,
+bool Field::insertItemAt(CJS_Runtime* pRuntime,
                          const std::vector<CJS_Value>& params,
                          CJS_Value& vRet,
                          CFX_WideString& sError) {
   return true;
 }
 
-bool Field::isBoxChecked(IJS_Context* cc,
+bool Field::isBoxChecked(CJS_Runtime* pRuntime,
                          const std::vector<CJS_Value>& params,
                          CJS_Value& vRet,
                          CFX_WideString& sError) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-
   int nIndex = -1;
   if (params.size() >= 1)
     nIndex = params[0].ToInt(pRuntime);
@@ -3140,12 +3057,10 @@
   return true;
 }
 
-bool Field::isDefaultChecked(IJS_Context* cc,
+bool Field::isDefaultChecked(CJS_Runtime* pRuntime,
                              const std::vector<CJS_Value>& params,
                              CJS_Value& vRet,
                              CFX_WideString& sError) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-
   int nIndex = -1;
   if (params.size() >= 1)
     nIndex = params[0].ToInt(pRuntime);
@@ -3165,14 +3080,14 @@
   return true;
 }
 
-bool Field::setAction(IJS_Context* cc,
+bool Field::setAction(CJS_Runtime* pRuntime,
                       const std::vector<CJS_Value>& params,
                       CJS_Value& vRet,
                       CFX_WideString& sError) {
   return true;
 }
 
-bool Field::setFocus(IJS_Context* cc,
+bool Field::setFocus(CJS_Runtime* pRuntime,
                      const std::vector<CJS_Value>& params,
                      CJS_Value& vRet,
                      CFX_WideString& sError) {
@@ -3217,63 +3132,65 @@
   return true;
 }
 
-bool Field::setItems(IJS_Context* cc,
+bool Field::setItems(CJS_Runtime* pRuntime,
                      const std::vector<CJS_Value>& params,
                      CJS_Value& vRet,
                      CFX_WideString& sError) {
   return true;
 }
 
-bool Field::setLock(IJS_Context* cc,
+bool Field::setLock(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError) {
   return false;
 }
 
-bool Field::signatureGetModifications(IJS_Context* cc,
+bool Field::signatureGetModifications(CJS_Runtime* pRuntime,
                                       const std::vector<CJS_Value>& params,
                                       CJS_Value& vRet,
                                       CFX_WideString& sError) {
   return false;
 }
 
-bool Field::signatureGetSeedValue(IJS_Context* cc,
+bool Field::signatureGetSeedValue(CJS_Runtime* pRuntime,
                                   const std::vector<CJS_Value>& params,
                                   CJS_Value& vRet,
                                   CFX_WideString& sError) {
   return false;
 }
 
-bool Field::signatureInfo(IJS_Context* cc,
+bool Field::signatureInfo(CJS_Runtime* pRuntime,
                           const std::vector<CJS_Value>& params,
                           CJS_Value& vRet,
                           CFX_WideString& sError) {
   return false;
 }
 
-bool Field::signatureSetSeedValue(IJS_Context* cc,
+bool Field::signatureSetSeedValue(CJS_Runtime* pRuntime,
                                   const std::vector<CJS_Value>& params,
                                   CJS_Value& vRet,
                                   CFX_WideString& sError) {
   return false;
 }
 
-bool Field::signatureSign(IJS_Context* cc,
+bool Field::signatureSign(CJS_Runtime* pRuntime,
                           const std::vector<CJS_Value>& params,
                           CJS_Value& vRet,
                           CFX_WideString& sError) {
   return false;
 }
 
-bool Field::signatureValidate(IJS_Context* cc,
+bool Field::signatureValidate(CJS_Runtime* pRuntime,
                               const std::vector<CJS_Value>& params,
                               CJS_Value& vRet,
                               CFX_WideString& sError) {
   return false;
 }
 
-bool Field::source(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool Field::source(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError) {
   if (vp.IsGetting()) {
     vp << (CJS_Object*)nullptr;
   }
diff --git a/fpdfsdk/javascript/Field.h b/fpdfsdk/javascript/Field.h
index f3948ff..462c127 100644
--- a/fpdfsdk/javascript/Field.h
+++ b/fpdfsdk/javascript/Field.h
@@ -77,182 +77,240 @@
   explicit Field(CJS_Object* pJSObject);
   ~Field() override;
 
-  bool alignment(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool borderStyle(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool buttonAlignX(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool buttonAlignY(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool buttonFitBounds(IJS_Context* cc,
+  bool alignment(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError);
+  bool borderStyle(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError);
+  bool buttonAlignX(CJS_Runtime* pRuntime,
+                    CJS_PropValue& vp,
+                    CFX_WideString& sError);
+  bool buttonAlignY(CJS_Runtime* pRuntime,
+                    CJS_PropValue& vp,
+                    CFX_WideString& sError);
+  bool buttonFitBounds(CJS_Runtime* pRuntime,
                        CJS_PropValue& vp,
                        CFX_WideString& sError);
-  bool buttonPosition(IJS_Context* cc,
+  bool buttonPosition(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError);
-  bool buttonScaleHow(IJS_Context* cc,
+  bool buttonScaleHow(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError);
-  bool buttonScaleWhen(IJS_Context* cc,
+  bool buttonScaleWhen(CJS_Runtime* pRuntime,
                        CJS_PropValue& vp,
                        CFX_WideString& sError);
-  bool calcOrderIndex(IJS_Context* cc,
+  bool calcOrderIndex(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError);
-  bool charLimit(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool comb(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool commitOnSelChange(IJS_Context* cc,
+  bool charLimit(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError);
+  bool comb(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool commitOnSelChange(CJS_Runtime* pRuntime,
                          CJS_PropValue& vp,
                          CFX_WideString& sError);
-  bool currentValueIndices(IJS_Context* cc,
+  bool currentValueIndices(CJS_Runtime* pRuntime,
                            CJS_PropValue& vp,
                            CFX_WideString& sError);
-  bool defaultStyle(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool defaultValue(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool doNotScroll(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool doNotSpellCheck(IJS_Context* cc,
+  bool defaultStyle(CJS_Runtime* pRuntime,
+                    CJS_PropValue& vp,
+                    CFX_WideString& sError);
+  bool defaultValue(CJS_Runtime* pRuntime,
+                    CJS_PropValue& vp,
+                    CFX_WideString& sError);
+  bool doNotScroll(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError);
+  bool doNotSpellCheck(CJS_Runtime* pRuntime,
                        CJS_PropValue& vp,
                        CFX_WideString& sError);
-  bool delay(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool display(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool doc(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool editable(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool exportValues(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool fileSelect(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool fillColor(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool hidden(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool highlight(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool lineWidth(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool multiline(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool multipleSelection(IJS_Context* cc,
+  bool delay(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool display(CJS_Runtime* pRuntime,
+               CJS_PropValue& vp,
+               CFX_WideString& sError);
+  bool doc(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool editable(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool exportValues(CJS_Runtime* pRuntime,
+                    CJS_PropValue& vp,
+                    CFX_WideString& sError);
+  bool fileSelect(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError);
+  bool fillColor(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError);
+  bool hidden(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool highlight(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError);
+  bool lineWidth(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError);
+  bool multiline(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError);
+  bool multipleSelection(CJS_Runtime* pRuntime,
                          CJS_PropValue& vp,
                          CFX_WideString& sError);
-  bool name(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool numItems(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool page(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool password(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool print(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool radiosInUnison(IJS_Context* cc,
+  bool name(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool numItems(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool page(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool password(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool print(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool radiosInUnison(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError);
-  bool readonly(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool rect(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool required(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool richText(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool richValue(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool rotation(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool strokeColor(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool style(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool submitName(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool textColor(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool textFont(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool textSize(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool type(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool userName(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool value(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool valueAsString(IJS_Context* cc,
+  bool readonly(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool rect(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool required(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool richText(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool richValue(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError);
+  bool rotation(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool strokeColor(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError);
+  bool style(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool submitName(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError);
+  bool textColor(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError);
+  bool textFont(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool textSize(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool type(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool userName(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool value(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool valueAsString(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError);
-  bool source(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
+  bool source(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
 
-  bool browseForFileToSubmit(IJS_Context* cc,
+  bool browseForFileToSubmit(CJS_Runtime* pRuntime,
                              const std::vector<CJS_Value>& params,
                              CJS_Value& vRet,
                              CFX_WideString& sError);
-  bool buttonGetCaption(IJS_Context* cc,
+  bool buttonGetCaption(CJS_Runtime* pRuntime,
                         const std::vector<CJS_Value>& params,
                         CJS_Value& vRet,
                         CFX_WideString& sError);
-  bool buttonGetIcon(IJS_Context* cc,
+  bool buttonGetIcon(CJS_Runtime* pRuntime,
                      const std::vector<CJS_Value>& params,
                      CJS_Value& vRet,
                      CFX_WideString& sError);
-  bool buttonImportIcon(IJS_Context* cc,
+  bool buttonImportIcon(CJS_Runtime* pRuntime,
                         const std::vector<CJS_Value>& params,
                         CJS_Value& vRet,
                         CFX_WideString& sError);
-  bool buttonSetCaption(IJS_Context* cc,
+  bool buttonSetCaption(CJS_Runtime* pRuntime,
                         const std::vector<CJS_Value>& params,
                         CJS_Value& vRet,
                         CFX_WideString& sError);
-  bool buttonSetIcon(IJS_Context* cc,
+  bool buttonSetIcon(CJS_Runtime* pRuntime,
                      const std::vector<CJS_Value>& params,
                      CJS_Value& vRet,
                      CFX_WideString& sError);
-  bool checkThisBox(IJS_Context* cc,
+  bool checkThisBox(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError);
-  bool clearItems(IJS_Context* cc,
+  bool clearItems(CJS_Runtime* pRuntime,
                   const std::vector<CJS_Value>& params,
                   CJS_Value& vRet,
                   CFX_WideString& sError);
-  bool defaultIsChecked(IJS_Context* cc,
+  bool defaultIsChecked(CJS_Runtime* pRuntime,
                         const std::vector<CJS_Value>& params,
                         CJS_Value& vRet,
                         CFX_WideString& sError);
-  bool deleteItemAt(IJS_Context* cc,
+  bool deleteItemAt(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError);
-  bool getArray(IJS_Context* cc,
+  bool getArray(CJS_Runtime* pRuntime,
                 const std::vector<CJS_Value>& params,
                 CJS_Value& vRet,
                 CFX_WideString& sError);
-  bool getItemAt(IJS_Context* cc,
+  bool getItemAt(CJS_Runtime* pRuntime,
                  const std::vector<CJS_Value>& params,
                  CJS_Value& vRet,
                  CFX_WideString& sError);
-  bool getLock(IJS_Context* cc,
+  bool getLock(CJS_Runtime* pRuntime,
                const std::vector<CJS_Value>& params,
                CJS_Value& vRet,
                CFX_WideString& sError);
-  bool insertItemAt(IJS_Context* cc,
+  bool insertItemAt(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError);
-  bool isBoxChecked(IJS_Context* cc,
+  bool isBoxChecked(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError);
-  bool isDefaultChecked(IJS_Context* cc,
+  bool isDefaultChecked(CJS_Runtime* pRuntime,
                         const std::vector<CJS_Value>& params,
                         CJS_Value& vRet,
                         CFX_WideString& sError);
-  bool setAction(IJS_Context* cc,
+  bool setAction(CJS_Runtime* pRuntime,
                  const std::vector<CJS_Value>& params,
                  CJS_Value& vRet,
                  CFX_WideString& sError);
-  bool setFocus(IJS_Context* cc,
+  bool setFocus(CJS_Runtime* pRuntime,
                 const std::vector<CJS_Value>& params,
                 CJS_Value& vRet,
                 CFX_WideString& sError);
-  bool setItems(IJS_Context* cc,
+  bool setItems(CJS_Runtime* pRuntime,
                 const std::vector<CJS_Value>& params,
                 CJS_Value& vRet,
                 CFX_WideString& sError);
-  bool setLock(IJS_Context* cc,
+  bool setLock(CJS_Runtime* pRuntime,
                const std::vector<CJS_Value>& params,
                CJS_Value& vRet,
                CFX_WideString& sError);
-  bool signatureGetModifications(IJS_Context* cc,
+  bool signatureGetModifications(CJS_Runtime* pRuntime,
                                  const std::vector<CJS_Value>& params,
                                  CJS_Value& vRet,
                                  CFX_WideString& sError);
-  bool signatureGetSeedValue(IJS_Context* cc,
+  bool signatureGetSeedValue(CJS_Runtime* pRuntime,
                              const std::vector<CJS_Value>& params,
                              CJS_Value& vRet,
                              CFX_WideString& sError);
-  bool signatureInfo(IJS_Context* cc,
+  bool signatureInfo(CJS_Runtime* pRuntime,
                      const std::vector<CJS_Value>& params,
                      CJS_Value& vRet,
                      CFX_WideString& sError);
-  bool signatureSetSeedValue(IJS_Context* cc,
+  bool signatureSetSeedValue(CJS_Runtime* pRuntime,
                              const std::vector<CJS_Value>& params,
                              CJS_Value& vRet,
                              CFX_WideString& sError);
-  bool signatureSign(IJS_Context* cc,
+  bool signatureSign(CJS_Runtime* pRuntime,
                      const std::vector<CJS_Value>& params,
                      CJS_Value& vRet,
                      CFX_WideString& sError);
-  bool signatureValidate(IJS_Context* cc,
+  bool signatureValidate(CJS_Runtime* pRuntime,
                          const std::vector<CJS_Value>& params,
                          CJS_Value& vRet,
                          CFX_WideString& sError);
diff --git a/fpdfsdk/javascript/Icon.cpp b/fpdfsdk/javascript/Icon.cpp
index 94841ef..fa2f92f 100644
--- a/fpdfsdk/javascript/Icon.cpp
+++ b/fpdfsdk/javascript/Icon.cpp
@@ -10,41 +10,24 @@
 #include "fpdfsdk/javascript/JS_Object.h"
 #include "fpdfsdk/javascript/JS_Value.h"
 
-BEGIN_JS_STATIC_CONST(CJS_Icon)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Icon::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
 
-BEGIN_JS_STATIC_PROP(CJS_Icon)
-JS_STATIC_PROP_ENTRY(name)
-END_JS_STATIC_PROP()
+JSPropertySpec CJS_Icon::PropertySpecs[] = {
+    {"name", get_name_static, set_name_static},
+    {0, 0, 0}};
 
-BEGIN_JS_STATIC_METHOD(CJS_Icon)
-END_JS_STATIC_METHOD()
+JSMethodSpec CJS_Icon::MethodSpecs[] = {{0, 0}};
 
 IMPLEMENT_JS_CLASS(CJS_Icon, Icon)
 
 Icon::Icon(CJS_Object* pJSObject)
-    : CJS_EmbedObj(pJSObject), m_pIconStream(nullptr), m_swIconName(L"") {}
+    : CJS_EmbedObj(pJSObject), m_swIconName(L"") {}
 
 Icon::~Icon() {}
 
-void Icon::SetStream(CPDF_Stream* pIconStream) {
-  if (pIconStream)
-    m_pIconStream = pIconStream;
-}
-
-CPDF_Stream* Icon::GetStream() {
-  return m_pIconStream;
-}
-
-void Icon::SetIconName(CFX_WideString name) {
-  m_swIconName = name;
-}
-
-CFX_WideString Icon::GetIconName() {
-  return m_swIconName;
-}
-
-bool Icon::name(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool Icon::name(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 
diff --git a/fpdfsdk/javascript/Icon.h b/fpdfsdk/javascript/Icon.h
index 98a479c..5580678 100644
--- a/fpdfsdk/javascript/Icon.h
+++ b/fpdfsdk/javascript/Icon.h
@@ -16,14 +16,11 @@
   explicit Icon(CJS_Object* pJSObject);
   ~Icon() override;
 
-  bool name(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  void SetStream(CPDF_Stream* pIconStream);
-  CPDF_Stream* GetStream();
-  void SetIconName(CFX_WideString name);
-  CFX_WideString GetIconName();
+  bool name(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  CFX_WideString GetIconName() const { return m_swIconName; }
+  void SetIconName(CFX_WideString name) { m_swIconName = name; }
 
  private:
-  CPDF_Stream* m_pIconStream;
   CFX_WideString m_swIconName;
 };
 
diff --git a/fpdfsdk/javascript/JS_Define.h b/fpdfsdk/javascript/JS_Define.h
index feab4d1..375ca3a 100644
--- a/fpdfsdk/javascript/JS_Define.h
+++ b/fpdfsdk/javascript/JS_Define.h
@@ -15,62 +15,26 @@
 #include "fxjs/fxjs_v8.h"
 
 struct JSConstSpec {
-  const wchar_t* pName;
+  enum Type { Number = 0, String = 1 };
+
+  const char* pName;
+  Type eType;
   double number;
-  const wchar_t* str;
-  uint8_t t;              // 0:double 1:str
+  const char* pStr;
 };
 
 struct JSPropertySpec {
-  const wchar_t* pName;
+  const char* pName;
   v8::AccessorGetterCallback pPropGet;
   v8::AccessorSetterCallback pPropPut;
 };
 
 struct JSMethodSpec {
-  const wchar_t* pName;
+  const char* pName;
   v8::FunctionCallback pMethodCall;
 };
 
-#define JS_WIDESTRING(widestring) L## #widestring
-#define BEGIN_JS_STATIC_CONST(js_class_name) \
-  JSConstSpec js_class_name::JS_Class_Consts[] = {
-#define JS_STATIC_CONST_ENTRY_NUMBER(const_name, pValue) \
-  { const_name, pValue, L"", 0 }                         \
-  ,
-
-#define JS_STATIC_CONST_ENTRY_STRING(const_name, pValue) \
-  { const_name, 0, pValue, 1 }                           \
-  ,
-
-#define END_JS_STATIC_CONST() \
-  { 0, 0, 0, 0 }              \
-  }                           \
-  ;  // NOLINT
-
-#define BEGIN_JS_STATIC_PROP(js_class_name) \
-  JSPropertySpec js_class_name::JS_Class_Properties[] = {
-#define JS_STATIC_PROP_ENTRY(prop_name)                \
-  {JS_WIDESTRING(prop_name), get_##prop_name##_static, \
-   set_##prop_name##_static},  // NOLINT
-
-#define END_JS_STATIC_PROP() \
-  { 0, 0, 0 }                \
-  }                          \
-  ;  // NOLINT
-
-#define BEGIN_JS_STATIC_METHOD(js_class_name) \
-  JSMethodSpec js_class_name::JS_Class_Methods[] = {
-#define JS_STATIC_METHOD_ENTRY(method_name)            \
-  { JS_WIDESTRING(method_name), method_name##_static } \
-  ,
-
-#define END_JS_STATIC_METHOD() \
-  { 0, 0 }                     \
-  }                            \
-  ;  // NOLINT
-
-template <class C, bool (C::*M)(IJS_Context*, CJS_PropValue&, CFX_WideString&)>
+template <class C, bool (C::*M)(CJS_Runtime*, CJS_PropValue&, CFX_WideString&)>
 void JSPropGetter(const char* prop_name_string,
                   const char* class_name_string,
                   v8::Local<v8::String> property,
@@ -81,11 +45,13 @@
     return;
   CJS_Object* pJSObj =
       static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
+  if (!pJSObj)
+    return;
   C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject());
   CFX_WideString sError;
   CJS_PropValue value(pRuntime);
   value.StartGetting();
-  if (!(pObj->*M)(pRuntime->GetCurrentContext(), value, sError)) {
+  if (!(pObj->*M)(pRuntime, value, sError)) {
     pRuntime->Error(
         JSFormatErrorString(class_name_string, prop_name_string, sError));
     return;
@@ -93,7 +59,7 @@
   info.GetReturnValue().Set(value.GetJSValue()->ToV8Value(pRuntime));
 }
 
-template <class C, bool (C::*M)(IJS_Context*, CJS_PropValue&, CFX_WideString&)>
+template <class C, bool (C::*M)(CJS_Runtime*, CJS_PropValue&, CFX_WideString&)>
 void JSPropSetter(const char* prop_name_string,
                   const char* class_name_string,
                   v8::Local<v8::String> property,
@@ -105,11 +71,13 @@
     return;
   CJS_Object* pJSObj =
       static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
+  if (!pJSObj)
+    return;
   C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject());
   CFX_WideString sError;
   CJS_PropValue propValue(pRuntime, CJS_Value(pRuntime, value));
   propValue.StartSetting();
-  if (!(pObj->*M)(pRuntime->GetCurrentContext(), propValue, sError)) {
+  if (!(pObj->*M)(pRuntime, propValue, sError)) {
     pRuntime->Error(
         JSFormatErrorString(class_name_string, prop_name_string, sError));
   }
@@ -130,7 +98,7 @@
   }
 
 template <class C,
-          bool (C::*M)(IJS_Context*,
+          bool (C::*M)(CJS_Runtime*,
                        const std::vector<CJS_Value>&,
                        CJS_Value&,
                        CFX_WideString&)>
@@ -147,11 +115,12 @@
   }
   CJS_Object* pJSObj =
       static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
+  if (!pJSObj)
+    return;
   C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject());
   CFX_WideString sError;
   CJS_Value valueRes(pRuntime);
-  if (!(pObj->*M)(pRuntime->GetCurrentContext(), parameters, valueRes,
-                  sError)) {
+  if (!(pObj->*M)(pRuntime, parameters, valueRes, sError)) {
     pRuntime->Error(
         JSFormatErrorString(class_name_string, method_name_string, sError));
     return;
@@ -176,13 +145,13 @@
 // All JS classes have a name, an object defintion ID, and the ability to
 // register themselves with FXJS_V8. We never make a BASE class on its own
 // because it can't really do anything.
-#define DECLARE_JS_CLASS_BASE_PART()  \
-  static const wchar_t* g_pClassName; \
-  static int g_nObjDefnID;            \
+#define DECLARE_JS_CLASS_BASE_PART() \
+  static const char* g_pClassName;   \
+  static int g_nObjDefnID;           \
   static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
 
-#define IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name)           \
-  const wchar_t* js_class_name::g_pClassName = JS_WIDESTRING(class_name); \
+#define IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name) \
+  const char* js_class_name::g_pClassName = #class_name;        \
   int js_class_name::g_nObjDefnID = -1;
 
 // CONST classes provide constants, but not constructors, methods, or props.
@@ -200,19 +169,18 @@
     DefineConsts(pEngine);                                                   \
   }
 
-#define DECLARE_JS_CLASS_CONST_PART()   \
-  static JSConstSpec JS_Class_Consts[]; \
+#define DECLARE_JS_CLASS_CONST_PART() \
+  static JSConstSpec ConstSpecs[];    \
   static void DefineConsts(CFXJS_Engine* pEngine);
 
-#define IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)     \
-  void js_class_name::DefineConsts(CFXJS_Engine* pEngine) {          \
-    for (size_t i = 0; i < FX_ArraySize(JS_Class_Consts) - 1; ++i) { \
-      pEngine->DefineObjConst(                                       \
-          g_nObjDefnID, JS_Class_Consts[i].pName,                    \
-          JS_Class_Consts[i].t == 0                                  \
-              ? pEngine->NewNumber(JS_Class_Consts[i].number)        \
-              : pEngine->NewString(JS_Class_Consts[i].str));         \
-    }                                                                \
+#define IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)             \
+  void js_class_name::DefineConsts(CFXJS_Engine* pEngine) {                  \
+    for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {              \
+      pEngine->DefineObjConst(g_nObjDefnID, ConstSpecs[i].pName,             \
+                              ConstSpecs[i].eType == JSConstSpec::Number     \
+                                  ? pEngine->NewNumber(ConstSpecs[i].number) \
+                                  : pEngine->NewString(ConstSpecs[i].pStr)); \
+    }                                                                        \
   }
 
 // Convenience macros for declaring classes without an alternate.
@@ -245,36 +213,34 @@
   static void JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);  \
   static void DefineProps(CFXJS_Engine* pEngine);                              \
   static void DefineMethods(CFXJS_Engine* pEngine);                            \
-  static JSPropertySpec JS_Class_Properties[];                                 \
-  static JSMethodSpec JS_Class_Methods[];
+  static JSPropertySpec PropertySpecs[];                                       \
+  static JSMethodSpec MethodSpecs[];
 
-#define IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate,         \
-                                     class_name)                             \
-  void js_class_name::JSConstructor(CFXJS_Engine* pEngine,                   \
-                                    v8::Local<v8::Object> obj) {             \
-    CJS_Object* pObj = new js_class_name(obj);                               \
-    pObj->SetEmbedObject(new class_alternate(pObj));                         \
-    pEngine->SetObjectPrivate(obj, (void*)pObj);                             \
-    pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));                  \
-  }                                                                          \
-  void js_class_name::JSDestructor(CFXJS_Engine* pEngine,                    \
-                                   v8::Local<v8::Object> obj) {              \
-    js_class_name* pObj =                                                    \
-        static_cast<js_class_name*>(pEngine->GetObjectPrivate(obj));         \
-    delete pObj;                                                             \
-  }                                                                          \
-  void js_class_name::DefineProps(CFXJS_Engine* pEngine) {                   \
-    for (size_t i = 0; i < FX_ArraySize(JS_Class_Properties) - 1; ++i) {     \
-      pEngine->DefineObjProperty(g_nObjDefnID, JS_Class_Properties[i].pName, \
-                                 JS_Class_Properties[i].pPropGet,            \
-                                 JS_Class_Properties[i].pPropPut);           \
-    }                                                                        \
-  }                                                                          \
-  void js_class_name::DefineMethods(CFXJS_Engine* pEngine) {                 \
-    for (size_t i = 0; i < FX_ArraySize(JS_Class_Methods) - 1; ++i) {        \
-      pEngine->DefineObjMethod(g_nObjDefnID, JS_Class_Methods[i].pName,      \
-                               JS_Class_Methods[i].pMethodCall);             \
-    }                                                                        \
+#define IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate,    \
+                                     class_name)                        \
+  void js_class_name::JSConstructor(CFXJS_Engine* pEngine,              \
+                                    v8::Local<v8::Object> obj) {        \
+    CJS_Object* pObj = new js_class_name(obj);                          \
+    pObj->SetEmbedObject(new class_alternate(pObj));                    \
+    pEngine->SetObjectPrivate(obj, (void*)pObj);                        \
+    pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));             \
+  }                                                                     \
+  void js_class_name::JSDestructor(CFXJS_Engine* pEngine,               \
+                                   v8::Local<v8::Object> obj) {         \
+    delete static_cast<js_class_name*>(pEngine->GetObjectPrivate(obj)); \
+  }                                                                     \
+  void js_class_name::DefineProps(CFXJS_Engine* pEngine) {              \
+    for (size_t i = 0; i < FX_ArraySize(PropertySpecs) - 1; ++i) {      \
+      pEngine->DefineObjProperty(g_nObjDefnID, PropertySpecs[i].pName,  \
+                                 PropertySpecs[i].pPropGet,             \
+                                 PropertySpecs[i].pPropPut);            \
+    }                                                                   \
+  }                                                                     \
+  void js_class_name::DefineMethods(CFXJS_Engine* pEngine) {            \
+    for (size_t i = 0; i < FX_ArraySize(MethodSpecs) - 1; ++i) {        \
+      pEngine->DefineObjMethod(g_nObjDefnID, MethodSpecs[i].pName,      \
+                               MethodSpecs[i].pMethodCall);             \
+    }                                                                   \
   }
 
 // Special JS classes implement methods, props, and queries, but not consts.
@@ -348,12 +314,18 @@
                         const v8::PropertyCallbackInfo<v8::Integer>& info) {
   CJS_Runtime* pRuntime =
       CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
+  if (!pRuntime)
+    return;
+
+  CJS_Object* pJSObj =
+      static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
+  if (!pJSObj)
+    return;
+
+  Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
   v8::String::Utf8Value utf8_value(property);
   CFX_WideString propname = CFX_WideString::FromUTF8(
       CFX_ByteStringC(*utf8_value, utf8_value.length()));
-  CJS_Object* pJSObj =
-      static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
-  Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
   bool bRet = pObj->QueryProperty(propname.c_str());
   info.GetReturnValue().Set(bRet ? 4 : 0);
 }
@@ -366,8 +338,12 @@
       CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
   if (!pRuntime)
     return;
+
   CJS_Object* pJSObj =
       static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
+  if (!pJSObj)
+    return;
+
   Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
   v8::String::Utf8Value utf8_value(property);
   CFX_WideString propname = CFX_WideString::FromUTF8(
@@ -375,8 +351,7 @@
   CFX_WideString sError;
   CJS_PropValue value(pRuntime);
   value.StartGetting();
-  if (!pObj->DoProperty(pRuntime->GetCurrentContext(), propname.c_str(), value,
-                        sError)) {
+  if (!pObj->DoProperty(pRuntime, propname.c_str(), value, sError)) {
     pRuntime->Error(JSFormatErrorString(class_name, "GetProperty", sError));
     return;
   }
@@ -392,8 +367,12 @@
       CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
   if (!pRuntime)
     return;
+
   CJS_Object* pJSObj =
       static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
+  if (!pJSObj)
+    return;
+
   Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
   v8::String::Utf8Value utf8_value(property);
   CFX_WideString propname = CFX_WideString::FromUTF8(
@@ -401,8 +380,7 @@
   CFX_WideString sError;
   CJS_PropValue PropValue(pRuntime, CJS_Value(pRuntime, value));
   PropValue.StartSetting();
-  if (!pObj->DoProperty(pRuntime->GetCurrentContext(), propname.c_str(),
-                        PropValue, sError)) {
+  if (!pObj->DoProperty(pRuntime, propname.c_str(), PropValue, sError)) {
     pRuntime->Error(JSFormatErrorString(class_name, "PutProperty", sError));
   }
 }
@@ -415,22 +393,25 @@
       CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
   if (!pRuntime)
     return;
+
   CJS_Object* pJSObj =
       static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
+  if (!pJSObj)
+    return;
+
   Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
   v8::String::Utf8Value utf8_value(property);
   CFX_WideString propname = CFX_WideString::FromUTF8(
       CFX_ByteStringC(*utf8_value, utf8_value.length()));
   CFX_WideString sError;
-  if (!pObj->DelProperty(pRuntime->GetCurrentContext(), propname.c_str(),
-                         sError)) {
+  if (!pObj->DelProperty(pRuntime, propname.c_str(), sError)) {
     CFX_ByteString cbName;
     cbName.Format("%s.%s", class_name, "DelProperty");
     // Probably a missing call to JSFX_Error().
   }
 }
 
-template <bool (*F)(IJS_Context*,
+template <bool (*F)(CJS_Runtime*,
                     const std::vector<CJS_Value>&,
                     CJS_Value&,
                     CFX_WideString&)>
@@ -446,7 +427,7 @@
   }
   CJS_Value valueRes(pRuntime);
   CFX_WideString sError;
-  if (!(*F)(pRuntime->GetCurrentContext(), parameters, valueRes, sError)) {
+  if (!(*F)(pRuntime, parameters, valueRes, sError)) {
     pRuntime->Error(JSFormatErrorString(func_name_string, nullptr, sError));
     return;
   }
@@ -459,24 +440,17 @@
     JSGlobalFunc<fun_name>(#fun_name, info);             \
   }
 
-#define JS_STATIC_DECLARE_GLOBAL_FUN()  \
-  static JSMethodSpec global_methods[]; \
+#define JS_STATIC_DECLARE_GLOBAL_FUN()       \
+  static JSMethodSpec GlobalFunctionSpecs[]; \
   static void DefineJSObjects(CFXJS_Engine* pEngine)
 
-#define BEGIN_JS_STATIC_GLOBAL_FUN(js_class_name) \
-  JSMethodSpec js_class_name::global_methods[] = {
-#define JS_STATIC_GLOBAL_FUN_ENTRY(method_name) \
-  JS_STATIC_METHOD_ENTRY(method_name)
-
-#define END_JS_STATIC_GLOBAL_FUN() END_JS_STATIC_METHOD()
-
-#define IMPLEMENT_JS_STATIC_GLOBAL_FUN(js_class_name)               \
-  void js_class_name::DefineJSObjects(CFXJS_Engine* pEngine) {      \
-    for (size_t i = 0; i < FX_ArraySize(global_methods) - 1; ++i) { \
-      pEngine->DefineGlobalMethod(                                  \
-          js_class_name::global_methods[i].pName,                   \
-          js_class_name::global_methods[i].pMethodCall);            \
-    }                                                               \
+#define IMPLEMENT_JS_STATIC_GLOBAL_FUN(js_class_name)                    \
+  void js_class_name::DefineJSObjects(CFXJS_Engine* pEngine) {           \
+    for (size_t i = 0; i < FX_ArraySize(GlobalFunctionSpecs) - 1; ++i) { \
+      pEngine->DefineGlobalMethod(                                       \
+          js_class_name::GlobalFunctionSpecs[i].pName,                   \
+          js_class_name::GlobalFunctionSpecs[i].pMethodCall);            \
+    }                                                                    \
   }
 
 #endif  // FPDFSDK_JAVASCRIPT_JS_DEFINE_H_
diff --git a/fpdfsdk/javascript/JS_EventHandler.cpp b/fpdfsdk/javascript/JS_EventHandler.cpp
index 5715cb9..bd1c8e2 100644
--- a/fpdfsdk/javascript/JS_EventHandler.cpp
+++ b/fpdfsdk/javascript/JS_EventHandler.cpp
@@ -11,11 +11,11 @@
 #include "fpdfsdk/javascript/JS_Define.h"
 #include "fpdfsdk/javascript/JS_Object.h"
 #include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/cjs_context.h"
+#include "fpdfsdk/javascript/cjs_event_context.h"
 #include "fpdfsdk/javascript/cjs_runtime.h"
 
-CJS_EventHandler::CJS_EventHandler(CJS_Context* pContext)
-    : m_pJSContext(pContext),
+CJS_EventHandler::CJS_EventHandler(CJS_EventContext* pContext)
+    : m_pJSEventContext(pContext),
       m_eEventType(JET_UNKNOWN),
       m_bValid(false),
       m_pWideStrChange(nullptr),
@@ -45,60 +45,60 @@
 void CJS_EventHandler::OnDoc_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv,
                                   const CFX_WideString& strTargetName) {
   Initial(JET_DOC_OPEN);
-  m_pTargetFormFillEnv = pFormFillEnv;
+  m_pTargetFormFillEnv.Reset(pFormFillEnv);
   m_strTargetName = strTargetName;
 }
 
 void CJS_EventHandler::OnDoc_WillPrint(
     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
   Initial(JET_DOC_WILLPRINT);
-  m_pTargetFormFillEnv = pFormFillEnv;
+  m_pTargetFormFillEnv.Reset(pFormFillEnv);
 }
 
 void CJS_EventHandler::OnDoc_DidPrint(
     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
   Initial(JET_DOC_DIDPRINT);
-  m_pTargetFormFillEnv = pFormFillEnv;
+  m_pTargetFormFillEnv.Reset(pFormFillEnv);
 }
 
 void CJS_EventHandler::OnDoc_WillSave(
     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
   Initial(JET_DOC_WILLSAVE);
-  m_pTargetFormFillEnv = pFormFillEnv;
+  m_pTargetFormFillEnv.Reset(pFormFillEnv);
 }
 
 void CJS_EventHandler::OnDoc_DidSave(
     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
   Initial(JET_DOC_DIDSAVE);
-  m_pTargetFormFillEnv = pFormFillEnv;
+  m_pTargetFormFillEnv.Reset(pFormFillEnv);
 }
 
 void CJS_EventHandler::OnDoc_WillClose(
     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
   Initial(JET_DOC_WILLCLOSE);
-  m_pTargetFormFillEnv = pFormFillEnv;
+  m_pTargetFormFillEnv.Reset(pFormFillEnv);
 }
 
 void CJS_EventHandler::OnPage_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
   Initial(JET_PAGE_OPEN);
-  m_pTargetFormFillEnv = pFormFillEnv;
+  m_pTargetFormFillEnv.Reset(pFormFillEnv);
 }
 
 void CJS_EventHandler::OnPage_Close(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
   Initial(JET_PAGE_CLOSE);
-  m_pTargetFormFillEnv = pFormFillEnv;
+  m_pTargetFormFillEnv.Reset(pFormFillEnv);
 }
 
 void CJS_EventHandler::OnPage_InView(
     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
   Initial(JET_PAGE_INVIEW);
-  m_pTargetFormFillEnv = pFormFillEnv;
+  m_pTargetFormFillEnv.Reset(pFormFillEnv);
 }
 
 void CJS_EventHandler::OnPage_OutView(
     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
   Initial(JET_PAGE_OUTVIEW);
-  m_pTargetFormFillEnv = pFormFillEnv;
+  m_pTargetFormFillEnv.Reset(pFormFillEnv);
 }
 
 void CJS_EventHandler::OnField_MouseEnter(bool bModifier,
@@ -247,7 +247,7 @@
 
   m_bModifier = bModifier;
   m_bShift = bShift;
-  m_pTargetAnnot = pScreen;
+  m_pTargetAnnot.Reset(pScreen);
 }
 
 void CJS_EventHandler::OnScreen_Blur(bool bModifier,
@@ -257,7 +257,7 @@
 
   m_bModifier = bModifier;
   m_bShift = bShift;
-  m_pTargetAnnot = pScreen;
+  m_pTargetAnnot.Reset(pScreen);
 }
 
 void CJS_EventHandler::OnScreen_Open(bool bModifier,
@@ -267,7 +267,7 @@
 
   m_bModifier = bModifier;
   m_bShift = bShift;
-  m_pTargetAnnot = pScreen;
+  m_pTargetAnnot.Reset(pScreen);
 }
 
 void CJS_EventHandler::OnScreen_Close(bool bModifier,
@@ -277,7 +277,7 @@
 
   m_bModifier = bModifier;
   m_bShift = bShift;
-  m_pTargetAnnot = pScreen;
+  m_pTargetAnnot.Reset(pScreen);
 }
 
 void CJS_EventHandler::OnScreen_MouseDown(bool bModifier,
@@ -287,7 +287,7 @@
 
   m_bModifier = bModifier;
   m_bShift = bShift;
-  m_pTargetAnnot = pScreen;
+  m_pTargetAnnot.Reset(pScreen);
 }
 
 void CJS_EventHandler::OnScreen_MouseUp(bool bModifier,
@@ -297,7 +297,7 @@
 
   m_bModifier = bModifier;
   m_bShift = bShift;
-  m_pTargetAnnot = pScreen;
+  m_pTargetAnnot.Reset(pScreen);
 }
 
 void CJS_EventHandler::OnScreen_MouseEnter(bool bModifier,
@@ -307,7 +307,7 @@
 
   m_bModifier = bModifier;
   m_bShift = bShift;
-  m_pTargetAnnot = pScreen;
+  m_pTargetAnnot.Reset(pScreen);
 }
 
 void CJS_EventHandler::OnScreen_MouseExit(bool bModifier,
@@ -317,38 +317,35 @@
 
   m_bModifier = bModifier;
   m_bShift = bShift;
-  m_pTargetAnnot = pScreen;
+  m_pTargetAnnot.Reset(pScreen);
 }
 
 void CJS_EventHandler::OnScreen_InView(bool bModifier,
                                        bool bShift,
                                        CPDFSDK_Annot* pScreen) {
   Initial(JET_SCREEN_INVIEW);
-
   m_bModifier = bModifier;
   m_bShift = bShift;
-  m_pTargetAnnot = pScreen;
+  m_pTargetAnnot.Reset(pScreen);
 }
 
 void CJS_EventHandler::OnScreen_OutView(bool bModifier,
                                         bool bShift,
                                         CPDFSDK_Annot* pScreen) {
   Initial(JET_SCREEN_OUTVIEW);
-
   m_bModifier = bModifier;
   m_bShift = bShift;
-  m_pTargetAnnot = pScreen;
+  m_pTargetAnnot.Reset(pScreen);
 }
 
 void CJS_EventHandler::OnLink_MouseUp(
     CPDFSDK_FormFillEnvironment* pTargetFormFillEnv) {
   Initial(JET_LINK_MOUSEUP);
-  m_pTargetFormFillEnv = pTargetFormFillEnv;
+  m_pTargetFormFillEnv.Reset(pTargetFormFillEnv);
 }
 
 void CJS_EventHandler::OnBookmark_MouseUp(CPDF_Bookmark* pBookMark) {
   Initial(JET_BOOKMARK_MOUSEUP);
-
   m_pTargetBookMark = pBookMark;
 }
 
@@ -356,7 +353,7 @@
     CPDFSDK_FormFillEnvironment* pTargetFormFillEnv,
     const CFX_WideString& strTargetName) {
   Initial(JET_MENU_EXEC);
-  m_pTargetFormFillEnv = pTargetFormFillEnv;
+  m_pTargetFormFillEnv.Reset(pTargetFormFillEnv);
   m_strTargetName = strTargetName;
 }
 
@@ -367,7 +364,7 @@
 void CJS_EventHandler::OnBatchExec(
     CPDFSDK_FormFillEnvironment* pTargetFormFillEnv) {
   Initial(JET_BATCH_EXEC);
-  m_pTargetFormFillEnv = pTargetFormFillEnv;
+  m_pTargetFormFillEnv.Reset(pTargetFormFillEnv);
 }
 
 void CJS_EventHandler::OnConsole_Exec() {
@@ -397,8 +394,8 @@
   m_bRcDu = false;
 
   m_pTargetBookMark = nullptr;
-  m_pTargetFormFillEnv = nullptr;
-  m_pTargetAnnot = nullptr;
+  m_pTargetFormFillEnv.Reset();
+  m_pTargetAnnot.Reset();
 
   m_bValid = true;
 }
@@ -590,49 +587,55 @@
 }
 
 Field* CJS_EventHandler::Source() {
-  CJS_Runtime* pRuntime = m_pJSContext->GetJSRuntime();
+  CJS_Runtime* pRuntime = m_pJSEventContext->GetJSRuntime();
   v8::Local<v8::Object> pDocObj =
       pRuntime->NewFxDynamicObj(CJS_Document::g_nObjDefnID);
-  ASSERT(!pDocObj.IsEmpty());
+  if (pDocObj.IsEmpty())
+    return nullptr;
 
   v8::Local<v8::Object> pFieldObj =
       pRuntime->NewFxDynamicObj(CJS_Field::g_nObjDefnID);
-  ASSERT(!pFieldObj.IsEmpty());
+  if (pFieldObj.IsEmpty())
+    return nullptr;
 
   CJS_Document* pJSDocument =
       static_cast<CJS_Document*>(pRuntime->GetObjectPrivate(pDocObj));
-  Document* pDocument = (Document*)pJSDocument->GetEmbedObject();
-  pDocument->SetFormFillEnv(m_pTargetFormFillEnv
-                                ? m_pTargetFormFillEnv
-                                : m_pJSContext->GetFormFillEnv());
-
   CJS_Field* pJSField =
       static_cast<CJS_Field*>(pRuntime->GetObjectPrivate(pFieldObj));
-  Field* pField = (Field*)pJSField->GetEmbedObject();
+
+  Document* pDocument = static_cast<Document*>(pJSDocument->GetEmbedObject());
+  pDocument->SetFormFillEnv(m_pTargetFormFillEnv
+                                ? m_pTargetFormFillEnv.Get()
+                                : m_pJSEventContext->GetFormFillEnv());
+
+  Field* pField = static_cast<Field*>(pJSField->GetEmbedObject());
   pField->AttachField(pDocument, m_strSourceName);
   return pField;
 }
 
 Field* CJS_EventHandler::Target_Field() {
-  CJS_Runtime* pRuntime = m_pJSContext->GetJSRuntime();
+  CJS_Runtime* pRuntime = m_pJSEventContext->GetJSRuntime();
   v8::Local<v8::Object> pDocObj =
       pRuntime->NewFxDynamicObj(CJS_Document::g_nObjDefnID);
-  ASSERT(!pDocObj.IsEmpty());
+  if (pDocObj.IsEmpty())
+    return nullptr;
 
   v8::Local<v8::Object> pFieldObj =
       pRuntime->NewFxDynamicObj(CJS_Field::g_nObjDefnID);
-  ASSERT(!pFieldObj.IsEmpty());
+  if (pFieldObj.IsEmpty())
+    return nullptr;
 
   CJS_Document* pJSDocument =
       static_cast<CJS_Document*>(pRuntime->GetObjectPrivate(pDocObj));
-  Document* pDocument = (Document*)pJSDocument->GetEmbedObject();
-  pDocument->SetFormFillEnv(m_pTargetFormFillEnv
-                                ? m_pTargetFormFillEnv
-                                : m_pJSContext->GetFormFillEnv());
-
   CJS_Field* pJSField =
       static_cast<CJS_Field*>(pRuntime->GetObjectPrivate(pFieldObj));
-  Field* pField = (Field*)pJSField->GetEmbedObject();
+
+  Document* pDocument = static_cast<Document*>(pJSDocument->GetEmbedObject());
+  pDocument->SetFormFillEnv(m_pTargetFormFillEnv
+                                ? m_pTargetFormFillEnv.Get()
+                                : m_pJSEventContext->GetFormFillEnv());
+
+  Field* pField = static_cast<Field*>(pJSField->GetEmbedObject());
   pField->AttachField(pDocument, m_strTargetName);
   return pField;
 }
diff --git a/fpdfsdk/javascript/JS_EventHandler.h b/fpdfsdk/javascript/JS_EventHandler.h
index 8cfcfa7..b9836b0 100644
--- a/fpdfsdk/javascript/JS_EventHandler.h
+++ b/fpdfsdk/javascript/JS_EventHandler.h
@@ -9,10 +9,10 @@
 
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
+#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 
-class CJS_Context;
+class CJS_EventContext;
 class CPDFSDK_Annot;
-class CPDFSDK_FormFillEnvironment;
 class CPDF_Bookmark;
 class CPDF_FormField;
 class Field;
@@ -60,7 +60,7 @@
 
 class CJS_EventHandler {
  public:
-  explicit CJS_EventHandler(CJS_Context* pContext);
+  explicit CJS_EventHandler(CJS_EventContext* pContext);
   virtual ~CJS_EventHandler();
 
   void OnApp_Init();
@@ -165,7 +165,7 @@
   JS_EVENT_T EventType() { return m_eEventType; }
 
  public:
-  CJS_Context* m_pJSContext;
+  CJS_EventContext* const m_pJSEventContext;  // Not Owned.
   JS_EVENT_T m_eEventType;
   bool m_bValid;
 
@@ -189,8 +189,8 @@
   bool m_bRcDu;
 
   CPDF_Bookmark* m_pTargetBookMark;
-  CPDFSDK_FormFillEnvironment* m_pTargetFormFillEnv;
-  CPDFSDK_Annot* m_pTargetAnnot;
+  CPDFSDK_FormFillEnvironment::ObservedPtr m_pTargetFormFillEnv;
+  CPDFSDK_Annot::ObservedPtr m_pTargetAnnot;
 };
 
 #endif  // FPDFSDK_JAVASCRIPT_JS_EVENTHANDLER_H_
diff --git a/fpdfsdk/javascript/JS_Object.cpp b/fpdfsdk/javascript/JS_Object.cpp
index 9ef6cdd..cd86889 100644
--- a/fpdfsdk/javascript/JS_Object.cpp
+++ b/fpdfsdk/javascript/JS_Object.cpp
@@ -7,7 +7,7 @@
 #include "fpdfsdk/javascript/JS_Object.h"
 
 #include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/cjs_context.h"
+#include "fpdfsdk/javascript/cjs_event_context.h"
 
 CJS_EmbedObj::CJS_EmbedObj(CJS_Object* pJSObject) : m_pJSObject(pJSObject) {}
 
diff --git a/fpdfsdk/javascript/JS_Object.h b/fpdfsdk/javascript/JS_Object.h
index 658a5e2..2e5c75c 100644
--- a/fpdfsdk/javascript/JS_Object.h
+++ b/fpdfsdk/javascript/JS_Object.h
@@ -14,7 +14,7 @@
 #include "fpdfsdk/javascript/cjs_runtime.h"
 #include "fxjs/fxjs_v8.h"
 
-class CJS_Context;
+class CJS_EventContext;
 class CJS_Object;
 class CPDFSDK_FormFillEnvironment;
 
diff --git a/fpdfsdk/javascript/JS_Runtime_Stub.cpp b/fpdfsdk/javascript/JS_Runtime_Stub.cpp
index 96148d8..dcd8ceb 100644
--- a/fpdfsdk/javascript/JS_Runtime_Stub.cpp
+++ b/fpdfsdk/javascript/JS_Runtime_Stub.cpp
@@ -6,16 +6,16 @@
 
 #include <memory>
 
-#include "fpdfsdk/javascript/ijs_context.h"
+#include "fpdfsdk/javascript/ijs_event_context.h"
 #include "fpdfsdk/javascript/ijs_runtime.h"
 #include "third_party/base/ptr_util.h"
 
-class CJS_ContextStub final : public IJS_Context {
+class CJS_EventContextStub final : public IJS_EventContext {
  public:
-  CJS_ContextStub() {}
-  ~CJS_ContextStub() override {}
+  CJS_EventContextStub() {}
+  ~CJS_EventContextStub() override {}
 
-  // IJS_Context:
+  // IJS_EventContext:
   bool RunScript(const CFX_WideString& script, CFX_WideString* info) override {
     return false;
   }
@@ -124,14 +124,13 @@
       : m_pFormFillEnv(pFormFillEnv) {}
   ~CJS_RuntimeStub() override {}
 
-  IJS_Context* NewContext() override {
+  IJS_EventContext* NewEventContext() override {
     if (!m_pContext)
-      m_pContext = pdfium::MakeUnique<CJS_ContextStub>();
-    return GetCurrentContext();
+      m_pContext = pdfium::MakeUnique<CJS_EventContextStub>();
+    return m_pContext.get();
   }
 
-  IJS_Context* GetCurrentContext() override { return m_pContext.get(); }
-  void ReleaseContext(IJS_Context* pContext) override {}
+  void ReleaseEventContext(IJS_EventContext* pContext) override {}
 
   CPDFSDK_FormFillEnvironment* GetFormFillEnv() const override {
     return m_pFormFillEnv;
@@ -154,7 +153,7 @@
 
  protected:
   CPDFSDK_FormFillEnvironment* m_pFormFillEnv;
-  std::unique_ptr<CJS_ContextStub> m_pContext;
+  std::unique_ptr<CJS_EventContextStub> m_pContext;
 };
 
 // static
diff --git a/fpdfsdk/javascript/JS_Value.cpp b/fpdfsdk/javascript/JS_Value.cpp
index 7900914..b058847 100644
--- a/fpdfsdk/javascript/JS_Value.cpp
+++ b/fpdfsdk/javascript/JS_Value.cpp
@@ -677,8 +677,9 @@
     if (v->IsFunction()) {
       v8::Local<v8::Function> funC = v8::Local<v8::Function>::Cast(v);
       const int argc = 1;
-      v8::Local<v8::String> timeStr =
-          CJS_Runtime::CurrentRuntimeFromIsolate(pIsolate)->WSToJSString(str);
+      v8::Local<v8::Value> timeStr =
+          CJS_Runtime::CurrentRuntimeFromIsolate(pIsolate)->NewString(
+              str.AsStringC());
       v8::Local<v8::Value> argv[argc] = {timeStr};
       v = funC->Call(context, context->Global(), argc, argv).ToLocalChecked();
       if (v->IsNumber()) {
diff --git a/fpdfsdk/javascript/PublicMethods.cpp b/fpdfsdk/javascript/PublicMethods.cpp
index c0ea84c..3bcbc34 100644
--- a/fpdfsdk/javascript/PublicMethods.cpp
+++ b/fpdfsdk/javascript/PublicMethods.cpp
@@ -22,7 +22,7 @@
 #include "fpdfsdk/javascript/JS_EventHandler.h"
 #include "fpdfsdk/javascript/JS_Object.h"
 #include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/cjs_context.h"
+#include "fpdfsdk/javascript/cjs_event_context.h"
 #include "fpdfsdk/javascript/cjs_runtime.h"
 #include "fpdfsdk/javascript/color.h"
 #include "fpdfsdk/javascript/resource.h"
@@ -30,30 +30,30 @@
 
 #define DOUBLE_CORRECT 0.000000000000001
 
-BEGIN_JS_STATIC_GLOBAL_FUN(CJS_PublicMethods)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFNumber_Format)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFNumber_Keystroke)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFPercent_Format)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFPercent_Keystroke)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFDate_FormatEx)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFDate_KeystrokeEx)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFDate_Format)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFDate_Keystroke)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFTime_FormatEx)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFTime_KeystrokeEx)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFTime_Format)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFTime_Keystroke)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFSpecial_Format)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFSpecial_Keystroke)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFSpecial_KeystrokeEx)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFSimple)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFMakeNumber)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFSimple_Calculate)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFRange_Validate)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFMergeChange)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFParseDateEx)
-JS_STATIC_GLOBAL_FUN_ENTRY(AFExtractNums)
-END_JS_STATIC_GLOBAL_FUN()
+JSMethodSpec CJS_PublicMethods::GlobalFunctionSpecs[] = {
+    {"AFNumber_Format", AFNumber_Format_static},
+    {"AFNumber_Keystroke", AFNumber_Keystroke_static},
+    {"AFPercent_Format", AFPercent_Format_static},
+    {"AFPercent_Keystroke", AFPercent_Keystroke_static},
+    {"AFDate_FormatEx", AFDate_FormatEx_static},
+    {"AFDate_KeystrokeEx", AFDate_KeystrokeEx_static},
+    {"AFDate_Format", AFDate_Format_static},
+    {"AFDate_Keystroke", AFDate_Keystroke_static},
+    {"AFTime_FormatEx", AFTime_FormatEx_static},
+    {"AFTime_KeystrokeEx", AFTime_KeystrokeEx_static},
+    {"AFTime_Format", AFTime_Format_static},
+    {"AFTime_Keystroke", AFTime_Keystroke_static},
+    {"AFSpecial_Format", AFSpecial_Format_static},
+    {"AFSpecial_Keystroke", AFSpecial_Keystroke_static},
+    {"AFSpecial_KeystrokeEx", AFSpecial_KeystrokeEx_static},
+    {"AFSimple", AFSimple_static},
+    {"AFMakeNumber", AFMakeNumber_static},
+    {"AFSimple_Calculate", AFSimple_Calculate_static},
+    {"AFRange_Validate", AFRange_Validate_static},
+    {"AFMergeChange", AFMergeChange_static},
+    {"AFParseDateEx", AFParseDateEx_static},
+    {"AFExtractNums", AFExtractNums_static},
+    {0, 0}};
 
 IMPLEMENT_JS_STATIC_GLOBAL_FUN(CJS_PublicMethods)
 
@@ -82,7 +82,7 @@
   return result;
 }
 
-void AlertIfPossible(CJS_Context* pContext, const FX_WCHAR* swMsg) {
+void AlertIfPossible(CJS_EventContext* pContext, const FX_WCHAR* swMsg) {
   CPDFSDK_FormFillEnvironment* pFormFillEnv = pContext->GetFormFillEnv();
   if (pFormFillEnv)
     pFormFillEnv->JS_appAlert(swMsg, nullptr, 0, 3);
@@ -750,7 +750,7 @@
 
 // function AFNumber_Format(nDec, sepStyle, negStyle, currStyle, strCurrency,
 // bCurrencyPrepend)
-bool CJS_PublicMethods::AFNumber_Format(IJS_Context* cc,
+bool CJS_PublicMethods::AFNumber_Format(CJS_Runtime* pRuntime,
                                         const std::vector<CJS_Value>& params,
                                         CJS_Value& vRet,
                                         CFX_WideString& sError) {
@@ -760,9 +760,8 @@
     return false;
   }
 
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
   if (!pEvent->m_pValue)
     return false;
 
@@ -855,7 +854,7 @@
         vProp.StartGetting();
         vProp << arColor;
         vProp.StartSetting();
-        fTarget->textColor(cc, vProp, sError);  // red
+        fTarget->textColor(pRuntime, vProp, sError);  // red
       }
     }
   } else {
@@ -872,7 +871,7 @@
 
         CJS_PropValue vProp(pRuntime);
         vProp.StartGetting();
-        fTarget->textColor(cc, vProp, sError);
+        fTarget->textColor(pRuntime, vProp, sError);
 
         CJS_Array aProp;
         vProp.GetJSValue()->ConvertToArray(pRuntime, aProp);
@@ -887,7 +886,7 @@
           vProp2.StartGetting();
           vProp2 << arColor;
           vProp2.StartSetting();
-          fTarget->textColor(cc, vProp2, sError);
+          fTarget->textColor(pRuntime, vProp2, sError);
         }
       }
     }
@@ -898,16 +897,15 @@
 
 // function AFNumber_Keystroke(nDec, sepStyle, negStyle, currStyle, strCurrency,
 // bCurrencyPrepend)
-bool CJS_PublicMethods::AFNumber_Keystroke(IJS_Context* cc,
+bool CJS_PublicMethods::AFNumber_Keystroke(CJS_Runtime* pRuntime,
                                            const std::vector<CJS_Value>& params,
                                            CJS_Value& vRet,
                                            CFX_WideString& sError) {
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
-
   if (params.size() < 2)
     return false;
 
+  CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
+  CJS_EventHandler* pEvent = pContext->GetEventHandler();
   if (!pEvent->m_pValue)
     return false;
 
@@ -945,7 +943,6 @@
     }
   }
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   int iSepStyle = params[1].ToInt(pRuntime);
   if (iSepStyle < 0 || iSepStyle > 3)
     iSepStyle = 0;
@@ -999,19 +996,18 @@
 }
 
 // function AFPercent_Format(nDec, sepStyle)
-bool CJS_PublicMethods::AFPercent_Format(IJS_Context* cc,
+bool CJS_PublicMethods::AFPercent_Format(CJS_Runtime* pRuntime,
                                          const std::vector<CJS_Value>& params,
                                          CJS_Value& vRet,
                                          CFX_WideString& sError) {
 #if _FX_OS_ != _FX_ANDROID_
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
-
   if (params.size() != 2) {
     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
     return false;
   }
+
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
   if (!pEvent->m_pValue)
     return false;
 
@@ -1092,26 +1088,25 @@
 }
 // AFPercent_Keystroke(nDec, sepStyle)
 bool CJS_PublicMethods::AFPercent_Keystroke(
-    IJS_Context* cc,
+    CJS_Runtime* pRuntime,
     const std::vector<CJS_Value>& params,
     CJS_Value& vRet,
     CFX_WideString& sError) {
-  return AFNumber_Keystroke(cc, params, vRet, sError);
+  return AFNumber_Keystroke(pRuntime, params, vRet, sError);
 }
 
 // function AFDate_FormatEx(cFormat)
-bool CJS_PublicMethods::AFDate_FormatEx(IJS_Context* cc,
+bool CJS_PublicMethods::AFDate_FormatEx(CJS_Runtime* pRuntime,
                                         const std::vector<CJS_Value>& params,
                                         CJS_Value& vRet,
                                         CFX_WideString& sError) {
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
-
   if (params.size() != 1) {
     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
     return false;
   }
+
+  CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
+  CJS_EventHandler* pEvent = pContext->GetEventHandler();
   if (!pEvent->m_pValue)
     return false;
 
@@ -1200,22 +1195,21 @@
 }
 
 // AFDate_KeystrokeEx(cFormat)
-bool CJS_PublicMethods::AFDate_KeystrokeEx(IJS_Context* cc,
+bool CJS_PublicMethods::AFDate_KeystrokeEx(CJS_Runtime* pRuntime,
                                            const std::vector<CJS_Value>& params,
                                            CJS_Value& vRet,
                                            CFX_WideString& sError) {
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
-
   if (params.size() != 1) {
     sError = L"AFDate_KeystrokeEx's parameters' size r not correct";
     return false;
   }
 
+  CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
+  CJS_EventHandler* pEvent = pContext->GetEventHandler();
   if (pEvent->WillCommit()) {
     if (!pEvent->m_pValue)
       return false;
+
     CFX_WideString strValue = pEvent->Value();
     if (strValue.IsEmpty())
       return true;
@@ -1235,7 +1229,7 @@
   return true;
 }
 
-bool CJS_PublicMethods::AFDate_Format(IJS_Context* cc,
+bool CJS_PublicMethods::AFDate_Format(CJS_Runtime* pRuntime,
                                       const std::vector<CJS_Value>& params,
                                       CJS_Value& vRet,
                                       CFX_WideString& sError) {
@@ -1244,7 +1238,6 @@
     return false;
   }
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   int iIndex = params[0].ToInt(pRuntime);
   const FX_WCHAR* cFormats[] = {L"m/d",
                                 L"m/d/yy",
@@ -1265,13 +1258,12 @@
     iIndex = 0;
 
   std::vector<CJS_Value> newParams;
-  newParams.push_back(
-      CJS_Value(CJS_Runtime::FromContext(cc), cFormats[iIndex]));
-  return AFDate_FormatEx(cc, newParams, vRet, sError);
+  newParams.push_back(CJS_Value(pRuntime, cFormats[iIndex]));
+  return AFDate_FormatEx(pRuntime, newParams, vRet, sError);
 }
 
 // AFDate_KeystrokeEx(cFormat)
-bool CJS_PublicMethods::AFDate_Keystroke(IJS_Context* cc,
+bool CJS_PublicMethods::AFDate_Keystroke(CJS_Runtime* pRuntime,
                                          const std::vector<CJS_Value>& params,
                                          CJS_Value& vRet,
                                          CFX_WideString& sError) {
@@ -1280,7 +1272,6 @@
     return false;
   }
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   int iIndex = params[0].ToInt(pRuntime);
   const FX_WCHAR* cFormats[] = {L"m/d",
                                 L"m/d/yy",
@@ -1301,13 +1292,12 @@
     iIndex = 0;
 
   std::vector<CJS_Value> newParams;
-  newParams.push_back(
-      CJS_Value(CJS_Runtime::FromContext(cc), cFormats[iIndex]));
-  return AFDate_KeystrokeEx(cc, newParams, vRet, sError);
+  newParams.push_back(CJS_Value(pRuntime, cFormats[iIndex]));
+  return AFDate_KeystrokeEx(pRuntime, newParams, vRet, sError);
 }
 
 // function AFTime_Format(ptf)
-bool CJS_PublicMethods::AFTime_Format(IJS_Context* cc,
+bool CJS_PublicMethods::AFTime_Format(CJS_Runtime* pRuntime,
                                       const std::vector<CJS_Value>& params,
                                       CJS_Value& vRet,
                                       CFX_WideString& sError) {
@@ -1316,7 +1306,6 @@
     return false;
   }
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   int iIndex = params[0].ToInt(pRuntime);
   const FX_WCHAR* cFormats[] = {L"HH:MM", L"h:MM tt", L"HH:MM:ss",
                                 L"h:MM:ss tt"};
@@ -1325,12 +1314,11 @@
     iIndex = 0;
 
   std::vector<CJS_Value> newParams;
-  newParams.push_back(
-      CJS_Value(CJS_Runtime::FromContext(cc), cFormats[iIndex]));
-  return AFDate_FormatEx(cc, newParams, vRet, sError);
+  newParams.push_back(CJS_Value(pRuntime, cFormats[iIndex]));
+  return AFDate_FormatEx(pRuntime, newParams, vRet, sError);
 }
 
-bool CJS_PublicMethods::AFTime_Keystroke(IJS_Context* cc,
+bool CJS_PublicMethods::AFTime_Keystroke(CJS_Runtime* pRuntime,
                                          const std::vector<CJS_Value>& params,
                                          CJS_Value& vRet,
                                          CFX_WideString& sError) {
@@ -1339,7 +1327,6 @@
     return false;
   }
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   int iIndex = params[0].ToInt(pRuntime);
   const FX_WCHAR* cFormats[] = {L"HH:MM", L"h:MM tt", L"HH:MM:ss",
                                 L"h:MM:ss tt"};
@@ -1348,27 +1335,26 @@
     iIndex = 0;
 
   std::vector<CJS_Value> newParams;
-  newParams.push_back(
-      CJS_Value(CJS_Runtime::FromContext(cc), cFormats[iIndex]));
-  return AFDate_KeystrokeEx(cc, newParams, vRet, sError);
+  newParams.push_back(CJS_Value(pRuntime, cFormats[iIndex]));
+  return AFDate_KeystrokeEx(pRuntime, newParams, vRet, sError);
 }
 
-bool CJS_PublicMethods::AFTime_FormatEx(IJS_Context* cc,
+bool CJS_PublicMethods::AFTime_FormatEx(CJS_Runtime* pRuntime,
                                         const std::vector<CJS_Value>& params,
                                         CJS_Value& vRet,
                                         CFX_WideString& sError) {
-  return AFDate_FormatEx(cc, params, vRet, sError);
+  return AFDate_FormatEx(pRuntime, params, vRet, sError);
 }
 
-bool CJS_PublicMethods::AFTime_KeystrokeEx(IJS_Context* cc,
+bool CJS_PublicMethods::AFTime_KeystrokeEx(CJS_Runtime* pRuntime,
                                            const std::vector<CJS_Value>& params,
                                            CJS_Value& vRet,
                                            CFX_WideString& sError) {
-  return AFDate_KeystrokeEx(cc, params, vRet, sError);
+  return AFDate_KeystrokeEx(pRuntime, params, vRet, sError);
 }
 
 // function AFSpecial_Format(psf)
-bool CJS_PublicMethods::AFSpecial_Format(IJS_Context* cc,
+bool CJS_PublicMethods::AFSpecial_Format(CJS_Runtime* pRuntime,
                                          const std::vector<CJS_Value>& params,
                                          CJS_Value& vRet,
                                          CFX_WideString& sError) {
@@ -1377,12 +1363,11 @@
     return false;
   }
 
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
   if (!pEvent->m_pValue)
     return false;
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CFX_WideString wsSource = pEvent->Value();
   CFX_WideString wsFormat;
   switch (params[0].ToInt(pRuntime)) {
@@ -1409,19 +1394,17 @@
 
 // function AFSpecial_KeystrokeEx(mask)
 bool CJS_PublicMethods::AFSpecial_KeystrokeEx(
-    IJS_Context* cc,
+    CJS_Runtime* pRuntime,
     const std::vector<CJS_Value>& params,
     CJS_Value& vRet,
     CFX_WideString& sError) {
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
-
   if (params.size() < 1) {
     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
     return false;
   }
 
+  CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
+  CJS_EventHandler* pEvent = pContext->GetEventHandler();
   if (!pEvent->m_pValue)
     return false;
 
@@ -1494,7 +1477,7 @@
 
 // function AFSpecial_Keystroke(psf)
 bool CJS_PublicMethods::AFSpecial_Keystroke(
-    IJS_Context* cc,
+    CJS_Runtime* pRuntime,
     const std::vector<CJS_Value>& params,
     CJS_Value& vRet,
     CFX_WideString& sError) {
@@ -1503,13 +1486,12 @@
     return false;
   }
 
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
   if (!pEvent->m_pValue)
     return false;
 
   const char* cFormat = "";
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   switch (params[0].ToInt(pRuntime)) {
     case 0:
       cFormat = "99999";
@@ -1529,11 +1511,11 @@
   }
 
   std::vector<CJS_Value> params2;
-  params2.push_back(CJS_Value(CJS_Runtime::FromContext(cc), cFormat));
-  return AFSpecial_KeystrokeEx(cc, params2, vRet, sError);
+  params2.push_back(CJS_Value(pRuntime, cFormat));
+  return AFSpecial_KeystrokeEx(pRuntime, params2, vRet, sError);
 }
 
-bool CJS_PublicMethods::AFMergeChange(IJS_Context* cc,
+bool CJS_PublicMethods::AFMergeChange(CJS_Runtime* pRuntime,
                                       const std::vector<CJS_Value>& params,
                                       CJS_Value& vRet,
                                       CFX_WideString& sError) {
@@ -1542,9 +1524,8 @@
     return false;
   }
 
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-  CJS_EventHandler* pEventHandler = pContext->GetEventHandler();
+  CJS_EventHandler* pEventHandler =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
 
   CFX_WideString swValue;
   if (pEventHandler->m_pValue)
@@ -1574,7 +1555,7 @@
   return true;
 }
 
-bool CJS_PublicMethods::AFParseDateEx(IJS_Context* cc,
+bool CJS_PublicMethods::AFParseDateEx(CJS_Runtime* pRuntime,
                                       const std::vector<CJS_Value>& params,
                                       CJS_Value& vRet,
                                       CFX_WideString& sError) {
@@ -1583,17 +1564,14 @@
     return false;
   }
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CFX_WideString sValue = params[0].ToCFXWideString(pRuntime);
   CFX_WideString sFormat = params[1].ToCFXWideString(pRuntime);
-
   double dDate = MakeRegularDate(sValue, sFormat, nullptr);
-
   if (JS_PortIsNan(dDate)) {
     CFX_WideString swMsg;
     swMsg.Format(JSGetStringFromID(IDS_STRING_JSPARSEDATE).c_str(),
                  sFormat.c_str());
-    AlertIfPossible((CJS_Context*)cc, swMsg.c_str());
+    AlertIfPossible(pRuntime->GetCurrentEventContext(), swMsg.c_str());
     return false;
   }
 
@@ -1601,7 +1579,7 @@
   return true;
 }
 
-bool CJS_PublicMethods::AFSimple(IJS_Context* cc,
+bool CJS_PublicMethods::AFSimple(CJS_Runtime* pRuntime,
                                  const std::vector<CJS_Value>& params,
                                  CJS_Value& vRet,
                                  CFX_WideString& sError) {
@@ -1610,7 +1588,6 @@
     return false;
   }
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   vRet = CJS_Value(pRuntime, static_cast<double>(AF_Simple(
                                  params[0].ToCFXWideString(pRuntime).c_str(),
                                  params[1].ToDouble(pRuntime),
@@ -1619,7 +1596,7 @@
   return true;
 }
 
-bool CJS_PublicMethods::AFMakeNumber(IJS_Context* cc,
+bool CJS_PublicMethods::AFMakeNumber(CJS_Runtime* pRuntime,
                                      const std::vector<CJS_Value>& params,
                                      CJS_Value& vRet,
                                      CFX_WideString& sError) {
@@ -1628,7 +1605,6 @@
     return false;
   }
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CFX_WideString ws = params[0].ToCFXWideString(pRuntime);
   ws.Replace(L",", L".");
   vRet = CJS_Value(pRuntime, ws.c_str());
@@ -1638,7 +1614,7 @@
   return true;
 }
 
-bool CJS_PublicMethods::AFSimple_Calculate(IJS_Context* cc,
+bool CJS_PublicMethods::AFSimple_Calculate(CJS_Runtime* pRuntime,
                                            const std::vector<CJS_Value>& params,
                                            CJS_Value& vRet,
                                            CFX_WideString& sError) {
@@ -1653,10 +1629,8 @@
     return false;
   }
 
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CPDFSDK_InterForm* pReaderInterForm =
-      pContext->GetFormFillEnv()->GetInterForm();
+      pRuntime->GetFormFillEnv()->GetInterForm();
   CPDF_InterForm* pInterForm = pReaderInterForm->GetInterForm();
 
   CFX_WideString sFunction = params[0].ToCFXWideString(pRuntime);
@@ -1727,7 +1701,9 @@
 
   dValue = (double)floor(dValue * FXSYS_pow((double)10, (double)6) + 0.49) /
            FXSYS_pow((double)10, (double)6);
+
   CJS_Value jsValue(pRuntime, dValue);
+  CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
   if (pContext->GetEventHandler()->m_pValue)
     pContext->GetEventHandler()->Value() = jsValue.ToCFXWideString(pRuntime);
 
@@ -1737,7 +1713,7 @@
 /* This function validates the current event to ensure that its value is
 ** within the specified range. */
 
-bool CJS_PublicMethods::AFRange_Validate(IJS_Context* cc,
+bool CJS_PublicMethods::AFRange_Validate(CJS_Runtime* pRuntime,
                                          const std::vector<CJS_Value>& params,
                                          CJS_Value& vRet,
                                          CFX_WideString& sError) {
@@ -1745,8 +1721,7 @@
     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
     return false;
   }
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
+  CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
   CJS_EventHandler* pEvent = pContext->GetEventHandler();
   if (!pEvent->m_pValue)
     return false;
@@ -1784,7 +1759,7 @@
   return true;
 }
 
-bool CJS_PublicMethods::AFExtractNums(IJS_Context* cc,
+bool CJS_PublicMethods::AFExtractNums(CJS_Runtime* pRuntime,
                                       const std::vector<CJS_Value>& params,
                                       CJS_Value& vRet,
                                       CFX_WideString& sError) {
@@ -1793,14 +1768,12 @@
     return false;
   }
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CFX_WideString str = params[0].ToCFXWideString(pRuntime);
-  CFX_WideString sPart;
-  CJS_Array nums;
-
   if (str.GetAt(0) == L'.' || str.GetAt(0) == L',')
     str = L"0" + str;
 
+  CFX_WideString sPart;
+  CJS_Array nums;
   int nIndex = 0;
   for (int i = 0, sz = str.GetLength(); i < sz; i++) {
     FX_WCHAR wc = str.GetAt(i);
diff --git a/fpdfsdk/javascript/PublicMethods.h b/fpdfsdk/javascript/PublicMethods.h
index 0820c40..060c743 100644
--- a/fpdfsdk/javascript/PublicMethods.h
+++ b/fpdfsdk/javascript/PublicMethods.h
@@ -18,91 +18,91 @@
       : CJS_Object(pObject) {}
   ~CJS_PublicMethods() override {}
 
-  static bool AFNumber_Format(IJS_Context* cc,
+  static bool AFNumber_Format(CJS_Runtime* pRuntime,
                               const std::vector<CJS_Value>& params,
                               CJS_Value& vRet,
                               CFX_WideString& sError);
-  static bool AFNumber_Keystroke(IJS_Context* cc,
+  static bool AFNumber_Keystroke(CJS_Runtime* pRuntime,
                                  const std::vector<CJS_Value>& params,
                                  CJS_Value& vRet,
                                  CFX_WideString& sError);
-  static bool AFPercent_Format(IJS_Context* cc,
+  static bool AFPercent_Format(CJS_Runtime* pRuntime,
                                const std::vector<CJS_Value>& params,
                                CJS_Value& vRet,
                                CFX_WideString& sError);
-  static bool AFPercent_Keystroke(IJS_Context* cc,
+  static bool AFPercent_Keystroke(CJS_Runtime* pRuntime,
                                   const std::vector<CJS_Value>& params,
                                   CJS_Value& vRet,
                                   CFX_WideString& sError);
-  static bool AFDate_FormatEx(IJS_Context* cc,
+  static bool AFDate_FormatEx(CJS_Runtime* pRuntime,
                               const std::vector<CJS_Value>& params,
                               CJS_Value& vRet,
                               CFX_WideString& sError);
-  static bool AFDate_KeystrokeEx(IJS_Context* cc,
+  static bool AFDate_KeystrokeEx(CJS_Runtime* pRuntime,
                                  const std::vector<CJS_Value>& params,
                                  CJS_Value& vRet,
                                  CFX_WideString& sError);
-  static bool AFDate_Format(IJS_Context* cc,
+  static bool AFDate_Format(CJS_Runtime* pRuntime,
                             const std::vector<CJS_Value>& params,
                             CJS_Value& vRet,
                             CFX_WideString& sError);
-  static bool AFDate_Keystroke(IJS_Context* cc,
+  static bool AFDate_Keystroke(CJS_Runtime* pRuntime,
                                const std::vector<CJS_Value>& params,
                                CJS_Value& vRet,
                                CFX_WideString& sError);
-  static bool AFTime_FormatEx(IJS_Context* cc,
+  static bool AFTime_FormatEx(CJS_Runtime* pRuntime,
                               const std::vector<CJS_Value>& params,
                               CJS_Value& vRet,
                               CFX_WideString& sError);  //
-  static bool AFTime_KeystrokeEx(IJS_Context* cc,
+  static bool AFTime_KeystrokeEx(CJS_Runtime* pRuntime,
                                  const std::vector<CJS_Value>& params,
                                  CJS_Value& vRet,
                                  CFX_WideString& sError);
-  static bool AFTime_Format(IJS_Context* cc,
+  static bool AFTime_Format(CJS_Runtime* pRuntime,
                             const std::vector<CJS_Value>& params,
                             CJS_Value& vRet,
                             CFX_WideString& sError);
-  static bool AFTime_Keystroke(IJS_Context* cc,
+  static bool AFTime_Keystroke(CJS_Runtime* pRuntime,
                                const std::vector<CJS_Value>& params,
                                CJS_Value& vRet,
                                CFX_WideString& sError);
-  static bool AFSpecial_Format(IJS_Context* cc,
+  static bool AFSpecial_Format(CJS_Runtime* pRuntime,
                                const std::vector<CJS_Value>& params,
                                CJS_Value& vRet,
                                CFX_WideString& sError);
-  static bool AFSpecial_Keystroke(IJS_Context* cc,
+  static bool AFSpecial_Keystroke(CJS_Runtime* pRuntime,
                                   const std::vector<CJS_Value>& params,
                                   CJS_Value& vRet,
                                   CFX_WideString& sError);
-  static bool AFSpecial_KeystrokeEx(IJS_Context* cc,
+  static bool AFSpecial_KeystrokeEx(CJS_Runtime* pRuntime,
                                     const std::vector<CJS_Value>& params,
                                     CJS_Value& vRet,
                                     CFX_WideString& sError);  //
-  static bool AFSimple(IJS_Context* cc,
+  static bool AFSimple(CJS_Runtime* pRuntime,
                        const std::vector<CJS_Value>& params,
                        CJS_Value& vRet,
                        CFX_WideString& sError);
-  static bool AFMakeNumber(IJS_Context* cc,
+  static bool AFMakeNumber(CJS_Runtime* pRuntime,
                            const std::vector<CJS_Value>& params,
                            CJS_Value& vRet,
                            CFX_WideString& sError);
-  static bool AFSimple_Calculate(IJS_Context* cc,
+  static bool AFSimple_Calculate(CJS_Runtime* pRuntime,
                                  const std::vector<CJS_Value>& params,
                                  CJS_Value& vRet,
                                  CFX_WideString& sError);
-  static bool AFRange_Validate(IJS_Context* cc,
+  static bool AFRange_Validate(CJS_Runtime* pRuntime,
                                const std::vector<CJS_Value>& params,
                                CJS_Value& vRet,
                                CFX_WideString& sError);
-  static bool AFMergeChange(IJS_Context* cc,
+  static bool AFMergeChange(CJS_Runtime* pRuntime,
                             const std::vector<CJS_Value>& params,
                             CJS_Value& vRet,
                             CFX_WideString& sError);
-  static bool AFParseDateEx(IJS_Context* cc,
+  static bool AFParseDateEx(CJS_Runtime* pRuntime,
                             const std::vector<CJS_Value>& params,
                             CJS_Value& vRet,
                             CFX_WideString& sError);
-  static bool AFExtractNums(IJS_Context* cc,
+  static bool AFExtractNums(CJS_Runtime* pRuntime,
                             const std::vector<CJS_Value>& params,
                             CJS_Value& vRet,
                             CFX_WideString& sError);
diff --git a/fpdfsdk/javascript/app.cpp b/fpdfsdk/javascript/app.cpp
index 6562d1b..3a8bf08 100644
--- a/fpdfsdk/javascript/app.cpp
+++ b/fpdfsdk/javascript/app.cpp
@@ -17,7 +17,7 @@
 #include "fpdfsdk/javascript/JS_EventHandler.h"
 #include "fpdfsdk/javascript/JS_Object.h"
 #include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/cjs_context.h"
+#include "fpdfsdk/javascript/cjs_event_context.h"
 #include "fpdfsdk/javascript/cjs_runtime.h"
 #include "fpdfsdk/javascript/resource.h"
 #include "third_party/base/stl_util.h"
@@ -55,7 +55,7 @@
   const uint32_t m_dwTimeOut;
   const CFX_WideString m_swJScript;
   CJS_Runtime::ObservedPtr m_pRuntime;
-  CPDFSDK_FormFillEnvironment* const m_pFormFillEnv;
+  CPDFSDK_FormFillEnvironment::ObservedPtr m_pFormFillEnv;
 };
 
 GlobalTimer::GlobalTimer(app* pObj,
@@ -131,14 +131,11 @@
   return s_TimerMap;
 }
 
-BEGIN_JS_STATIC_CONST(CJS_TimerObj)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_TimerObj::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
 
-BEGIN_JS_STATIC_PROP(CJS_TimerObj)
-END_JS_STATIC_PROP()
+JSPropertySpec CJS_TimerObj::PropertySpecs[] = {{0, 0, 0}};
 
-BEGIN_JS_STATIC_METHOD(CJS_TimerObj)
-END_JS_STATIC_METHOD()
+JSMethodSpec CJS_TimerObj::MethodSpecs[] = {{0, 0}};
 
 IMPLEMENT_JS_CLASS(CJS_TimerObj, TimerObj)
 
@@ -161,47 +158,46 @@
 #endif  // PDF_ENABLE_XFA
 #define JS_NUM_FORMSVERSION 7
 
-BEGIN_JS_STATIC_CONST(CJS_App)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_App::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
 
-BEGIN_JS_STATIC_PROP(CJS_App)
-JS_STATIC_PROP_ENTRY(activeDocs)
-JS_STATIC_PROP_ENTRY(calculate)
-JS_STATIC_PROP_ENTRY(formsVersion)
-JS_STATIC_PROP_ENTRY(fs)
-JS_STATIC_PROP_ENTRY(fullscreen)
-JS_STATIC_PROP_ENTRY(language)
-JS_STATIC_PROP_ENTRY(media)
-JS_STATIC_PROP_ENTRY(platform)
-JS_STATIC_PROP_ENTRY(runtimeHighlight)
-JS_STATIC_PROP_ENTRY(viewerType)
-JS_STATIC_PROP_ENTRY(viewerVariation)
-JS_STATIC_PROP_ENTRY(viewerVersion)
-END_JS_STATIC_PROP()
+JSPropertySpec CJS_App::PropertySpecs[] = {
+    {"activeDocs", get_activeDocs_static, set_activeDocs_static},
+    {"calculate", get_calculate_static, set_calculate_static},
+    {"formsVersion", get_formsVersion_static, set_formsVersion_static},
+    {"fs", get_fs_static, set_fs_static},
+    {"fullscreen", get_fullscreen_static, set_fullscreen_static},
+    {"language", get_language_static, set_language_static},
+    {"media", get_media_static, set_media_static},
+    {"platform", get_platform_static, set_platform_static},
+    {"runtimeHighlight", get_runtimeHighlight_static,
+     set_runtimeHighlight_static},
+    {"viewerType", get_viewerType_static, set_viewerType_static},
+    {"viewerVariation", get_viewerVariation_static, set_viewerVariation_static},
+    {"viewerVersion", get_viewerVersion_static, set_viewerVersion_static},
+    {0, 0, 0}};
 
-BEGIN_JS_STATIC_METHOD(CJS_App)
-JS_STATIC_METHOD_ENTRY(alert)
-JS_STATIC_METHOD_ENTRY(beep)
-JS_STATIC_METHOD_ENTRY(browseForDoc)
-JS_STATIC_METHOD_ENTRY(clearInterval)
-JS_STATIC_METHOD_ENTRY(clearTimeOut)
-JS_STATIC_METHOD_ENTRY(execDialog)
-JS_STATIC_METHOD_ENTRY(execMenuItem)
-JS_STATIC_METHOD_ENTRY(findComponent)
-JS_STATIC_METHOD_ENTRY(goBack)
-JS_STATIC_METHOD_ENTRY(goForward)
-JS_STATIC_METHOD_ENTRY(launchURL)
-JS_STATIC_METHOD_ENTRY(mailMsg)
-JS_STATIC_METHOD_ENTRY(newFDF)
-JS_STATIC_METHOD_ENTRY(newDoc)
-JS_STATIC_METHOD_ENTRY(openDoc)
-JS_STATIC_METHOD_ENTRY(openFDF)
-JS_STATIC_METHOD_ENTRY(popUpMenuEx)
-JS_STATIC_METHOD_ENTRY(popUpMenu)
-JS_STATIC_METHOD_ENTRY(response)
-JS_STATIC_METHOD_ENTRY(setInterval)
-JS_STATIC_METHOD_ENTRY(setTimeOut)
-END_JS_STATIC_METHOD()
+JSMethodSpec CJS_App::MethodSpecs[] = {{"alert", alert_static},
+                                       {"beep", beep_static},
+                                       {"browseForDoc", browseForDoc_static},
+                                       {"clearInterval", clearInterval_static},
+                                       {"clearTimeOut", clearTimeOut_static},
+                                       {"execDialog", execDialog_static},
+                                       {"execMenuItem", execMenuItem_static},
+                                       {"findComponent", findComponent_static},
+                                       {"goBack", goBack_static},
+                                       {"goForward", goForward_static},
+                                       {"launchURL", launchURL_static},
+                                       {"mailMsg", mailMsg_static},
+                                       {"newFDF", newFDF_static},
+                                       {"newDoc", newDoc_static},
+                                       {"openDoc", openDoc_static},
+                                       {"openFDF", openFDF_static},
+                                       {"popUpMenuEx", popUpMenuEx_static},
+                                       {"popUpMenu", popUpMenu_static},
+                                       {"response", response_static},
+                                       {"setInterval", setInterval_static},
+                                       {"setTimeOut", setTimeOut_static},
+                                       {0, 0}};
 
 IMPLEMENT_JS_CLASS(CJS_App, app)
 
@@ -211,23 +207,19 @@
 app::~app() {
 }
 
-bool app::activeDocs(IJS_Context* cc,
+bool app::activeDocs(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
   CJS_Document* pJSDocument = nullptr;
   v8::Local<v8::Object> pObj = pRuntime->GetThisObj();
-  if (CFXJS_Engine::GetObjDefnID(pObj) == CJS_Document::g_nObjDefnID) {
+  if (CFXJS_Engine::GetObjDefnID(pObj) == CJS_Document::g_nObjDefnID)
     pJSDocument = static_cast<CJS_Document*>(pRuntime->GetObjectPrivate(pObj));
-  }
 
   CJS_Array aDocs;
   aDocs.SetElement(pRuntime, 0, CJS_Value(pRuntime, pJSDocument));
-
   if (aDocs.GetLength(pRuntime) > 0)
     vp << aDocs;
   else
@@ -236,16 +228,14 @@
   return true;
 }
 
-bool app::calculate(IJS_Context* cc,
+bool app::calculate(CJS_Runtime* pRuntime,
                     CJS_PropValue& vp,
                     CFX_WideString& sError) {
   if (vp.IsSetting()) {
     bool bVP;
     vp >> bVP;
     m_bCalculate = (bool)bVP;
-
-    CJS_Context* pContext = (CJS_Context*)cc;
-    pContext->GetFormFillEnv()->GetInterForm()->EnableCalculate(
+    pRuntime->GetFormFillEnv()->GetInterForm()->EnableCalculate(
         (bool)m_bCalculate);
   } else {
     vp << (bool)m_bCalculate;
@@ -253,7 +243,7 @@
   return true;
 }
 
-bool app::formsVersion(IJS_Context* cc,
+bool app::formsVersion(CJS_Runtime* pRuntime,
                        CJS_PropValue& vp,
                        CFX_WideString& sError) {
   if (vp.IsGetting()) {
@@ -264,7 +254,7 @@
   return false;
 }
 
-bool app::viewerType(IJS_Context* cc,
+bool app::viewerType(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   if (vp.IsGetting()) {
@@ -275,7 +265,7 @@
   return false;
 }
 
-bool app::viewerVariation(IJS_Context* cc,
+bool app::viewerVariation(CJS_Runtime* pRuntime,
                           CJS_PropValue& vp,
                           CFX_WideString& sError) {
   if (vp.IsGetting()) {
@@ -286,14 +276,13 @@
   return false;
 }
 
-bool app::viewerVersion(IJS_Context* cc,
+bool app::viewerVersion(CJS_Runtime* pRuntime,
                         CJS_PropValue& vp,
                         CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 #ifdef PDF_ENABLE_XFA
-  CJS_Context* pJSContext = static_cast<CJS_Context*>(cc);
-  CPDFXFA_Context* pXFAContext = pJSContext->GetFormFillEnv()->GetXFAContext();
+  CPDFXFA_Context* pXFAContext = pRuntime->GetFormFillEnv()->GetXFAContext();
   if (pXFAContext->GetDocType() == 1 || pXFAContext->GetDocType() == 2) {
     vp << JS_NUM_VIEWERVERSION_XFA;
     return true;
@@ -303,12 +292,13 @@
   return true;
 }
 
-bool app::platform(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool app::platform(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 #ifdef PDF_ENABLE_XFA
-  CPDFSDK_FormFillEnvironment* pFormFillEnv =
-      static_cast<CJS_Context*>(cc)->GetJSRuntime()->GetFormFillEnv();
+  CPDFSDK_FormFillEnvironment* pFormFillEnv = pRuntime->GetFormFillEnv();
   if (!pFormFillEnv)
     return false;
   CFX_WideString platfrom = pFormFillEnv->GetPlatform();
@@ -321,12 +311,13 @@
   return true;
 }
 
-bool app::language(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool app::language(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 #ifdef PDF_ENABLE_XFA
-  CPDFSDK_FormFillEnvironment* pFormFillEnv =
-      static_cast<CJS_Context*>(cc)->GetJSRuntime()->GetFormFillEnv();
+  CPDFSDK_FormFillEnvironment* pFormFillEnv = pRuntime->GetFormFillEnv();
   if (!pFormFillEnv)
     return false;
   CFX_WideString language = pFormFillEnv->GetLanguage();
@@ -343,7 +334,7 @@
 // comment: need reader support
 // note:
 // CFDF_Document * CPDFSDK_FormFillEnvironment::NewFDF();
-bool app::newFDF(IJS_Context* cc,
+bool app::newFDF(CJS_Runtime* pRuntime,
                  const std::vector<CJS_Value>& params,
                  CJS_Value& vRet,
                  CFX_WideString& sError) {
@@ -356,18 +347,17 @@
 // CFDF_Document * CPDFSDK_FormFillEnvironment::OpenFDF(string strPath,bool
 // bUserConv);
 
-bool app::openFDF(IJS_Context* cc,
+bool app::openFDF(CJS_Runtime* pRuntime,
                   const std::vector<CJS_Value>& params,
                   CJS_Value& vRet,
                   CFX_WideString& sError) {
   return true;
 }
 
-bool app::alert(IJS_Context* cc,
+bool app::alert(CJS_Runtime* pRuntime,
                 const std::vector<CJS_Value>& params,
                 CJS_Value& vRet,
                 CFX_WideString& sError) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   std::vector<CJS_Value> newParams = JS_ExpandKeywordParams(
       pRuntime, params, 4, L"cMsg", L"nIcon", L"nType", L"cTitle");
 
@@ -425,12 +415,11 @@
   return true;
 }
 
-bool app::beep(IJS_Context* cc,
+bool app::beep(CJS_Runtime* pRuntime,
                const std::vector<CJS_Value>& params,
                CJS_Value& vRet,
                CFX_WideString& sError) {
   if (params.size() == 1) {
-    CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
     pRuntime->GetFormFillEnv()->JS_appBeep(params[0].ToInt(pRuntime));
     return true;
   }
@@ -439,25 +428,25 @@
   return false;
 }
 
-bool app::findComponent(IJS_Context* cc,
+bool app::findComponent(CJS_Runtime* pRuntime,
                         const std::vector<CJS_Value>& params,
                         CJS_Value& vRet,
                         CFX_WideString& sError) {
   return true;
 }
 
-bool app::popUpMenuEx(IJS_Context* cc,
+bool app::popUpMenuEx(CJS_Runtime* pRuntime,
                       const std::vector<CJS_Value>& params,
                       CJS_Value& vRet,
                       CFX_WideString& sError) {
   return false;
 }
 
-bool app::fs(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool app::fs(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError) {
   return false;
 }
 
-bool app::setInterval(IJS_Context* cc,
+bool app::setInterval(CJS_Runtime* pRuntime,
                       const std::vector<CJS_Value>& params,
                       CJS_Value& vRet,
                       CFX_WideString& sError) {
@@ -466,7 +455,6 @@
     return false;
   }
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CFX_WideString script =
       params.size() > 0 ? params[0].ToCFXWideString(pRuntime) : L"";
   if (script.IsEmpty()) {
@@ -482,6 +470,9 @@
 
   v8::Local<v8::Object> pRetObj =
       pRuntime->NewFxDynamicObj(CJS_TimerObj::g_nObjDefnID);
+  if (pRetObj.IsEmpty())
+    return false;
+
   CJS_TimerObj* pJS_TimerObj =
       static_cast<CJS_TimerObj*>(pRuntime->GetObjectPrivate(pRetObj));
   TimerObj* pTimerObj = static_cast<TimerObj*>(pJS_TimerObj->GetEmbedObject());
@@ -491,7 +482,7 @@
   return true;
 }
 
-bool app::setTimeOut(IJS_Context* cc,
+bool app::setTimeOut(CJS_Runtime* pRuntime,
                      const std::vector<CJS_Value>& params,
                      CJS_Value& vRet,
                      CFX_WideString& sError) {
@@ -500,7 +491,6 @@
     return false;
   }
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CFX_WideString script = params[0].ToCFXWideString(pRuntime);
   if (script.IsEmpty()) {
     sError = JSGetStringFromID(IDS_STRING_JSAFNUMBER_KEYSTROKE);
@@ -515,18 +505,18 @@
 
   v8::Local<v8::Object> pRetObj =
       pRuntime->NewFxDynamicObj(CJS_TimerObj::g_nObjDefnID);
+  if (pRetObj.IsEmpty())
+    return false;
 
   CJS_TimerObj* pJS_TimerObj =
       static_cast<CJS_TimerObj*>(pRuntime->GetObjectPrivate(pRetObj));
-
   TimerObj* pTimerObj = static_cast<TimerObj*>(pJS_TimerObj->GetEmbedObject());
   pTimerObj->SetTimer(timerRef);
-
   vRet = CJS_Value(pRuntime, pRetObj);
   return true;
 }
 
-bool app::clearTimeOut(IJS_Context* cc,
+bool app::clearTimeOut(CJS_Runtime* pRuntime,
                        const std::vector<CJS_Value>& params,
                        CJS_Value& vRet,
                        CFX_WideString& sError) {
@@ -535,11 +525,11 @@
     return false;
   }
 
-  app::ClearTimerCommon(CJS_Runtime::FromContext(cc), params[0]);
+  app::ClearTimerCommon(pRuntime, params[0]);
   return true;
 }
 
-bool app::clearInterval(IJS_Context* cc,
+bool app::clearInterval(CJS_Runtime* pRuntime,
                         const std::vector<CJS_Value>& params,
                         CJS_Value& vRet,
                         CFX_WideString& sError) {
@@ -548,7 +538,7 @@
     return false;
   }
 
-  app::ClearTimerCommon(CJS_Runtime::FromContext(cc), params[0]);
+  app::ClearTimerCommon(pRuntime, params[0]);
   return true;
 }
 
@@ -571,7 +561,7 @@
   GlobalTimer::Cancel(pTimerObj->GetTimerID());
 }
 
-bool app::execMenuItem(IJS_Context* cc,
+bool app::execMenuItem(CJS_Runtime* pRuntime,
                        const std::vector<CJS_Value>& params,
                        CJS_Value& vRet,
                        CFX_WideString& sError) {
@@ -590,15 +580,15 @@
 
 void app::RunJsScript(CJS_Runtime* pRuntime, const CFX_WideString& wsScript) {
   if (!pRuntime->IsBlocking()) {
-    IJS_Context* pContext = pRuntime->NewContext();
+    IJS_EventContext* pContext = pRuntime->NewEventContext();
     pContext->OnExternal_Exec();
     CFX_WideString wtInfo;
     pContext->RunScript(wsScript, &wtInfo);
-    pRuntime->ReleaseContext(pContext);
+    pRuntime->ReleaseEventContext(pContext);
   }
 }
 
-bool app::goBack(IJS_Context* cc,
+bool app::goBack(CJS_Runtime* pRuntime,
                  const std::vector<CJS_Value>& params,
                  CJS_Value& vRet,
                  CFX_WideString& sError) {
@@ -606,7 +596,7 @@
   return true;
 }
 
-bool app::goForward(IJS_Context* cc,
+bool app::goForward(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError) {
@@ -614,11 +604,10 @@
   return true;
 }
 
-bool app::mailMsg(IJS_Context* cc,
+bool app::mailMsg(CJS_Runtime* pRuntime,
                   const std::vector<CJS_Value>& params,
                   CJS_Value& vRet,
                   CFX_WideString& sError) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   std::vector<CJS_Value> newParams =
       JS_ExpandKeywordParams(pRuntime, params, 6, L"bUI", L"cTo", L"cCc",
                              L"cBcc", L"cSubject", L"cMsg");
@@ -657,15 +646,14 @@
     cMsg = newParams[5].ToCFXWideString(pRuntime);
 
   pRuntime->BeginBlock();
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  pContext->GetFormFillEnv()->JS_docmailForm(nullptr, 0, bUI, cTo.c_str(),
+  pRuntime->GetFormFillEnv()->JS_docmailForm(nullptr, 0, bUI, cTo.c_str(),
                                              cSubject.c_str(), cCc.c_str(),
                                              cBcc.c_str(), cMsg.c_str());
   pRuntime->EndBlock();
   return true;
 }
 
-bool app::launchURL(IJS_Context* cc,
+bool app::launchURL(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError) {
@@ -673,7 +661,7 @@
   return true;
 }
 
-bool app::runtimeHighlight(IJS_Context* cc,
+bool app::runtimeHighlight(CJS_Runtime* pRuntime,
                            CJS_PropValue& vp,
                            CFX_WideString& sError) {
   if (vp.IsSetting()) {
@@ -684,20 +672,20 @@
   return true;
 }
 
-bool app::fullscreen(IJS_Context* cc,
+bool app::fullscreen(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   return false;
 }
 
-bool app::popUpMenu(IJS_Context* cc,
+bool app::popUpMenu(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError) {
   return false;
 }
 
-bool app::browseForDoc(IJS_Context* cc,
+bool app::browseForDoc(CJS_Runtime* pRuntime,
                        const std::vector<CJS_Value>& params,
                        CJS_Value& vRet,
                        CFX_WideString& sError) {
@@ -723,25 +711,24 @@
   return sRet;
 }
 
-bool app::newDoc(IJS_Context* cc,
+bool app::newDoc(CJS_Runtime* pRuntime,
                  const std::vector<CJS_Value>& params,
                  CJS_Value& vRet,
                  CFX_WideString& sError) {
   return false;
 }
 
-bool app::openDoc(IJS_Context* cc,
+bool app::openDoc(CJS_Runtime* pRuntime,
                   const std::vector<CJS_Value>& params,
                   CJS_Value& vRet,
                   CFX_WideString& sError) {
   return false;
 }
 
-bool app::response(IJS_Context* cc,
+bool app::response(CJS_Runtime* pRuntime,
                    const std::vector<CJS_Value>& params,
                    CJS_Value& vRet,
                    CFX_WideString& sError) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   std::vector<CJS_Value> newParams =
       JS_ExpandKeywordParams(pRuntime, params, 5, L"cQuestion", L"cTitle",
                              L"cDefault", L"bPassword", L"cLabel");
@@ -772,8 +759,7 @@
   std::unique_ptr<char[]> pBuff(new char[MAX_INPUT_BYTES + 2]);
   memset(pBuff.get(), 0, MAX_INPUT_BYTES + 2);
 
-  CJS_Context* pContext = static_cast<CJS_Context*>(cc);
-  int nLengthBytes = pContext->GetFormFillEnv()->JS_appResponse(
+  int nLengthBytes = pRuntime->GetFormFillEnv()->JS_appResponse(
       swQuestion.c_str(), swTitle.c_str(), swDefault.c_str(), swLabel.c_str(),
       bPassword, pBuff.get(), MAX_INPUT_BYTES);
 
@@ -790,11 +776,13 @@
   return true;
 }
 
-bool app::media(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool app::media(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError) {
   return false;
 }
 
-bool app::execDialog(IJS_Context* cc,
+bool app::execDialog(CJS_Runtime* pRuntime,
                      const std::vector<CJS_Value>& params,
                      CJS_Value& vRet,
                      CFX_WideString& sError) {
diff --git a/fpdfsdk/javascript/app.h b/fpdfsdk/javascript/app.h
index e8c7241..9e11b82 100644
--- a/fpdfsdk/javascript/app.h
+++ b/fpdfsdk/javascript/app.h
@@ -41,106 +41,120 @@
   explicit app(CJS_Object* pJSObject);
   ~app() override;
 
-  bool activeDocs(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool calculate(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool formsVersion(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool fs(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool fullscreen(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool language(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool media(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool platform(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool runtimeHighlight(IJS_Context* cc,
+  bool activeDocs(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError);
+  bool calculate(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError);
+  bool formsVersion(CJS_Runtime* pRuntime,
+                    CJS_PropValue& vp,
+                    CFX_WideString& sError);
+  bool fs(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool fullscreen(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError);
+  bool language(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool media(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool platform(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool runtimeHighlight(CJS_Runtime* pRuntime,
                         CJS_PropValue& vp,
                         CFX_WideString& sError);
-  bool viewerType(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool viewerVariation(IJS_Context* cc,
+  bool viewerType(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError);
+  bool viewerVariation(CJS_Runtime* pRuntime,
                        CJS_PropValue& vp,
                        CFX_WideString& sError);
-  bool viewerVersion(IJS_Context* cc,
+  bool viewerVersion(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError);
 
-  bool alert(IJS_Context* cc,
+  bool alert(CJS_Runtime* pRuntime,
              const std::vector<CJS_Value>& params,
              CJS_Value& vRet,
              CFX_WideString& sError);
-  bool beep(IJS_Context* cc,
+  bool beep(CJS_Runtime* pRuntime,
             const std::vector<CJS_Value>& params,
             CJS_Value& vRet,
             CFX_WideString& sError);
-  bool browseForDoc(IJS_Context* cc,
+  bool browseForDoc(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError);
-  bool clearInterval(IJS_Context* cc,
+  bool clearInterval(CJS_Runtime* pRuntime,
                      const std::vector<CJS_Value>& params,
                      CJS_Value& vRet,
                      CFX_WideString& sError);
-  bool clearTimeOut(IJS_Context* cc,
+  bool clearTimeOut(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError);
-  bool execDialog(IJS_Context* cc,
+  bool execDialog(CJS_Runtime* pRuntime,
                   const std::vector<CJS_Value>& params,
                   CJS_Value& vRet,
                   CFX_WideString& sError);
-  bool execMenuItem(IJS_Context* cc,
+  bool execMenuItem(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError);
-  bool findComponent(IJS_Context* cc,
+  bool findComponent(CJS_Runtime* pRuntime,
                      const std::vector<CJS_Value>& params,
                      CJS_Value& vRet,
                      CFX_WideString& sError);
-  bool goBack(IJS_Context* cc,
+  bool goBack(CJS_Runtime* pRuntime,
               const std::vector<CJS_Value>& params,
               CJS_Value& vRet,
               CFX_WideString& sError);
-  bool goForward(IJS_Context* cc,
+  bool goForward(CJS_Runtime* pRuntime,
                  const std::vector<CJS_Value>& params,
                  CJS_Value& vRet,
                  CFX_WideString& sError);
-  bool launchURL(IJS_Context* cc,
+  bool launchURL(CJS_Runtime* pRuntime,
                  const std::vector<CJS_Value>& params,
                  CJS_Value& vRet,
                  CFX_WideString& sError);
-  bool mailMsg(IJS_Context* cc,
+  bool mailMsg(CJS_Runtime* pRuntime,
                const std::vector<CJS_Value>& params,
                CJS_Value& vRet,
                CFX_WideString& sError);
-  bool newFDF(IJS_Context* cc,
+  bool newFDF(CJS_Runtime* pRuntime,
               const std::vector<CJS_Value>& params,
               CJS_Value& vRet,
               CFX_WideString& sError);
-  bool newDoc(IJS_Context* cc,
+  bool newDoc(CJS_Runtime* pRuntime,
               const std::vector<CJS_Value>& params,
               CJS_Value& vRet,
               CFX_WideString& sError);
-  bool openDoc(IJS_Context* cc,
+  bool openDoc(CJS_Runtime* pRuntime,
                const std::vector<CJS_Value>& params,
                CJS_Value& vRet,
                CFX_WideString& sError);
-  bool openFDF(IJS_Context* cc,
+  bool openFDF(CJS_Runtime* pRuntime,
                const std::vector<CJS_Value>& params,
                CJS_Value& vRet,
                CFX_WideString& sError);
-  bool popUpMenuEx(IJS_Context* cc,
+  bool popUpMenuEx(CJS_Runtime* pRuntime,
                    const std::vector<CJS_Value>& params,
                    CJS_Value& vRet,
                    CFX_WideString& sError);
-  bool popUpMenu(IJS_Context* cc,
+  bool popUpMenu(CJS_Runtime* pRuntime,
                  const std::vector<CJS_Value>& params,
                  CJS_Value& vRet,
                  CFX_WideString& sError);
-  bool response(IJS_Context* cc,
+  bool response(CJS_Runtime* pRuntime,
                 const std::vector<CJS_Value>& params,
                 CJS_Value& vRet,
                 CFX_WideString& sError);
-  bool setInterval(IJS_Context* cc,
+  bool setInterval(CJS_Runtime* pRuntime,
                    const std::vector<CJS_Value>& params,
                    CJS_Value& vRet,
                    CFX_WideString& sError);
-  bool setTimeOut(IJS_Context* cc,
+  bool setTimeOut(CJS_Runtime* pRuntime,
                   const std::vector<CJS_Value>& params,
                   CJS_Value& vRet,
                   CFX_WideString& sError);
diff --git a/fpdfsdk/javascript/cjs_context.cpp b/fpdfsdk/javascript/cjs_context.cpp
deleted file mode 100644
index e356bdd..0000000
--- a/fpdfsdk/javascript/cjs_context.cpp
+++ /dev/null
@@ -1,272 +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 "fpdfsdk/javascript/cjs_context.h"
-
-#include "fpdfsdk/javascript/JS_EventHandler.h"
-#include "fpdfsdk/javascript/cjs_runtime.h"
-#include "fpdfsdk/javascript/resource.h"
-
-CJS_Context::CJS_Context(CJS_Runtime* pRuntime)
-    : m_pRuntime(pRuntime),
-      m_pEventHandler(new CJS_EventHandler(this)),
-      m_bBusy(false) {}
-
-CJS_Context::~CJS_Context() {}
-
-CPDFSDK_FormFillEnvironment* CJS_Context::GetFormFillEnv() {
-  return m_pRuntime->GetFormFillEnv();
-}
-
-bool CJS_Context::RunScript(const CFX_WideString& script,
-                            CFX_WideString* info) {
-  v8::Isolate::Scope isolate_scope(m_pRuntime->GetIsolate());
-  v8::HandleScope handle_scope(m_pRuntime->GetIsolate());
-  v8::Local<v8::Context> context = m_pRuntime->NewLocalContext();
-  v8::Context::Scope context_scope(context);
-
-  if (m_bBusy) {
-    *info = JSGetStringFromID(IDS_STRING_JSBUSY);
-    return false;
-  }
-  m_bBusy = true;
-
-  ASSERT(m_pEventHandler->IsValid());
-  CJS_Runtime::FieldEvent event(m_pEventHandler->TargetName(),
-                                m_pEventHandler->EventType());
-  if (!m_pRuntime->AddEventToSet(event)) {
-    *info = JSGetStringFromID(IDS_STRING_JSEVENT);
-    return false;
-  }
-
-  CFX_WideString sErrorMessage;
-  int nRet = 0;
-  if (script.GetLength() > 0) {
-    nRet = m_pRuntime->ExecuteScript(script.c_str(), &sErrorMessage);
-  }
-
-  if (nRet < 0) {
-    *info += sErrorMessage;
-  } else {
-    *info = JSGetStringFromID(IDS_STRING_RUN);
-  }
-
-  m_pRuntime->RemoveEventFromSet(event);
-  m_pEventHandler->Destroy();
-  m_bBusy = false;
-
-  return nRet >= 0;
-}
-
-void CJS_Context::OnApp_Init() {
-  m_pEventHandler->OnApp_Init();
-}
-
-void CJS_Context::OnDoc_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                             const CFX_WideString& strTargetName) {
-  m_pEventHandler->OnDoc_Open(pFormFillEnv, strTargetName);
-}
-
-void CJS_Context::OnDoc_WillPrint(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  m_pEventHandler->OnDoc_WillPrint(pFormFillEnv);
-}
-
-void CJS_Context::OnDoc_DidPrint(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  m_pEventHandler->OnDoc_DidPrint(pFormFillEnv);
-}
-
-void CJS_Context::OnDoc_WillSave(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  m_pEventHandler->OnDoc_WillSave(pFormFillEnv);
-}
-
-void CJS_Context::OnDoc_DidSave(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  m_pEventHandler->OnDoc_DidSave(pFormFillEnv);
-}
-
-void CJS_Context::OnDoc_WillClose(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  m_pEventHandler->OnDoc_WillClose(pFormFillEnv);
-}
-
-void CJS_Context::OnPage_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  m_pEventHandler->OnPage_Open(pFormFillEnv);
-}
-
-void CJS_Context::OnPage_Close(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  m_pEventHandler->OnPage_Close(pFormFillEnv);
-}
-
-void CJS_Context::OnPage_InView(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  m_pEventHandler->OnPage_InView(pFormFillEnv);
-}
-
-void CJS_Context::OnPage_OutView(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  m_pEventHandler->OnPage_OutView(pFormFillEnv);
-}
-
-void CJS_Context::OnField_MouseDown(bool bModifier,
-                                    bool bShift,
-                                    CPDF_FormField* pTarget) {
-  m_pEventHandler->OnField_MouseDown(bModifier, bShift, pTarget);
-}
-
-void CJS_Context::OnField_MouseEnter(bool bModifier,
-                                     bool bShift,
-                                     CPDF_FormField* pTarget) {
-  m_pEventHandler->OnField_MouseEnter(bModifier, bShift, pTarget);
-}
-
-void CJS_Context::OnField_MouseExit(bool bModifier,
-                                    bool bShift,
-                                    CPDF_FormField* pTarget) {
-  m_pEventHandler->OnField_MouseExit(bModifier, bShift, pTarget);
-}
-
-void CJS_Context::OnField_MouseUp(bool bModifier,
-                                  bool bShift,
-                                  CPDF_FormField* pTarget) {
-  m_pEventHandler->OnField_MouseUp(bModifier, bShift, pTarget);
-}
-
-void CJS_Context::OnField_Focus(bool bModifier,
-                                bool bShift,
-                                CPDF_FormField* pTarget,
-                                const CFX_WideString& Value) {
-  m_pEventHandler->OnField_Focus(bModifier, bShift, pTarget, Value);
-}
-
-void CJS_Context::OnField_Blur(bool bModifier,
-                               bool bShift,
-                               CPDF_FormField* pTarget,
-                               const CFX_WideString& Value) {
-  m_pEventHandler->OnField_Blur(bModifier, bShift, pTarget, Value);
-}
-
-void CJS_Context::OnField_Calculate(CPDF_FormField* pSource,
-                                    CPDF_FormField* pTarget,
-                                    CFX_WideString& Value,
-                                    bool& bRc) {
-  m_pEventHandler->OnField_Calculate(pSource, pTarget, Value, bRc);
-}
-
-void CJS_Context::OnField_Format(CPDF_FormField* pTarget,
-                                 CFX_WideString& Value,
-                                 bool bWillCommit) {
-  m_pEventHandler->OnField_Format(pTarget, Value, bWillCommit);
-}
-
-void CJS_Context::OnField_Keystroke(CFX_WideString& strChange,
-                                    const CFX_WideString& strChangeEx,
-                                    bool bKeyDown,
-                                    bool bModifier,
-                                    int& nSelEnd,
-                                    int& nSelStart,
-                                    bool bShift,
-                                    CPDF_FormField* pTarget,
-                                    CFX_WideString& Value,
-                                    bool bWillCommit,
-                                    bool bFieldFull,
-                                    bool& bRc) {
-  m_pEventHandler->OnField_Keystroke(
-      strChange, strChangeEx, bKeyDown, bModifier, nSelEnd, nSelStart, bShift,
-      pTarget, Value, bWillCommit, bFieldFull, bRc);
-}
-
-void CJS_Context::OnField_Validate(CFX_WideString& strChange,
-                                   const CFX_WideString& strChangeEx,
-                                   bool bKeyDown,
-                                   bool bModifier,
-                                   bool bShift,
-                                   CPDF_FormField* pTarget,
-                                   CFX_WideString& Value,
-                                   bool& bRc) {
-  m_pEventHandler->OnField_Validate(strChange, strChangeEx, bKeyDown, bModifier,
-                                    bShift, pTarget, Value, bRc);
-}
-
-void CJS_Context::OnScreen_Focus(bool bModifier,
-                                 bool bShift,
-                                 CPDFSDK_Annot* pScreen) {
-  m_pEventHandler->OnScreen_Focus(bModifier, bShift, pScreen);
-}
-
-void CJS_Context::OnScreen_Blur(bool bModifier,
-                                bool bShift,
-                                CPDFSDK_Annot* pScreen) {
-  m_pEventHandler->OnScreen_Blur(bModifier, bShift, pScreen);
-}
-
-void CJS_Context::OnScreen_Open(bool bModifier,
-                                bool bShift,
-                                CPDFSDK_Annot* pScreen) {
-  m_pEventHandler->OnScreen_Open(bModifier, bShift, pScreen);
-}
-
-void CJS_Context::OnScreen_Close(bool bModifier,
-                                 bool bShift,
-                                 CPDFSDK_Annot* pScreen) {
-  m_pEventHandler->OnScreen_Close(bModifier, bShift, pScreen);
-}
-
-void CJS_Context::OnScreen_MouseDown(bool bModifier,
-                                     bool bShift,
-                                     CPDFSDK_Annot* pScreen) {
-  m_pEventHandler->OnScreen_MouseDown(bModifier, bShift, pScreen);
-}
-
-void CJS_Context::OnScreen_MouseUp(bool bModifier,
-                                   bool bShift,
-                                   CPDFSDK_Annot* pScreen) {
-  m_pEventHandler->OnScreen_MouseUp(bModifier, bShift, pScreen);
-}
-
-void CJS_Context::OnScreen_MouseEnter(bool bModifier,
-                                      bool bShift,
-                                      CPDFSDK_Annot* pScreen) {
-  m_pEventHandler->OnScreen_MouseEnter(bModifier, bShift, pScreen);
-}
-
-void CJS_Context::OnScreen_MouseExit(bool bModifier,
-                                     bool bShift,
-                                     CPDFSDK_Annot* pScreen) {
-  m_pEventHandler->OnScreen_MouseExit(bModifier, bShift, pScreen);
-}
-
-void CJS_Context::OnScreen_InView(bool bModifier,
-                                  bool bShift,
-                                  CPDFSDK_Annot* pScreen) {
-  m_pEventHandler->OnScreen_InView(bModifier, bShift, pScreen);
-}
-
-void CJS_Context::OnScreen_OutView(bool bModifier,
-                                   bool bShift,
-                                   CPDFSDK_Annot* pScreen) {
-  m_pEventHandler->OnScreen_OutView(bModifier, bShift, pScreen);
-}
-
-void CJS_Context::OnBookmark_MouseUp(CPDF_Bookmark* pBookMark) {
-  m_pEventHandler->OnBookmark_MouseUp(pBookMark);
-}
-
-void CJS_Context::OnLink_MouseUp(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  m_pEventHandler->OnLink_MouseUp(pFormFillEnv);
-}
-
-void CJS_Context::OnConsole_Exec() {
-  m_pEventHandler->OnConsole_Exec();
-}
-
-void CJS_Context::OnExternal_Exec() {
-  m_pEventHandler->OnExternal_Exec();
-}
-
-void CJS_Context::OnBatchExec(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  m_pEventHandler->OnBatchExec(pFormFillEnv);
-}
-
-void CJS_Context::OnMenu_Exec(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                              const CFX_WideString& strTargetName) {
-  m_pEventHandler->OnMenu_Exec(pFormFillEnv, strTargetName);
-}
diff --git a/fpdfsdk/javascript/cjs_event_context.cpp b/fpdfsdk/javascript/cjs_event_context.cpp
new file mode 100644
index 0000000..abfb6da
--- /dev/null
+++ b/fpdfsdk/javascript/cjs_event_context.cpp
@@ -0,0 +1,280 @@
+// 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 "fpdfsdk/javascript/cjs_event_context.h"
+
+#include "fpdfsdk/javascript/JS_EventHandler.h"
+#include "fpdfsdk/javascript/cjs_runtime.h"
+#include "fpdfsdk/javascript/resource.h"
+
+CJS_EventContext::CJS_EventContext(CJS_Runtime* pRuntime)
+    : m_pRuntime(pRuntime),
+      m_pEventHandler(new CJS_EventHandler(this)),
+      m_bBusy(false) {
+  ASSERT(pRuntime);
+}
+
+CJS_EventContext::~CJS_EventContext() {}
+
+CPDFSDK_FormFillEnvironment* CJS_EventContext::GetFormFillEnv() {
+  return m_pRuntime->GetFormFillEnv();
+}
+
+bool CJS_EventContext::RunScript(const CFX_WideString& script,
+                                 CFX_WideString* info) {
+  v8::Isolate::Scope isolate_scope(m_pRuntime->GetIsolate());
+  v8::HandleScope handle_scope(m_pRuntime->GetIsolate());
+  v8::Local<v8::Context> context = m_pRuntime->NewLocalContext();
+  v8::Context::Scope context_scope(context);
+
+  if (m_bBusy) {
+    *info = JSGetStringFromID(IDS_STRING_JSBUSY);
+    return false;
+  }
+
+  CFX_AutoRestorer<bool> restorer(&m_bBusy);
+  m_bBusy = true;
+
+  ASSERT(m_pEventHandler->IsValid());
+  CJS_Runtime::FieldEvent event(m_pEventHandler->TargetName(),
+                                m_pEventHandler->EventType());
+  if (!m_pRuntime->AddEventToSet(event)) {
+    *info = JSGetStringFromID(IDS_STRING_JSEVENT);
+    return false;
+  }
+
+  CFX_WideString sErrorMessage;
+  int nRet = 0;
+  if (script.GetLength() > 0)
+    nRet = m_pRuntime->ExecuteScript(script.c_str(), &sErrorMessage);
+
+  if (nRet < 0)
+    *info += sErrorMessage;
+  else
+    *info = JSGetStringFromID(IDS_STRING_RUN);
+
+  m_pRuntime->RemoveEventFromSet(event);
+  m_pEventHandler->Destroy();
+  return nRet >= 0;
+}
+
+void CJS_EventContext::OnApp_Init() {
+  m_pEventHandler->OnApp_Init();
+}
+
+void CJS_EventContext::OnDoc_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv,
+                                  const CFX_WideString& strTargetName) {
+  m_pEventHandler->OnDoc_Open(pFormFillEnv, strTargetName);
+}
+
+void CJS_EventContext::OnDoc_WillPrint(
+    CPDFSDK_FormFillEnvironment* pFormFillEnv) {
+  m_pEventHandler->OnDoc_WillPrint(pFormFillEnv);
+}
+
+void CJS_EventContext::OnDoc_DidPrint(
+    CPDFSDK_FormFillEnvironment* pFormFillEnv) {
+  m_pEventHandler->OnDoc_DidPrint(pFormFillEnv);
+}
+
+void CJS_EventContext::OnDoc_WillSave(
+    CPDFSDK_FormFillEnvironment* pFormFillEnv) {
+  m_pEventHandler->OnDoc_WillSave(pFormFillEnv);
+}
+
+void CJS_EventContext::OnDoc_DidSave(
+    CPDFSDK_FormFillEnvironment* pFormFillEnv) {
+  m_pEventHandler->OnDoc_DidSave(pFormFillEnv);
+}
+
+void CJS_EventContext::OnDoc_WillClose(
+    CPDFSDK_FormFillEnvironment* pFormFillEnv) {
+  m_pEventHandler->OnDoc_WillClose(pFormFillEnv);
+}
+
+void CJS_EventContext::OnPage_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
+  m_pEventHandler->OnPage_Open(pFormFillEnv);
+}
+
+void CJS_EventContext::OnPage_Close(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
+  m_pEventHandler->OnPage_Close(pFormFillEnv);
+}
+
+void CJS_EventContext::OnPage_InView(
+    CPDFSDK_FormFillEnvironment* pFormFillEnv) {
+  m_pEventHandler->OnPage_InView(pFormFillEnv);
+}
+
+void CJS_EventContext::OnPage_OutView(
+    CPDFSDK_FormFillEnvironment* pFormFillEnv) {
+  m_pEventHandler->OnPage_OutView(pFormFillEnv);
+}
+
+void CJS_EventContext::OnField_MouseDown(bool bModifier,
+                                         bool bShift,
+                                         CPDF_FormField* pTarget) {
+  m_pEventHandler->OnField_MouseDown(bModifier, bShift, pTarget);
+}
+
+void CJS_EventContext::OnField_MouseEnter(bool bModifier,
+                                          bool bShift,
+                                          CPDF_FormField* pTarget) {
+  m_pEventHandler->OnField_MouseEnter(bModifier, bShift, pTarget);
+}
+
+void CJS_EventContext::OnField_MouseExit(bool bModifier,
+                                         bool bShift,
+                                         CPDF_FormField* pTarget) {
+  m_pEventHandler->OnField_MouseExit(bModifier, bShift, pTarget);
+}
+
+void CJS_EventContext::OnField_MouseUp(bool bModifier,
+                                       bool bShift,
+                                       CPDF_FormField* pTarget) {
+  m_pEventHandler->OnField_MouseUp(bModifier, bShift, pTarget);
+}
+
+void CJS_EventContext::OnField_Focus(bool bModifier,
+                                     bool bShift,
+                                     CPDF_FormField* pTarget,
+                                     const CFX_WideString& Value) {
+  m_pEventHandler->OnField_Focus(bModifier, bShift, pTarget, Value);
+}
+
+void CJS_EventContext::OnField_Blur(bool bModifier,
+                                    bool bShift,
+                                    CPDF_FormField* pTarget,
+                                    const CFX_WideString& Value) {
+  m_pEventHandler->OnField_Blur(bModifier, bShift, pTarget, Value);
+}
+
+void CJS_EventContext::OnField_Calculate(CPDF_FormField* pSource,
+                                         CPDF_FormField* pTarget,
+                                         CFX_WideString& Value,
+                                         bool& bRc) {
+  m_pEventHandler->OnField_Calculate(pSource, pTarget, Value, bRc);
+}
+
+void CJS_EventContext::OnField_Format(CPDF_FormField* pTarget,
+                                      CFX_WideString& Value,
+                                      bool bWillCommit) {
+  m_pEventHandler->OnField_Format(pTarget, Value, bWillCommit);
+}
+
+void CJS_EventContext::OnField_Keystroke(CFX_WideString& strChange,
+                                         const CFX_WideString& strChangeEx,
+                                         bool bKeyDown,
+                                         bool bModifier,
+                                         int& nSelEnd,
+                                         int& nSelStart,
+                                         bool bShift,
+                                         CPDF_FormField* pTarget,
+                                         CFX_WideString& Value,
+                                         bool bWillCommit,
+                                         bool bFieldFull,
+                                         bool& bRc) {
+  m_pEventHandler->OnField_Keystroke(
+      strChange, strChangeEx, bKeyDown, bModifier, nSelEnd, nSelStart, bShift,
+      pTarget, Value, bWillCommit, bFieldFull, bRc);
+}
+
+void CJS_EventContext::OnField_Validate(CFX_WideString& strChange,
+                                        const CFX_WideString& strChangeEx,
+                                        bool bKeyDown,
+                                        bool bModifier,
+                                        bool bShift,
+                                        CPDF_FormField* pTarget,
+                                        CFX_WideString& Value,
+                                        bool& bRc) {
+  m_pEventHandler->OnField_Validate(strChange, strChangeEx, bKeyDown, bModifier,
+                                    bShift, pTarget, Value, bRc);
+}
+
+void CJS_EventContext::OnScreen_Focus(bool bModifier,
+                                      bool bShift,
+                                      CPDFSDK_Annot* pScreen) {
+  m_pEventHandler->OnScreen_Focus(bModifier, bShift, pScreen);
+}
+
+void CJS_EventContext::OnScreen_Blur(bool bModifier,
+                                     bool bShift,
+                                     CPDFSDK_Annot* pScreen) {
+  m_pEventHandler->OnScreen_Blur(bModifier, bShift, pScreen);
+}
+
+void CJS_EventContext::OnScreen_Open(bool bModifier,
+                                     bool bShift,
+                                     CPDFSDK_Annot* pScreen) {
+  m_pEventHandler->OnScreen_Open(bModifier, bShift, pScreen);
+}
+
+void CJS_EventContext::OnScreen_Close(bool bModifier,
+                                      bool bShift,
+                                      CPDFSDK_Annot* pScreen) {
+  m_pEventHandler->OnScreen_Close(bModifier, bShift, pScreen);
+}
+
+void CJS_EventContext::OnScreen_MouseDown(bool bModifier,
+                                          bool bShift,
+                                          CPDFSDK_Annot* pScreen) {
+  m_pEventHandler->OnScreen_MouseDown(bModifier, bShift, pScreen);
+}
+
+void CJS_EventContext::OnScreen_MouseUp(bool bModifier,
+                                        bool bShift,
+                                        CPDFSDK_Annot* pScreen) {
+  m_pEventHandler->OnScreen_MouseUp(bModifier, bShift, pScreen);
+}
+
+void CJS_EventContext::OnScreen_MouseEnter(bool bModifier,
+                                           bool bShift,
+                                           CPDFSDK_Annot* pScreen) {
+  m_pEventHandler->OnScreen_MouseEnter(bModifier, bShift, pScreen);
+}
+
+void CJS_EventContext::OnScreen_MouseExit(bool bModifier,
+                                          bool bShift,
+                                          CPDFSDK_Annot* pScreen) {
+  m_pEventHandler->OnScreen_MouseExit(bModifier, bShift, pScreen);
+}
+
+void CJS_EventContext::OnScreen_InView(bool bModifier,
+                                       bool bShift,
+                                       CPDFSDK_Annot* pScreen) {
+  m_pEventHandler->OnScreen_InView(bModifier, bShift, pScreen);
+}
+
+void CJS_EventContext::OnScreen_OutView(bool bModifier,
+                                        bool bShift,
+                                        CPDFSDK_Annot* pScreen) {
+  m_pEventHandler->OnScreen_OutView(bModifier, bShift, pScreen);
+}
+
+void CJS_EventContext::OnBookmark_MouseUp(CPDF_Bookmark* pBookMark) {
+  m_pEventHandler->OnBookmark_MouseUp(pBookMark);
+}
+
+void CJS_EventContext::OnLink_MouseUp(
+    CPDFSDK_FormFillEnvironment* pFormFillEnv) {
+  m_pEventHandler->OnLink_MouseUp(pFormFillEnv);
+}
+
+void CJS_EventContext::OnConsole_Exec() {
+  m_pEventHandler->OnConsole_Exec();
+}
+
+void CJS_EventContext::OnExternal_Exec() {
+  m_pEventHandler->OnExternal_Exec();
+}
+
+void CJS_EventContext::OnBatchExec(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
+  m_pEventHandler->OnBatchExec(pFormFillEnv);
+}
+
+void CJS_EventContext::OnMenu_Exec(CPDFSDK_FormFillEnvironment* pFormFillEnv,
+                                   const CFX_WideString& strTargetName) {
+  m_pEventHandler->OnMenu_Exec(pFormFillEnv, strTargetName);
+}
diff --git a/fpdfsdk/javascript/cjs_context.h b/fpdfsdk/javascript/cjs_event_context.h
similarity index 92%
rename from fpdfsdk/javascript/cjs_context.h
rename to fpdfsdk/javascript/cjs_event_context.h
index 95a63ad..7bfe528 100644
--- a/fpdfsdk/javascript/cjs_context.h
+++ b/fpdfsdk/javascript/cjs_event_context.h
@@ -1,28 +1,28 @@
-// Copyright 2014 PDFium Authors. All rights reserved.
+// 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 FPDFSDK_JAVASCRIPT_CJS_CONTEXT_H_
-#define FPDFSDK_JAVASCRIPT_CJS_CONTEXT_H_
+#ifndef FPDFSDK_JAVASCRIPT_CJS_EVENT_CONTEXT_H_
+#define FPDFSDK_JAVASCRIPT_CJS_EVENT_CONTEXT_H_
 
 #include <memory>
 
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
-#include "fpdfsdk/javascript/ijs_context.h"
+#include "fpdfsdk/javascript/ijs_event_context.h"
 
 class CJS_EventHandler;
 class CJS_Runtime;
 class CPDFSDK_FormFillEnvironment;
 
-class CJS_Context : public IJS_Context {
+class CJS_EventContext : public IJS_EventContext {
  public:
-  explicit CJS_Context(CJS_Runtime* pRuntime);
-  ~CJS_Context() override;
+  explicit CJS_EventContext(CJS_Runtime* pRuntime);
+  ~CJS_EventContext() override;
 
-  // IJS_Context
+  // IJS_EventContext
   bool RunScript(const CFX_WideString& script, CFX_WideString* info) override;
   void OnApp_Init() override;
   void OnDoc_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv,
@@ -132,4 +132,4 @@
   bool m_bBusy;
 };
 
-#endif  // FPDFSDK_JAVASCRIPT_CJS_CONTEXT_H_
+#endif  // FPDFSDK_JAVASCRIPT_CJS_EVENT_CONTEXT_H_
diff --git a/fpdfsdk/javascript/cjs_runtime.cpp b/fpdfsdk/javascript/cjs_runtime.cpp
index f55a59c..1ece0b6 100644
--- a/fpdfsdk/javascript/cjs_runtime.cpp
+++ b/fpdfsdk/javascript/cjs_runtime.cpp
@@ -21,7 +21,7 @@
 #include "fpdfsdk/javascript/JS_Value.h"
 #include "fpdfsdk/javascript/PublicMethods.h"
 #include "fpdfsdk/javascript/app.h"
-#include "fpdfsdk/javascript/cjs_context.h"
+#include "fpdfsdk/javascript/cjs_event_context.h"
 #include "fpdfsdk/javascript/color.h"
 #include "fpdfsdk/javascript/console.h"
 #include "fpdfsdk/javascript/event.h"
@@ -51,12 +51,6 @@
 }
 
 // static
-CJS_Runtime* CJS_Runtime::FromContext(const IJS_Context* cc) {
-  const CJS_Context* pContext = static_cast<const CJS_Context*>(cc);
-  return pContext->GetJSRuntime();
-}
-
-// static
 CJS_Runtime* CJS_Runtime::CurrentRuntimeFromIsolate(v8::Isolate* pIsolate) {
   return static_cast<CJS_Runtime*>(
       CFXJS_Engine::CurrentEngineFromIsolate(pIsolate));
@@ -89,10 +83,9 @@
   if (m_isolateManaged || FXJS_GlobalIsolateRefCount() == 0)
     DefineJSObjects();
 
-  CJS_Context* pContext = (CJS_Context*)NewContext();
+  IJS_EventContext* pContext = NewEventContext();
   InitializeEngine();
-  ReleaseContext(pContext);
-
+  ReleaseEventContext(pContext);
   SetFormFillEnvToDocument();
 }
 
@@ -153,22 +146,23 @@
   CJS_Annot::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
 }
 
-IJS_Context* CJS_Runtime::NewContext() {
-  m_ContextArray.push_back(std::unique_ptr<CJS_Context>(new CJS_Context(this)));
-  return m_ContextArray.back().get();
+IJS_EventContext* CJS_Runtime::NewEventContext() {
+  m_EventContextArray.push_back(
+      std::unique_ptr<CJS_EventContext>(new CJS_EventContext(this)));
+  return m_EventContextArray.back().get();
 }
 
-void CJS_Runtime::ReleaseContext(IJS_Context* pContext) {
-  for (auto it = m_ContextArray.begin(); it != m_ContextArray.end(); ++it) {
-    if (it->get() == static_cast<CJS_Context*>(pContext)) {
-      m_ContextArray.erase(it);
-      return;
-    }
-  }
+void CJS_Runtime::ReleaseEventContext(IJS_EventContext* pContext) {
+  auto it = std::find(m_EventContextArray.begin(), m_EventContextArray.end(),
+                      pdfium::FakeUniquePtr<CJS_EventContext>(
+                          static_cast<CJS_EventContext*>(pContext)));
+  if (it != m_EventContextArray.end())
+    m_EventContextArray.erase(it);
 }
 
-IJS_Context* CJS_Runtime::GetCurrentContext() {
-  return m_ContextArray.empty() ? nullptr : m_ContextArray.back().get();
+CJS_EventContext* CJS_Runtime::GetCurrentEventContext() const {
+  return m_EventContextArray.empty() ? nullptr
+                                     : m_EventContextArray.back().get();
 }
 
 void CJS_Runtime::SetFormFillEnvToDocument() {
@@ -193,11 +187,11 @@
   if (!pDocument)
     return;
 
-  pDocument->SetFormFillEnv(m_pFormFillEnv);
+  pDocument->SetFormFillEnv(m_pFormFillEnv.Get());
 }
 
 CPDFSDK_FormFillEnvironment* CJS_Runtime::GetFormFillEnv() const {
-  return m_pFormFillEnv;
+  return m_pFormFillEnv.Get();
 }
 
 int CJS_Runtime::ExecuteScript(const CFX_WideString& script,
diff --git a/fpdfsdk/javascript/cjs_runtime.h b/fpdfsdk/javascript/cjs_runtime.h
index 66f0877..0bde51f 100644
--- a/fpdfsdk/javascript/cjs_runtime.h
+++ b/fpdfsdk/javascript/cjs_runtime.h
@@ -15,11 +15,12 @@
 
 #include "core/fxcrt/cfx_observable.h"
 #include "core/fxcrt/fx_basic.h"
+#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 #include "fpdfsdk/javascript/JS_EventHandler.h"
 #include "fpdfsdk/javascript/ijs_runtime.h"
 #include "fxjs/fxjs_v8.h"
 
-class CJS_Context;
+class CJS_EventContext;
 
 class CJS_Runtime : public IJS_Runtime,
                     public CFXJS_Engine,
@@ -27,22 +28,20 @@
  public:
   using FieldEvent = std::pair<CFX_WideString, JS_EVENT_T>;
 
-  static CJS_Runtime* FromContext(const IJS_Context* cc);
   static CJS_Runtime* CurrentRuntimeFromIsolate(v8::Isolate* pIsolate);
 
   explicit CJS_Runtime(CPDFSDK_FormFillEnvironment* pFormFillEnv);
   ~CJS_Runtime() override;
 
   // IJS_Runtime
-  IJS_Context* NewContext() override;
-  void ReleaseContext(IJS_Context* pContext) override;
-  IJS_Context* GetCurrentContext() override;
-
+  IJS_EventContext* NewEventContext() override;
+  void ReleaseEventContext(IJS_EventContext* pContext) override;
   CPDFSDK_FormFillEnvironment* GetFormFillEnv() const override;
-
   int ExecuteScript(const CFX_WideString& script,
                     CFX_WideString* info) override;
 
+  CJS_EventContext* GetCurrentEventContext() const;
+
   // Returns true if the event isn't already found in the set.
   bool AddEventToSet(const FieldEvent& event);
   void RemoveEventFromSet(const FieldEvent& event);
@@ -62,8 +61,8 @@
   void DefineJSObjects();
   void SetFormFillEnvToDocument();
 
-  std::vector<std::unique_ptr<CJS_Context>> m_ContextArray;
-  CPDFSDK_FormFillEnvironment* const m_pFormFillEnv;
+  std::vector<std::unique_ptr<CJS_EventContext>> m_EventContextArray;
+  CPDFSDK_FormFillEnvironment::ObservedPtr m_pFormFillEnv;
   bool m_bBlocking;
   bool m_isolateManaged;
   std::set<FieldEvent> m_FieldEventSet;
diff --git a/fpdfsdk/javascript/color.cpp b/fpdfsdk/javascript/color.cpp
index 882a903..b5ccbad 100644
--- a/fpdfsdk/javascript/color.cpp
+++ b/fpdfsdk/javascript/color.cpp
@@ -12,31 +12,29 @@
 #include "fpdfsdk/javascript/JS_EventHandler.h"
 #include "fpdfsdk/javascript/JS_Object.h"
 #include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/cjs_context.h"
+#include "fpdfsdk/javascript/cjs_event_context.h"
 #include "fpdfsdk/javascript/cjs_runtime.h"
 
-BEGIN_JS_STATIC_CONST(CJS_Color)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Color::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
 
-BEGIN_JS_STATIC_PROP(CJS_Color)
-JS_STATIC_PROP_ENTRY(black)
-JS_STATIC_PROP_ENTRY(blue)
-JS_STATIC_PROP_ENTRY(cyan)
-JS_STATIC_PROP_ENTRY(dkGray)
-JS_STATIC_PROP_ENTRY(gray)
-JS_STATIC_PROP_ENTRY(green)
-JS_STATIC_PROP_ENTRY(ltGray)
-JS_STATIC_PROP_ENTRY(magenta)
-JS_STATIC_PROP_ENTRY(red)
-JS_STATIC_PROP_ENTRY(transparent)
-JS_STATIC_PROP_ENTRY(white)
-JS_STATIC_PROP_ENTRY(yellow)
-END_JS_STATIC_PROP()
+JSPropertySpec CJS_Color::PropertySpecs[] = {
+    {"black", get_black_static, set_black_static},
+    {"blue", get_blue_static, set_blue_static},
+    {"cyan", get_cyan_static, set_cyan_static},
+    {"dkGray", get_dkGray_static, set_dkGray_static},
+    {"gray", get_gray_static, set_gray_static},
+    {"green", get_green_static, set_green_static},
+    {"ltGray", get_ltGray_static, set_ltGray_static},
+    {"magenta", get_magenta_static, set_magenta_static},
+    {"red", get_red_static, set_red_static},
+    {"transparent", get_transparent_static, set_transparent_static},
+    {"white", get_white_static, set_white_static},
+    {"yellow", get_yellow_static, set_yellow_static},
+    {0, 0, 0}};
 
-BEGIN_JS_STATIC_METHOD(CJS_Color)
-JS_STATIC_METHOD_ENTRY(convert)
-JS_STATIC_METHOD_ENTRY(equal)
-END_JS_STATIC_METHOD()
+JSMethodSpec CJS_Color::MethodSpecs[] = {{"convert", convert_static},
+                                         {"equal", equal_static},
+                                         {0, 0}};
 
 IMPLEMENT_JS_CLASS(CJS_Color, color)
 
@@ -133,36 +131,95 @@
   }
 }
 
-#define JS_IMPLEMENT_COLORPROP(prop, var)                    \
-  bool color::prop(IJS_Context* cc, CJS_PropValue& vp,       \
-                   CFX_WideString& sError) {                 \
-    CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);    \
-    CJS_Array array;                                         \
-    if (vp.IsGetting()) {                                    \
-      ConvertPWLColorToArray(pRuntime, var, &array);         \
-      vp << array;                                           \
-    } else {                                                 \
-      if (!vp.GetJSValue()->ConvertToArray(pRuntime, array)) \
-        return false;                                        \
-      ConvertArrayToPWLColor(pRuntime, array, &var);         \
-    }                                                        \
-    return true;                                             \
+bool color::transparent(CJS_Runtime* pRuntime,
+                        CJS_PropValue& vp,
+                        CFX_WideString& sError) {
+  return PropertyHelper(pRuntime, vp, &m_crTransparent);
+}
+
+bool color::black(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError) {
+  return PropertyHelper(pRuntime, vp, &m_crBlack);
+}
+
+bool color::white(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError) {
+  return PropertyHelper(pRuntime, vp, &m_crWhite);
+}
+
+bool color::red(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError) {
+  return PropertyHelper(pRuntime, vp, &m_crRed);
+}
+
+bool color::green(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError) {
+  return PropertyHelper(pRuntime, vp, &m_crGreen);
+}
+
+bool color::blue(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError) {
+  return PropertyHelper(pRuntime, vp, &m_crBlue);
+}
+
+bool color::cyan(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError) {
+  return PropertyHelper(pRuntime, vp, &m_crCyan);
+}
+
+bool color::magenta(CJS_Runtime* pRuntime,
+                    CJS_PropValue& vp,
+                    CFX_WideString& sError) {
+  return PropertyHelper(pRuntime, vp, &m_crMagenta);
+}
+
+bool color::yellow(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError) {
+  return PropertyHelper(pRuntime, vp, &m_crYellow);
+}
+
+bool color::dkGray(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError) {
+  return PropertyHelper(pRuntime, vp, &m_crDKGray);
+}
+
+bool color::gray(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError) {
+  return PropertyHelper(pRuntime, vp, &m_crGray);
+}
+
+bool color::ltGray(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError) {
+  return PropertyHelper(pRuntime, vp, &m_crLTGray);
+}
+
+bool color::PropertyHelper(CJS_Runtime* pRuntime,
+                           CJS_PropValue& vp,
+                           CPWL_Color* var) {
+  CJS_Array array;
+  if (vp.IsGetting()) {
+    ConvertPWLColorToArray(pRuntime, *var, &array);
+    vp << array;
+    return true;
   }
+  if (!vp.GetJSValue()->ConvertToArray(pRuntime, array))
+    return false;
 
-JS_IMPLEMENT_COLORPROP(transparent, m_crTransparent)
-JS_IMPLEMENT_COLORPROP(black, m_crBlack)
-JS_IMPLEMENT_COLORPROP(white, m_crWhite)
-JS_IMPLEMENT_COLORPROP(red, m_crRed)
-JS_IMPLEMENT_COLORPROP(green, m_crGreen)
-JS_IMPLEMENT_COLORPROP(blue, m_crBlue)
-JS_IMPLEMENT_COLORPROP(cyan, m_crCyan)
-JS_IMPLEMENT_COLORPROP(magenta, m_crMagenta)
-JS_IMPLEMENT_COLORPROP(yellow, m_crYellow)
-JS_IMPLEMENT_COLORPROP(dkGray, m_crDKGray)
-JS_IMPLEMENT_COLORPROP(gray, m_crGray)
-JS_IMPLEMENT_COLORPROP(ltGray, m_crLTGray)
+  ConvertArrayToPWLColor(pRuntime, array, var);
+  return true;
+}
 
-bool color::convert(IJS_Context* cc,
+bool color::convert(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError) {
@@ -170,7 +227,6 @@
   if (iSize < 2)
     return false;
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CJS_Array aSource;
   if (!params[0].ConvertToArray(pRuntime, aSource))
     return false;
@@ -192,22 +248,20 @@
   }
 
   CJS_Array aDest;
-  CPWL_Color crDest = crSource;
-  crDest.ConvertColorType(nColorType);
+  CPWL_Color crDest = crSource.ConvertColorType(nColorType);
   ConvertPWLColorToArray(pRuntime, crDest, &aDest);
   vRet = CJS_Value(pRuntime, aDest);
 
   return true;
 }
 
-bool color::equal(IJS_Context* cc,
+bool color::equal(CJS_Runtime* pRuntime,
                   const std::vector<CJS_Value>& params,
                   CJS_Value& vRet,
                   CFX_WideString& sError) {
   if (params.size() < 2)
     return false;
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CJS_Array array1;
   CJS_Array array2;
   if (!params[0].ConvertToArray(pRuntime, array1))
@@ -219,7 +273,7 @@
   CPWL_Color color2;
   ConvertArrayToPWLColor(pRuntime, array1, &color1);
   ConvertArrayToPWLColor(pRuntime, array2, &color2);
-  color1.ConvertColorType(color2.nColorType);
+  color1 = color1.ConvertColorType(color2.nColorType);
   vRet = CJS_Value(pRuntime, color1 == color2);
   return true;
 }
diff --git a/fpdfsdk/javascript/color.h b/fpdfsdk/javascript/color.h
index 9ea4d63..8d6187a 100644
--- a/fpdfsdk/javascript/color.h
+++ b/fpdfsdk/javascript/color.h
@@ -17,24 +17,28 @@
   explicit color(CJS_Object* pJSObject);
   ~color() override;
 
-  bool black(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool blue(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool cyan(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool dkGray(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool gray(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool green(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool ltGray(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool magenta(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool red(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool transparent(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool white(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool yellow(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
+  bool black(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool blue(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool cyan(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool dkGray(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool gray(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool green(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool ltGray(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool magenta(CJS_Runtime* pRuntime,
+               CJS_PropValue& vp,
+               CFX_WideString& sError);
+  bool red(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool transparent(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError);
+  bool white(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool yellow(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
 
-  bool convert(IJS_Context* cc,
+  bool convert(CJS_Runtime* pRuntime,
                const std::vector<CJS_Value>& params,
                CJS_Value& vRet,
                CFX_WideString& sError);
-  bool equal(IJS_Context* cc,
+  bool equal(CJS_Runtime* pRuntime,
              const std::vector<CJS_Value>& params,
              CJS_Value& vRet,
              CFX_WideString& sError);
@@ -47,6 +51,10 @@
                                      CPWL_Color* color);
 
  private:
+  bool PropertyHelper(CJS_Runtime* pRuntime,
+                      CJS_PropValue& vp,
+                      CPWL_Color* val);
+
   CPWL_Color m_crTransparent;
   CPWL_Color m_crBlack;
   CPWL_Color m_crWhite;
diff --git a/fpdfsdk/javascript/console.cpp b/fpdfsdk/javascript/console.cpp
index 0a8c1e0..e9d1308 100644
--- a/fpdfsdk/javascript/console.cpp
+++ b/fpdfsdk/javascript/console.cpp
@@ -12,20 +12,17 @@
 #include "fpdfsdk/javascript/JS_EventHandler.h"
 #include "fpdfsdk/javascript/JS_Object.h"
 #include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/cjs_context.h"
+#include "fpdfsdk/javascript/cjs_event_context.h"
 
-BEGIN_JS_STATIC_CONST(CJS_Console)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Console::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
 
-BEGIN_JS_STATIC_PROP(CJS_Console)
-END_JS_STATIC_PROP()
+JSPropertySpec CJS_Console::PropertySpecs[] = {{0, 0, 0}};
 
-BEGIN_JS_STATIC_METHOD(CJS_Console)
-JS_STATIC_METHOD_ENTRY(clear)
-JS_STATIC_METHOD_ENTRY(hide)
-JS_STATIC_METHOD_ENTRY(println)
-JS_STATIC_METHOD_ENTRY(show)
-END_JS_STATIC_METHOD()
+JSMethodSpec CJS_Console::MethodSpecs[] = {{"clear", clear_static},
+                                           {"hide", hide_static},
+                                           {"println", println_static},
+                                           {"show", show_static},
+                                           {0, 0}};
 
 IMPLEMENT_JS_CLASS(CJS_Console, console)
 
@@ -33,21 +30,21 @@
 
 console::~console() {}
 
-bool console::clear(IJS_Context* cc,
+bool console::clear(CJS_Runtime* pRuntime,
                     const std::vector<CJS_Value>& params,
                     CJS_Value& vRet,
                     CFX_WideString& sError) {
   return true;
 }
 
-bool console::hide(IJS_Context* cc,
+bool console::hide(CJS_Runtime* pRuntime,
                    const std::vector<CJS_Value>& params,
                    CJS_Value& vRet,
                    CFX_WideString& sError) {
   return true;
 }
 
-bool console::println(IJS_Context* cc,
+bool console::println(CJS_Runtime* pRuntime,
                       const std::vector<CJS_Value>& params,
                       CJS_Value& vRet,
                       CFX_WideString& sError) {
@@ -57,7 +54,7 @@
   return true;
 }
 
-bool console::show(IJS_Context* cc,
+bool console::show(CJS_Runtime* pRuntime,
                    const std::vector<CJS_Value>& params,
                    CJS_Value& vRet,
                    CFX_WideString& sError) {
diff --git a/fpdfsdk/javascript/console.h b/fpdfsdk/javascript/console.h
index 069a81d..a7e4d8e 100644
--- a/fpdfsdk/javascript/console.h
+++ b/fpdfsdk/javascript/console.h
@@ -17,19 +17,19 @@
   ~console() override;
 
  public:
-  bool clear(IJS_Context* cc,
+  bool clear(CJS_Runtime* pRuntime,
              const std::vector<CJS_Value>& params,
              CJS_Value& vRet,
              CFX_WideString& sError);
-  bool hide(IJS_Context* cc,
+  bool hide(CJS_Runtime* pRuntime,
             const std::vector<CJS_Value>& params,
             CJS_Value& vRet,
             CFX_WideString& sError);
-  bool println(IJS_Context* cc,
+  bool println(CJS_Runtime* pRuntime,
                const std::vector<CJS_Value>& params,
                CJS_Value& vRet,
                CFX_WideString& sError);
-  bool show(IJS_Context* cc,
+  bool show(CJS_Runtime* pRuntime,
             const std::vector<CJS_Value>& params,
             CJS_Value& vRet,
             CFX_WideString& sError);
diff --git a/fpdfsdk/javascript/event.cpp b/fpdfsdk/javascript/event.cpp
index b4fb951..2b00cbc 100644
--- a/fpdfsdk/javascript/event.cpp
+++ b/fpdfsdk/javascript/event.cpp
@@ -11,36 +11,34 @@
 #include "fpdfsdk/javascript/JS_EventHandler.h"
 #include "fpdfsdk/javascript/JS_Object.h"
 #include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/cjs_context.h"
+#include "fpdfsdk/javascript/cjs_event_context.h"
 
-BEGIN_JS_STATIC_CONST(CJS_Event)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Event::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
 
-BEGIN_JS_STATIC_PROP(CJS_Event)
-JS_STATIC_PROP_ENTRY(change)
-JS_STATIC_PROP_ENTRY(changeEx)
-JS_STATIC_PROP_ENTRY(commitKey)
-JS_STATIC_PROP_ENTRY(fieldFull)
-JS_STATIC_PROP_ENTRY(keyDown)
-JS_STATIC_PROP_ENTRY(modifier)
-JS_STATIC_PROP_ENTRY(name)
-JS_STATIC_PROP_ENTRY(rc)
-JS_STATIC_PROP_ENTRY(richChange)
-JS_STATIC_PROP_ENTRY(richChangeEx)
-JS_STATIC_PROP_ENTRY(richValue)
-JS_STATIC_PROP_ENTRY(selEnd)
-JS_STATIC_PROP_ENTRY(selStart)
-JS_STATIC_PROP_ENTRY(shift)
-JS_STATIC_PROP_ENTRY(source)
-JS_STATIC_PROP_ENTRY(target)
-JS_STATIC_PROP_ENTRY(targetName)
-JS_STATIC_PROP_ENTRY(type)
-JS_STATIC_PROP_ENTRY(value)
-JS_STATIC_PROP_ENTRY(willCommit)
-END_JS_STATIC_PROP()
+JSPropertySpec CJS_Event::PropertySpecs[] = {
+    {"change", get_change_static, set_change_static},
+    {"changeEx", get_changeEx_static, set_changeEx_static},
+    {"commitKey", get_commitKey_static, set_commitKey_static},
+    {"fieldFull", get_fieldFull_static, set_fieldFull_static},
+    {"keyDown", get_keyDown_static, set_keyDown_static},
+    {"modifier", get_modifier_static, set_modifier_static},
+    {"name", get_name_static, set_name_static},
+    {"rc", get_rc_static, set_rc_static},
+    {"richChange", get_richChange_static, set_richChange_static},
+    {"richChangeEx", get_richChangeEx_static, set_richChangeEx_static},
+    {"richValue", get_richValue_static, set_richValue_static},
+    {"selEnd", get_selEnd_static, set_selEnd_static},
+    {"selStart", get_selStart_static, set_selStart_static},
+    {"shift", get_shift_static, set_shift_static},
+    {"source", get_source_static, set_source_static},
+    {"target", get_target_static, set_target_static},
+    {"targetName", get_targetName_static, set_targetName_static},
+    {"type", get_type_static, set_type_static},
+    {"value", get_value_static, set_value_static},
+    {"willCommit", get_willCommit_static, set_willCommit_static},
+    {0, 0, 0}};
 
-BEGIN_JS_STATIC_METHOD(CJS_Event)
-END_JS_STATIC_METHOD()
+JSMethodSpec CJS_Event::MethodSpecs[] = {{0, 0}};
 
 IMPLEMENT_JS_CLASS(CJS_Event, event)
 
@@ -48,260 +46,264 @@
 
 event::~event() {}
 
-bool event::change(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+bool event::change(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError) {
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
   CFX_WideString& wChange = pEvent->Change();
   if (vp.IsSetting()) {
     if (vp.GetJSValue()->GetType() == CJS_Value::VT_string)
       vp >> wChange;
-  } else {
-    vp << wChange;
+    return true;
   }
+  vp << wChange;
   return true;
 }
 
-bool event::changeEx(IJS_Context* cc,
+bool event::changeEx(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
 
   vp << pEvent->ChangeEx();
   return true;
 }
 
-bool event::commitKey(IJS_Context* cc,
+bool event::commitKey(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
 
   vp << pEvent->CommitKey();
   return true;
 }
 
-bool event::fieldFull(IJS_Context* cc,
+bool event::fieldFull(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
 
   if (!vp.IsGetting() &&
       wcscmp((const wchar_t*)pEvent->Name(), L"Keystroke") != 0)
     return false;
 
-  if (pEvent->FieldFull())
-    vp << true;
-  else
-    vp << false;
+  vp << pEvent->FieldFull();
   return true;
 }
 
-bool event::keyDown(IJS_Context* cc,
+bool event::keyDown(CJS_Runtime* pRuntime,
                     CJS_PropValue& vp,
                     CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
 
-  if (pEvent->KeyDown())
-    vp << true;
-  else
-    vp << false;
+  vp << pEvent->KeyDown();
   return true;
 }
 
-bool event::modifier(IJS_Context* cc,
+bool event::modifier(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
 
-  if (pEvent->Modifier())
-    vp << true;
-  else
-    vp << false;
+  vp << pEvent->Modifier();
   return true;
 }
 
-bool event::name(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool event::name(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
 
   vp << pEvent->Name();
   return true;
 }
 
-bool event::rc(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+bool event::rc(CJS_Runtime* pRuntime,
+               CJS_PropValue& vp,
+               CFX_WideString& sError) {
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
 
   bool& bRc = pEvent->Rc();
-  if (vp.IsSetting()) {
+  if (vp.IsSetting())
     vp >> bRc;
-  } else {
+  else
     vp << bRc;
-  }
+
   return true;
 }
 
-bool event::richChange(IJS_Context* cc,
+bool event::richChange(CJS_Runtime* pRuntime,
                        CJS_PropValue& vp,
                        CFX_WideString& sError) {
   return true;
 }
 
-bool event::richChangeEx(IJS_Context* cc,
+bool event::richChangeEx(CJS_Runtime* pRuntime,
                          CJS_PropValue& vp,
                          CFX_WideString& sError) {
   return true;
 }
 
-bool event::richValue(IJS_Context* cc,
+bool event::richValue(CJS_Runtime* pRuntime,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
   return true;
 }
 
-bool event::selEnd(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+bool event::selEnd(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError) {
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
 
-  if (wcscmp((const wchar_t*)pEvent->Name(), L"Keystroke") != 0) {
+  if (wcscmp((const wchar_t*)pEvent->Name(), L"Keystroke") != 0)
     return true;
-  }
 
   int& iSelEnd = pEvent->SelEnd();
-  if (vp.IsSetting()) {
+  if (vp.IsSetting())
     vp >> iSelEnd;
-  } else {
+  else
     vp << iSelEnd;
-  }
+
   return true;
 }
 
-bool event::selStart(IJS_Context* cc,
+bool event::selStart(CJS_Runtime* pRuntime,
                      CJS_PropValue& vp,
                      CFX_WideString& sError) {
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
 
-  if (wcscmp((const wchar_t*)pEvent->Name(), L"Keystroke") != 0) {
+  if (wcscmp((const wchar_t*)pEvent->Name(), L"Keystroke") != 0)
     return true;
-  }
+
   int& iSelStart = pEvent->SelStart();
-  if (vp.IsSetting()) {
+  if (vp.IsSetting())
     vp >> iSelStart;
-  } else {
-    vp << iSelStart;
-  }
-  return true;
-}
-
-bool event::shift(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
-
-  if (pEvent->Shift())
-    vp << true;
   else
-    vp << false;
+    vp << iSelStart;
+
   return true;
 }
 
-bool event::source(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool event::shift(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
+
+  vp << pEvent->Shift();
+  return true;
+}
+
+bool event::source(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError) {
+  if (!vp.IsGetting())
+    return false;
+
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
 
   vp << pEvent->Source()->GetJSObject();
   return true;
 }
 
-bool event::target(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool event::target(CJS_Runtime* pRuntime,
+                   CJS_PropValue& vp,
+                   CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
 
   vp << pEvent->Target_Field()->GetJSObject();
   return true;
 }
 
-bool event::targetName(IJS_Context* cc,
+bool event::targetName(CJS_Runtime* pRuntime,
                        CJS_PropValue& vp,
                        CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
 
   vp << pEvent->TargetName();
   return true;
 }
 
-bool event::type(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
+bool event::type(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
 
   vp << pEvent->Type();
   return true;
 }
 
-bool event::value(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+bool event::value(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError) {
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
 
   if (wcscmp((const wchar_t*)pEvent->Type(), L"Field") != 0)
     return false;
+
   if (!pEvent->m_pValue)
     return false;
+
   CFX_WideString& val = pEvent->Value();
-  if (vp.IsSetting()) {
+  if (vp.IsSetting())
     vp >> val;
-  } else {
+  else
     vp << val;
-  }
+
   return true;
 }
 
-bool event::willCommit(IJS_Context* cc,
+bool event::willCommit(CJS_Runtime* pRuntime,
                        CJS_PropValue& vp,
                        CFX_WideString& sError) {
   if (!vp.IsGetting())
     return false;
 
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
+  CJS_EventHandler* pEvent =
+      pRuntime->GetCurrentEventContext()->GetEventHandler();
 
-  if (pEvent->WillCommit())
-    vp << true;
-  else
-    vp << false;
+  vp << pEvent->WillCommit();
   return true;
 }
diff --git a/fpdfsdk/javascript/event.h b/fpdfsdk/javascript/event.h
index 6719494..2be8a0a 100644
--- a/fpdfsdk/javascript/event.h
+++ b/fpdfsdk/javascript/event.h
@@ -15,26 +15,48 @@
   ~event() override;
 
  public:
-  bool change(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool changeEx(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool commitKey(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool fieldFull(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool keyDown(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool modifier(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool name(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool rc(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool richChange(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool richChangeEx(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool richValue(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool selEnd(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool selStart(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool shift(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool source(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool target(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool targetName(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool type(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool value(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
-  bool willCommit(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError);
+  bool change(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool changeEx(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool commitKey(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError);
+  bool fieldFull(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError);
+  bool keyDown(CJS_Runtime* pRuntime,
+               CJS_PropValue& vp,
+               CFX_WideString& sError);
+  bool modifier(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool name(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool rc(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool richChange(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError);
+  bool richChangeEx(CJS_Runtime* pRuntime,
+                    CJS_PropValue& vp,
+                    CFX_WideString& sError);
+  bool richValue(CJS_Runtime* pRuntime,
+                 CJS_PropValue& vp,
+                 CFX_WideString& sError);
+  bool selEnd(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool selStart(CJS_Runtime* pRuntime,
+                CJS_PropValue& vp,
+                CFX_WideString& sError);
+  bool shift(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool source(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool target(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool targetName(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError);
+  bool type(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool value(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
+  bool willCommit(CJS_Runtime* pRuntime,
+                  CJS_PropValue& vp,
+                  CFX_WideString& sError);
 };
 
 class CJS_Event : public CJS_Object {
diff --git a/fpdfsdk/javascript/global.cpp b/fpdfsdk/javascript/global.cpp
index aca8697..a450606 100644
--- a/fpdfsdk/javascript/global.cpp
+++ b/fpdfsdk/javascript/global.cpp
@@ -14,18 +14,16 @@
 #include "fpdfsdk/javascript/JS_GlobalData.h"
 #include "fpdfsdk/javascript/JS_Object.h"
 #include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/cjs_context.h"
+#include "fpdfsdk/javascript/cjs_event_context.h"
 #include "fpdfsdk/javascript/resource.h"
 
-BEGIN_JS_STATIC_CONST(CJS_Global)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Global::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
 
-BEGIN_JS_STATIC_PROP(CJS_Global)
-END_JS_STATIC_PROP()
+JSPropertySpec CJS_Global::PropertySpecs[] = {{0, 0, 0}};
 
-BEGIN_JS_STATIC_METHOD(CJS_Global)
-JS_STATIC_METHOD_ENTRY(setPersistent)
-END_JS_STATIC_METHOD()
+JSMethodSpec CJS_Global::MethodSpecs[] = {
+    {"setPersistent", setPersistent_static},
+    {0, 0}};
 
 IMPLEMENT_SPECIAL_JS_CLASS(CJS_Global, JSGlobalAlternate, global);
 
@@ -57,7 +55,7 @@
 }
 
 void JSGlobalAlternate::Initial(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  m_pFormFillEnv = pFormFillEnv;
+  m_pFormFillEnv.Reset(pFormFillEnv);
   m_pGlobalData = CJS_GlobalData::GetRetainedInstance(pFormFillEnv);
   UpdateGlobalPersistentVariables();
 }
@@ -66,7 +64,7 @@
   return CFX_WideString(propname) != L"setPersistent";
 }
 
-bool JSGlobalAlternate::DelProperty(IJS_Context* cc,
+bool JSGlobalAlternate::DelProperty(CJS_Runtime* pRuntime,
                                     const FX_WCHAR* propname,
                                     CFX_WideString& sError) {
   auto it = m_mapGlobal.find(CFX_ByteString::FromUnicode(propname));
@@ -77,11 +75,10 @@
   return true;
 }
 
-bool JSGlobalAlternate::DoProperty(IJS_Context* cc,
+bool JSGlobalAlternate::DoProperty(CJS_Runtime* pRuntime,
                                    const FX_WCHAR* propname,
                                    CJS_PropValue& vp,
                                    CFX_WideString& sError) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   if (vp.IsSetting()) {
     CFX_ByteString sPropName = CFX_ByteString::FromUnicode(propname);
     switch (vp.GetJSValue()->GetType()) {
@@ -114,7 +111,7 @@
                                   false, "", v8::Local<v8::Object>(), false);
       }
       case CJS_Value::VT_undefined: {
-        DelProperty(cc, propname, sError);
+        DelProperty(pRuntime, propname, sError);
         return true;
       }
       default:
@@ -157,7 +154,7 @@
   return false;
 }
 
-bool JSGlobalAlternate::setPersistent(IJS_Context* cc,
+bool JSGlobalAlternate::setPersistent(CJS_Runtime* pRuntime,
                                       const std::vector<CJS_Value>& params,
                                       CJS_Value& vRet,
                                       CFX_WideString& sError) {
@@ -166,7 +163,6 @@
     return false;
   }
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   auto it = m_mapGlobal.find(params[0].ToCFXByteString(pRuntime));
   if (it != m_mapGlobal.end()) {
     JSGlobalData* pData = it->second;
@@ -210,7 +206,7 @@
                            pData->bPersistent == 1);
         pRuntime->PutObjectProperty(
             m_pJSObject->ToV8Object(), pData->data.sKey.UTF8Decode(),
-            pRuntime->NewString(pData->data.sData.UTF8Decode()));
+            pRuntime->NewString(pData->data.sData.UTF8Decode().AsStringC()));
         break;
       case JS_GlobalDataType::OBJECT: {
         v8::Local<v8::Object> pObj = pRuntime->NewFxDynamicObj(-1);
@@ -232,7 +228,8 @@
   }
 }
 
-void JSGlobalAlternate::CommitGlobalPersisitentVariables(IJS_Context* cc) {
+void JSGlobalAlternate::CommitGlobalPersisitentVariables(
+    CJS_Runtime* pRuntime) {
   for (auto it = m_mapGlobal.begin(); it != m_mapGlobal.end(); ++it) {
     CFX_ByteString name = it->first;
     JSGlobalData* pData = it->second;
@@ -256,7 +253,7 @@
           CJS_GlobalVariableArray array;
           v8::Local<v8::Object> obj = v8::Local<v8::Object>::New(
               GetJSObject()->GetIsolate(), pData->pData);
-          ObjectToArray(cc, obj, array);
+          ObjectToArray(pRuntime, obj, array);
           m_pGlobalData->SetGlobalVariableObject(name, array);
           m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
         } break;
@@ -269,10 +266,9 @@
   }
 }
 
-void JSGlobalAlternate::ObjectToArray(IJS_Context* cc,
+void JSGlobalAlternate::ObjectToArray(CJS_Runtime* pRuntime,
                                       v8::Local<v8::Object> pObj,
                                       CJS_GlobalVariableArray& array) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   std::vector<CFX_WideString> pKeyList = pRuntime->GetObjectPropertyNames(pObj);
   for (const auto& ws : pKeyList) {
     CFX_ByteString sKey = ws.UTF8Encode();
@@ -305,7 +301,7 @@
         CJS_KeyValue* pObjElement = new CJS_KeyValue;
         pObjElement->nType = JS_GlobalDataType::OBJECT;
         pObjElement->sKey = sKey;
-        ObjectToArray(cc, pRuntime->ToObject(v), pObjElement->objData);
+        ObjectToArray(pRuntime, pRuntime->ToObject(v), pObjElement->objData);
         array.Add(pObjElement);
       } break;
       case CJS_Value::VT_null: {
@@ -339,7 +335,7 @@
       case JS_GlobalDataType::STRING:
         pRuntime->PutObjectProperty(
             pObj, pObjData->sKey.UTF8Decode(),
-            pRuntime->NewString(pObjData->sData.UTF8Decode()));
+            pRuntime->NewString(pObjData->sData.UTF8Decode().AsStringC()));
         break;
       case JS_GlobalDataType::OBJECT: {
         v8::Local<v8::Object> pNewObj = pRuntime->NewFxDynamicObj(-1);
diff --git a/fpdfsdk/javascript/global.h b/fpdfsdk/javascript/global.h
index 9a6568b..e313929 100644
--- a/fpdfsdk/javascript/global.h
+++ b/fpdfsdk/javascript/global.h
@@ -35,23 +35,23 @@
   explicit JSGlobalAlternate(CJS_Object* pJSObject);
   ~JSGlobalAlternate() override;
 
-  bool setPersistent(IJS_Context* cc,
+  bool setPersistent(CJS_Runtime* pRuntime,
                      const std::vector<CJS_Value>& params,
                      CJS_Value& vRet,
                      CFX_WideString& sError);
   bool QueryProperty(const FX_WCHAR* propname);
-  bool DoProperty(IJS_Context* cc,
+  bool DoProperty(CJS_Runtime* pRuntime,
                   const FX_WCHAR* propname,
                   CJS_PropValue& vp,
                   CFX_WideString& sError);
-  bool DelProperty(IJS_Context* cc,
+  bool DelProperty(CJS_Runtime* pRuntime,
                    const FX_WCHAR* propname,
                    CFX_WideString& sError);
   void Initial(CPDFSDK_FormFillEnvironment* pFormFillEnv);
 
  private:
   void UpdateGlobalPersistentVariables();
-  void CommitGlobalPersisitentVariables(IJS_Context* cc);
+  void CommitGlobalPersisitentVariables(CJS_Runtime* pRuntime);
   void DestroyGlobalPersisitentVariables();
   bool SetGlobalVariables(const CFX_ByteString& propname,
                           JS_GlobalDataType nType,
@@ -60,7 +60,7 @@
                           const CFX_ByteString& sData,
                           v8::Local<v8::Object> pData,
                           bool bDefaultPersistent);
-  void ObjectToArray(IJS_Context* cc,
+  void ObjectToArray(CJS_Runtime* pRuntime,
                      v8::Local<v8::Object> pObj,
                      CJS_GlobalVariableArray& array);
   void PutObjectProperty(v8::Local<v8::Object> obj, CJS_KeyValue* pData);
@@ -68,7 +68,7 @@
   std::map<CFX_ByteString, JSGlobalData*> m_mapGlobal;
   CFX_WideString m_sFilePath;
   CJS_GlobalData* m_pGlobalData;
-  CPDFSDK_FormFillEnvironment* m_pFormFillEnv;
+  CPDFSDK_FormFillEnvironment::ObservedPtr m_pFormFillEnv;
 };
 
 class CJS_Global : public CJS_Object {
diff --git a/fpdfsdk/javascript/ijs_context.h b/fpdfsdk/javascript/ijs_event_context.h
similarity index 94%
rename from fpdfsdk/javascript/ijs_context.h
rename to fpdfsdk/javascript/ijs_event_context.h
index 2d2248f..8428072 100644
--- a/fpdfsdk/javascript/ijs_context.h
+++ b/fpdfsdk/javascript/ijs_event_context.h
@@ -4,8 +4,8 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
-#ifndef FPDFSDK_JAVASCRIPT_IJS_CONTEXT_H_
-#define FPDFSDK_JAVASCRIPT_IJS_CONTEXT_H_
+#ifndef FPDFSDK_JAVASCRIPT_IJS_EVENT_CONTEXT_H_
+#define FPDFSDK_JAVASCRIPT_IJS_EVENT_CONTEXT_H_
 
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
@@ -15,8 +15,10 @@
 class CPDFSDK_Annot;
 class CPDFSDK_FormFillEnvironment;
 
-// Records the details of an event and triggers JS execution for it.
-class IJS_Context {
+// Records the details of an event and triggers JS execution for it. There
+// can be more than one of these at any given time, as JS callbacks to C++
+// may trigger new events on top of one another.
+class IJS_EventContext {
  public:
   virtual bool RunScript(const CFX_WideString& script,
                          CFX_WideString* info) = 0;
@@ -126,7 +128,7 @@
   virtual void OnExternal_Exec() = 0;
 
  protected:
-  virtual ~IJS_Context() {}
+  virtual ~IJS_EventContext() {}
 };
 
-#endif  // FPDFSDK_JAVASCRIPT_IJS_CONTEXT_H_
+#endif  // FPDFSDK_JAVASCRIPT_IJS_EVENT_CONTEXT_H_
diff --git a/fpdfsdk/javascript/ijs_runtime.h b/fpdfsdk/javascript/ijs_runtime.h
index 027c500..babc418 100644
--- a/fpdfsdk/javascript/ijs_runtime.h
+++ b/fpdfsdk/javascript/ijs_runtime.h
@@ -15,7 +15,7 @@
 #endif  // PDF_ENABLE_XFA
 
 class CPDFSDK_FormFillEnvironment;
-class IJS_Context;
+class IJS_EventContext;
 
 // Owns the FJXS objects needed to actually execute JS.
 class IJS_Runtime {
@@ -25,12 +25,9 @@
   static IJS_Runtime* Create(CPDFSDK_FormFillEnvironment* pFormFillEnv);
   virtual ~IJS_Runtime() {}
 
-  virtual IJS_Context* NewContext() = 0;
-  virtual void ReleaseContext(IJS_Context* pContext) = 0;
-  virtual IJS_Context* GetCurrentContext() = 0;
-
+  virtual IJS_EventContext* NewEventContext() = 0;
+  virtual void ReleaseEventContext(IJS_EventContext* pContext) = 0;
   virtual CPDFSDK_FormFillEnvironment* GetFormFillEnv() const = 0;
-
   virtual int ExecuteScript(const CFX_WideString& script,
                             CFX_WideString* info) = 0;
 
diff --git a/fpdfsdk/javascript/report.cpp b/fpdfsdk/javascript/report.cpp
index ba6e97d..c9c986d 100644
--- a/fpdfsdk/javascript/report.cpp
+++ b/fpdfsdk/javascript/report.cpp
@@ -12,16 +12,13 @@
 #include "fpdfsdk/javascript/JS_Object.h"
 #include "fpdfsdk/javascript/JS_Value.h"
 
-BEGIN_JS_STATIC_CONST(CJS_Report)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Report::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
 
-BEGIN_JS_STATIC_PROP(CJS_Report)
-END_JS_STATIC_PROP()
+JSPropertySpec CJS_Report::PropertySpecs[] = {{0, 0, 0}};
 
-BEGIN_JS_STATIC_METHOD(CJS_Report)
-JS_STATIC_METHOD_ENTRY(save)
-JS_STATIC_METHOD_ENTRY(writeText)
-END_JS_STATIC_METHOD()
+JSMethodSpec CJS_Report::MethodSpecs[] = {{"save", save_static},
+                                          {"writeText", writeText_static},
+                                          {0, 0}};
 
 IMPLEMENT_JS_CLASS(CJS_Report, Report)
 
@@ -29,7 +26,7 @@
 
 Report::~Report() {}
 
-bool Report::writeText(IJS_Context* cc,
+bool Report::writeText(CJS_Runtime* pRuntime,
                        const std::vector<CJS_Value>& params,
                        CJS_Value& vRet,
                        CFX_WideString& sError) {
@@ -37,7 +34,7 @@
   return true;
 }
 
-bool Report::save(IJS_Context* cc,
+bool Report::save(CJS_Runtime* pRuntime,
                   const std::vector<CJS_Value>& params,
                   CJS_Value& vRet,
                   CFX_WideString& sError) {
diff --git a/fpdfsdk/javascript/report.h b/fpdfsdk/javascript/report.h
index fef2369..c66db80 100644
--- a/fpdfsdk/javascript/report.h
+++ b/fpdfsdk/javascript/report.h
@@ -17,11 +17,11 @@
   ~Report() override;
 
  public:
-  bool save(IJS_Context* cc,
+  bool save(CJS_Runtime* pRuntime,
             const std::vector<CJS_Value>& params,
             CJS_Value& vRet,
             CFX_WideString& sError);
-  bool writeText(IJS_Context* cc,
+  bool writeText(CJS_Runtime* pRuntime,
                  const std::vector<CJS_Value>& params,
                  CJS_Value& vRet,
                  CFX_WideString& sError);
diff --git a/fpdfsdk/javascript/resource.h b/fpdfsdk/javascript/resource.h
index 663cf3b..af7788f 100644
--- a/fpdfsdk/javascript/resource.h
+++ b/fpdfsdk/javascript/resource.h
@@ -9,7 +9,7 @@
 
 #include "core/fxcrt/fx_string.h"
 
-class CJS_Context;
+class CJS_EventContext;
 
 #define IDS_STRING_JSALERT 25613
 #define IDS_STRING_JSPARAMERROR 25614
diff --git a/fpdfsdk/javascript/util.cpp b/fpdfsdk/javascript/util.cpp
index 3967ceb..3221cfb 100644
--- a/fpdfsdk/javascript/util.cpp
+++ b/fpdfsdk/javascript/util.cpp
@@ -18,7 +18,7 @@
 #include "fpdfsdk/javascript/JS_Object.h"
 #include "fpdfsdk/javascript/JS_Value.h"
 #include "fpdfsdk/javascript/PublicMethods.h"
-#include "fpdfsdk/javascript/cjs_context.h"
+#include "fpdfsdk/javascript/cjs_event_context.h"
 #include "fpdfsdk/javascript/cjs_runtime.h"
 #include "fpdfsdk/javascript/resource.h"
 
@@ -26,19 +26,14 @@
 #include <ctype.h>
 #endif
 
-BEGIN_JS_STATIC_CONST(CJS_Util)
-END_JS_STATIC_CONST()
+JSConstSpec CJS_Util::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
 
-BEGIN_JS_STATIC_PROP(CJS_Util)
-END_JS_STATIC_PROP()
+JSPropertySpec CJS_Util::PropertySpecs[] = {{0, 0, 0}};
 
-BEGIN_JS_STATIC_METHOD(CJS_Util)
-JS_STATIC_METHOD_ENTRY(printd)
-JS_STATIC_METHOD_ENTRY(printf)
-JS_STATIC_METHOD_ENTRY(printx)
-JS_STATIC_METHOD_ENTRY(scand)
-JS_STATIC_METHOD_ENTRY(byteToChar)
-END_JS_STATIC_METHOD()
+JSMethodSpec CJS_Util::MethodSpecs[] = {
+    {"printd", printd_static},         {"printf", printf_static},
+    {"printx", printx_static},         {"scand", scand_static},
+    {"byteToChar", byteToChar_static}, {0, 0}};
 
 IMPLEMENT_JS_CLASS(CJS_Util, util)
 
@@ -114,11 +109,10 @@
 
 util::~util() {}
 
-bool util::printf(IJS_Context* cc,
+bool util::printf(CJS_Runtime* pRuntime,
                   const std::vector<CJS_Value>& params,
                   CJS_Value& vRet,
                   CFX_WideString& sError) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   int iSize = params.size();
   if (iSize < 1)
     return false;
@@ -177,7 +171,7 @@
   return true;
 }
 
-bool util::printd(IJS_Context* cc,
+bool util::printd(CJS_Runtime* pRuntime,
                   const std::vector<CJS_Value>& params,
                   CJS_Value& vRet,
                   CFX_WideString& sError) {
@@ -185,7 +179,6 @@
   if (iSize < 2)
     return false;
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CJS_Value p1 = params[0];
   CJS_Value p2 = params[1];
   CJS_Date jsDate;
@@ -307,7 +300,7 @@
   return false;
 }
 
-bool util::printx(IJS_Context* cc,
+bool util::printx(CJS_Runtime* pRuntime,
                   const std::vector<CJS_Value>& params,
                   CJS_Value& vRet,
                   CFX_WideString& sError) {
@@ -316,7 +309,6 @@
     return false;
   }
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   vRet = CJS_Value(pRuntime, printx(params[0].ToCFXWideString(pRuntime),
                                     params[1].ToCFXWideString(pRuntime))
                                  .c_str());
@@ -425,11 +417,10 @@
   return wsResult;
 }
 
-bool util::scand(IJS_Context* cc,
+bool util::scand(CJS_Runtime* pRuntime,
                  const std::vector<CJS_Value>& params,
                  CJS_Value& vRet,
                  CFX_WideString& sError) {
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   int iSize = params.size();
   if (iSize < 2)
     return false;
@@ -450,7 +441,7 @@
   return true;
 }
 
-bool util::byteToChar(IJS_Context* cc,
+bool util::byteToChar(CJS_Runtime* pRuntime,
                       const std::vector<CJS_Value>& params,
                       CJS_Value& vRet,
                       CFX_WideString& sError) {
@@ -459,7 +450,6 @@
     return false;
   }
 
-  CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   int arg = params[0].ToInt(pRuntime);
   if (arg < 0 || arg > 255) {
     sError = JSGetStringFromID(IDS_STRING_JSVALUEERROR);
diff --git a/fpdfsdk/javascript/util.h b/fpdfsdk/javascript/util.h
index 80763d1..98761b6 100644
--- a/fpdfsdk/javascript/util.h
+++ b/fpdfsdk/javascript/util.h
@@ -17,23 +17,23 @@
   explicit util(CJS_Object* pJSObject);
   ~util() override;
 
-  bool printd(IJS_Context* cc,
+  bool printd(CJS_Runtime* pRuntime,
               const std::vector<CJS_Value>& params,
               CJS_Value& vRet,
               CFX_WideString& sError);
-  bool printf(IJS_Context* cc,
+  bool printf(CJS_Runtime* pRuntime,
               const std::vector<CJS_Value>& params,
               CJS_Value& vRet,
               CFX_WideString& sError);
-  bool printx(IJS_Context* cc,
+  bool printx(CJS_Runtime* pRuntime,
               const std::vector<CJS_Value>& params,
               CJS_Value& vRet,
               CFX_WideString& sError);
-  bool scand(IJS_Context* cc,
+  bool scand(CJS_Runtime* pRuntime,
              const std::vector<CJS_Value>& params,
              CJS_Value& vRet,
              CFX_WideString& sError);
-  bool byteToChar(IJS_Context* cc,
+  bool byteToChar(CJS_Runtime* pRuntime,
                   const std::vector<CJS_Value>& params,
                   CJS_Value& vRet,
                   CFX_WideString& sError);
diff --git a/fpdfsdk/pdfwindow/PWL_Button.cpp b/fpdfsdk/pdfwindow/PWL_Button.cpp
index 972e55e..96be469 100644
--- a/fpdfsdk/pdfwindow/PWL_Button.cpp
+++ b/fpdfsdk/pdfwindow/PWL_Button.cpp
@@ -20,7 +20,7 @@
   cp.eCursorType = FXCT_HAND;
 }
 
-bool CPWL_Button::OnLButtonDown(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_Button::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonDown(point, nFlag);
 
   m_bMouseDown = true;
@@ -29,7 +29,7 @@
   return true;
 }
 
-bool CPWL_Button::OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_Button::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonUp(point, nFlag);
 
   ReleaseCapture();
diff --git a/fpdfsdk/pdfwindow/PWL_Button.h b/fpdfsdk/pdfwindow/PWL_Button.h
index f35e9ad..2d1193f 100644
--- a/fpdfsdk/pdfwindow/PWL_Button.h
+++ b/fpdfsdk/pdfwindow/PWL_Button.h
@@ -17,8 +17,8 @@
   // CPWL_Wnd
   CFX_ByteString GetClassName() const override;
   void OnCreate(PWL_CREATEPARAM& cp) override;
-  bool OnLButtonDown(const CFX_FloatPoint& point, uint32_t nFlag) override;
-  bool OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) override;
+  bool OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) override;
+  bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) override;
 
  protected:
   bool m_bMouseDown;
diff --git a/fpdfsdk/pdfwindow/PWL_Caret.cpp b/fpdfsdk/pdfwindow/PWL_Caret.cpp
index 8a5f539..3360bbf 100644
--- a/fpdfsdk/pdfwindow/PWL_Caret.cpp
+++ b/fpdfsdk/pdfwindow/PWL_Caret.cpp
@@ -14,6 +14,8 @@
 
 #define PWL_CARET_FLASHINTERVAL 500
 
+PWL_CARET_INFO::PWL_CARET_INFO() : bVisible(false) {}
+
 CPWL_Caret::CPWL_Caret() : m_bFlash(false), m_fWidth(0.4f), m_nDelay(0) {}
 
 CPWL_Caret::~CPWL_Caret() {}
@@ -23,7 +25,7 @@
 }
 
 void CPWL_Caret::GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) {
-  GetCaretApp(sAppStream, CFX_FloatPoint(0.0f, 0.0f));
+  GetCaretApp(sAppStream, CFX_PointF());
 }
 
 void CPWL_Caret::DrawThisAppearance(CFX_RenderDevice* pDevice,
@@ -32,26 +34,23 @@
     CFX_FloatRect rcRect = GetCaretRect();
     CFX_FloatRect rcClip = GetClipRect();
     CFX_PathData path;
-    path.SetPointCount(2);
 
     FX_FLOAT fCaretX = rcRect.left + m_fWidth * 0.5f;
     FX_FLOAT fCaretTop = rcRect.top;
     FX_FLOAT fCaretBottom = rcRect.bottom;
     if (!rcClip.IsEmpty()) {
       rcRect.Intersect(rcClip);
-      if (!rcRect.IsEmpty()) {
-        fCaretTop = rcRect.top;
-        fCaretBottom = rcRect.bottom;
-        path.SetPoint(0, fCaretX, fCaretBottom, FXPT_MOVETO);
-        path.SetPoint(1, fCaretX, fCaretTop, FXPT_LINETO);
-      } else {
+      if (rcRect.IsEmpty())
         return;
-      }
-    } else {
-      path.SetPoint(0, fCaretX, fCaretBottom, FXPT_MOVETO);
-      path.SetPoint(1, fCaretX, fCaretTop, FXPT_LINETO);
+
+      fCaretTop = rcRect.top;
+      fCaretBottom = rcRect.bottom;
     }
 
+    path.AppendPoint(CFX_PointF(fCaretX, fCaretBottom), FXPT_TYPE::MoveTo,
+                     false);
+    path.AppendPoint(CFX_PointF(fCaretX, fCaretTop), FXPT_TYPE::LineTo, false);
+
     CFX_GraphStateData gsd;
     gsd.m_LineWidth = m_fWidth;
     pDevice->DrawPath(&path, pUser2Device, &gsd, 0, ArgbEncode(255, 0, 0, 0),
@@ -60,7 +59,7 @@
 }
 
 void CPWL_Caret::GetCaretApp(CFX_ByteTextBuf& sAppStream,
-                             const CFX_FloatPoint& ptOffset) {
+                             const CFX_PointF& ptOffset) {
   if (IsVisible() && m_bFlash) {
     CFX_ByteTextBuf sCaret;
 
@@ -85,7 +84,7 @@
 }
 
 CFX_ByteString CPWL_Caret::GetCaretAppearanceStream(
-    const CFX_FloatPoint& ptOffset) {
+    const CFX_PointF& ptOffset) {
   CFX_ByteTextBuf sCaret;
   GetCaretApp(sCaret, ptOffset);
   return sCaret.MakeString();
@@ -106,8 +105,8 @@
 }
 
 void CPWL_Caret::SetCaret(bool bVisible,
-                          const CFX_FloatPoint& ptHead,
-                          const CFX_FloatPoint& ptFoot) {
+                          const CFX_PointF& ptHead,
+                          const CFX_PointF& ptFoot) {
   if (bVisible) {
     if (IsVisible()) {
       if (m_ptHead != ptHead || m_ptFoot != ptFoot) {
@@ -126,8 +125,8 @@
       Move(m_rcInvalid, false, true);
     }
   } else {
-    m_ptHead = CFX_FloatPoint();
-    m_ptFoot = CFX_FloatPoint();
+    m_ptHead = CFX_PointF();
+    m_ptFoot = CFX_PointF();
     m_bFlash = false;
     if (IsVisible()) {
       EndTimer();
diff --git a/fpdfsdk/pdfwindow/PWL_Caret.h b/fpdfsdk/pdfwindow/PWL_Caret.h
index ccee961..60ebbdc 100644
--- a/fpdfsdk/pdfwindow/PWL_Caret.h
+++ b/fpdfsdk/pdfwindow/PWL_Caret.h
@@ -11,11 +11,11 @@
 
 struct PWL_CARET_INFO {
  public:
-  PWL_CARET_INFO() : bVisible(false) {}
+  PWL_CARET_INFO();
 
   bool bVisible;
-  CFX_FloatPoint ptHead;
-  CFX_FloatPoint ptFoot;
+  CFX_PointF ptHead;
+  CFX_PointF ptFoot;
 };
 
 class CPWL_Caret : public CPWL_Wnd {
@@ -33,18 +33,18 @@
   void TimerProc() override;
 
   void SetCaret(bool bVisible,
-                const CFX_FloatPoint& ptHead,
-                const CFX_FloatPoint& ptFoot);
-  CFX_ByteString GetCaretAppearanceStream(const CFX_FloatPoint& ptOffset);
+                const CFX_PointF& ptHead,
+                const CFX_PointF& ptFoot);
+  CFX_ByteString GetCaretAppearanceStream(const CFX_PointF& ptOffset);
   void SetInvalidRect(CFX_FloatRect rc) { m_rcInvalid = rc; }
 
  private:
-  void GetCaretApp(CFX_ByteTextBuf& sAppStream, const CFX_FloatPoint& ptOffset);
+  void GetCaretApp(CFX_ByteTextBuf& sAppStream, const CFX_PointF& ptOffset);
   CFX_FloatRect GetCaretRect() const;
 
   bool m_bFlash;
-  CFX_FloatPoint m_ptHead;
-  CFX_FloatPoint m_ptFoot;
+  CFX_PointF m_ptHead;
+  CFX_PointF m_ptFoot;
   FX_FLOAT m_fWidth;
   int32_t m_nDelay;
   CFX_FloatRect m_rcInvalid;
diff --git a/fpdfsdk/pdfwindow/PWL_ComboBox.cpp b/fpdfsdk/pdfwindow/PWL_ComboBox.cpp
index 8e9a04b..bc6909a 100644
--- a/fpdfsdk/pdfwindow/PWL_ComboBox.cpp
+++ b/fpdfsdk/pdfwindow/PWL_ComboBox.cpp
@@ -18,7 +18,7 @@
 
 #define PWLCB_DEFAULTFONTSIZE 12.0f
 
-bool CPWL_CBListBox::OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_CBListBox::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonUp(point, nFlag);
 
   if (!m_bMouseDown)
@@ -102,14 +102,14 @@
   if (IsVisible() && !rectWnd.IsEmpty()) {
     CFX_ByteTextBuf sButton;
 
-    CFX_FloatPoint ptCenter = GetCenterPoint();
+    CFX_PointF ptCenter = GetCenterPoint();
 
-    CFX_FloatPoint pt1(ptCenter.x - PWL_CBBUTTON_TRIANGLE_HALFLEN,
-                       ptCenter.y + PWL_CBBUTTON_TRIANGLE_HALFLEN * 0.5f);
-    CFX_FloatPoint pt2(ptCenter.x + PWL_CBBUTTON_TRIANGLE_HALFLEN,
-                       ptCenter.y + PWL_CBBUTTON_TRIANGLE_HALFLEN * 0.5f);
-    CFX_FloatPoint pt3(ptCenter.x,
-                       ptCenter.y - PWL_CBBUTTON_TRIANGLE_HALFLEN * 0.5f);
+    CFX_PointF pt1(ptCenter.x - PWL_CBBUTTON_TRIANGLE_HALFLEN,
+                   ptCenter.y + PWL_CBBUTTON_TRIANGLE_HALFLEN * 0.5f);
+    CFX_PointF pt2(ptCenter.x + PWL_CBBUTTON_TRIANGLE_HALFLEN,
+                   ptCenter.y + PWL_CBBUTTON_TRIANGLE_HALFLEN * 0.5f);
+    CFX_PointF pt3(ptCenter.x,
+                   ptCenter.y - PWL_CBBUTTON_TRIANGLE_HALFLEN * 0.5f);
 
     if (IsFloatBigger(rectWnd.right - rectWnd.left,
                       PWL_CBBUTTON_TRIANGLE_HALFLEN * 2) &&
@@ -133,36 +133,33 @@
   CFX_FloatRect rectWnd = CPWL_Wnd::GetWindowRect();
 
   if (IsVisible() && !rectWnd.IsEmpty()) {
-    CFX_FloatPoint ptCenter = GetCenterPoint();
+    CFX_PointF ptCenter = GetCenterPoint();
 
-    CFX_FloatPoint pt1(ptCenter.x - PWL_CBBUTTON_TRIANGLE_HALFLEN,
-                       ptCenter.y + PWL_CBBUTTON_TRIANGLE_HALFLEN * 0.5f);
-    CFX_FloatPoint pt2(ptCenter.x + PWL_CBBUTTON_TRIANGLE_HALFLEN,
-                       ptCenter.y + PWL_CBBUTTON_TRIANGLE_HALFLEN * 0.5f);
-    CFX_FloatPoint pt3(ptCenter.x,
-                       ptCenter.y - PWL_CBBUTTON_TRIANGLE_HALFLEN * 0.5f);
+    CFX_PointF pt1(ptCenter.x - PWL_CBBUTTON_TRIANGLE_HALFLEN,
+                   ptCenter.y + PWL_CBBUTTON_TRIANGLE_HALFLEN * 0.5f);
+    CFX_PointF pt2(ptCenter.x + PWL_CBBUTTON_TRIANGLE_HALFLEN,
+                   ptCenter.y + PWL_CBBUTTON_TRIANGLE_HALFLEN * 0.5f);
+    CFX_PointF pt3(ptCenter.x,
+                   ptCenter.y - PWL_CBBUTTON_TRIANGLE_HALFLEN * 0.5f);
 
     if (IsFloatBigger(rectWnd.right - rectWnd.left,
                       PWL_CBBUTTON_TRIANGLE_HALFLEN * 2) &&
         IsFloatBigger(rectWnd.top - rectWnd.bottom,
                       PWL_CBBUTTON_TRIANGLE_HALFLEN)) {
       CFX_PathData path;
-
-      path.SetPointCount(4);
-      path.SetPoint(0, pt1.x, pt1.y, FXPT_MOVETO);
-      path.SetPoint(1, pt2.x, pt2.y, FXPT_LINETO);
-      path.SetPoint(2, pt3.x, pt3.y, FXPT_LINETO);
-      path.SetPoint(3, pt1.x, pt1.y, FXPT_LINETO);
+      path.AppendPoint(pt1, FXPT_TYPE::MoveTo, false);
+      path.AppendPoint(pt2, FXPT_TYPE::LineTo, false);
+      path.AppendPoint(pt3, FXPT_TYPE::LineTo, false);
+      path.AppendPoint(pt1, FXPT_TYPE::LineTo, false);
 
       pDevice->DrawPath(&path, pUser2Device, nullptr,
-                        CPWL_Utils::PWLColorToFXColor(PWL_DEFAULT_BLACKCOLOR,
-                                                      GetTransparency()),
-                        0, FXFILL_ALTERNATE);
+                        PWL_DEFAULT_BLACKCOLOR.ToFXColor(GetTransparency()), 0,
+                        FXFILL_ALTERNATE);
     }
   }
 }
 
-bool CPWL_CBButton::OnLButtonDown(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_CBButton::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonDown(point, nFlag);
 
   SetCapture();
@@ -175,7 +172,7 @@
   return true;
 }
 
-bool CPWL_CBButton::OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_CBButton::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonUp(point, nFlag);
 
   ReleaseCapture();
diff --git a/fpdfsdk/pdfwindow/PWL_ComboBox.h b/fpdfsdk/pdfwindow/PWL_ComboBox.h
index 8426119..e1a8df7 100644
--- a/fpdfsdk/pdfwindow/PWL_ComboBox.h
+++ b/fpdfsdk/pdfwindow/PWL_ComboBox.h
@@ -23,7 +23,7 @@
   ~CPWL_CBListBox() override {}
 
   // CPWL_ListBox
-  bool OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) override;
+  bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) override;
 
   bool OnKeyDownWithExit(uint16_t nChar, bool& bExit, uint32_t nFlag);
   bool OnCharWithExit(uint16_t nChar, bool& bExit, uint32_t nFlag);
@@ -40,8 +40,8 @@
   void GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) override;
   void DrawThisAppearance(CFX_RenderDevice* pDevice,
                           CFX_Matrix* pUser2Device) override;
-  bool OnLButtonDown(const CFX_FloatPoint& point, uint32_t nFlag) override;
-  bool OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) override;
+  bool OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) override;
+  bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) override;
 };
 
 class CPWL_ComboBox : public CPWL_Wnd {
diff --git a/fpdfsdk/pdfwindow/PWL_Edit.cpp b/fpdfsdk/pdfwindow/PWL_Edit.cpp
index bb8ec91..b77aad9 100644
--- a/fpdfsdk/pdfwindow/PWL_Edit.cpp
+++ b/fpdfsdk/pdfwindow/PWL_Edit.cpp
@@ -6,6 +6,7 @@
 
 #include "fpdfsdk/pdfwindow/PWL_Edit.h"
 
+#include <memory>
 #include <vector>
 
 #include "core/fpdfapi/font/cpdf_font.h"
@@ -41,35 +42,41 @@
 
 void CPWL_Edit::SetText(const CFX_WideString& csText) {
   CFX_WideString swText = csText;
-  if (HasFlag(PES_RICH)) {
-    CFX_ByteString sValue = CFX_ByteString::FromUnicode(swText);
-    if (CXML_Element* pXML =
-            CXML_Element::Parse(sValue.c_str(), sValue.GetLength())) {
-      int32_t nCount = pXML->CountChildren();
-      bool bFirst = true;
+  if (!HasFlag(PES_RICH)) {
+    m_pEdit->SetText(swText);
+    return;
+  }
 
-      swText.clear();
+  CFX_ByteString sValue = CFX_ByteString::FromUnicode(swText);
+  std::unique_ptr<CXML_Element> pXML(
+      CXML_Element::Parse(sValue.c_str(), sValue.GetLength()));
+  if (!pXML) {
+    m_pEdit->SetText(swText);
+    return;
+  }
 
-      for (int32_t i = 0; i < nCount; i++) {
-        if (CXML_Element* pSubElement = pXML->GetElement(i)) {
-          CFX_ByteString tag = pSubElement->GetTagName();
-          if (tag.EqualNoCase("p")) {
-            int nChild = pSubElement->CountChildren();
-            CFX_WideString swSection;
-            for (int32_t j = 0; j < nChild; j++) {
-              swSection += pSubElement->GetContent(j);
-            }
+  int32_t nCount = pXML->CountChildren();
+  bool bFirst = true;
 
-            if (bFirst)
-              bFirst = false;
-            else
-              swText += FWL_VKEY_Return;
-            swText += swSection;
-          }
-        }
-      }
+  swText.clear();
 
-      delete pXML;
+  for (int32_t i = 0; i < nCount; i++) {
+    CXML_Element* pSubElement = pXML->GetElement(i);
+    if (!pSubElement)
+      continue;
+
+    CFX_ByteString tag = pSubElement->GetTagName();
+    if (tag.EqualNoCase("p")) {
+      int nChild = pSubElement->CountChildren();
+      CFX_WideString swSection;
+      for (int32_t j = 0; j < nChild; j++)
+        swSection += pSubElement->GetContent(j);
+
+      if (bFirst)
+        bFirst = false;
+      else
+        swText += FWL_VKEY_Return;
+      swText += swSection;
     }
   }
 
@@ -243,7 +250,7 @@
   sAppStream << sLine;
 
   CFX_ByteTextBuf sText;
-  CFX_FloatPoint ptOffset = CFX_FloatPoint();
+  CFX_PointF ptOffset;
   CPVT_WordRange wrWhole = m_pEdit->GetWholeWordRange();
   CPVT_WordRange wrSelect = GetSelectWordRange();
   CPVT_WordRange wrVisible =
@@ -266,7 +273,8 @@
       m_pEdit->GetPasswordChar());
 
   if (sEditBefore.GetLength() > 0)
-    sText << "BT\n" << CPWL_Utils::GetColorAppStream(GetTextColor()).AsStringC()
+    sText << "BT\n"
+          << CPWL_Utils::GetColorAppStream(GetTextColor()).AsStringC()
           << sEditBefore.AsStringC() << "ET\n";
 
   wrTemp = CPWL_Utils::OverlapWordRange(wrVisible, wrSelect);
@@ -286,7 +294,8 @@
       m_pEdit->GetPasswordChar());
 
   if (sEditAfter.GetLength() > 0)
-    sText << "BT\n" << CPWL_Utils::GetColorAppStream(GetTextColor()).AsStringC()
+    sText << "BT\n"
+          << CPWL_Utils::GetColorAppStream(GetTextColor()).AsStringC()
           << sEditAfter.AsStringC() << "ET\n";
 
   if (sText.GetLength() > 0) {
@@ -323,25 +332,24 @@
         gsd.m_LineWidth = (FX_FLOAT)GetBorderWidth();
 
         CFX_PathData path;
-        path.SetPointCount(nCharArraySafe.ValueOrDie());
 
         for (int32_t i = 0; i < nCharArray - 1; i++) {
-          path.SetPoint(
-              i * 2,
-              rcClient.left +
-                  ((rcClient.right - rcClient.left) / nCharArray) * (i + 1),
-              rcClient.bottom, FXPT_MOVETO);
-          path.SetPoint(
-              i * 2 + 1,
-              rcClient.left +
-                  ((rcClient.right - rcClient.left) / nCharArray) * (i + 1),
-              rcClient.top, FXPT_LINETO);
+          path.AppendPoint(
+              CFX_PointF(
+                  rcClient.left +
+                      ((rcClient.right - rcClient.left) / nCharArray) * (i + 1),
+                  rcClient.bottom),
+              FXPT_TYPE::MoveTo, false);
+          path.AppendPoint(
+              CFX_PointF(
+                  rcClient.left +
+                      ((rcClient.right - rcClient.left) / nCharArray) * (i + 1),
+                  rcClient.top),
+              FXPT_TYPE::LineTo, false);
         }
-        if (path.GetPointCount() > 0) {
-          pDevice->DrawPath(
-              &path, pUser2Device, &gsd, 0,
-              CPWL_Utils::PWLColorToFXColor(GetBorderColor(), 255),
-              FXFILL_ALTERNATE);
+        if (!path.GetPoints().empty()) {
+          pDevice->DrawPath(&path, pUser2Device, &gsd, 0,
+                            GetBorderColor().ToFXColor(255), FXFILL_ALTERNATE);
         }
         break;
       }
@@ -355,25 +363,23 @@
         gsd.m_DashPhase = (FX_FLOAT)GetBorderDash().nPhase;
 
         CFX_PathData path;
-        path.SetPointCount(nCharArraySafe.ValueOrDie());
-
         for (int32_t i = 0; i < nCharArray - 1; i++) {
-          path.SetPoint(
-              i * 2,
-              rcClient.left +
-                  ((rcClient.right - rcClient.left) / nCharArray) * (i + 1),
-              rcClient.bottom, FXPT_MOVETO);
-          path.SetPoint(
-              i * 2 + 1,
-              rcClient.left +
-                  ((rcClient.right - rcClient.left) / nCharArray) * (i + 1),
-              rcClient.top, FXPT_LINETO);
+          path.AppendPoint(
+              CFX_PointF(
+                  rcClient.left +
+                      ((rcClient.right - rcClient.left) / nCharArray) * (i + 1),
+                  rcClient.bottom),
+              FXPT_TYPE::MoveTo, false);
+          path.AppendPoint(
+              CFX_PointF(
+                  rcClient.left +
+                      ((rcClient.right - rcClient.left) / nCharArray) * (i + 1),
+                  rcClient.top),
+              FXPT_TYPE::LineTo, false);
         }
-        if (path.GetPointCount() > 0) {
-          pDevice->DrawPath(
-              &path, pUser2Device, &gsd, 0,
-              CPWL_Utils::PWLColorToFXColor(GetBorderColor(), 255),
-              FXFILL_ALTERNATE);
+        if (!path.GetPoints().empty()) {
+          pDevice->DrawPath(&path, pUser2Device, &gsd, 0,
+                            GetBorderColor().ToFXColor(255), FXFILL_ALTERNATE);
         }
         break;
       }
@@ -391,14 +397,12 @@
   }
 
   CFX_SystemHandler* pSysHandler = GetSystemHandler();
-  CFX_Edit::DrawEdit(
-      pDevice, pUser2Device, m_pEdit.get(),
-      CPWL_Utils::PWLColorToFXColor(GetTextColor(), GetTransparency()),
-      CPWL_Utils::PWLColorToFXColor(GetTextStrokeColor(), GetTransparency()),
-      rcClip, CFX_FloatPoint(), pRange, pSysHandler, m_pFormFiller);
+  CFX_Edit::DrawEdit(pDevice, pUser2Device, m_pEdit.get(),
+                     GetTextColor().ToFXColor(GetTransparency()), rcClip,
+                     CFX_PointF(), pRange, pSysHandler, m_pFormFiller);
 }
 
-bool CPWL_Edit::OnLButtonDown(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_Edit::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonDown(point, nFlag);
 
   if (HasFlag(PES_TEXTOVERFLOW) || ClientHitTest(point)) {
@@ -414,7 +418,7 @@
   return true;
 }
 
-bool CPWL_Edit::OnLButtonDblClk(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_Edit::OnLButtonDblClk(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonDblClk(point, nFlag);
 
   if (HasFlag(PES_TEXTOVERFLOW) || ClientHitTest(point)) {
@@ -424,7 +428,7 @@
   return true;
 }
 
-bool CPWL_Edit::OnRButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_Edit::OnRButtonUp(const CFX_PointF& point, uint32_t nFlag) {
   if (m_bMouseDown)
     return false;
 
@@ -454,7 +458,7 @@
 void CPWL_Edit::OnKillFocus() {
   ShowVScrollBar(false);
   m_pEdit->SelectNone();
-  SetCaret(false, CFX_FloatPoint(), CFX_FloatPoint());
+  SetCaret(false, CFX_PointF(), CFX_PointF());
   SetCharSet(FXFONT_ANSI_CHARSET);
   m_bFocus = false;
 }
@@ -464,7 +468,7 @@
 }
 
 CFX_ByteString CPWL_Edit::GetSelectAppearanceStream(
-    const CFX_FloatPoint& ptOffset) const {
+    const CFX_PointF& ptOffset) const {
   CPVT_WordRange wr = GetSelectWordRange();
   return CPWL_Utils::GetEditSelAppStream(m_pEdit.get(), ptOffset, &wr);
 }
@@ -486,35 +490,34 @@
 }
 
 CFX_ByteString CPWL_Edit::GetTextAppearanceStream(
-    const CFX_FloatPoint& ptOffset) const {
+    const CFX_PointF& ptOffset) const {
   CFX_ByteTextBuf sRet;
   CFX_ByteString sEdit = CPWL_Utils::GetEditAppStream(m_pEdit.get(), ptOffset);
   if (sEdit.GetLength() > 0) {
-    sRet << "BT\n" << CPWL_Utils::GetColorAppStream(GetTextColor()).AsStringC()
+    sRet << "BT\n"
+         << CPWL_Utils::GetColorAppStream(GetTextColor()).AsStringC()
          << sEdit.AsStringC() << "ET\n";
   }
   return sRet.MakeString();
 }
 
 CFX_ByteString CPWL_Edit::GetCaretAppearanceStream(
-    const CFX_FloatPoint& ptOffset) const {
+    const CFX_PointF& ptOffset) const {
   if (m_pEditCaret)
     return m_pEditCaret->GetCaretAppearanceStream(ptOffset);
 
   return CFX_ByteString();
 }
 
-CFX_FloatPoint CPWL_Edit::GetWordRightBottomPoint(
-    const CPVT_WordPlace& wpWord) {
+CFX_PointF CPWL_Edit::GetWordRightBottomPoint(const CPVT_WordPlace& wpWord) {
   CFX_Edit_Iterator* pIterator = m_pEdit->GetIterator();
   CPVT_WordPlace wpOld = pIterator->GetAt();
   pIterator->SetAt(wpWord);
 
-  CFX_FloatPoint pt;
+  CFX_PointF pt;
   CPVT_Word word;
   if (pIterator->GetWord(word)) {
-    pt = CFX_FloatPoint(word.ptWord.x + word.fWidth,
-                        word.ptWord.y + word.fDescent);
+    pt = CFX_PointF(word.ptWord.x + word.fWidth, word.ptWord.y + word.fDescent);
   }
   pIterator->SetAt(wpOld);
   return pt;
@@ -720,10 +723,10 @@
 }
 
 bool CPWL_Edit::OnMouseWheel(short zDelta,
-                             const CFX_FloatPoint& point,
+                             const CFX_PointF& point,
                              uint32_t nFlag) {
   if (HasFlag(PES_MULTILINE)) {
-    CFX_FloatPoint ptScroll = GetScrollPos();
+    CFX_PointF ptScroll = GetScrollPos();
 
     if (zDelta > 0) {
       ptScroll.y += GetFontSize();
@@ -805,8 +808,7 @@
   return wrRet;
 }
 
-CPVT_WordRange CPWL_Edit::GetLatinWordsRange(
-    const CFX_FloatPoint& point) const {
+CPVT_WordRange CPWL_Edit::GetLatinWordsRange(const CFX_PointF& point) const {
   return GetSameWordsRange(m_pEdit->SearchWordPlace(point), true, false);
 }
 
@@ -874,21 +876,3 @@
   range.Set(wpStart, wpEnd);
   return range;
 }
-
-void CPWL_Edit::GeneratePageObjects(CPDF_PageObjectHolder* pObjectHolder,
-                                    const CFX_FloatPoint& ptOffset,
-                                    std::vector<CPDF_TextObject*>* ObjArray) {
-  CFX_Edit::GeneratePageObjects(
-      pObjectHolder, m_pEdit.get(), ptOffset, nullptr,
-      CPWL_Utils::PWLColorToFXColor(GetTextColor(), GetTransparency()),
-      ObjArray);
-}
-
-void CPWL_Edit::GeneratePageObjects(CPDF_PageObjectHolder* pObjectHolder,
-                                    const CFX_FloatPoint& ptOffset) {
-  std::vector<CPDF_TextObject*> ObjArray;
-  CFX_Edit::GeneratePageObjects(
-      pObjectHolder, m_pEdit.get(), ptOffset, nullptr,
-      CPWL_Utils::PWLColorToFXColor(GetTextColor(), GetTransparency()),
-      &ObjArray);
-}
diff --git a/fpdfsdk/pdfwindow/PWL_Edit.h b/fpdfsdk/pdfwindow/PWL_Edit.h
index 801dedd..b6d0130 100644
--- a/fpdfsdk/pdfwindow/PWL_Edit.h
+++ b/fpdfsdk/pdfwindow/PWL_Edit.h
@@ -60,11 +60,11 @@
   void GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) override;
   void DrawThisAppearance(CFX_RenderDevice* pDevice,
                           CFX_Matrix* pUser2Device) override;
-  bool OnLButtonDown(const CFX_FloatPoint& point, uint32_t nFlag) override;
-  bool OnLButtonDblClk(const CFX_FloatPoint& point, uint32_t nFlag) override;
-  bool OnRButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) override;
+  bool OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) override;
+  bool OnLButtonDblClk(const CFX_PointF& point, uint32_t nFlag) override;
+  bool OnRButtonUp(const CFX_PointF& point, uint32_t nFlag) override;
   bool OnMouseWheel(short zDelta,
-                    const CFX_FloatPoint& point,
+                    const CFX_PointF& point,
                     uint32_t nFlag) override;
   bool OnKeyDown(uint16_t nChar, uint32_t nFlag) override;
   bool OnChar(uint16_t nChar, uint32_t nFlag) override;
@@ -90,10 +90,9 @@
   void SetText(const CFX_WideString& csText);
   void ReplaceSel(const CFX_WideString& csText);
 
-  CFX_ByteString GetTextAppearanceStream(const CFX_FloatPoint& ptOffset) const;
-  CFX_ByteString GetCaretAppearanceStream(const CFX_FloatPoint& ptOffset) const;
-  CFX_ByteString GetSelectAppearanceStream(
-      const CFX_FloatPoint& ptOffset) const;
+  CFX_ByteString GetTextAppearanceStream(const CFX_PointF& ptOffset) const;
+  CFX_ByteString GetCaretAppearanceStream(const CFX_PointF& ptOffset) const;
+  CFX_ByteString GetSelectAppearanceStream(const CFX_PointF& ptOffset) const;
 
   bool IsTextFull() const;
 
@@ -105,12 +104,6 @@
     m_pFillerNotify = pNotify;
   }
 
-  void GeneratePageObjects(CPDF_PageObjectHolder* pObjectHolder,
-                           const CFX_FloatPoint& ptOffset,
-                           std::vector<CPDF_TextObject*>* ObjArray);
-  void GeneratePageObjects(CPDF_PageObjectHolder* pObjectHolder,
-                           const CFX_FloatPoint& ptOffset);
-
   bool IsProceedtoOnChar(uint16_t nKeyCode, uint32_t nFlag);
   void AttachFFLData(CFFL_FormFiller* pData) { m_pFormFiller = pData; }
 
@@ -131,11 +124,11 @@
   void SetParamByFlag();
 
   FX_FLOAT GetCharArrayAutoFontSize(int32_t nCharArray);
-  CFX_FloatPoint GetWordRightBottomPoint(const CPVT_WordPlace& wpWord);
+  CFX_PointF GetWordRightBottomPoint(const CPVT_WordPlace& wpWord);
 
   CPVT_WordRange CombineWordRange(const CPVT_WordRange& wr1,
                                   const CPVT_WordRange& wr2);
-  CPVT_WordRange GetLatinWordsRange(const CFX_FloatPoint& point) const;
+  CPVT_WordRange GetLatinWordsRange(const CFX_PointF& point) const;
   CPVT_WordRange GetLatinWordsRange(const CPVT_WordPlace& place) const;
   CPVT_WordRange GetArabicWordsRange(const CPVT_WordPlace& place) const;
   CPVT_WordRange GetSameWordsRange(const CPVT_WordPlace& place,
diff --git a/fpdfsdk/pdfwindow/PWL_EditCtrl.cpp b/fpdfsdk/pdfwindow/PWL_EditCtrl.cpp
index 9459215..4921ab7 100644
--- a/fpdfsdk/pdfwindow/PWL_EditCtrl.cpp
+++ b/fpdfsdk/pdfwindow/PWL_EditCtrl.cpp
@@ -40,13 +40,7 @@
 
 bool CPWL_EditCtrl::IsWndHorV() {
   CFX_Matrix mt = GetWindowMatrix();
-  CFX_FloatPoint point1(0, 1);
-  CFX_FloatPoint point2(1, 1);
-
-  mt.Transform(point1.x, point1.y);
-  mt.Transform(point2.x, point2.y);
-
-  return point2.y == point1.y;
+  return mt.Transform(CFX_PointF(1, 1)).y == mt.Transform(CFX_PointF(0, 1)).y;
 }
 
 void CPWL_EditCtrl::SetCursor() {
@@ -93,8 +87,7 @@
       FX_FLOAT fPos = *(FX_FLOAT*)lParam;
       switch (wParam) {
         case SBT_VSCROLL:
-          m_pEdit->SetScrollPos(
-              CFX_FloatPoint(m_pEdit->GetScrollPos().x, fPos));
+          m_pEdit->SetScrollPos(CFX_PointF(m_pEdit->GetScrollPos().x, fPos));
           break;
       }
     } break;
@@ -281,7 +274,7 @@
   return true;
 }
 
-bool CPWL_EditCtrl::OnLButtonDown(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_EditCtrl::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonDown(point, nFlag);
 
   if (ClientHitTest(point)) {
@@ -297,7 +290,7 @@
   return true;
 }
 
-bool CPWL_EditCtrl::OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_EditCtrl::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonUp(point, nFlag);
 
   if (m_bMouseDown) {
@@ -312,7 +305,7 @@
   return true;
 }
 
-bool CPWL_EditCtrl::OnMouseMove(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_EditCtrl::OnMouseMove(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnMouseMove(point, nFlag);
 
   if (m_bMouseDown)
@@ -326,44 +319,36 @@
 }
 
 void CPWL_EditCtrl::SetEditCaret(bool bVisible) {
-  CFX_FloatPoint ptHead;
-  CFX_FloatPoint ptFoot;
+  CFX_PointF ptHead;
+  CFX_PointF ptFoot;
   if (bVisible)
-    GetCaretInfo(ptHead, ptFoot);
+    GetCaretInfo(&ptHead, &ptFoot);
 
   CPVT_WordPlace wpTemp = m_pEdit->GetCaretWordPlace();
   IOnSetCaret(bVisible, ptHead, ptFoot, wpTemp);
 }
 
-void CPWL_EditCtrl::GetCaretInfo(CFX_FloatPoint& ptHead,
-                                 CFX_FloatPoint& ptFoot) const {
+void CPWL_EditCtrl::GetCaretInfo(CFX_PointF* ptHead, CFX_PointF* ptFoot) const {
   CFX_Edit_Iterator* pIterator = m_pEdit->GetIterator();
   pIterator->SetAt(m_pEdit->GetCaret());
   CPVT_Word word;
   CPVT_Line line;
   if (pIterator->GetWord(word)) {
-    ptHead.x = word.ptWord.x + word.fWidth;
-    ptHead.y = word.ptWord.y + word.fAscent;
-    ptFoot.x = word.ptWord.x + word.fWidth;
-    ptFoot.y = word.ptWord.y + word.fDescent;
+    ptHead->x = word.ptWord.x + word.fWidth;
+    ptHead->y = word.ptWord.y + word.fAscent;
+    ptFoot->x = word.ptWord.x + word.fWidth;
+    ptFoot->y = word.ptWord.y + word.fDescent;
   } else if (pIterator->GetLine(line)) {
-    ptHead.x = line.ptLine.x;
-    ptHead.y = line.ptLine.y + line.fLineAscent;
-    ptFoot.x = line.ptLine.x;
-    ptFoot.y = line.ptLine.y + line.fLineDescent;
+    ptHead->x = line.ptLine.x;
+    ptHead->y = line.ptLine.y + line.fLineAscent;
+    ptFoot->x = line.ptLine.x;
+    ptFoot->y = line.ptLine.y + line.fLineDescent;
   }
 }
 
-void CPWL_EditCtrl::GetCaretPos(int32_t& x, int32_t& y) const {
-  CFX_FloatPoint ptHead;
-  CFX_FloatPoint ptFoot;
-  GetCaretInfo(ptHead, ptFoot);
-  PWLtoWnd(ptHead, x, y);
-}
-
 void CPWL_EditCtrl::SetCaret(bool bVisible,
-                             const CFX_FloatPoint& ptHead,
-                             const CFX_FloatPoint& ptFoot) {
+                             const CFX_PointF& ptHead,
+                             const CFX_PointF& ptFoot) {
   if (m_pEditCaret) {
     if (!IsFocused() || m_pEdit->IsSelected())
       bVisible = false;
@@ -413,11 +398,11 @@
   return m_pEdit->GetTotalWords();
 }
 
-void CPWL_EditCtrl::SetScrollPos(const CFX_FloatPoint& point) {
+void CPWL_EditCtrl::SetScrollPos(const CFX_PointF& point) {
   m_pEdit->SetScrollPos(point);
 }
 
-CFX_FloatPoint CPWL_EditCtrl::GetScrollPos() const {
+CFX_PointF CPWL_EditCtrl::GetScrollPos() const {
   return m_pEdit->GetScrollPos();
 }
 
@@ -544,8 +529,8 @@
 }
 
 void CPWL_EditCtrl::IOnSetCaret(bool bVisible,
-                                const CFX_FloatPoint& ptHead,
-                                const CFX_FloatPoint& ptFoot,
+                                const CFX_PointF& ptHead,
+                                const CFX_PointF& ptFoot,
                                 const CPVT_WordPlace& place) {
   PWL_CARET_INFO cInfo;
   cInfo.bVisible = bVisible;
@@ -572,9 +557,9 @@
                                  int32_t& nStartChar,
                                  int32_t& nEndChar) const {
   nStartChar = m_pEdit->WordPlaceToWordIndex(
-      m_pEdit->SearchWordPlace(CFX_FloatPoint(rect.left, rect.top)));
+      m_pEdit->SearchWordPlace(CFX_PointF(rect.left, rect.top)));
   nEndChar = m_pEdit->WordPlaceToWordIndex(
-      m_pEdit->SearchWordPlace(CFX_FloatPoint(rect.right, rect.bottom)));
+      m_pEdit->SearchWordPlace(CFX_PointF(rect.right, rect.bottom)));
 }
 
 CFX_WideString CPWL_EditCtrl::GetText(int32_t& nStartChar,
diff --git a/fpdfsdk/pdfwindow/PWL_EditCtrl.h b/fpdfsdk/pdfwindow/PWL_EditCtrl.h
index 3ff5cc6..498570b 100644
--- a/fpdfsdk/pdfwindow/PWL_EditCtrl.h
+++ b/fpdfsdk/pdfwindow/PWL_EditCtrl.h
@@ -34,7 +34,6 @@
   ~CPWL_EditCtrl() override;
 
   CFX_FloatRect GetContentRect() const;
-  void GetCaretPos(int32_t& x, int32_t& y) const;
 
   CFX_WideString GetText() const;
   void SetSel(int32_t nStartChar, int32_t nEndChar);
@@ -53,8 +52,8 @@
   void Paint();
 
   void EnableRefresh(bool bRefresh);
-  CFX_FloatPoint GetScrollPos() const;
-  void SetScrollPos(const CFX_FloatPoint& point);
+  CFX_PointF GetScrollPos() const;
+  void SetScrollPos(const CFX_PointF& point);
 
   void SetCharSet(uint8_t nCharSet) { m_nCharSet = nCharSet; }
   int32_t GetCharSet() const;
@@ -77,9 +76,9 @@
   void OnCreated() override;
   bool OnKeyDown(uint16_t nChar, uint32_t nFlag) override;
   bool OnChar(uint16_t nChar, uint32_t nFlag) override;
-  bool OnLButtonDown(const CFX_FloatPoint& point, uint32_t nFlag) override;
-  bool OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) override;
-  bool OnMouseMove(const CFX_FloatPoint& point, uint32_t nFlag) override;
+  bool OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) override;
+  bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) override;
+  bool OnMouseMove(const CFX_PointF& point, uint32_t nFlag) override;
   void OnNotify(CPWL_Wnd* pWnd,
                 uint32_t msg,
                 intptr_t wParam = 0,
@@ -98,8 +97,8 @@
                          FX_FLOAT fBigStep);
   void IOnSetScrollPosY(FX_FLOAT fy);
   void IOnSetCaret(bool bVisible,
-                   const CFX_FloatPoint& ptHead,
-                   const CFX_FloatPoint& ptFoot,
+                   const CFX_PointF& ptHead,
+                   const CFX_PointF& ptFoot,
                    const CPVT_WordPlace& place);
   void IOnCaretChange(const CPVT_SecProps& secProps,
                       const CPVT_WordProps& wordProps);
@@ -121,10 +120,10 @@
   void Delete();
   void Backspace();
 
-  void GetCaretInfo(CFX_FloatPoint& ptHead, CFX_FloatPoint& ptFoot) const;
+  void GetCaretInfo(CFX_PointF* ptHead, CFX_PointF* ptFoot) const;
   void SetCaret(bool bVisible,
-                const CFX_FloatPoint& ptHead,
-                const CFX_FloatPoint& ptFoot);
+                const CFX_PointF& ptHead,
+                const CFX_PointF& ptFoot);
 
   void SetEditCaret(bool bVisible);
 
diff --git a/fpdfsdk/pdfwindow/PWL_Icon.cpp b/fpdfsdk/pdfwindow/PWL_Icon.cpp
index 877921d..b0d0c76 100644
--- a/fpdfsdk/pdfwindow/PWL_Icon.cpp
+++ b/fpdfsdk/pdfwindow/PWL_Icon.cpp
@@ -6,6 +6,8 @@
 
 #include "fpdfsdk/pdfwindow/PWL_Icon.h"
 
+#include <algorithm>
+
 #include "core/fpdfapi/parser/cpdf_array.h"
 #include "core/fpdfapi/parser/cpdf_stream.h"
 #include "fpdfsdk/pdfwindow/PWL_Utils.h"
@@ -39,8 +41,8 @@
 
     sAppStream << fHScale << " 0 0 " << fVScale << " " << rcPlate.left + fx
                << " " << rcPlate.bottom + fy << " cm\n";
-    sAppStream << mt.GetA() << " " << mt.GetB() << " " << mt.GetC() << " "
-               << mt.GetD() << " " << mt.GetE() << " " << mt.GetF() << " cm\n";
+    sAppStream << mt.a << " " << mt.b << " " << mt.c << " " << mt.d << " "
+               << mt.e << " " << mt.f << " cm\n";
 
     sAppStream << "0 g 0 G 1 w /" << sAlias.AsStringC() << " Do\n"
                << "Q\n";
@@ -169,20 +171,20 @@
     switch (nScaleMethod) {
       default:
       case 0:
-        fHScale = fPlateWidth / PWL_MAX(fImageWidth, 1.0f);
-        fVScale = fPlateHeight / PWL_MAX(fImageHeight, 1.0f);
+        fHScale = fPlateWidth / std::max(fImageWidth, 1.0f);
+        fVScale = fPlateHeight / std::max(fImageHeight, 1.0f);
         break;
       case 1:
         if (fPlateWidth < fImageWidth)
-          fHScale = fPlateWidth / PWL_MAX(fImageWidth, 1.0f);
+          fHScale = fPlateWidth / std::max(fImageWidth, 1.0f);
         if (fPlateHeight < fImageHeight)
-          fVScale = fPlateHeight / PWL_MAX(fImageHeight, 1.0f);
+          fVScale = fPlateHeight / std::max(fImageHeight, 1.0f);
         break;
       case 2:
         if (fPlateWidth > fImageWidth)
-          fHScale = fPlateWidth / PWL_MAX(fImageWidth, 1.0f);
+          fHScale = fPlateWidth / std::max(fImageWidth, 1.0f);
         if (fPlateHeight > fImageHeight)
-          fVScale = fPlateHeight / PWL_MAX(fImageHeight, 1.0f);
+          fVScale = fPlateHeight / std::max(fImageHeight, 1.0f);
         break;
       case 3:
         break;
@@ -190,7 +192,7 @@
 
     FX_FLOAT fMinScale;
     if (IsProportionalScale()) {
-      fMinScale = PWL_MIN(fHScale, fVScale);
+      fMinScale = std::min(fHScale, fVScale);
       fHScale = fMinScale;
       fVScale = fMinScale;
     }
diff --git a/fpdfsdk/pdfwindow/PWL_ListBox.cpp b/fpdfsdk/pdfwindow/PWL_ListBox.cpp
index 12cad7b..ed96e20 100644
--- a/fpdfsdk/pdfwindow/PWL_ListBox.cpp
+++ b/fpdfsdk/pdfwindow/PWL_ListBox.cpp
@@ -106,7 +106,7 @@
     if (rcItem.bottom > rcPlate.top || rcItem.top < rcPlate.bottom)
       continue;
 
-    CFX_FloatPoint ptOffset(rcItem.left, (rcItem.top + rcItem.bottom) * 0.5f);
+    CFX_PointF ptOffset(rcItem.left, (rcItem.top + rcItem.bottom) * 0.5f);
     if (m_pList->IsItemSelected(i)) {
       sListItems << CPWL_Utils::GetRectFillAppStream(rcItem,
                                                      PWL_DEFAULT_SELBACKCOLOR)
@@ -158,7 +158,7 @@
     if (rcItem.bottom > rcPlate.top || rcItem.top < rcPlate.bottom)
       continue;
 
-    CFX_FloatPoint ptOffset(rcItem.left, (rcItem.top + rcItem.bottom) * 0.5f);
+    CFX_PointF ptOffset(rcItem.left, (rcItem.top + rcItem.bottom) * 0.5f);
     if (CFX_Edit* pEdit = m_pList->GetItemEdit(i)) {
       CFX_FloatRect rcContent = pEdit->GetContentRect();
       if (rcContent.Width() > rcClient.Width())
@@ -171,24 +171,21 @@
       CFX_SystemHandler* pSysHandler = GetSystemHandler();
       if (pSysHandler && pSysHandler->IsSelectionImplemented()) {
         CFX_Edit::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i),
-                           CPWL_Utils::PWLColorToFXColor(GetTextColor()),
-                           CPWL_Utils::PWLColorToFXColor(GetTextStrokeColor()),
-                           rcList, ptOffset, nullptr, pSysHandler,
-                           m_pFormFiller);
+                           GetTextColor().ToFXColor(255), rcList, ptOffset,
+                           nullptr, pSysHandler, m_pFormFiller);
         pSysHandler->OutputSelectedRect(m_pFormFiller, rcItem);
       } else {
         CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcItem,
                                  ArgbEncode(255, 0, 51, 113));
         CFX_Edit::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i),
-                           ArgbEncode(255, 255, 255, 255), 0, rcList, ptOffset,
+                           ArgbEncode(255, 255, 255, 255), rcList, ptOffset,
                            nullptr, pSysHandler, m_pFormFiller);
       }
     } else {
       CFX_SystemHandler* pSysHandler = GetSystemHandler();
       CFX_Edit::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i),
-                         CPWL_Utils::PWLColorToFXColor(GetTextColor()),
-                         CPWL_Utils::PWLColorToFXColor(GetTextStrokeColor()),
-                         rcList, ptOffset, nullptr, pSysHandler, nullptr);
+                         GetTextColor().ToFXColor(255), rcList, ptOffset,
+                         nullptr, pSysHandler, nullptr);
     }
   }
 }
@@ -249,7 +246,7 @@
   return true;
 }
 
-bool CPWL_ListBox::OnLButtonDown(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_ListBox::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonDown(point, nFlag);
 
   if (ClientHitTest(point)) {
@@ -263,7 +260,7 @@
   return true;
 }
 
-bool CPWL_ListBox::OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_ListBox::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonUp(point, nFlag);
 
   if (m_bMouseDown) {
@@ -281,7 +278,7 @@
   m_bHoverSel = bHoverSel;
 }
 
-bool CPWL_ListBox::OnMouseMove(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_ListBox::OnMouseMove(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnMouseMove(point, nFlag);
 
   if (m_bHoverSel && !IsCaptureMouse() && ClientHitTest(point))
@@ -323,7 +320,7 @@
       fPos = *(FX_FLOAT*)lParam;
       switch (wParam) {
         case SBT_VSCROLL:
-          m_pList->SetScrollPos(CFX_FloatPoint(0, fPos));
+          m_pList->SetScrollPos(CFX_PointF(0, fPos));
           break;
       }
       break;
@@ -449,7 +446,7 @@
 }
 
 bool CPWL_ListBox::OnMouseWheel(short zDelta,
-                                const CFX_FloatPoint& point,
+                                const CFX_PointF& point,
                                 uint32_t nFlag) {
   if (zDelta < 0)
     m_pList->OnVK_DOWN(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
diff --git a/fpdfsdk/pdfwindow/PWL_ListBox.h b/fpdfsdk/pdfwindow/PWL_ListBox.h
index 6db4ecb..f9108a1 100644
--- a/fpdfsdk/pdfwindow/PWL_ListBox.h
+++ b/fpdfsdk/pdfwindow/PWL_ListBox.h
@@ -35,8 +35,8 @@
   void IOnInvalidateRect(CFX_FloatRect* pRect);
 
   void IOnSetCaret(bool bVisible,
-                   const CFX_FloatPoint& ptHead,
-                   const CFX_FloatPoint& ptFoot,
+                   const CFX_PointF& ptHead,
+                   const CFX_PointF& ptFoot,
                    const CPVT_WordPlace& place);
 
  private:
@@ -57,11 +57,11 @@
                           CFX_Matrix* pUser2Device) override;
   bool OnKeyDown(uint16_t nChar, uint32_t nFlag) override;
   bool OnChar(uint16_t nChar, uint32_t nFlag) override;
-  bool OnLButtonDown(const CFX_FloatPoint& point, uint32_t nFlag) override;
-  bool OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) override;
-  bool OnMouseMove(const CFX_FloatPoint& point, uint32_t nFlag) override;
+  bool OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) override;
+  bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) override;
+  bool OnMouseMove(const CFX_PointF& point, uint32_t nFlag) override;
   bool OnMouseWheel(short zDelta,
-                    const CFX_FloatPoint& point,
+                    const CFX_PointF& point,
                     uint32_t nFlag) override;
   void KillFocus() override;
   void OnNotify(CPWL_Wnd* pWnd,
diff --git a/fpdfsdk/pdfwindow/PWL_ScrollBar.cpp b/fpdfsdk/pdfwindow/PWL_ScrollBar.cpp
index 8a09ac6..e379936 100644
--- a/fpdfsdk/pdfwindow/PWL_ScrollBar.cpp
+++ b/fpdfsdk/pdfwindow/PWL_ScrollBar.cpp
@@ -137,18 +137,17 @@
 
   sAppStream << "q\n";
 
-  CFX_FloatPoint ptCenter = GetCenterPoint();
+  CFX_PointF ptCenter = GetCenterPoint();
 
   switch (m_eScrollBarType) {
     case SBT_HSCROLL:
       switch (m_eSBButtonType) {
         case PSBT_MIN: {
-          CFX_FloatPoint pt1(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f,
-                             ptCenter.y);
-          CFX_FloatPoint pt2(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f,
-                             ptCenter.y + PWL_TRIANGLE_HALFLEN);
-          CFX_FloatPoint pt3(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f,
-                             ptCenter.y - PWL_TRIANGLE_HALFLEN);
+          CFX_PointF pt1(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f, ptCenter.y);
+          CFX_PointF pt2(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f,
+                         ptCenter.y + PWL_TRIANGLE_HALFLEN);
+          CFX_PointF pt3(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f,
+                         ptCenter.y - PWL_TRIANGLE_HALFLEN);
 
           if (rectWnd.right - rectWnd.left > PWL_TRIANGLE_HALFLEN * 2 &&
               rectWnd.top - rectWnd.bottom > PWL_TRIANGLE_HALFLEN) {
@@ -162,12 +161,11 @@
           }
         } break;
         case PSBT_MAX: {
-          CFX_FloatPoint pt1(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f,
-                             ptCenter.y);
-          CFX_FloatPoint pt2(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f,
-                             ptCenter.y + PWL_TRIANGLE_HALFLEN);
-          CFX_FloatPoint pt3(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f,
-                             ptCenter.y - PWL_TRIANGLE_HALFLEN);
+          CFX_PointF pt1(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f, ptCenter.y);
+          CFX_PointF pt2(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f,
+                         ptCenter.y + PWL_TRIANGLE_HALFLEN);
+          CFX_PointF pt3(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f,
+                         ptCenter.y - PWL_TRIANGLE_HALFLEN);
 
           if (rectWnd.right - rectWnd.left > PWL_TRIANGLE_HALFLEN * 2 &&
               rectWnd.top - rectWnd.bottom > PWL_TRIANGLE_HALFLEN) {
@@ -187,12 +185,11 @@
     case SBT_VSCROLL:
       switch (m_eSBButtonType) {
         case PSBT_MIN: {
-          CFX_FloatPoint pt1(ptCenter.x - PWL_TRIANGLE_HALFLEN,
-                             ptCenter.y - PWL_TRIANGLE_HALFLEN * 0.5f);
-          CFX_FloatPoint pt2(ptCenter.x + PWL_TRIANGLE_HALFLEN,
-                             ptCenter.y - PWL_TRIANGLE_HALFLEN * 0.5f);
-          CFX_FloatPoint pt3(ptCenter.x,
-                             ptCenter.y + PWL_TRIANGLE_HALFLEN * 0.5f);
+          CFX_PointF pt1(ptCenter.x - PWL_TRIANGLE_HALFLEN,
+                         ptCenter.y - PWL_TRIANGLE_HALFLEN * 0.5f);
+          CFX_PointF pt2(ptCenter.x + PWL_TRIANGLE_HALFLEN,
+                         ptCenter.y - PWL_TRIANGLE_HALFLEN * 0.5f);
+          CFX_PointF pt3(ptCenter.x, ptCenter.y + PWL_TRIANGLE_HALFLEN * 0.5f);
 
           if (rectWnd.right - rectWnd.left > PWL_TRIANGLE_HALFLEN * 2 &&
               rectWnd.top - rectWnd.bottom > PWL_TRIANGLE_HALFLEN) {
@@ -206,12 +203,11 @@
           }
         } break;
         case PSBT_MAX: {
-          CFX_FloatPoint pt1(ptCenter.x - PWL_TRIANGLE_HALFLEN,
-                             ptCenter.y + PWL_TRIANGLE_HALFLEN * 0.5f);
-          CFX_FloatPoint pt2(ptCenter.x + PWL_TRIANGLE_HALFLEN,
-                             ptCenter.y + PWL_TRIANGLE_HALFLEN * 0.5f);
-          CFX_FloatPoint pt3(ptCenter.x,
-                             ptCenter.y - PWL_TRIANGLE_HALFLEN * 0.5f);
+          CFX_PointF pt1(ptCenter.x - PWL_TRIANGLE_HALFLEN,
+                         ptCenter.y + PWL_TRIANGLE_HALFLEN * 0.5f);
+          CFX_PointF pt2(ptCenter.x + PWL_TRIANGLE_HALFLEN,
+                         ptCenter.y + PWL_TRIANGLE_HALFLEN * 0.5f);
+          CFX_PointF pt3(ptCenter.x, ptCenter.y - PWL_TRIANGLE_HALFLEN * 0.5f);
 
           if (rectWnd.right - rectWnd.left > PWL_TRIANGLE_HALFLEN * 2 &&
               rectWnd.top - rectWnd.bottom > PWL_TRIANGLE_HALFLEN) {
@@ -244,58 +240,50 @@
   if (rectWnd.IsEmpty())
     return;
 
-  CFX_FloatPoint ptCenter = GetCenterPoint();
-  int32_t nTransparancy = GetTransparency();
+  CFX_PointF ptCenter = GetCenterPoint();
+  int32_t nTransparency = GetTransparency();
 
   switch (m_eScrollBarType) {
     case SBT_HSCROLL:
       CPWL_Wnd::DrawThisAppearance(pDevice, pUser2Device);
       switch (m_eSBButtonType) {
         case PSBT_MIN: {
-          CFX_FloatPoint pt1(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f,
-                             ptCenter.y);
-          CFX_FloatPoint pt2(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f,
-                             ptCenter.y + PWL_TRIANGLE_HALFLEN);
-          CFX_FloatPoint pt3(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f,
-                             ptCenter.y - PWL_TRIANGLE_HALFLEN);
+          CFX_PointF pt1(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f, ptCenter.y);
+          CFX_PointF pt2(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f,
+                         ptCenter.y + PWL_TRIANGLE_HALFLEN);
+          CFX_PointF pt3(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f,
+                         ptCenter.y - PWL_TRIANGLE_HALFLEN);
 
           if (rectWnd.right - rectWnd.left > PWL_TRIANGLE_HALFLEN * 2 &&
               rectWnd.top - rectWnd.bottom > PWL_TRIANGLE_HALFLEN) {
             CFX_PathData path;
-
-            path.SetPointCount(4);
-            path.SetPoint(0, pt1.x, pt1.y, FXPT_MOVETO);
-            path.SetPoint(1, pt2.x, pt2.y, FXPT_LINETO);
-            path.SetPoint(2, pt3.x, pt3.y, FXPT_LINETO);
-            path.SetPoint(3, pt1.x, pt1.y, FXPT_LINETO);
+            path.AppendPoint(pt1, FXPT_TYPE::MoveTo, false);
+            path.AppendPoint(pt2, FXPT_TYPE::LineTo, false);
+            path.AppendPoint(pt3, FXPT_TYPE::LineTo, false);
+            path.AppendPoint(pt1, FXPT_TYPE::LineTo, false);
 
             pDevice->DrawPath(&path, pUser2Device, nullptr,
-                              CPWL_Utils::PWLColorToFXColor(
-                                  PWL_DEFAULT_BLACKCOLOR, nTransparancy),
+                              PWL_DEFAULT_BLACKCOLOR.ToFXColor(nTransparency),
                               0, FXFILL_ALTERNATE);
           }
         } break;
         case PSBT_MAX: {
-          CFX_FloatPoint pt1(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f,
-                             ptCenter.y);
-          CFX_FloatPoint pt2(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f,
-                             ptCenter.y + PWL_TRIANGLE_HALFLEN);
-          CFX_FloatPoint pt3(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f,
-                             ptCenter.y - PWL_TRIANGLE_HALFLEN);
+          CFX_PointF pt1(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f, ptCenter.y);
+          CFX_PointF pt2(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f,
+                         ptCenter.y + PWL_TRIANGLE_HALFLEN);
+          CFX_PointF pt3(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f,
+                         ptCenter.y - PWL_TRIANGLE_HALFLEN);
 
           if (rectWnd.right - rectWnd.left > PWL_TRIANGLE_HALFLEN * 2 &&
               rectWnd.top - rectWnd.bottom > PWL_TRIANGLE_HALFLEN) {
             CFX_PathData path;
-
-            path.SetPointCount(4);
-            path.SetPoint(0, pt1.x, pt1.y, FXPT_MOVETO);
-            path.SetPoint(1, pt2.x, pt2.y, FXPT_LINETO);
-            path.SetPoint(2, pt3.x, pt3.y, FXPT_LINETO);
-            path.SetPoint(3, pt1.x, pt1.y, FXPT_LINETO);
+            path.AppendPoint(pt1, FXPT_TYPE::MoveTo, false);
+            path.AppendPoint(pt2, FXPT_TYPE::LineTo, false);
+            path.AppendPoint(pt3, FXPT_TYPE::LineTo, false);
+            path.AppendPoint(pt1, FXPT_TYPE::LineTo, false);
 
             pDevice->DrawPath(&path, pUser2Device, nullptr,
-                              CPWL_Utils::PWLColorToFXColor(
-                                  PWL_DEFAULT_BLACKCOLOR, nTransparancy),
+                              PWL_DEFAULT_BLACKCOLOR.ToFXColor(nTransparency),
                               0, FXFILL_ALTERNATE);
           }
         } break;
@@ -309,13 +297,13 @@
           // draw border
           CFX_FloatRect rcDraw = rectWnd;
           CPWL_Utils::DrawStrokeRect(pDevice, pUser2Device, rcDraw,
-                                     ArgbEncode(nTransparancy, 100, 100, 100),
+                                     ArgbEncode(nTransparency, 100, 100, 100),
                                      0.0f);
 
           // draw inner border
           rcDraw = CPWL_Utils::DeflateRect(rectWnd, 0.5f);
           CPWL_Utils::DrawStrokeRect(pDevice, pUser2Device, rcDraw,
-                                     ArgbEncode(nTransparancy, 255, 255, 255),
+                                     ArgbEncode(nTransparency, 255, 255, 255),
                                      1.0f);
 
           // draw background
@@ -324,7 +312,7 @@
 
           if (IsEnabled())
             CPWL_Utils::DrawShadow(pDevice, pUser2Device, true, false, rcDraw,
-                                   nTransparancy, 80, 220);
+                                   nTransparency, 80, 220);
           else
             CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcDraw,
                                      ArgbEncode(255, 255, 255, 255));
@@ -334,42 +322,42 @@
           if (rectWnd.top - rectWnd.bottom > 6.0f) {
             FX_FLOAT fX = rectWnd.left + 1.5f;
             FX_FLOAT fY = rectWnd.bottom;
-            CFX_FloatPoint pts[7] = {CFX_FloatPoint(fX + 2.5f, fY + 4.0f),
-                                     CFX_FloatPoint(fX + 2.5f, fY + 3.0f),
-                                     CFX_FloatPoint(fX + 4.5f, fY + 5.0f),
-                                     CFX_FloatPoint(fX + 6.5f, fY + 3.0f),
-                                     CFX_FloatPoint(fX + 6.5f, fY + 4.0f),
-                                     CFX_FloatPoint(fX + 4.5f, fY + 6.0f),
-                                     CFX_FloatPoint(fX + 2.5f, fY + 4.0f)};
+            CFX_PointF pts[7] = {CFX_PointF(fX + 2.5f, fY + 4.0f),
+                                 CFX_PointF(fX + 2.5f, fY + 3.0f),
+                                 CFX_PointF(fX + 4.5f, fY + 5.0f),
+                                 CFX_PointF(fX + 6.5f, fY + 3.0f),
+                                 CFX_PointF(fX + 6.5f, fY + 4.0f),
+                                 CFX_PointF(fX + 4.5f, fY + 6.0f),
+                                 CFX_PointF(fX + 2.5f, fY + 4.0f)};
 
             if (IsEnabled())
               CPWL_Utils::DrawFillArea(
                   pDevice, pUser2Device, pts, 7,
-                  ArgbEncode(nTransparancy, 255, 255, 255));
+                  ArgbEncode(nTransparency, 255, 255, 255));
             else
-              CPWL_Utils::DrawFillArea(pDevice, pUser2Device, pts, 7,
-                                       CPWL_Utils::PWLColorToFXColor(
-                                           PWL_DEFAULT_HEAVYGRAYCOLOR, 255));
+              CPWL_Utils::DrawFillArea(
+                  pDevice, pUser2Device, pts, 7,
+                  PWL_DEFAULT_HEAVYGRAYCOLOR.ToFXColor(255));
           }
         } break;
         case PSBT_MAX: {
           // draw border
           CFX_FloatRect rcDraw = rectWnd;
           CPWL_Utils::DrawStrokeRect(pDevice, pUser2Device, rcDraw,
-                                     ArgbEncode(nTransparancy, 100, 100, 100),
+                                     ArgbEncode(nTransparency, 100, 100, 100),
                                      0.0f);
 
           // draw inner border
           rcDraw = CPWL_Utils::DeflateRect(rectWnd, 0.5f);
           CPWL_Utils::DrawStrokeRect(pDevice, pUser2Device, rcDraw,
-                                     ArgbEncode(nTransparancy, 255, 255, 255),
+                                     ArgbEncode(nTransparency, 255, 255, 255),
                                      1.0f);
 
           // draw background
           rcDraw = CPWL_Utils::DeflateRect(rectWnd, 1.0f);
           if (IsEnabled())
             CPWL_Utils::DrawShadow(pDevice, pUser2Device, true, false, rcDraw,
-                                   nTransparancy, 80, 220);
+                                   nTransparency, 80, 220);
           else
             CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcDraw,
                                      ArgbEncode(255, 255, 255, 255));
@@ -380,113 +368,112 @@
             FX_FLOAT fX = rectWnd.left + 1.5f;
             FX_FLOAT fY = rectWnd.bottom;
 
-            CFX_FloatPoint pts[7] = {CFX_FloatPoint(fX + 2.5f, fY + 5.0f),
-                                     CFX_FloatPoint(fX + 2.5f, fY + 6.0f),
-                                     CFX_FloatPoint(fX + 4.5f, fY + 4.0f),
-                                     CFX_FloatPoint(fX + 6.5f, fY + 6.0f),
-                                     CFX_FloatPoint(fX + 6.5f, fY + 5.0f),
-                                     CFX_FloatPoint(fX + 4.5f, fY + 3.0f),
-                                     CFX_FloatPoint(fX + 2.5f, fY + 5.0f)};
+            CFX_PointF pts[7] = {CFX_PointF(fX + 2.5f, fY + 5.0f),
+                                 CFX_PointF(fX + 2.5f, fY + 6.0f),
+                                 CFX_PointF(fX + 4.5f, fY + 4.0f),
+                                 CFX_PointF(fX + 6.5f, fY + 6.0f),
+                                 CFX_PointF(fX + 6.5f, fY + 5.0f),
+                                 CFX_PointF(fX + 4.5f, fY + 3.0f),
+                                 CFX_PointF(fX + 2.5f, fY + 5.0f)};
 
             if (IsEnabled())
               CPWL_Utils::DrawFillArea(
                   pDevice, pUser2Device, pts, 7,
-                  ArgbEncode(nTransparancy, 255, 255, 255));
+                  ArgbEncode(nTransparency, 255, 255, 255));
             else
-              CPWL_Utils::DrawFillArea(pDevice, pUser2Device, pts, 7,
-                                       CPWL_Utils::PWLColorToFXColor(
-                                           PWL_DEFAULT_HEAVYGRAYCOLOR, 255));
+              CPWL_Utils::DrawFillArea(
+                  pDevice, pUser2Device, pts, 7,
+                  PWL_DEFAULT_HEAVYGRAYCOLOR.ToFXColor(255));
           }
         } break;
         case PSBT_POS: {
           // draw border
           CFX_FloatRect rcDraw = rectWnd;
           CPWL_Utils::DrawStrokeRect(pDevice, pUser2Device, rcDraw,
-                                     ArgbEncode(nTransparancy, 100, 100, 100),
+                                     ArgbEncode(nTransparency, 100, 100, 100),
                                      0.0f);
 
           // draw inner border
           rcDraw = CPWL_Utils::DeflateRect(rectWnd, 0.5f);
           CPWL_Utils::DrawStrokeRect(pDevice, pUser2Device, rcDraw,
-                                     ArgbEncode(nTransparancy, 255, 255, 255),
+                                     ArgbEncode(nTransparency, 255, 255, 255),
                                      1.0f);
 
           if (IsEnabled()) {
             // draw shadow effect
 
-            CFX_FloatPoint ptTop =
-                CFX_FloatPoint(rectWnd.left, rectWnd.top - 1.0f);
-            CFX_FloatPoint ptBottom =
-                CFX_FloatPoint(rectWnd.left, rectWnd.bottom + 1.0f);
+            CFX_PointF ptTop = CFX_PointF(rectWnd.left, rectWnd.top - 1.0f);
+            CFX_PointF ptBottom =
+                CFX_PointF(rectWnd.left, rectWnd.bottom + 1.0f);
 
             ptTop.x += 1.5f;
             ptBottom.x += 1.5f;
 
             CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparancy, 210, 210, 210),
+                                       ArgbEncode(nTransparency, 210, 210, 210),
                                        1.0f);
 
             ptTop.x += 1.0f;
             ptBottom.x += 1.0f;
 
             CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparancy, 220, 220, 220),
+                                       ArgbEncode(nTransparency, 220, 220, 220),
                                        1.0f);
 
             ptTop.x += 1.0f;
             ptBottom.x += 1.0f;
 
             CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparancy, 240, 240, 240),
+                                       ArgbEncode(nTransparency, 240, 240, 240),
                                        1.0f);
 
             ptTop.x += 1.0f;
             ptBottom.x += 1.0f;
 
             CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparancy, 240, 240, 240),
+                                       ArgbEncode(nTransparency, 240, 240, 240),
                                        1.0f);
 
             ptTop.x += 1.0f;
             ptBottom.x += 1.0f;
 
             CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparancy, 210, 210, 210),
+                                       ArgbEncode(nTransparency, 210, 210, 210),
                                        1.0f);
 
             ptTop.x += 1.0f;
             ptBottom.x += 1.0f;
 
             CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparancy, 180, 180, 180),
+                                       ArgbEncode(nTransparency, 180, 180, 180),
                                        1.0f);
 
             ptTop.x += 1.0f;
             ptBottom.x += 1.0f;
 
             CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparancy, 150, 150, 150),
+                                       ArgbEncode(nTransparency, 150, 150, 150),
                                        1.0f);
 
             ptTop.x += 1.0f;
             ptBottom.x += 1.0f;
 
             CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparancy, 150, 150, 150),
+                                       ArgbEncode(nTransparency, 150, 150, 150),
                                        1.0f);
 
             ptTop.x += 1.0f;
             ptBottom.x += 1.0f;
 
             CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparancy, 180, 180, 180),
+                                       ArgbEncode(nTransparency, 180, 180, 180),
                                        1.0f);
 
             ptTop.x += 1.0f;
             ptBottom.x += 1.0f;
 
             CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparancy, 210, 210, 210),
+                                       ArgbEncode(nTransparency, 210, 210, 210),
                                        1.0f);
           } else {
             CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcDraw,
@@ -496,20 +483,19 @@
           // draw friction
 
           if (rectWnd.Height() > 8.0f) {
-            FX_COLORREF crStroke = ArgbEncode(nTransparancy, 120, 120, 120);
+            FX_COLORREF crStroke = ArgbEncode(nTransparency, 120, 120, 120);
             if (!IsEnabled())
-              crStroke = CPWL_Utils::PWLColorToFXColor(
-                  PWL_DEFAULT_HEAVYGRAYCOLOR, 255);
+              crStroke = PWL_DEFAULT_HEAVYGRAYCOLOR.ToFXColor(255);
 
             FX_FLOAT nFrictionWidth = 5.0f;
             FX_FLOAT nFrictionHeight = 5.5f;
 
-            CFX_FloatPoint ptLeft =
-                CFX_FloatPoint(ptCenter.x - nFrictionWidth / 2.0f,
-                               ptCenter.y - nFrictionHeight / 2.0f + 0.5f);
-            CFX_FloatPoint ptRight =
-                CFX_FloatPoint(ptCenter.x + nFrictionWidth / 2.0f,
-                               ptCenter.y - nFrictionHeight / 2.0f + 0.5f);
+            CFX_PointF ptLeft =
+                CFX_PointF(ptCenter.x - nFrictionWidth / 2.0f,
+                           ptCenter.y - nFrictionHeight / 2.0f + 0.5f);
+            CFX_PointF ptRight =
+                CFX_PointF(ptCenter.x + nFrictionWidth / 2.0f,
+                           ptCenter.y - nFrictionHeight / 2.0f + 0.5f);
 
             CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptLeft, ptRight,
                                        crStroke, 1.0f);
@@ -536,7 +522,7 @@
   }
 }
 
-bool CPWL_SBButton::OnLButtonDown(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_SBButton::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonDown(point, nFlag);
 
   if (CPWL_Wnd* pParent = GetParentWindow())
@@ -548,7 +534,7 @@
   return true;
 }
 
-bool CPWL_SBButton::OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_SBButton::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonUp(point, nFlag);
 
   if (CPWL_Wnd* pParent = GetParentWindow())
@@ -560,7 +546,7 @@
   return true;
 }
 
-bool CPWL_SBButton::OnMouseMove(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_SBButton::OnMouseMove(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnMouseMove(point, nFlag);
 
   if (CPWL_Wnd* pParent = GetParentWindow()) {
@@ -683,20 +669,19 @@
 
     CPWL_Utils::DrawStrokeLine(
         pDevice, pUser2Device,
-        CFX_FloatPoint(rectWnd.left + 2.0f, rectWnd.top - 2.0f),
-        CFX_FloatPoint(rectWnd.left + 2.0f, rectWnd.bottom + 2.0f),
+        CFX_PointF(rectWnd.left + 2.0f, rectWnd.top - 2.0f),
+        CFX_PointF(rectWnd.left + 2.0f, rectWnd.bottom + 2.0f),
         ArgbEncode(GetTransparency(), 100, 100, 100), 1.0f);
 
     CPWL_Utils::DrawStrokeLine(
         pDevice, pUser2Device,
-        CFX_FloatPoint(rectWnd.right - 2.0f, rectWnd.top - 2.0f),
-        CFX_FloatPoint(rectWnd.right - 2.0f, rectWnd.bottom + 2.0f),
+        CFX_PointF(rectWnd.right - 2.0f, rectWnd.top - 2.0f),
+        CFX_PointF(rectWnd.right - 2.0f, rectWnd.bottom + 2.0f),
         ArgbEncode(GetTransparency(), 100, 100, 100), 1.0f);
   }
 }
 
-bool CPWL_ScrollBar::OnLButtonDown(const CFX_FloatPoint& point,
-                                   uint32_t nFlag) {
+bool CPWL_ScrollBar::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonDown(point, nFlag);
 
   if (HasFlag(PWS_AUTOTRANSPARENT)) {
@@ -735,13 +720,13 @@
     rcMinArea.Normalize();
     rcMaxArea.Normalize();
 
-    if (rcMinArea.Contains(point.x, point.y)) {
+    if (rcMinArea.Contains(point)) {
       m_sData.SubBig();
       MovePosButton(true);
       NotifyScrollWindow();
     }
 
-    if (rcMaxArea.Contains(point.x, point.y)) {
+    if (rcMaxArea.Contains(point)) {
       m_sData.AddBig();
       MovePosButton(true);
       NotifyScrollWindow();
@@ -751,12 +736,12 @@
   return true;
 }
 
-bool CPWL_ScrollBar::OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_ScrollBar::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonUp(point, nFlag);
 
   if (HasFlag(PWS_AUTOTRANSPARENT)) {
-    if (GetTransparency() != PWL_SCROLLBAR_TRANSPARANCY) {
-      SetTransparency(PWL_SCROLLBAR_TRANSPARANCY);
+    if (GetTransparency() != PWL_SCROLLBAR_TRANSPARENCY) {
+      SetTransparency(PWL_SCROLLBAR_TRANSPARENCY);
       InvalidateRect();
     }
   }
@@ -776,41 +761,41 @@
   switch (msg) {
     case PNM_LBUTTONDOWN:
       if (pWnd == m_pMinButton) {
-        OnMinButtonLBDown(*(CFX_FloatPoint*)lParam);
+        OnMinButtonLBDown(*(CFX_PointF*)lParam);
       }
 
       if (pWnd == m_pMaxButton) {
-        OnMaxButtonLBDown(*(CFX_FloatPoint*)lParam);
+        OnMaxButtonLBDown(*(CFX_PointF*)lParam);
       }
 
       if (pWnd == m_pPosButton) {
-        OnPosButtonLBDown(*(CFX_FloatPoint*)lParam);
+        OnPosButtonLBDown(*(CFX_PointF*)lParam);
       }
       break;
     case PNM_LBUTTONUP:
       if (pWnd == m_pMinButton) {
-        OnMinButtonLBUp(*(CFX_FloatPoint*)lParam);
+        OnMinButtonLBUp(*(CFX_PointF*)lParam);
       }
 
       if (pWnd == m_pMaxButton) {
-        OnMaxButtonLBUp(*(CFX_FloatPoint*)lParam);
+        OnMaxButtonLBUp(*(CFX_PointF*)lParam);
       }
 
       if (pWnd == m_pPosButton) {
-        OnPosButtonLBUp(*(CFX_FloatPoint*)lParam);
+        OnPosButtonLBUp(*(CFX_PointF*)lParam);
       }
       break;
     case PNM_MOUSEMOVE:
       if (pWnd == m_pMinButton) {
-        OnMinButtonMouseMove(*(CFX_FloatPoint*)lParam);
+        OnMinButtonMouseMove(*(CFX_PointF*)lParam);
       }
 
       if (pWnd == m_pMaxButton) {
-        OnMaxButtonMouseMove(*(CFX_FloatPoint*)lParam);
+        OnMaxButtonMouseMove(*(CFX_PointF*)lParam);
       }
 
       if (pWnd == m_pPosButton) {
-        OnPosButtonMouseMove(*(CFX_FloatPoint*)lParam);
+        OnPosButtonMouseMove(*(CFX_PointF*)lParam);
       }
       break;
     case PNM_SETSCROLLINFO: {
@@ -954,7 +939,7 @@
   }
 }
 
-void CPWL_ScrollBar::OnMinButtonLBDown(const CFX_FloatPoint& point) {
+void CPWL_ScrollBar::OnMinButtonLBDown(const CFX_PointF& point) {
   m_sData.SubSmall();
   MovePosButton(true);
   NotifyScrollWindow();
@@ -965,11 +950,11 @@
   BeginTimer(100);
 }
 
-void CPWL_ScrollBar::OnMinButtonLBUp(const CFX_FloatPoint& point) {}
+void CPWL_ScrollBar::OnMinButtonLBUp(const CFX_PointF& point) {}
 
-void CPWL_ScrollBar::OnMinButtonMouseMove(const CFX_FloatPoint& point) {}
+void CPWL_ScrollBar::OnMinButtonMouseMove(const CFX_PointF& point) {}
 
-void CPWL_ScrollBar::OnMaxButtonLBDown(const CFX_FloatPoint& point) {
+void CPWL_ScrollBar::OnMaxButtonLBDown(const CFX_PointF& point) {
   m_sData.AddSmall();
   MovePosButton(true);
   NotifyScrollWindow();
@@ -980,11 +965,11 @@
   BeginTimer(100);
 }
 
-void CPWL_ScrollBar::OnMaxButtonLBUp(const CFX_FloatPoint& point) {}
+void CPWL_ScrollBar::OnMaxButtonLBUp(const CFX_PointF& point) {}
 
-void CPWL_ScrollBar::OnMaxButtonMouseMove(const CFX_FloatPoint& point) {}
+void CPWL_ScrollBar::OnMaxButtonMouseMove(const CFX_PointF& point) {}
 
-void CPWL_ScrollBar::OnPosButtonLBDown(const CFX_FloatPoint& point) {
+void CPWL_ScrollBar::OnPosButtonLBDown(const CFX_PointF& point) {
   m_bMouseDown = true;
 
   if (m_pPosButton) {
@@ -1003,7 +988,7 @@
   }
 }
 
-void CPWL_ScrollBar::OnPosButtonLBUp(const CFX_FloatPoint& point) {
+void CPWL_ScrollBar::OnPosButtonLBUp(const CFX_PointF& point) {
   if (m_bMouseDown) {
     if (!m_bNotifyForever)
       NotifyScrollWindow();
@@ -1011,7 +996,7 @@
   m_bMouseDown = false;
 }
 
-void CPWL_ScrollBar::OnPosButtonMouseMove(const CFX_FloatPoint& point) {
+void CPWL_ScrollBar::OnPosButtonMouseMove(const CFX_PointF& point) {
   FX_FLOAT fOldScrollPos = m_sData.fScrollPos;
 
   FX_FLOAT fNewPos = 0;
diff --git a/fpdfsdk/pdfwindow/PWL_ScrollBar.h b/fpdfsdk/pdfwindow/PWL_ScrollBar.h
index bcfb0a6..9546a9e 100644
--- a/fpdfsdk/pdfwindow/PWL_ScrollBar.h
+++ b/fpdfsdk/pdfwindow/PWL_ScrollBar.h
@@ -53,9 +53,9 @@
   void GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) override;
   void DrawThisAppearance(CFX_RenderDevice* pDevice,
                           CFX_Matrix* pUser2Device) override;
-  bool OnLButtonDown(const CFX_FloatPoint& point, uint32_t nFlag) override;
-  bool OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) override;
-  bool OnMouseMove(const CFX_FloatPoint& point, uint32_t nFlag) override;
+  bool OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) override;
+  bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) override;
+  bool OnMouseMove(const CFX_PointF& point, uint32_t nFlag) override;
 
  protected:
   PWL_SCROLLBAR_TYPE m_eScrollBarType;
@@ -127,8 +127,8 @@
   void GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) override;
   void DrawThisAppearance(CFX_RenderDevice* pDevice,
                           CFX_Matrix* pUser2Device) override;
-  bool OnLButtonDown(const CFX_FloatPoint& point, uint32_t nFlag) override;
-  bool OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) override;
+  bool OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) override;
+  bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) override;
   void OnNotify(CPWL_Wnd* pWnd,
                 uint32_t msg,
                 intptr_t wParam = 0,
@@ -152,17 +152,17 @@
  private:
   void CreateButtons(const PWL_CREATEPARAM& cp);
 
-  void OnMinButtonLBDown(const CFX_FloatPoint& point);
-  void OnMinButtonLBUp(const CFX_FloatPoint& point);
-  void OnMinButtonMouseMove(const CFX_FloatPoint& point);
+  void OnMinButtonLBDown(const CFX_PointF& point);
+  void OnMinButtonLBUp(const CFX_PointF& point);
+  void OnMinButtonMouseMove(const CFX_PointF& point);
 
-  void OnMaxButtonLBDown(const CFX_FloatPoint& point);
-  void OnMaxButtonLBUp(const CFX_FloatPoint& point);
-  void OnMaxButtonMouseMove(const CFX_FloatPoint& point);
+  void OnMaxButtonLBDown(const CFX_PointF& point);
+  void OnMaxButtonLBUp(const CFX_PointF& point);
+  void OnMaxButtonMouseMove(const CFX_PointF& point);
 
-  void OnPosButtonLBDown(const CFX_FloatPoint& point);
-  void OnPosButtonLBUp(const CFX_FloatPoint& point);
-  void OnPosButtonMouseMove(const CFX_FloatPoint& point);
+  void OnPosButtonLBDown(const CFX_PointF& point);
+  void OnPosButtonLBUp(const CFX_PointF& point);
+  void OnPosButtonMouseMove(const CFX_PointF& point);
 
   FX_FLOAT TrueToFace(FX_FLOAT);
   FX_FLOAT FaceToTrue(FX_FLOAT);
diff --git a/fpdfsdk/pdfwindow/PWL_SpecialButton.cpp b/fpdfsdk/pdfwindow/PWL_SpecialButton.cpp
index defb992..1c46c37 100644
--- a/fpdfsdk/pdfwindow/PWL_SpecialButton.cpp
+++ b/fpdfsdk/pdfwindow/PWL_SpecialButton.cpp
@@ -37,7 +37,7 @@
   return m_bChecked;
 }
 
-bool CPWL_CheckBox::OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) {
+bool CPWL_CheckBox::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
   if (IsReadOnly())
     return false;
 
@@ -58,8 +58,7 @@
   return "CPWL_RadioButton";
 }
 
-bool CPWL_RadioButton::OnLButtonUp(const CFX_FloatPoint& point,
-                                   uint32_t nFlag) {
+bool CPWL_RadioButton::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
   if (IsReadOnly())
     return false;
 
diff --git a/fpdfsdk/pdfwindow/PWL_SpecialButton.h b/fpdfsdk/pdfwindow/PWL_SpecialButton.h
index 0aa6c45..93f611b 100644
--- a/fpdfsdk/pdfwindow/PWL_SpecialButton.h
+++ b/fpdfsdk/pdfwindow/PWL_SpecialButton.h
@@ -26,7 +26,7 @@
 
   // CPWL_Button
   CFX_ByteString GetClassName() const override;
-  bool OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) override;
+  bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) override;
   bool OnChar(uint16_t nChar, uint32_t nFlag) override;
 
   void SetCheck(bool bCheck);
@@ -43,7 +43,7 @@
 
   // CPWL_Button
   CFX_ByteString GetClassName() const override;
-  bool OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag) override;
+  bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) override;
   bool OnChar(uint16_t nChar, uint32_t nFlag) override;
 
   void SetCheck(bool bCheck);
diff --git a/fpdfsdk/pdfwindow/PWL_Utils.cpp b/fpdfsdk/pdfwindow/PWL_Utils.cpp
index 713a193..45668b6 100644
--- a/fpdfsdk/pdfwindow/PWL_Utils.cpp
+++ b/fpdfsdk/pdfwindow/PWL_Utils.cpp
@@ -17,71 +17,6 @@
 #include "fpdfsdk/pdfwindow/PWL_Icon.h"
 #include "fpdfsdk/pdfwindow/PWL_Wnd.h"
 
-CFX_ByteString CPWL_Utils::GetAppStreamFromArray(const CPWL_PathData* pPathData,
-                                                 int32_t nCount) {
-  CFX_ByteTextBuf csAP;
-
-  for (int32_t i = 0; i < nCount; i++) {
-    switch (pPathData[i].type) {
-      case PWLPT_MOVETO:
-        csAP << pPathData[i].point.x << " " << pPathData[i].point.y << " m\n";
-        break;
-      case PWLPT_LINETO:
-        csAP << pPathData[i].point.x << " " << pPathData[i].point.y << " l\n";
-        break;
-      case PWLPT_BEZIERTO:
-        csAP << pPathData[i].point.x << " " << pPathData[i].point.y << " "
-             << pPathData[i + 1].point.x << " " << pPathData[i + 1].point.y
-             << " " << pPathData[i + 2].point.x << " "
-             << pPathData[i + 2].point.y << " c\n";
-
-        i += 2;
-        break;
-      default:
-        break;
-    }
-  }
-
-  return csAP.MakeString();
-}
-
-void CPWL_Utils::GetPathDataFromArray(CFX_PathData& path,
-                                      const CPWL_PathData* pPathData,
-                                      int32_t nCount) {
-  path.SetPointCount(nCount);
-
-  for (int32_t i = 0; i < nCount; i++) {
-    switch (pPathData[i].type) {
-      case PWLPT_MOVETO:
-        path.SetPoint(i, pPathData[i].point.x, pPathData[i].point.y,
-                      FXPT_MOVETO);
-        break;
-      case PWLPT_LINETO:
-        path.SetPoint(i, pPathData[i].point.x, pPathData[i].point.y,
-                      FXPT_LINETO);
-        break;
-      case PWLPT_BEZIERTO:
-        path.SetPoint(i, pPathData[i].point.x, pPathData[i].point.y,
-                      FXPT_BEZIERTO);
-        break;
-      default:
-        break;
-    }
-  }
-}
-
-CFX_FloatRect CPWL_Utils::MaxRect(const CFX_FloatRect& rect1,
-                                  const CFX_FloatRect& rect2) {
-  CFX_FloatRect rcRet;
-
-  rcRet.left = PWL_MIN(rect1.left, rect2.left);
-  rcRet.bottom = PWL_MIN(rect1.bottom, rect2.bottom);
-  rcRet.right = PWL_MAX(rect1.right, rect2.right);
-  rcRet.top = PWL_MAX(rect1.top, rect2.top);
-
-  return rcRet;
-}
-
 CFX_FloatRect CPWL_Utils::OffsetRect(const CFX_FloatRect& rect,
                                      FX_FLOAT x,
                                      FX_FLOAT y) {
@@ -89,28 +24,6 @@
                        rect.top + y);
 }
 
-bool CPWL_Utils::ContainsRect(const CFX_FloatRect& rcParent,
-                              const CFX_FloatRect& rcChild) {
-  return rcChild.left >= rcParent.left && rcChild.bottom >= rcParent.bottom &&
-         rcChild.right <= rcParent.right && rcChild.top <= rcParent.top;
-}
-
-bool CPWL_Utils::IntersectRect(const CFX_FloatRect& rect1,
-                               const CFX_FloatRect& rect2) {
-  FX_FLOAT left = rect1.left > rect2.left ? rect1.left : rect2.left;
-  FX_FLOAT right = rect1.right < rect2.right ? rect1.right : rect2.right;
-  FX_FLOAT bottom = rect1.bottom > rect2.bottom ? rect1.bottom : rect2.bottom;
-  FX_FLOAT top = rect1.top < rect2.top ? rect1.top : rect2.top;
-
-  return left < right && bottom < top;
-}
-
-CFX_FloatPoint CPWL_Utils::OffsetPoint(const CFX_FloatPoint& point,
-                                       FX_FLOAT x,
-                                       FX_FLOAT y) {
-  return CFX_FloatPoint(point.x + x, point.y + y);
-}
-
 CPVT_WordRange CPWL_Utils::OverlapWordRange(const CPVT_WordRange& wr1,
                                             const CPVT_WordRange& wr2) {
   CPVT_WordRange wrRet;
@@ -141,22 +54,22 @@
   const FX_FLOAT fWidth = crBBox.right - crBBox.left;
   const FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
 
-  CPWL_Point pts[8][3] = {{CPWL_Point(0.28f, 0.52f), CPWL_Point(0.27f, 0.48f),
-                           CPWL_Point(0.29f, 0.40f)},
-                          {CPWL_Point(0.30f, 0.33f), CPWL_Point(0.31f, 0.29f),
-                           CPWL_Point(0.31f, 0.28f)},
-                          {CPWL_Point(0.39f, 0.28f), CPWL_Point(0.49f, 0.29f),
-                           CPWL_Point(0.77f, 0.67f)},
-                          {CPWL_Point(0.76f, 0.68f), CPWL_Point(0.78f, 0.69f),
-                           CPWL_Point(0.76f, 0.75f)},
-                          {CPWL_Point(0.76f, 0.75f), CPWL_Point(0.73f, 0.80f),
-                           CPWL_Point(0.68f, 0.75f)},
-                          {CPWL_Point(0.68f, 0.74f), CPWL_Point(0.68f, 0.74f),
-                           CPWL_Point(0.44f, 0.47f)},
-                          {CPWL_Point(0.43f, 0.47f), CPWL_Point(0.40f, 0.47f),
-                           CPWL_Point(0.41f, 0.58f)},
-                          {CPWL_Point(0.40f, 0.60f), CPWL_Point(0.28f, 0.66f),
-                           CPWL_Point(0.30f, 0.56f)}};
+  CFX_PointF pts[8][3] = {{CFX_PointF(0.28f, 0.52f), CFX_PointF(0.27f, 0.48f),
+                           CFX_PointF(0.29f, 0.40f)},
+                          {CFX_PointF(0.30f, 0.33f), CFX_PointF(0.31f, 0.29f),
+                           CFX_PointF(0.31f, 0.28f)},
+                          {CFX_PointF(0.39f, 0.28f), CFX_PointF(0.49f, 0.29f),
+                           CFX_PointF(0.77f, 0.67f)},
+                          {CFX_PointF(0.76f, 0.68f), CFX_PointF(0.78f, 0.69f),
+                           CFX_PointF(0.76f, 0.75f)},
+                          {CFX_PointF(0.76f, 0.75f), CFX_PointF(0.73f, 0.80f),
+                           CFX_PointF(0.68f, 0.75f)},
+                          {CFX_PointF(0.68f, 0.74f), CFX_PointF(0.68f, 0.74f),
+                           CFX_PointF(0.44f, 0.47f)},
+                          {CFX_PointF(0.43f, 0.47f), CFX_PointF(0.40f, 0.47f),
+                           CFX_PointF(0.41f, 0.58f)},
+                          {CFX_PointF(0.40f, 0.60f), CFX_PointF(0.28f, 0.66f),
+                           CFX_PointF(0.30f, 0.56f)}};
 
   for (size_t i = 0; i < FX_ArraySize(pts); ++i) {
     for (size_t j = 0; j < FX_ArraySize(pts[0]); ++j) {
@@ -192,10 +105,10 @@
   FX_FLOAT fWidth = crBBox.right - crBBox.left;
   FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
 
-  CFX_FloatPoint pt1(crBBox.left, crBBox.bottom + fHeight / 2);
-  CFX_FloatPoint pt2(crBBox.left + fWidth / 2, crBBox.top);
-  CFX_FloatPoint pt3(crBBox.right, crBBox.bottom + fHeight / 2);
-  CFX_FloatPoint pt4(crBBox.left + fWidth / 2, crBBox.bottom);
+  CFX_PointF pt1(crBBox.left, crBBox.bottom + fHeight / 2);
+  CFX_PointF pt2(crBBox.left + fWidth / 2, crBBox.top);
+  CFX_PointF pt3(crBBox.right, crBBox.bottom + fHeight / 2);
+  CFX_PointF pt4(crBBox.left + fWidth / 2, crBBox.bottom);
 
   csAP << pt1.x << " " << pt1.y << " m\n";
 
@@ -245,10 +158,10 @@
   FX_FLOAT fWidth = crBBox.right - crBBox.left;
   FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
 
-  CFX_FloatPoint pt1(crBBox.left, crBBox.bottom + fHeight / 2);
-  CFX_FloatPoint pt2(crBBox.left + fWidth / 2, crBBox.top);
-  CFX_FloatPoint pt3(crBBox.right, crBBox.bottom + fHeight / 2);
-  CFX_FloatPoint pt4(crBBox.left + fWidth / 2, crBBox.bottom);
+  CFX_PointF pt1(crBBox.left, crBBox.bottom + fHeight / 2);
+  CFX_PointF pt2(crBBox.left + fWidth / 2, crBBox.top);
+  CFX_PointF pt3(crBBox.right, crBBox.bottom + fHeight / 2);
+  CFX_PointF pt4(crBBox.left + fWidth / 2, crBBox.bottom);
 
   csAP << pt1.x << " " << pt1.y << " m\n";
   csAP << pt2.x << " " << pt2.y << " l\n";
@@ -276,8 +189,8 @@
 
   FX_FLOAT fRadius =
       (crBBox.top - crBBox.bottom) / (1 + (FX_FLOAT)cos(FX_PI / 5.0f));
-  CFX_FloatPoint ptCenter = CFX_FloatPoint((crBBox.left + crBBox.right) / 2.0f,
-                                           (crBBox.top + crBBox.bottom) / 2.0f);
+  CFX_PointF ptCenter = CFX_PointF((crBBox.left + crBBox.right) / 2.0f,
+                                   (crBBox.top + crBBox.bottom) / 2.0f);
 
   FX_FLOAT px[5], py[5];
 
@@ -310,9 +223,9 @@
   FX_FLOAT fWidth = crBBox.right - crBBox.left;
   FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
 
-  CFX_FloatPoint pt1(-fWidth / 2, 0);
-  CFX_FloatPoint pt2(0, fHeight / 2);
-  CFX_FloatPoint pt3(fWidth / 2, 0);
+  CFX_PointF pt1(-fWidth / 2, 0);
+  CFX_PointF pt2(0, fHeight / 2);
+  CFX_PointF pt3(fWidth / 2, 0);
 
   FX_FLOAT px, py;
 
@@ -365,8 +278,8 @@
   FX_FLOAT fHalfWidth = (rcRect.right - rcRect.left) / 2.0f;
   FX_FLOAT fHalfHeight = (rcRect.top - rcRect.bottom) / 2.0f;
 
-  CFX_FloatPoint ptCenter = CFX_FloatPoint((rcRect.left + rcRect.right) / 2,
-                                           (rcRect.top + rcRect.bottom) / 2);
+  CFX_PointF ptCenter = CFX_PointF((rcRect.left + rcRect.right) / 2,
+                                   (rcRect.top + rcRect.bottom) / 2);
 
   return CFX_FloatRect(
       ptCenter.x - fHalfWidth * fScale, ptCenter.y - fHalfHeight * fScale,
@@ -411,7 +324,7 @@
 }
 
 CFX_ByteString CPWL_Utils::GetEditAppStream(CFX_Edit* pEdit,
-                                            const CFX_FloatPoint& ptOffset,
+                                            const CFX_PointF& ptOffset,
                                             const CPVT_WordRange* pRange,
                                             bool bContinuous,
                                             uint16_t SubWord) {
@@ -420,45 +333,11 @@
 }
 
 CFX_ByteString CPWL_Utils::GetEditSelAppStream(CFX_Edit* pEdit,
-                                               const CFX_FloatPoint& ptOffset,
+                                               const CFX_PointF& ptOffset,
                                                const CPVT_WordRange* pRange) {
   return CFX_Edit::GetSelectAppearanceStream(pEdit, ptOffset, pRange);
 }
 
-CFX_ByteString CPWL_Utils::GetTextAppStream(const CFX_FloatRect& rcBBox,
-                                            IPVT_FontMap* pFontMap,
-                                            const CFX_WideString& sText,
-                                            int32_t nAlignmentH,
-                                            int32_t nAlignmentV,
-                                            FX_FLOAT fFontSize,
-                                            bool bMultiLine,
-                                            bool bAutoReturn,
-                                            const CPWL_Color& crText) {
-  CFX_ByteTextBuf sRet;
-
-  std::unique_ptr<CFX_Edit> pEdit(new CFX_Edit);
-  pEdit->SetFontMap(pFontMap);
-  pEdit->SetPlateRect(rcBBox);
-  pEdit->SetAlignmentH(nAlignmentH, true);
-  pEdit->SetAlignmentV(nAlignmentV, true);
-  pEdit->SetMultiLine(bMultiLine, true);
-  pEdit->SetAutoReturn(bAutoReturn, true);
-  if (IsFloatZero(fFontSize))
-    pEdit->SetAutoFontSize(true, true);
-  else
-    pEdit->SetFontSize(fFontSize);
-
-  pEdit->Initialize();
-  pEdit->SetText(sText);
-
-  CFX_ByteString sEdit =
-      CPWL_Utils::GetEditAppStream(pEdit.get(), CFX_FloatPoint(0.0f, 0.0f));
-  if (sEdit.GetLength() > 0)
-    sRet << "BT\n" << CPWL_Utils::GetColorAppStream(crText) << sEdit << "ET\n";
-
-  return sRet.MakeString();
-}
-
 CFX_ByteString CPWL_Utils::GetPushButtonAppStream(const CFX_FloatRect& rcBBox,
                                                   IPVT_FontMap* pFontMap,
                                                   CPDF_Stream* pIconStream,
@@ -664,7 +543,7 @@
   if (!rcLabel.IsEmpty()) {
     pEdit->SetPlateRect(rcLabel);
     CFX_ByteString sEdit =
-        CPWL_Utils::GetEditAppStream(pEdit.get(), CFX_FloatPoint(0.0f, 0.0f));
+        CPWL_Utils::GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, 0.0f));
     if (sEdit.GetLength() > 0) {
       sTemp << "BT\n"
             << CPWL_Utils::GetColorAppStream(crText) << sEdit << "ET\n";
@@ -920,57 +799,6 @@
   return sAppStream.MakeString();
 }
 
-CPWL_Color CPWL_Utils::SubstractColor(const CPWL_Color& sColor,
-                                      FX_FLOAT fColorSub) {
-  CPWL_Color sRet;
-  sRet.nColorType = sColor.nColorType;
-
-  switch (sColor.nColorType) {
-    case COLORTYPE_TRANSPARENT:
-      sRet.nColorType = COLORTYPE_RGB;
-      sRet.fColor1 = PWL_MAX(1 - fColorSub, 0.0f);
-      sRet.fColor2 = PWL_MAX(1 - fColorSub, 0.0f);
-      sRet.fColor3 = PWL_MAX(1 - fColorSub, 0.0f);
-      break;
-    case COLORTYPE_RGB:
-    case COLORTYPE_GRAY:
-    case COLORTYPE_CMYK:
-      sRet.fColor1 = PWL_MAX(sColor.fColor1 - fColorSub, 0.0f);
-      sRet.fColor2 = PWL_MAX(sColor.fColor2 - fColorSub, 0.0f);
-      sRet.fColor3 = PWL_MAX(sColor.fColor3 - fColorSub, 0.0f);
-      sRet.fColor4 = PWL_MAX(sColor.fColor4 - fColorSub, 0.0f);
-      break;
-  }
-
-  return sRet;
-}
-
-CPWL_Color CPWL_Utils::DevideColor(const CPWL_Color& sColor,
-                                   FX_FLOAT fColorDevide) {
-  CPWL_Color sRet;
-  sRet.nColorType = sColor.nColorType;
-
-  switch (sColor.nColorType) {
-    case COLORTYPE_TRANSPARENT:
-      sRet.nColorType = COLORTYPE_RGB;
-      sRet.fColor1 = 1 / fColorDevide;
-      sRet.fColor2 = 1 / fColorDevide;
-      sRet.fColor3 = 1 / fColorDevide;
-      break;
-    case COLORTYPE_RGB:
-    case COLORTYPE_GRAY:
-    case COLORTYPE_CMYK:
-      sRet = sColor;
-      sRet.fColor1 /= fColorDevide;
-      sRet.fColor2 /= fColorDevide;
-      sRet.fColor3 /= fColorDevide;
-      sRet.fColor4 /= fColorDevide;
-      break;
-  }
-
-  return sRet;
-}
-
 CFX_ByteString CPWL_Utils::GetAppStream_Check(const CFX_FloatRect& rcBBox,
                                               const CPWL_Color& crText) {
   CFX_ByteTextBuf sAP;
@@ -1089,8 +917,8 @@
                       CPWL_Dash(3, 0, 0))
                << "Q\n";
 
-    CFX_FloatPoint ptCenter = CFX_FloatPoint((rcBBox.left + rcBBox.right) / 2,
-                                             (rcBBox.top + rcBBox.bottom) / 2);
+    CFX_PointF ptCenter = CFX_PointF((rcBBox.left + rcBBox.right) / 2,
+                                     (rcBBox.top + rcBBox.bottom) / 2);
     if (IsFloatBigger(rcBBox.right - rcBBox.left, 6) &&
         IsFloatBigger(rcBBox.top - rcBBox.bottom, 6)) {
       sAppStream << "q\n"
@@ -1106,118 +934,6 @@
   return sAppStream.MakeString();
 }
 
-void CPWL_Utils::ConvertCMYK2GRAY(FX_FLOAT dC,
-                                  FX_FLOAT dM,
-                                  FX_FLOAT dY,
-                                  FX_FLOAT dK,
-                                  FX_FLOAT& dGray) {
-  if (dC < 0 || dC > 1 || dM < 0 || dM > 1 || dY < 0 || dY > 1 || dK < 0 ||
-      dK > 1)
-    return;
-  dGray = 1.0f - std::min(1.0f, 0.3f * dC + 0.59f * dM + 0.11f * dY + dK);
-}
-
-void CPWL_Utils::ConvertGRAY2CMYK(FX_FLOAT dGray,
-                                  FX_FLOAT& dC,
-                                  FX_FLOAT& dM,
-                                  FX_FLOAT& dY,
-                                  FX_FLOAT& dK) {
-  if (dGray < 0 || dGray > 1)
-    return;
-  dC = 0.0f;
-  dM = 0.0f;
-  dY = 0.0f;
-  dK = 1.0f - dGray;
-}
-
-void CPWL_Utils::ConvertGRAY2RGB(FX_FLOAT dGray,
-                                 FX_FLOAT& dR,
-                                 FX_FLOAT& dG,
-                                 FX_FLOAT& dB) {
-  if (dGray < 0 || dGray > 1)
-    return;
-  dR = dGray;
-  dG = dGray;
-  dB = dGray;
-}
-
-void CPWL_Utils::ConvertRGB2GRAY(FX_FLOAT dR,
-                                 FX_FLOAT dG,
-                                 FX_FLOAT dB,
-                                 FX_FLOAT& dGray) {
-  if (dR < 0 || dR > 1 || dG < 0 || dG > 0 || dB < 0 || dB > 1)
-    return;
-  dGray = 0.3f * dR + 0.59f * dG + 0.11f * dB;
-}
-
-void CPWL_Utils::ConvertCMYK2RGB(FX_FLOAT dC,
-                                 FX_FLOAT dM,
-                                 FX_FLOAT dY,
-                                 FX_FLOAT dK,
-                                 FX_FLOAT& dR,
-                                 FX_FLOAT& dG,
-                                 FX_FLOAT& dB) {
-  if (dC < 0 || dC > 1 || dM < 0 || dM > 1 || dY < 0 || dY > 1 || dK < 0 ||
-      dK > 1)
-    return;
-  dR = 1.0f - std::min(1.0f, dC + dK);
-  dG = 1.0f - std::min(1.0f, dM + dK);
-  dB = 1.0f - std::min(1.0f, dY + dK);
-}
-
-void CPWL_Utils::ConvertRGB2CMYK(FX_FLOAT dR,
-                                 FX_FLOAT dG,
-                                 FX_FLOAT dB,
-                                 FX_FLOAT& dC,
-                                 FX_FLOAT& dM,
-                                 FX_FLOAT& dY,
-                                 FX_FLOAT& dK) {
-  if (dR < 0 || dR > 1 || dG < 0 || dG > 1 || dB < 0 || dB > 1)
-    return;
-
-  dC = 1.0f - dR;
-  dM = 1.0f - dG;
-  dY = 1.0f - dB;
-  dK = std::min(dC, std::min(dM, dY));
-}
-
-void CPWL_Utils::PWLColorToARGB(const CPWL_Color& color,
-                                int32_t& alpha,
-                                FX_FLOAT& red,
-                                FX_FLOAT& green,
-                                FX_FLOAT& blue) {
-  switch (color.nColorType) {
-    case COLORTYPE_TRANSPARENT: {
-      alpha = 0;
-    } break;
-    case COLORTYPE_GRAY: {
-      ConvertGRAY2RGB(color.fColor1, red, green, blue);
-    } break;
-    case COLORTYPE_RGB: {
-      red = color.fColor1;
-      green = color.fColor2;
-      blue = color.fColor3;
-    } break;
-    case COLORTYPE_CMYK: {
-      ConvertCMYK2RGB(color.fColor1, color.fColor2, color.fColor3,
-                      color.fColor4, red, green, blue);
-    } break;
-  }
-}
-
-FX_COLORREF CPWL_Utils::PWLColorToFXColor(const CPWL_Color& color,
-                                          int32_t nTransparancy) {
-  int32_t nAlpha = nTransparancy;
-  FX_FLOAT dRed = 0;
-  FX_FLOAT dGreen = 0;
-  FX_FLOAT dBlue = 0;
-
-  PWLColorToARGB(color, nAlpha, dRed, dGreen, dBlue);
-
-  return ArgbEncode(nAlpha, (int32_t)(dRed * 255), (int32_t)(dGreen * 255),
-                    (int32_t)(dBlue * 255));
-}
-
 void CPWL_Utils::DrawFillRect(CFX_RenderDevice* pDevice,
                               CFX_Matrix* pUser2Device,
                               const CFX_FloatRect& rect,
@@ -1230,15 +946,13 @@
 
 void CPWL_Utils::DrawFillArea(CFX_RenderDevice* pDevice,
                               CFX_Matrix* pUser2Device,
-                              const CFX_FloatPoint* pPts,
+                              const CFX_PointF* pPts,
                               int32_t nCount,
                               const FX_COLORREF& color) {
   CFX_PathData path;
-  path.SetPointCount(nCount);
-
-  path.SetPoint(0, pPts[0].x, pPts[0].y, FXPT_MOVETO);
+  path.AppendPoint(pPts[0], FXPT_TYPE::MoveTo, false);
   for (int32_t i = 1; i < nCount; i++)
-    path.SetPoint(i, pPts[i].x, pPts[i].y, FXPT_LINETO);
+    path.AppendPoint(pPts[i], FXPT_TYPE::LineTo, false);
 
   pDevice->DrawPath(&path, pUser2Device, nullptr, color, 0, FXFILL_ALTERNATE);
 }
@@ -1260,14 +974,13 @@
 
 void CPWL_Utils::DrawStrokeLine(CFX_RenderDevice* pDevice,
                                 CFX_Matrix* pUser2Device,
-                                const CFX_FloatPoint& ptMoveTo,
-                                const CFX_FloatPoint& ptLineTo,
+                                const CFX_PointF& ptMoveTo,
+                                const CFX_PointF& ptLineTo,
                                 const FX_COLORREF& color,
                                 FX_FLOAT fWidth) {
   CFX_PathData path;
-  path.SetPointCount(2);
-  path.SetPoint(0, ptMoveTo.x, ptMoveTo.y, FXPT_MOVETO);
-  path.SetPoint(1, ptLineTo.x, ptLineTo.y, FXPT_LINETO);
+  path.AppendPoint(ptMoveTo, FXPT_TYPE::MoveTo, false);
+  path.AppendPoint(ptLineTo, FXPT_TYPE::LineTo, false);
 
   CFX_GraphStateData gsd;
   gsd.m_LineWidth = fWidth;
@@ -1279,9 +992,9 @@
                               CFX_Matrix* pUser2Device,
                               const CFX_FloatRect& rect,
                               const CPWL_Color& color,
-                              int32_t nTransparancy) {
+                              int32_t nTransparency) {
   CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rect,
-                           PWLColorToFXColor(color, nTransparancy));
+                           color.ToFXColor(nTransparency));
 }
 
 void CPWL_Utils::DrawShadow(CFX_RenderDevice* pDevice,
@@ -1289,7 +1002,7 @@
                             bool bVertical,
                             bool bHorizontal,
                             CFX_FloatRect rect,
-                            int32_t nTransparancy,
+                            int32_t nTransparency,
                             int32_t nStartGray,
                             int32_t nEndGray) {
   FX_FLOAT fStepGray = 1.0f;
@@ -1300,9 +1013,9 @@
     for (FX_FLOAT fy = rect.bottom + 0.5f; fy <= rect.top - 0.5f; fy += 1.0f) {
       int32_t nGray = nStartGray + (int32_t)(fStepGray * (fy - rect.bottom));
       CPWL_Utils::DrawStrokeLine(
-          pDevice, pUser2Device, CFX_FloatPoint(rect.left, fy),
-          CFX_FloatPoint(rect.right, fy),
-          ArgbEncode(nTransparancy, nGray, nGray, nGray), 1.5f);
+          pDevice, pUser2Device, CFX_PointF(rect.left, fy),
+          CFX_PointF(rect.right, fy),
+          ArgbEncode(nTransparency, nGray, nGray, nGray), 1.5f);
     }
   }
 
@@ -1312,9 +1025,9 @@
     for (FX_FLOAT fx = rect.left + 0.5f; fx <= rect.right - 0.5f; fx += 1.0f) {
       int32_t nGray = nStartGray + (int32_t)(fStepGray * (fx - rect.left));
       CPWL_Utils::DrawStrokeLine(
-          pDevice, pUser2Device, CFX_FloatPoint(fx, rect.bottom),
-          CFX_FloatPoint(fx, rect.top),
-          ArgbEncode(nTransparancy, nGray, nGray, nGray), 1.5f);
+          pDevice, pUser2Device, CFX_PointF(fx, rect.bottom),
+          CFX_PointF(fx, rect.top),
+          ArgbEncode(nTransparency, nGray, nGray, nGray), 1.5f);
     }
   }
 }
@@ -1327,7 +1040,7 @@
                             const CPWL_Color& crLeftTop,
                             const CPWL_Color& crRightBottom,
                             BorderStyle nStyle,
-                            int32_t nTransparancy) {
+                            int32_t nTransparency) {
   FX_FLOAT fLeft = rect.left;
   FX_FLOAT fRight = rect.right;
   FX_FLOAT fTop = rect.top;
@@ -1344,24 +1057,26 @@
         path.AppendRect(fLeft + fWidth, fBottom + fWidth, fRight - fWidth,
                         fTop - fWidth);
         pDevice->DrawPath(&path, pUser2Device, nullptr,
-                          PWLColorToFXColor(color, nTransparancy), 0,
-                          FXFILL_ALTERNATE);
+                          color.ToFXColor(nTransparency), 0, FXFILL_ALTERNATE);
         break;
       }
       case BorderStyle::DASH: {
         CFX_PathData path;
-
-        path.SetPointCount(5);
-        path.SetPoint(0, fLeft + fWidth / 2.0f, fBottom + fWidth / 2.0f,
-                      FXPT_MOVETO);
-        path.SetPoint(1, fLeft + fWidth / 2.0f, fTop - fWidth / 2.0f,
-                      FXPT_LINETO);
-        path.SetPoint(2, fRight - fWidth / 2.0f, fTop - fWidth / 2.0f,
-                      FXPT_LINETO);
-        path.SetPoint(3, fRight - fWidth / 2.0f, fBottom + fWidth / 2.0f,
-                      FXPT_LINETO);
-        path.SetPoint(4, fLeft + fWidth / 2.0f, fBottom + fWidth / 2.0f,
-                      FXPT_LINETO);
+        path.AppendPoint(
+            CFX_PointF(fLeft + fWidth / 2.0f, fBottom + fWidth / 2.0f),
+            FXPT_TYPE::MoveTo, false);
+        path.AppendPoint(
+            CFX_PointF(fLeft + fWidth / 2.0f, fTop - fWidth / 2.0f),
+            FXPT_TYPE::LineTo, false);
+        path.AppendPoint(
+            CFX_PointF(fRight - fWidth / 2.0f, fTop - fWidth / 2.0f),
+            FXPT_TYPE::LineTo, false);
+        path.AppendPoint(
+            CFX_PointF(fRight - fWidth / 2.0f, fBottom + fWidth / 2.0f),
+            FXPT_TYPE::LineTo, false);
+        path.AppendPoint(
+            CFX_PointF(fLeft + fWidth / 2.0f, fBottom + fWidth / 2.0f),
+            FXPT_TYPE::LineTo, false);
 
         CFX_GraphStateData gsd;
         gsd.SetDashCount(2);
@@ -1371,8 +1086,7 @@
 
         gsd.m_LineWidth = fWidth;
         pDevice->DrawPath(&path, pUser2Device, &gsd, 0,
-                          PWLColorToFXColor(color, nTransparancy),
-                          FXFILL_WINDING);
+                          color.ToFXColor(nTransparency), FXFILL_WINDING);
         break;
       }
       case BorderStyle::BEVELED:
@@ -1382,42 +1096,50 @@
 
         CFX_PathData pathLT;
 
-        pathLT.SetPointCount(7);
-        pathLT.SetPoint(0, fLeft + fHalfWidth, fBottom + fHalfWidth,
-                        FXPT_MOVETO);
-        pathLT.SetPoint(1, fLeft + fHalfWidth, fTop - fHalfWidth, FXPT_LINETO);
-        pathLT.SetPoint(2, fRight - fHalfWidth, fTop - fHalfWidth, FXPT_LINETO);
-        pathLT.SetPoint(3, fRight - fHalfWidth * 2, fTop - fHalfWidth * 2,
-                        FXPT_LINETO);
-        pathLT.SetPoint(4, fLeft + fHalfWidth * 2, fTop - fHalfWidth * 2,
-                        FXPT_LINETO);
-        pathLT.SetPoint(5, fLeft + fHalfWidth * 2, fBottom + fHalfWidth * 2,
-                        FXPT_LINETO);
-        pathLT.SetPoint(6, fLeft + fHalfWidth, fBottom + fHalfWidth,
-                        FXPT_LINETO);
+        pathLT.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth),
+                           FXPT_TYPE::MoveTo, false);
+        pathLT.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fTop - fHalfWidth),
+                           FXPT_TYPE::LineTo, false);
+        pathLT.AppendPoint(CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth),
+                           FXPT_TYPE::LineTo, false);
+        pathLT.AppendPoint(
+            CFX_PointF(fRight - fHalfWidth * 2, fTop - fHalfWidth * 2),
+            FXPT_TYPE::LineTo, false);
+        pathLT.AppendPoint(
+            CFX_PointF(fLeft + fHalfWidth * 2, fTop - fHalfWidth * 2),
+            FXPT_TYPE::LineTo, false);
+        pathLT.AppendPoint(
+            CFX_PointF(fLeft + fHalfWidth * 2, fBottom + fHalfWidth * 2),
+            FXPT_TYPE::LineTo, false);
+        pathLT.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth),
+                           FXPT_TYPE::LineTo, false);
 
         pDevice->DrawPath(&pathLT, pUser2Device, &gsd,
-                          PWLColorToFXColor(crLeftTop, nTransparancy), 0,
+                          crLeftTop.ToFXColor(nTransparency), 0,
                           FXFILL_ALTERNATE);
 
         CFX_PathData pathRB;
-
-        pathRB.SetPointCount(7);
-        pathRB.SetPoint(0, fRight - fHalfWidth, fTop - fHalfWidth, FXPT_MOVETO);
-        pathRB.SetPoint(1, fRight - fHalfWidth, fBottom + fHalfWidth,
-                        FXPT_LINETO);
-        pathRB.SetPoint(2, fLeft + fHalfWidth, fBottom + fHalfWidth,
-                        FXPT_LINETO);
-        pathRB.SetPoint(3, fLeft + fHalfWidth * 2, fBottom + fHalfWidth * 2,
-                        FXPT_LINETO);
-        pathRB.SetPoint(4, fRight - fHalfWidth * 2, fBottom + fHalfWidth * 2,
-                        FXPT_LINETO);
-        pathRB.SetPoint(5, fRight - fHalfWidth * 2, fTop - fHalfWidth * 2,
-                        FXPT_LINETO);
-        pathRB.SetPoint(6, fRight - fHalfWidth, fTop - fHalfWidth, FXPT_LINETO);
+        pathRB.AppendPoint(CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth),
+                           FXPT_TYPE::MoveTo, false);
+        pathRB.AppendPoint(
+            CFX_PointF(fRight - fHalfWidth, fBottom + fHalfWidth),
+            FXPT_TYPE::LineTo, false);
+        pathRB.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth),
+                           FXPT_TYPE::LineTo, false);
+        pathRB.AppendPoint(
+            CFX_PointF(fLeft + fHalfWidth * 2, fBottom + fHalfWidth * 2),
+            FXPT_TYPE::LineTo, false);
+        pathRB.AppendPoint(
+            CFX_PointF(fRight - fHalfWidth * 2, fBottom + fHalfWidth * 2),
+            FXPT_TYPE::LineTo, false);
+        pathRB.AppendPoint(
+            CFX_PointF(fRight - fHalfWidth * 2, fTop - fHalfWidth * 2),
+            FXPT_TYPE::LineTo, false);
+        pathRB.AppendPoint(CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth),
+                           FXPT_TYPE::LineTo, false);
 
         pDevice->DrawPath(&pathRB, pUser2Device, &gsd,
-                          PWLColorToFXColor(crRightBottom, nTransparancy), 0,
+                          crRightBottom.ToFXColor(nTransparency), 0,
                           FXFILL_ALTERNATE);
 
         CFX_PathData path;
@@ -1427,1936 +1149,24 @@
                         fRight - fHalfWidth, fTop - fHalfWidth);
 
         pDevice->DrawPath(&path, pUser2Device, &gsd,
-                          PWLColorToFXColor(color, nTransparancy), 0,
-                          FXFILL_ALTERNATE);
+                          color.ToFXColor(nTransparency), 0, FXFILL_ALTERNATE);
         break;
       }
       case BorderStyle::UNDERLINE: {
         CFX_PathData path;
-
-        path.SetPointCount(2);
-        path.SetPoint(0, fLeft, fBottom + fWidth / 2, FXPT_MOVETO);
-        path.SetPoint(1, fRight, fBottom + fWidth / 2, FXPT_LINETO);
+        path.AppendPoint(CFX_PointF(fLeft, fBottom + fWidth / 2),
+                         FXPT_TYPE::MoveTo, false);
+        path.AppendPoint(CFX_PointF(fRight, fBottom + fWidth / 2),
+                         FXPT_TYPE::LineTo, false);
 
         CFX_GraphStateData gsd;
         gsd.m_LineWidth = fWidth;
 
         pDevice->DrawPath(&path, pUser2Device, &gsd, 0,
-                          PWLColorToFXColor(color, nTransparancy),
-                          FXFILL_ALTERNATE);
+                          color.ToFXColor(nTransparency), FXFILL_ALTERNATE);
         break;
       }
     }
   }
 }
 
-bool CPWL_Utils::IsBlackOrWhite(const CPWL_Color& color) {
-  switch (color.nColorType) {
-    case COLORTYPE_TRANSPARENT:
-      return false;
-    case COLORTYPE_GRAY:
-      return color.fColor1 < 0.5f;
-    case COLORTYPE_RGB:
-      return color.fColor1 + color.fColor2 + color.fColor3 < 1.5f;
-    case COLORTYPE_CMYK:
-      return color.fColor1 + color.fColor2 + color.fColor3 + color.fColor4 >
-             2.0f;
-  }
-
-  return true;
-}
-
-CPWL_Color CPWL_Utils::GetReverseColor(const CPWL_Color& color) {
-  CPWL_Color crRet = color;
-
-  switch (color.nColorType) {
-    case COLORTYPE_GRAY:
-      crRet.fColor1 = 1.0f - crRet.fColor1;
-      break;
-    case COLORTYPE_RGB:
-      crRet.fColor1 = 1.0f - crRet.fColor1;
-      crRet.fColor2 = 1.0f - crRet.fColor2;
-      crRet.fColor3 = 1.0f - crRet.fColor3;
-      break;
-    case COLORTYPE_CMYK:
-      crRet.fColor1 = 1.0f - crRet.fColor1;
-      crRet.fColor2 = 1.0f - crRet.fColor2;
-      crRet.fColor3 = 1.0f - crRet.fColor3;
-      crRet.fColor4 = 1.0f - crRet.fColor4;
-      break;
-  }
-
-  return crRet;
-}
-
-CFX_ByteString CPWL_Utils::GetIconAppStream(int32_t nType,
-                                            const CFX_FloatRect& rect,
-                                            const CPWL_Color& crFill,
-                                            const CPWL_Color& crStroke) {
-  CFX_ByteString sAppStream = CPWL_Utils::GetColorAppStream(crStroke, false);
-  sAppStream += CPWL_Utils::GetColorAppStream(crFill, true);
-
-  CFX_ByteString sPath;
-  CFX_PathData path;
-
-  switch (nType) {
-    case PWL_ICONTYPE_CHECKMARK:
-      GetGraphics_Checkmark(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_CIRCLE:
-      GetGraphics_Circle(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_COMMENT:
-      GetGraphics_Comment(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_CROSS:
-      GetGraphics_Cross(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_HELP:
-      GetGraphics_Help(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_INSERTTEXT:
-      GetGraphics_InsertText(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_KEY:
-      GetGraphics_Key(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_NEWPARAGRAPH:
-      GetGraphics_NewParagraph(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_TEXTNOTE:
-      GetGraphics_TextNote(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_PARAGRAPH:
-      GetGraphics_Paragraph(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_RIGHTARROW:
-      GetGraphics_RightArrow(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_RIGHTPOINTER:
-      GetGraphics_RightPointer(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_STAR:
-      GetGraphics_Star(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_UPARROW:
-      GetGraphics_UpArrow(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_UPLEFTARROW:
-      GetGraphics_UpLeftArrow(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_GRAPH:
-      GetGraphics_Graph(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_PAPERCLIP:
-      GetGraphics_Paperclip(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_ATTACHMENT:
-      GetGraphics_Attachment(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_TAG:
-      GetGraphics_Tag(sPath, path, rect, PWLPT_STREAM);
-      break;
-    case PWL_ICONTYPE_FOXIT:
-      GetGraphics_Foxit(sPath, path, rect, PWLPT_STREAM);
-      break;
-  }
-
-  sAppStream += sPath;
-  if (crStroke.nColorType != COLORTYPE_TRANSPARENT)
-    sAppStream += "B*\n";
-  else
-    sAppStream += "f*\n";
-
-  return sAppStream;
-}
-
-void CPWL_Utils::DrawIconAppStream(CFX_RenderDevice* pDevice,
-                                   CFX_Matrix* pUser2Device,
-                                   int32_t nType,
-                                   const CFX_FloatRect& rect,
-                                   const CPWL_Color& crFill,
-                                   const CPWL_Color& crStroke,
-                                   const int32_t nTransparancy) {
-  CFX_GraphStateData gsd;
-  gsd.m_LineWidth = 1.0f;
-
-  CFX_ByteString sPath;
-  CFX_PathData path;
-
-  switch (nType) {
-    case PWL_ICONTYPE_CHECKMARK:
-      GetGraphics_Checkmark(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_CIRCLE:
-      GetGraphics_Circle(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_COMMENT:
-      GetGraphics_Comment(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_CROSS:
-      GetGraphics_Cross(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_HELP:
-      GetGraphics_Help(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_INSERTTEXT:
-      GetGraphics_InsertText(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_KEY:
-      GetGraphics_Key(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_NEWPARAGRAPH:
-      GetGraphics_NewParagraph(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_TEXTNOTE:
-      GetGraphics_TextNote(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_PARAGRAPH:
-      GetGraphics_Paragraph(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_RIGHTARROW:
-      GetGraphics_RightArrow(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_RIGHTPOINTER:
-      GetGraphics_RightPointer(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_STAR:
-      GetGraphics_Star(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_UPARROW:
-      GetGraphics_UpArrow(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_UPLEFTARROW:
-      GetGraphics_UpLeftArrow(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_GRAPH:
-      GetGraphics_Graph(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_PAPERCLIP:
-      GetGraphics_Paperclip(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_ATTACHMENT:
-      GetGraphics_Attachment(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_TAG:
-      GetGraphics_Tag(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    case PWL_ICONTYPE_FOXIT:
-      GetGraphics_Foxit(sPath, path, rect, PWLPT_PATHDATA);
-      break;
-    default:
-      return;
-  }
-
-  pDevice->DrawPath(
-      &path, pUser2Device, &gsd, PWLColorToFXColor(crFill, nTransparancy),
-      PWLColorToFXColor(crStroke, nTransparancy), FXFILL_ALTERNATE);
-}
-
-void CPWL_Utils::GetGraphics_Checkmark(CFX_ByteString& sPathData,
-                                       CFX_PathData& path,
-                                       const CFX_FloatRect& crBBox,
-                                       const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 15.0f,
-                               crBBox.bottom + fHeight * 2 / 5.0f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 15.0f +
-                         FX_BEZIER * (fWidth / 7.0f - fWidth / 15.0f),
-                     crBBox.bottom + fHeight * 2 / 5.0f +
-                         FX_BEZIER * (fHeight * 2 / 7.0f - fHeight * 2 / 5.0f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 4.5f +
-                         FX_BEZIER * (fWidth / 5.0f - fWidth / 4.5f),
-                     crBBox.bottom + fHeight / 16.0f +
-                         FX_BEZIER * (fHeight / 5.0f - fHeight / 16.0f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 4.5f,
-                               crBBox.bottom + fHeight / 16.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 4.5f +
-                                   FX_BEZIER * (fWidth / 4.4f - fWidth / 4.5f),
-                               crBBox.bottom + fHeight / 16.0f -
-                                   FX_BEZIER * fHeight / 16.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 3.0f +
-                                   FX_BEZIER * (fWidth / 4.0f - fWidth / 3.0f),
-                               crBBox.bottom),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 3.0f, crBBox.bottom),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 3.0f +
-                                   FX_BEZIER * fWidth * (1 / 7.0f + 2 / 15.0f),
-                               crBBox.bottom + FX_BEZIER * fHeight * 4 / 5.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 14 / 15.0f +
-                                   FX_BEZIER * fWidth * (1 / 7.0f - 7 / 15.0f),
-                               crBBox.bottom + fHeight * 15 / 16.0f +
-                                   FX_BEZIER * (fHeight * 4 / 5.0f -
-                                                fHeight * 15 / 16.0f)),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 14 / 15.0f,
-                               crBBox.bottom + fHeight * 15 / 16.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(
-              crBBox.left + fWidth * 14 / 15.0f +
-                  FX_BEZIER * (fWidth * 7 / 15.0f - fWidth * 14 / 15.0f),
-              crBBox.bottom + fHeight * 15 / 16.0f +
-                  FX_BEZIER * (fHeight * 8 / 7.0f - fHeight * 15 / 16.0f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 3.6f +
-                         FX_BEZIER * (fWidth / 3.4f - fWidth / 3.6f),
-                     crBBox.bottom + fHeight / 3.5f +
-                         FX_BEZIER * (fHeight / 3.5f - fHeight / 3.5f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 3.6f,
-                               crBBox.bottom + fHeight / 3.5f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 3.6f,
-                     crBBox.bottom + fHeight / 3.5f +
-                         FX_BEZIER * (fHeight / 4.0f - fHeight / 3.5f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 15.0f +
-                                   FX_BEZIER * (fWidth / 3.5f - fWidth / 15.0f),
-                               crBBox.bottom + fHeight * 2 / 5.0f +
-                                   FX_BEZIER * (fHeight * 3.5f / 5.0f -
-                                                fHeight * 2 / 5.0f)),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 15.0f,
-                               crBBox.bottom + fHeight * 2 / 5.0f),
-                    PWLPT_BEZIERTO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 16);
-  else
-    GetPathDataFromArray(path, PathArray, 16);
-}
-
-void CPWL_Utils::GetGraphics_Circle(CFX_ByteString& sPathData,
-                                    CFX_PathData& path,
-                                    const CFX_FloatRect& crBBox,
-                                    const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 15.0f,
-                               crBBox.bottom + fHeight / 2.0f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 15.0f,
-                     crBBox.bottom + fHeight / 2.0f +
-                         FX_BEZIER * (fHeight * 14 / 15.0f - fHeight / 2.0f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 2.0f -
-                                   FX_BEZIER * (fWidth / 2.0f - fWidth / 15.0f),
-                               crBBox.top - fHeight / 15.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 2.0f, crBBox.top - fHeight / 15.0f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 2.0f +
-                         FX_BEZIER * (fWidth * 14 / 15.0f - fWidth / 2.0f),
-                     crBBox.top - fHeight / 15.0f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth / 15.0f,
-                     crBBox.bottom + fHeight / 2.0f +
-                         FX_BEZIER * (fHeight * 14 / 15.0f - fHeight / 2.0f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 15.0f,
-                               crBBox.bottom + fHeight / 2.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth / 15.0f,
-                     crBBox.bottom + fHeight / 2.0f -
-                         FX_BEZIER * (fHeight / 2.0f - fHeight / 15.0f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 2.0f +
-                         FX_BEZIER * (fWidth * 14 / 15.0f - fWidth / 2.0f),
-                     crBBox.bottom + fHeight / 15.0f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 2.0f,
-                               crBBox.bottom + fHeight / 15.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 2.0f -
-                                   FX_BEZIER * (fWidth / 2.0f - fWidth / 15.0f),
-                               crBBox.bottom + fHeight / 15.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 15.0f,
-                     crBBox.bottom + fHeight / 2.0f -
-                         FX_BEZIER * (fHeight / 2.0f - fHeight / 15.0f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 15.0f,
-                               crBBox.bottom + fHeight / 2.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 3 / 15.0f,
-                               crBBox.bottom + fHeight / 2.0f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 3 / 15.0f,
-                     crBBox.bottom + fHeight / 2.0f +
-                         FX_BEZIER * (fHeight * 4 / 5.0f - fHeight / 2.0f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 2.0f -
-                         FX_BEZIER * (fWidth / 2.0f - fWidth * 3 / 15.0f),
-                     crBBox.top - fHeight * 3 / 15.0f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 2.0f,
-                               crBBox.top - fHeight * 3 / 15.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 2.0f +
-                         FX_BEZIER * (fWidth * 4 / 5.0f - fWidth / 2.0f),
-                     crBBox.top - fHeight * 3 / 15.0f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 3 / 15.0f,
-                     crBBox.bottom + fHeight / 2.0f +
-                         FX_BEZIER * (fHeight * 4 / 5.0f - fHeight / 2.0f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 3 / 15.0f,
-                               crBBox.bottom + fHeight / 2.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 3 / 15.0f,
-                     crBBox.bottom + fHeight / 2.0f -
-                         FX_BEZIER * (fHeight * 4 / 5.0f - fHeight / 2.0f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 2.0f +
-                         FX_BEZIER * (fWidth * 4 / 5.0f - fWidth / 2.0f),
-                     crBBox.bottom + fHeight * 3 / 15.0f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 2.0f,
-                               crBBox.bottom + fHeight * 3 / 15.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 2.0f -
-                         FX_BEZIER * (fWidth * 4 / 5.0f - fWidth / 2.0f),
-                     crBBox.bottom + fHeight * 3 / 15.0f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 3 / 15.0f,
-                     crBBox.bottom + fHeight / 2.0f -
-                         FX_BEZIER * (fHeight * 4 / 5.0f - fHeight / 2.0f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 3 / 15.0f,
-                               crBBox.bottom + fHeight / 2.0f),
-                    PWLPT_BEZIERTO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 26);
-  else
-    GetPathDataFromArray(path, PathArray, 26);
-}
-
-void CPWL_Utils::GetGraphics_Comment(CFX_ByteString& sPathData,
-                                     CFX_PathData& path,
-                                     const CFX_FloatRect& crBBox,
-                                     const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 15.0f, crBBox.top - fHeight / 6.0f),
-          PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 15.0f,
-                     crBBox.top - fHeight / 6.0f +
-                         FX_BEZIER * (fHeight / 6.0f - fHeight / 10.0f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 2 / 15.0f -
-                                   FX_BEZIER * fWidth / 15.0f,
-                               crBBox.top - fHeight / 10.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 2 / 15.0f,
-                               crBBox.top - fHeight / 10.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 2 / 15.0f,
-                               crBBox.top - fHeight / 10.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 2 / 15.0f +
-                                   FX_BEZIER * fWidth / 15.0f,
-                               crBBox.top - fHeight / 10.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth / 15.0f,
-                     crBBox.top - fHeight / 6 +
-                         FX_BEZIER * (fHeight / 6.0f - fHeight / 10.0f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 15.0f,
-                               crBBox.top - fHeight / 6.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 15.0f,
-                               crBBox.bottom + fHeight / 3.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 15.0f,
-                               crBBox.bottom + fHeight * 4 / 15.0f +
-                                   FX_BEZIER * fHeight / 15.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 2 / 15.0f +
-                                   FX_BEZIER * fWidth / 15.0f,
-                               crBBox.bottom + fHeight * 4 / 15.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 2 / 15.0f,
-                               crBBox.bottom + fHeight * 4 / 15.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 5 / 15.0f,
-                               crBBox.bottom + fHeight * 4 / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 5 / 15.0f,
-                               crBBox.bottom + fHeight * 2 / 15 +
-                                   FX_BEZIER * fHeight * 2 / 15.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 5 / 15.0f -
-                                   FX_BEZIER * fWidth * 2 / 15.0f,
-                               crBBox.bottom + fHeight * 2 / 15.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 6 / 30.0f,
-                               crBBox.bottom + fHeight * 2 / 15.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 7 / 30.0f +
-                                   FX_BEZIER * fWidth / 30.0f,
-                               crBBox.bottom + fHeight * 2 / 15.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 7 / 30.0f,
-                               crBBox.bottom + fHeight * 2 / 15.0f +
-                                   FX_BEZIER * fHeight * 2 / 15.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 7 / 30.0f,
-                               crBBox.bottom + fHeight * 4 / 15.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 2 / 15.0f,
-                               crBBox.bottom + fHeight * 4 / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 2 / 15.0f -
-                                   FX_BEZIER * fWidth / 15.0f,
-                               crBBox.bottom + fHeight * 4 / 15.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 15.0f,
-                               crBBox.bottom + fHeight / 3.0f -
-                                   FX_BEZIER * fHeight / 15.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 15.0f,
-                               crBBox.bottom + fHeight / 3.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 15.0f, crBBox.top - fHeight / 6.0f),
-          PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 2 / 15.0f,
-                               crBBox.top - fHeight * 8 / 30.0f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 2 / 15.0f,
-                               crBBox.top - fHeight * 8 / 30.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 2 / 15,
-                               crBBox.top - fHeight * 25 / 60.0f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 2 / 15.0f,
-                               crBBox.top - fHeight * 25 / 60.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 2 / 15.0f,
-                               crBBox.top - fHeight * 17 / 30.0f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 4 / 15.0f,
-                               crBBox.top - fHeight * 17 / 30.0f),
-                    PWLPT_LINETO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 30);
-  else
-    GetPathDataFromArray(path, PathArray, 30);
-}
-
-void CPWL_Utils::GetGraphics_Cross(CFX_ByteString& sPathData,
-                                   CFX_PathData& path,
-                                   const CFX_FloatRect& crBBox,
-                                   const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-  CPWL_Point center_point(crBBox.left + fWidth / 2,
-                          crBBox.bottom + fHeight / 2);
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(
-          CPWL_Point(center_point.x, center_point.y + fHeight / 10.0f),
-          PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(center_point.x + fWidth * 0.3f,
-                     center_point.y + fHeight / 10.0f + fWidth * 0.3f),
-          PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(center_point.x + fWidth / 10.0f + fWidth * 0.3f,
-                               center_point.y + fHeight * 0.3f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(center_point.x + fWidth / 10.0f, center_point.y),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(center_point.x + fWidth / 10.0f + fWidth * 0.3f,
-                               center_point.y - fHeight * 0.3f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(center_point.x + fWidth * 0.3f,
-                     center_point.y - fHeight / 10.0f - fHeight * 0.3f),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(center_point.x, center_point.y - fHeight / 10.0f),
-          PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(center_point.x - fWidth * 0.3f,
-                               center_point.y - fHeight / 10 - fHeight * 0.3f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(center_point.x - fWidth / 10.0f - fWidth * 0.3f,
-                               center_point.y - fHeight * 0.3f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(center_point.x - fWidth / 10, center_point.y),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(center_point.x - fWidth / 10 - fWidth * 0.3f,
-                               center_point.y + fHeight * 0.3f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(center_point.x - fWidth * 0.3f,
-                     center_point.y + fHeight / 10.0f + fHeight * 0.3f),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(center_point.x, center_point.y + fHeight / 10.0f),
-          PWLPT_LINETO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 13);
-  else
-    GetPathDataFromArray(path, PathArray, 13);
-}
-
-void CPWL_Utils::GetGraphics_Help(CFX_ByteString& sPathData,
-                                  CFX_PathData& path,
-                                  const CFX_FloatRect& crBBox,
-                                  const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 60.0f,
-                               crBBox.bottom + fHeight / 2.0f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 60.0f,
-                     crBBox.bottom + fHeight / 2.0f +
-                         FX_BEZIER * (fHeight / 60.0f - fHeight / 2.0f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 2.0f -
-                                   FX_BEZIER * (fWidth / 2.0f - fWidth / 60.0f),
-                               crBBox.bottom + fHeight / 60.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 2.0f,
-                               crBBox.bottom + fHeight / 60.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 2.0f +
-                                   FX_BEZIER * fWidth * 29 / 60.0f,
-                               crBBox.bottom + fHeight / 60.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth / 60.0f,
-                     crBBox.bottom + fHeight / 2.0f +
-                         FX_BEZIER * (fHeight / 60.0f - fHeight / 2.0f)),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 60.0f,
-                               crBBox.bottom + fHeight / 2.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 60.0f,
-                               crBBox.bottom + fHeight / 2.0f +
-                                   FX_BEZIER * fHeight * 29 / 60.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 2.0f +
-                                   FX_BEZIER * fWidth * 29 / 60.0f,
-                               crBBox.top - fHeight / 60.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 2.0f, crBBox.top - fHeight / 60.0f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 2.0f -
-                                   FX_BEZIER * fWidth * 29 / 60.0f,
-                               crBBox.top - fHeight / 60.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 60.0f,
-                               crBBox.bottom + fHeight / 2.0f +
-                                   FX_BEZIER * fHeight * 29 / 60.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 60.0f,
-                               crBBox.bottom + fHeight / 2.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.27f,
-                               crBBox.top - fHeight * 0.36f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.27f,
-                               crBBox.top - fHeight * 0.36f +
-                                   FX_BEZIER * fHeight * 0.23f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.5f - FX_BEZIER * fWidth * 0.23f,
-                     crBBox.bottom + fHeight * 0.87f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.5f,
-                               crBBox.bottom + fHeight * 0.87f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.5f + FX_BEZIER * fWidth * 0.23f,
-                     crBBox.bottom + fHeight * 0.87f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.27f,
-                               crBBox.top - fHeight * 0.36f +
-                                   FX_BEZIER * fHeight * 0.23f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.27f,
-                               crBBox.top - fHeight * 0.36f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 0.27f - fWidth * 0.08f * 0.2f,
-                     crBBox.top - fHeight * 0.36f - fHeight * 0.15f * 0.7f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 0.35f + fWidth * 0.08f * 0.2f,
-                     crBBox.top - fHeight * 0.51f + fHeight * 0.15f * 0.2f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.35f,
-                               crBBox.top - fHeight * 0.51f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 0.35f - fWidth * 0.1f * 0.5f,
-                     crBBox.top - fHeight * 0.51f - fHeight * 0.15f * 0.3f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 0.45f - fWidth * 0.1f * 0.5f,
-                     crBBox.top - fHeight * 0.68f + fHeight * 0.15f * 0.5f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.45f,
-                               crBBox.top - fHeight * 0.68f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.45f,
-                               crBBox.bottom + fHeight * 0.30f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 0.45f,
-                     crBBox.bottom + fHeight * 0.30f - fWidth * 0.1f * 0.7f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 0.55f,
-                     crBBox.bottom + fHeight * 0.30f - fWidth * 0.1f * 0.7f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.55f,
-                               crBBox.bottom + fHeight * 0.30f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.55f,
-                               crBBox.top - fHeight * 0.66f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 0.55f - fWidth * 0.1f * 0.05f,
-                     crBBox.top - fHeight * 0.66f + fHeight * 0.18f * 0.5f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 0.45f - fWidth * 0.1f * 0.05f,
-                     crBBox.top - fHeight * 0.48f - fHeight * 0.18f * 0.3f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.45f,
-                               crBBox.top - fHeight * 0.48f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 0.45f + fWidth * 0.08f * 0.2f,
-                     crBBox.top - fHeight * 0.48f + fHeight * 0.18f * 0.2f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 0.37f - fWidth * 0.08f * 0.2f,
-                     crBBox.top - fHeight * 0.36f - fHeight * 0.18f * 0.7f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.37f,
-                               crBBox.top - fHeight * 0.36f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.37f,
-                               crBBox.top - fHeight * 0.36f +
-                                   FX_BEZIER * fHeight * 0.13f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.5f + FX_BEZIER * fWidth * 0.13f,
-                     crBBox.bottom + fHeight * 0.77f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.5f,
-                               crBBox.bottom + fHeight * 0.77f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.5f - FX_BEZIER * fWidth * 0.13f,
-                     crBBox.bottom + fHeight * 0.77f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.37f,
-                               crBBox.top - fHeight * 0.36f +
-                                   FX_BEZIER * fHeight * 0.13f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.37f,
-                               crBBox.top - fHeight * 0.36f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.37f,
-                     crBBox.top - fHeight * 0.36f - fWidth * 0.1f * 0.6f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.27f,
-                     crBBox.top - fHeight * 0.36f - fWidth * 0.1f * 0.6f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.27f,
-                               crBBox.top - fHeight * 0.36f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.56f,
-                               crBBox.bottom + fHeight * 0.13f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.56f,
-                               crBBox.bottom + fHeight * 0.13f +
-                                   FX_BEZIER * fHeight * 0.055f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.505f -
-                                   FX_BEZIER * fWidth * 0.095f,
-                               crBBox.bottom + fHeight * 0.185f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.505f,
-                               crBBox.bottom + fHeight * 0.185f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.505f +
-                                   FX_BEZIER * fWidth * 0.065f,
-                               crBBox.bottom + fHeight * 0.185f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.44f,
-                               crBBox.bottom + fHeight * 0.13f +
-                                   FX_BEZIER * fHeight * 0.055f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.44f,
-                               crBBox.bottom + fHeight * 0.13f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.44f,
-                               crBBox.bottom + fHeight * 0.13f -
-                                   FX_BEZIER * fHeight * 0.055f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.505f +
-                                   FX_BEZIER * fWidth * 0.065f,
-                               crBBox.bottom + fHeight * 0.075f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.505f,
-                               crBBox.bottom + fHeight * 0.075f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.505f -
-                                   FX_BEZIER * fWidth * 0.065f,
-                               crBBox.bottom + fHeight * 0.075f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.56f,
-                               crBBox.bottom + fHeight * 0.13f -
-                                   FX_BEZIER * fHeight * 0.055f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.56f,
-                               crBBox.bottom + fHeight * 0.13f),
-                    PWLPT_BEZIERTO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 59);
-  else
-    GetPathDataFromArray(path, PathArray, 59);
-}
-
-void CPWL_Utils::GetGraphics_InsertText(CFX_ByteString& sPathData,
-                                        CFX_PathData& path,
-                                        const CFX_FloatRect& crBBox,
-                                        const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 10, crBBox.bottom + fHeight / 10),
-          PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 2, crBBox.top - fHeight * 2 / 15),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth / 10, crBBox.bottom + fHeight / 10),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 10, crBBox.bottom + fHeight / 10),
-          PWLPT_LINETO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 4);
-  else
-    GetPathDataFromArray(path, PathArray, 4);
-}
-
-void CPWL_Utils::GetGraphics_Key(CFX_ByteString& sPathData,
-                                 CFX_PathData& path,
-                                 const CFX_FloatRect& crBBox,
-                                 const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-  FX_FLOAT k = -fHeight / fWidth;
-  CPWL_Point tail;
-  CPWL_Point CicleCenter;
-  tail.x = crBBox.left + fWidth * 0.9f;
-  tail.y = k * (tail.x - crBBox.right) + crBBox.bottom;
-  CicleCenter.x = crBBox.left + fWidth * 0.15f;
-  CicleCenter.y = k * (CicleCenter.x - crBBox.right) + crBBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(
-          CPWL_Point(tail.x + fWidth / 30.0f, -fWidth / 30.0f / k + tail.y),
-          PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(tail.x + fWidth / 30.0f - fWidth * 0.18f,
-                               -k * fWidth * 0.18f - fWidth / 30 / k + tail.y),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(tail.x + fWidth / 30 - fWidth * 0.18f + fWidth * 0.07f,
-                     -fWidth * 0.07f / k - k * fWidth * 0.18f -
-                         fWidth / 30 / k + tail.y),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(tail.x + fWidth / 30 - fWidth * 0.18f - fWidth / 20 +
-                         fWidth * 0.07f,
-                     -fWidth * 0.07f / k - k * fWidth / 20 -
-                         k * fWidth * 0.18f - fWidth / 30 / k + tail.y),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(
-              tail.x + fWidth / 30 - fWidth * 0.18f - fWidth / 20,
-              -k * fWidth / 20 - k * fWidth * 0.18f - fWidth / 30 / k + tail.y),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(
-              tail.x + fWidth / 30 - fWidth * 0.18f - fWidth / 20 - fWidth / 15,
-              -k * fWidth / 15 - k * fWidth / 20 - k * fWidth * 0.18f -
-                  fWidth / 30 / k + tail.y),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(tail.x + fWidth / 30 - fWidth * 0.18f - fWidth / 20 -
-                         fWidth / 15 + fWidth * 0.07f,
-                     -fWidth * 0.07f / k - k * fWidth / 15 - k * fWidth / 20 -
-                         k * fWidth * 0.18f - fWidth / 30 / k + tail.y),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(tail.x + fWidth / 30 - fWidth * 0.18f - fWidth / 20 -
-                         fWidth / 15 - fWidth / 20 + fWidth * 0.07f,
-                     -fWidth * 0.07f / k + -k * fWidth / 20 + -k * fWidth / 15 -
-                         k * fWidth / 20 - k * fWidth * 0.18f -
-                         fWidth / 30 / k + tail.y),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(tail.x + fWidth / 30 - fWidth * 0.18f - fWidth / 20 -
-                         fWidth / 15 - fWidth / 20,
-                     -k * fWidth / 20 + -k * fWidth / 15 - k * fWidth / 20 -
-                         k * fWidth * 0.18f - fWidth / 30 / k + tail.y),
-          PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(tail.x + fWidth / 30 - fWidth * 0.45f,
-                               -k * fWidth * 0.45f - fWidth / 30 / k + tail.y),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(tail.x + fWidth / 30 - fWidth * 0.45f + fWidth * 0.2f,
-                     -fWidth * 0.4f / k - k * fWidth * 0.45f - fWidth / 30 / k +
-                         tail.y),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(CicleCenter.x + fWidth * 0.2f,
-                               -fWidth * 0.1f / k + CicleCenter.y),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(CicleCenter.x, CicleCenter.y), PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(CicleCenter.x - fWidth / 60.0f,
-                               -k * fWidth / 60 + CicleCenter.y),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(CicleCenter.x - fWidth / 60,
-                               -k * fWidth / 60 + CicleCenter.y),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(CicleCenter.x, CicleCenter.y), PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(CicleCenter.x - fWidth * 0.22f,
-                     fWidth * 0.35f / k + CicleCenter.y - fHeight * 0.05f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(tail.x - fWidth / 30 - fWidth * 0.45f - fWidth * 0.18f,
-                     fWidth * 0.05f / k - k * fWidth * 0.45f + fWidth / 30 / k +
-                         tail.y - fHeight * 0.05f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(tail.x - fWidth / 30.0f - fWidth * 0.45f,
-                     -k * fWidth * 0.45f + fWidth / 30.0f / k + tail.y),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(tail.x - fWidth / 30.0f, fWidth / 30.0f / k + tail.y),
-          PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(tail.x + fWidth / 30, -fWidth / 30 / k + tail.y),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(CicleCenter.x + fWidth * 0.08f,
-                               k * fWidth * 0.08f + CicleCenter.y),
-                    PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(CicleCenter.x + fWidth * 0.08f + fWidth * 0.1f,
-                     -fWidth * 0.1f / k + k * fWidth * 0.08f + CicleCenter.y),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(CicleCenter.x + fWidth * 0.22f + fWidth * 0.1f,
-                     k * fWidth * 0.22f + CicleCenter.y - fWidth * 0.1f / k),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(CicleCenter.x + fWidth * 0.22f,
-                               k * fWidth * 0.22f + CicleCenter.y),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(CicleCenter.x + fWidth * 0.22f - fWidth * 0.1f,
-                     fWidth * 0.1f / k + k * fWidth * 0.22f + CicleCenter.y),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(CicleCenter.x + fWidth * 0.08f - fWidth * 0.1f,
-                     fWidth * 0.1f / k + k * fWidth * 0.08f + CicleCenter.y),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(CicleCenter.x + fWidth * 0.08f,
-                               k * fWidth * 0.08f + CicleCenter.y),
-                    PWLPT_BEZIERTO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 28);
-  else
-    GetPathDataFromArray(path, PathArray, 28);
-}
-
-void CPWL_Utils::GetGraphics_NewParagraph(CFX_ByteString& sPathData,
-                                          CFX_PathData& path,
-                                          const CFX_FloatRect& crBBox,
-                                          const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 2.0f, crBBox.top - fHeight / 20.0f),
-          PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 10.0f, crBBox.top - fHeight / 2.0f),
-          PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 10.0f,
-                               crBBox.top - fHeight / 2.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 2.0f, crBBox.top - fHeight / 20.0f),
-          PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.12f,
-                               crBBox.top - fHeight * 17 / 30.0f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.12f,
-                               crBBox.bottom + fHeight / 10.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.22f,
-                               crBBox.bottom + fHeight / 10.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.22f,
-                     crBBox.top - fHeight * 17 / 30.0f - fWidth * 0.14f),
-          PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.38f,
-                               crBBox.bottom + fHeight / 10.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.48f,
-                               crBBox.bottom + fHeight / 10.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.48f,
-                               crBBox.top - fHeight * 17 / 30.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.38f,
-                               crBBox.top - fHeight * 17 / 30.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.38f,
-                               crBBox.bottom + fWidth * 0.24f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.22f,
-                               crBBox.top - fHeight * 17 / 30.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.12f,
-                               crBBox.top - fHeight * 17 / 30.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.6f,
-                               crBBox.bottom + fHeight / 10.0f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.7f,
-                               crBBox.bottom + fHeight / 10.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.7f,
-                     crBBox.bottom + fHeight / 10.0f + fHeight / 7.0f),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.97f,
-                     crBBox.bottom + fHeight / 10.0f + fHeight / 7.0f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.97f,
-                               crBBox.top - fHeight * 17 / 30.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.7f,
-                               crBBox.top - fHeight * 17 / 30.0f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.6f,
-                               crBBox.top - fHeight * 17 / 30.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.6f,
-                               crBBox.bottom + fHeight / 10.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.7f,
-                               crBBox.bottom + fHeight / 7 + fHeight * 0.18f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.85f,
-                               crBBox.bottom + fHeight / 7 + fHeight * 0.18f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.85f,
-                     crBBox.top - fHeight * 17 / 30.0f - fHeight * 0.08f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.7f,
-                     crBBox.top - fHeight * 17 / 30.0f - fHeight * 0.08f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.7f,
-                               crBBox.bottom + fHeight / 7 + fHeight * 0.18f),
-                    PWLPT_LINETO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 28);
-  else
-    GetPathDataFromArray(path, PathArray, 28);
-}
-
-void CPWL_Utils::GetGraphics_TextNote(CFX_ByteString& sPathData,
-                                      CFX_PathData& path,
-                                      const CFX_FloatRect& crBBox,
-                                      const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 3 / 10.0f,
-                               crBBox.bottom + fHeight / 15.0f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 7 / 10.0f,
-                               crBBox.bottom + fHeight * 4 / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 10.0f,
-                               crBBox.bottom + fHeight * 4 / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 10.0f,
-                               crBBox.top - fHeight / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 10.0f,
-                               crBBox.top - fHeight / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 10.0f,
-                               crBBox.bottom + fHeight / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 3 / 10.0f,
-                               crBBox.bottom + fHeight / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 10.0f,
-                               crBBox.bottom + fHeight * 4 / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 3 / 10.0f,
-                               crBBox.bottom + fHeight / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 3 / 10.0f,
-                               crBBox.bottom + fHeight * 4 / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 10.0f,
-                               crBBox.bottom + fHeight * 4 / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 5.0f,
-                               crBBox.top - fHeight * 4 / 15.0f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 5.0f,
-                               crBBox.top - fHeight * 4 / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 5.0f,
-                               crBBox.top - fHeight * 7 / 15.0f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 5.0f,
-                               crBBox.top - fHeight * 7 / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 5.0f,
-                               crBBox.top - fHeight * 10 / 15.0f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 3 / 10.0f,
-                               crBBox.top - fHeight * 10 / 15.0f),
-                    PWLPT_LINETO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 17);
-  else
-    GetPathDataFromArray(path, PathArray, 17);
-}
-
-void CPWL_Utils::GetGraphics_Paragraph(CFX_ByteString& sPathData,
-                                       CFX_PathData& path,
-                                       const CFX_FloatRect& crBBox,
-                                       const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 2.0f, crBBox.top - fHeight / 15.0f),
-          PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.7f, crBBox.top - fHeight / 15.0f),
-          PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.7f,
-                               crBBox.bottom + fHeight / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.634f,
-                               crBBox.bottom + fHeight / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.634f,
-                               crBBox.top - fHeight * 2 / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.566f,
-                               crBBox.top - fHeight * 2 / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.566f,
-                               crBBox.bottom + fHeight / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 2.0f,
-                               crBBox.bottom + fHeight / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 2.0f,
-                               crBBox.top - fHeight / 15.0f - fHeight * 0.4f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.2f,
-                               crBBox.top - fHeight / 15.0f - fHeight * 0.4f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.2f, crBBox.top - fHeight / 15.0f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 2.0f, crBBox.top - fHeight / 15.0f),
-          PWLPT_BEZIERTO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 12);
-  else
-    GetPathDataFromArray(path, PathArray, 12);
-}
-
-void CPWL_Utils::GetGraphics_RightArrow(CFX_ByteString& sPathData,
-                                        CFX_PathData& path,
-                                        const CFX_FloatRect& crBBox,
-                                        const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 15.0f,
-                               crBBox.top - fHeight / 2.0f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 2.0f + fWidth / 8.0f,
-                               crBBox.bottom + fHeight / 5.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 2.0f,
-                               crBBox.bottom + fHeight / 5.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 15.0f - fWidth * 0.15f,
-                               crBBox.top - fHeight / 2.0f - fWidth / 25.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.1f,
-                               crBBox.top - fHeight / 2.0f - fWidth / 25.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.1f,
-                               crBBox.top - fHeight / 2.0f + fWidth / 25.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 15.0f - fWidth * 0.15f,
-                               crBBox.top - fHeight / 2.0f + fWidth / 25.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 2.0f, crBBox.top - fHeight / 5.0f),
-          PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 2.0f + fWidth / 8.0f,
-                               crBBox.top - fHeight / 5.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 15.0f,
-                               crBBox.top - fHeight / 2.0f),
-                    PWLPT_LINETO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 10);
-  else
-    GetPathDataFromArray(path, PathArray, 10);
-}
-
-void CPWL_Utils::GetGraphics_RightPointer(CFX_ByteString& sPathData,
-                                          CFX_PathData& path,
-                                          const CFX_FloatRect& crBBox,
-                                          const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 30.0f,
-                               crBBox.top - fHeight / 2.0f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 30.0f,
-                               crBBox.bottom + fHeight / 6.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 4 / 15.0f,
-                               crBBox.top - fHeight / 2.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 30.0f, crBBox.top - fHeight / 6.0f),
-          PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 30.0f,
-                               crBBox.top - fHeight / 2.0f),
-                    PWLPT_LINETO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 5);
-  else
-    GetPathDataFromArray(path, PathArray, 5);
-}
-
-void CPWL_Utils::GetGraphics_Star(CFX_ByteString& sPathData,
-                                  CFX_PathData& path,
-                                  const CFX_FloatRect& crBBox,
-                                  const PWL_PATH_TYPE type) {
-  FX_FLOAT fLongRadius =
-      (crBBox.top - crBBox.bottom) / (1 + (FX_FLOAT)cos(FX_PI / 5.0f));
-  fLongRadius = fLongRadius * 0.7f;
-  FX_FLOAT fShortRadius = fLongRadius * 0.55f;
-  CFX_FloatPoint ptCenter = CFX_FloatPoint((crBBox.left + crBBox.right) / 2.0f,
-                                           (crBBox.top + crBBox.bottom) / 2.0f);
-
-  FX_FLOAT px1[5], py1[5];
-  FX_FLOAT px2[5], py2[5];
-
-  FX_FLOAT fAngel = FX_PI / 10.0f;
-
-  for (int32_t i = 0; i < 5; i++) {
-    px1[i] = ptCenter.x + fLongRadius * (FX_FLOAT)cos(fAngel);
-    py1[i] = ptCenter.y + fLongRadius * (FX_FLOAT)sin(fAngel);
-
-    fAngel += FX_PI * 2 / 5.0f;
-  }
-
-  fAngel = FX_PI / 5.0f + FX_PI / 10.0f;
-
-  for (int32_t j = 0; j < 5; j++) {
-    px2[j] = ptCenter.x + fShortRadius * (FX_FLOAT)cos(fAngel);
-    py2[j] = ptCenter.y + fShortRadius * (FX_FLOAT)sin(fAngel);
-
-    fAngel += FX_PI * 2 / 5.0f;
-  }
-
-  CPWL_PathData PathArray[11];
-  PathArray[0] = CPWL_PathData(CPWL_Point(px1[0], py1[0]), PWLPT_MOVETO);
-  PathArray[1] = CPWL_PathData(CPWL_Point(px2[0], py2[0]), PWLPT_LINETO);
-
-  for (int32_t k = 0; k < 4; k++) {
-    PathArray[(k + 1) * 2] =
-        CPWL_PathData(CPWL_Point(px1[k + 1], py1[k + 1]), PWLPT_LINETO);
-    PathArray[(k + 1) * 2 + 1] =
-        CPWL_PathData(CPWL_Point(px2[k + 1], py2[k + 1]), PWLPT_LINETO);
-  }
-
-  PathArray[10] = CPWL_PathData(CPWL_Point(px1[0], py1[0]), PWLPT_LINETO);
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 11);
-  else
-    GetPathDataFromArray(path, PathArray, 11);
-}
-
-void CPWL_Utils::GetGraphics_UpArrow(CFX_ByteString& sPathData,
-                                     CFX_PathData& path,
-                                     const CFX_FloatRect& crBBox,
-                                     const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 2.0f, crBBox.top - fHeight / 15.0f),
-          PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 10.0f,
-                               crBBox.top - fWidth * 3 / 5.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.6f,
-                               crBBox.top - fWidth * 3 / 5.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.6f,
-                               crBBox.bottom + fHeight / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.4f,
-                               crBBox.bottom + fHeight / 15.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.4f,
-                               crBBox.top - fWidth * 3 / 5.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 10, crBBox.top - fWidth * 3 / 5.0f),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 2.0f, crBBox.top - fHeight / 15.0f),
-          PWLPT_LINETO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 8);
-  else
-    GetPathDataFromArray(path, PathArray, 8);
-}
-
-void CPWL_Utils::GetGraphics_UpLeftArrow(CFX_ByteString& sPathData,
-                                         CFX_PathData& path,
-                                         const CFX_FloatRect& crBBox,
-                                         const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-  CPWL_Point leftup(crBBox.left, crBBox.top);
-  CPWL_Point rightdown(crBBox.right, crBBox.bottom);
-  FX_FLOAT k = -fHeight / fWidth;
-  CPWL_Point tail;
-  tail.x = crBBox.left + fWidth * 4 / 5.0f;
-  tail.y = k * (tail.x - crBBox.right) + rightdown.y;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(
-          CPWL_Point(
-              crBBox.left + fWidth / 20.0f,
-              k * (crBBox.left + fWidth / 20.0f - rightdown.x) + rightdown.y),
-          PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(fHeight * 17 / 60.0f / k + tail.x +
-                                   fWidth / 10.0f + fWidth / 5.0f,
-                               -fWidth / 5.0f / k + tail.y -
-                                   fWidth / 10.0f / k + fHeight * 17 / 60.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(fHeight * 17 / 60.0f / k + tail.x + fWidth / 10.0f,
-                     tail.y - fWidth / 10.0f / k + fHeight * 17 / 60.0f),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(tail.x + fWidth / 10.0f, tail.y - fWidth / 10.0f / k),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(tail.x - fWidth / 10.0f, tail.y + fWidth / 10.0f / k),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(fHeight * 17 / 60.0f / k + tail.x - fWidth / 10.0f,
-                     tail.y + fWidth / 10.0f / k + fHeight * 17 / 60.0f),
-          PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(fHeight * 17 / 60.0f / k + tail.x -
-                                   fWidth / 10.0f - fWidth / 5.0f,
-                               fWidth / 5.0f / k + tail.y + fWidth / 10.0f / k +
-                                   fHeight * 17 / 60.0f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(
-              crBBox.left + fWidth / 20.0f,
-              k * (crBBox.left + fWidth / 20.0f - rightdown.x) + rightdown.y),
-          PWLPT_LINETO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 8);
-  else
-    GetPathDataFromArray(path, PathArray, 8);
-}
-
-void CPWL_Utils::GetGraphics_Graph(CFX_ByteString& sPathData,
-                                   CFX_PathData& path,
-                                   const CFX_FloatRect& crBBox,
-                                   const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.05f, crBBox.top - fWidth * 0.15f),
-          PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.25f,
-                               crBBox.top - fHeight * 0.15f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.275f,
-                               crBBox.bottom + fHeight * 0.08f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.05f,
-                               crBBox.bottom + fHeight * 0.08f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.05f, crBBox.top - fWidth * 0.15f),
-          PWLPT_LINETO),
-
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.275f,
-                               crBBox.top - fWidth * 0.45f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.475f,
-                               crBBox.top - fWidth * 0.45f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.475f,
-                               crBBox.bottom + fHeight * 0.08f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.275f,
-                               crBBox.bottom + fHeight * 0.08f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.275f,
-                               crBBox.top - fWidth * 0.45f),
-                    PWLPT_LINETO),
-
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.5f, crBBox.top - fHeight * 0.05f),
-          PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.7f, crBBox.top - fHeight * 0.05f),
-          PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.7f,
-                               crBBox.bottom + fHeight * 0.08f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.5f,
-                               crBBox.bottom + fHeight * 0.08f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.5f, crBBox.top - fHeight * 0.05f),
-          PWLPT_LINETO),
-
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.725f,
-                               crBBox.top - fWidth * 0.35f),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.925f,
-                               crBBox.top - fWidth * 0.35f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.925f,
-                               crBBox.bottom + fHeight * 0.08f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.725f,
-                               crBBox.bottom + fHeight * 0.08f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.725f,
-                               crBBox.top - fWidth * 0.35f),
-                    PWLPT_LINETO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 20);
-  else
-    GetPathDataFromArray(path, PathArray, 20);
-}
-
-void CPWL_Utils::GetGraphics_Paperclip(CFX_ByteString& sPathData,
-                                       CFX_PathData& path,
-                                       const CFX_FloatRect& crBBox,
-                                       const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 60, crBBox.top - fHeight * 0.25f),
-          PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 60,
-                               crBBox.bottom + fHeight * 0.25f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 60,
-                               crBBox.bottom + fHeight * 0.25f -
-                                   fWidth * 57 / 60.0f * 0.35f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 30,
-                               crBBox.bottom + fHeight * 0.25f -
-                                   fWidth * 57 / 60.0f * 0.35f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 30,
-                               crBBox.bottom + fHeight * 0.25f),
-                    PWLPT_BEZIERTO),
-
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth / 30, crBBox.top - fHeight * 0.33f),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth / 30,
-                     crBBox.top - fHeight * 0.33f + fHeight / 15 * 0.5f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth / 30 - fWidth * 0.12f,
-                     crBBox.top - fHeight * 0.33f + fHeight / 15 * 0.5f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 30 - fWidth * 0.12f,
-                               crBBox.top - fHeight * 0.33f),
-                    PWLPT_BEZIERTO),
-
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 30 - fWidth * 0.12f,
-                               crBBox.bottom + fHeight * 0.2f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth / 30 - fWidth * 0.12f,
-                     crBBox.bottom + fHeight * 0.2f -
-                         (fWidth * 57 / 60.0f - fWidth * 0.24f) * 0.25f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 60 + fWidth * 0.12f,
-                     crBBox.bottom + fHeight * 0.2f -
-                         (fWidth * 57 / 60.0f - fWidth * 0.24f) * 0.25f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 60 + fWidth * 0.12f,
-                               crBBox.bottom + fHeight * 0.2f),
-                    PWLPT_BEZIERTO),
-
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 60 + fWidth * 0.12f,
-                               crBBox.top - fHeight * 0.2f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 60 + fWidth * 0.12f,
-                     crBBox.top - fHeight * 0.2f +
-                         (fWidth * 11 / 12.0f - fWidth * 0.36f) * 0.25f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth / 15 - fWidth * 0.24f,
-                     crBBox.top - fHeight * 0.2f +
-                         (fWidth * 11 / 12.0f - fWidth * 0.36f) * 0.25f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 15 - fWidth * 0.24f,
-                               crBBox.top - fHeight * 0.2f),
-                    PWLPT_BEZIERTO),
-
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 15 - fWidth * 0.24f,
-                               crBBox.bottom + fHeight * 0.25f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth / 15 - fWidth * 0.24f,
-                     crBBox.bottom + fHeight * 0.25f -
-                         (fWidth * 14 / 15.0f - fWidth * 0.53f) * 0.25f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.29f,
-                     crBBox.bottom + fHeight * 0.25f -
-                         (fWidth * 14 / 15.0f - fWidth * 0.53f) * 0.25f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.29f,
-                               crBBox.bottom + fHeight * 0.25f),
-                    PWLPT_BEZIERTO),
-
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.29f,
-                               crBBox.top - fHeight * 0.33f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.29f,
-                     crBBox.top - fHeight * 0.33f + fWidth * 0.12f * 0.35f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.17f,
-                     crBBox.top - fHeight * 0.33f + fWidth * 0.12f * 0.35f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.17f,
-                               crBBox.top - fHeight * 0.33f),
-                    PWLPT_BEZIERTO),
-
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.17f,
-                               crBBox.bottom + fHeight * 0.3f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.17f,
-                               crBBox.bottom + fHeight * 0.3f -
-                                   fWidth * (14 / 15.0f - 0.29f) * 0.35f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 15 - fWidth * 0.12f,
-                               crBBox.bottom + fHeight * 0.3f -
-                                   fWidth * (14 / 15.0f - 0.29f) * 0.35f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 15 - fWidth * 0.12f,
-                               crBBox.bottom + fHeight * 0.3f),
-                    PWLPT_BEZIERTO),
-
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 15 - fWidth * 0.12f,
-                               crBBox.top - fHeight * 0.25f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth / 15 - fWidth * 0.12f,
-                               crBBox.top - fHeight * 0.25f +
-                                   fWidth * 0.35f * (11 / 12.0f - 0.12f)),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth / 60,
-                               crBBox.top - fHeight * 0.25f +
-                                   fWidth * 0.35f * (11 / 12.0f - 0.12f)),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth / 60, crBBox.top - fHeight * 0.25f),
-          PWLPT_BEZIERTO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 33);
-  else
-    GetPathDataFromArray(path, PathArray, 33);
-}
-
-void CPWL_Utils::GetGraphics_Attachment(CFX_ByteString& sPathData,
-                                        CFX_PathData& path,
-                                        const CFX_FloatRect& crBBox,
-                                        const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.25f, crBBox.top - fHeight * 0.1f),
-          PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.4f, crBBox.top - fHeight * 0.23f),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.4f, crBBox.top - fHeight * 0.5f),
-          PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.4f,
-                               crBBox.top - fHeight * 0.5f + fWidth * 0.04f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.6f,
-                               crBBox.top - fHeight * 0.5f + fWidth * 0.04f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.6f, crBBox.top - fHeight * 0.5f),
-          PWLPT_BEZIERTO),
-
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.6f, crBBox.top - fHeight * 0.23f),
-          PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.25f,
-                               crBBox.top - fHeight * 0.1f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.25f, crBBox.top - fHeight * 0.1f),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.4f, crBBox.top - fHeight * 0.23f),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.6f, crBBox.top - fHeight * 0.23f),
-          PWLPT_LINETO),
-
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.4f, crBBox.top - fHeight * 0.5f),
-          PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.4f - fWidth * 0.25f * 0.4f,
-                     crBBox.top - fHeight * 0.5f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.15f,
-                     crBBox.top - fHeight * 0.65f + fHeight * 0.15f * 0.4f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.15f,
-                               crBBox.top - fHeight * 0.65f),
-                    PWLPT_BEZIERTO),
-
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.15f,
-                               crBBox.top - fHeight * 0.65f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 0.15f,
-                     crBBox.top - fHeight * 0.65f + fHeight * 0.15f * 0.4f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.6f + fWidth * 0.25f * 0.4f,
-                     crBBox.top - fHeight * 0.5f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.6f, crBBox.top - fHeight * 0.5f),
-          PWLPT_BEZIERTO),
-
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.6f,
-                               crBBox.top - fHeight * 0.5f + fWidth * 0.04f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.4f,
-                               crBBox.top - fHeight * 0.5f + fWidth * 0.04f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.4f, crBBox.top - fHeight * 0.5f),
-          PWLPT_BEZIERTO),
-
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.5f, crBBox.top - fHeight * 0.65f),
-          PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.5f,
-                               crBBox.bottom + fHeight * 0.1f),
-                    PWLPT_LINETO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 24);
-  else
-    GetPathDataFromArray(path, PathArray, 24);
-}
-
-void CPWL_Utils::GetGraphics_Tag(CFX_ByteString& sPathData,
-                                 CFX_PathData& path,
-                                 const CFX_FloatRect& crBBox,
-                                 const PWL_PATH_TYPE type) {
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.4f, crBBox.top - fHeight * 0.1f),
-          PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.1f, crBBox.top - fHeight * 0.5f),
-          PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.left + fWidth * 0.3f,
-                               crBBox.bottom + fHeight * 0.1f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crBBox.right - fWidth * 0.1f,
-                               crBBox.bottom + fHeight * 0.1f),
-                    PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 0.1f, crBBox.top - fHeight * 0.1f),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.4f, crBBox.top - fHeight * 0.1f),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.4f, crBBox.top - fHeight * 0.3f),
-          PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 0.2f, crBBox.top - fHeight * 0.3f),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.4f, crBBox.top - fHeight * 0.5f),
-          PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 0.2f, crBBox.top - fHeight * 0.5f),
-          PWLPT_LINETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.left + fWidth * 0.4f, crBBox.top - fHeight * 0.7f),
-          PWLPT_MOVETO),
-      CPWL_PathData(
-          CPWL_Point(crBBox.right - fWidth * 0.2f, crBBox.top - fHeight * 0.7f),
-          PWLPT_LINETO)};
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 12);
-  else
-    GetPathDataFromArray(path, PathArray, 12);
-}
-
-void CPWL_Utils::GetGraphics_Foxit(CFX_ByteString& sPathData,
-                                   CFX_PathData& path,
-                                   const CFX_FloatRect& crBBox,
-                                   const PWL_PATH_TYPE type) {
-  FX_FLOAT fOutWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fOutHeight = crBBox.top - crBBox.bottom;
-
-  CFX_FloatRect crInBox = crBBox;
-  crInBox.left = crBBox.left + fOutWidth * 0.08f;
-  crInBox.right = crBBox.right - fOutWidth * 0.08f;
-  crInBox.top = crBBox.top - fOutHeight * 0.08f;
-  crInBox.bottom = crBBox.bottom + fOutHeight * 0.08f;
-
-  FX_FLOAT fWidth = crInBox.right - crInBox.left;
-  FX_FLOAT fHeight = crInBox.top - crInBox.bottom;
-
-  CPWL_PathData PathArray[] = {
-      CPWL_PathData(CPWL_Point(crInBox.left, crInBox.top), PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crInBox.left + fWidth * 0.45f, crInBox.top),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crInBox.left + fWidth * 0.45f,
-                               crInBox.top - FX_BEZIER * fHeight * 0.4f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crInBox.left + fWidth * 0.45f - FX_BEZIER * fWidth * 0.45f,
-                     crInBox.top - fHeight * 0.4f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crInBox.left, crInBox.top - fHeight * 0.4f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crInBox.left, crInBox.top), PWLPT_LINETO),
-
-      CPWL_PathData(CPWL_Point(crInBox.left + fWidth * 0.60f, crInBox.top),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crInBox.left + fWidth * 0.75f, crInBox.top),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crInBox.left + fWidth * 0.75f,
-                               crInBox.top - FX_BEZIER * fHeight * 0.7f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crInBox.left + fWidth * 0.75f - FX_BEZIER * fWidth * 0.75f,
-                     crInBox.top - fHeight * 0.7f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crInBox.left, crInBox.top - fHeight * 0.7f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crInBox.left, crInBox.top - fHeight * 0.55f),
-                    PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crInBox.left + FX_BEZIER * fWidth * 0.60f,
-                               crInBox.top - fHeight * 0.55f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crInBox.left + fWidth * 0.60f,
-                               crInBox.top - FX_BEZIER * fHeight * 0.55f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crInBox.left + fWidth * 0.60f, crInBox.top),
-                    PWLPT_BEZIERTO),
-
-      CPWL_PathData(CPWL_Point(crInBox.left + fWidth * 0.90f, crInBox.top),
-                    PWLPT_MOVETO),
-      CPWL_PathData(CPWL_Point(crInBox.left + fWidth * 0.90f,
-                               crInBox.top - FX_BEZIER * fHeight * 0.85f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(
-          CPWL_Point(crInBox.left + fWidth * 0.90f - FX_BEZIER * fWidth * 0.90f,
-                     crInBox.top - fHeight * 0.85f),
-          PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crInBox.left, crInBox.top - fHeight * 0.85f),
-                    PWLPT_BEZIERTO),
-      CPWL_PathData(CPWL_Point(crInBox.left, crInBox.bottom), PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crInBox.right, crInBox.bottom), PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crInBox.right, crInBox.top), PWLPT_LINETO),
-      CPWL_PathData(CPWL_Point(crInBox.left + fWidth * 0.90f, crInBox.top),
-                    PWLPT_LINETO),
-  };
-
-  if (type == PWLPT_STREAM)
-    sPathData = GetAppStreamFromArray(PathArray, 23);
-  else
-    GetPathDataFromArray(path, PathArray, 23);
-}
-
-void CPWL_Color::ConvertColorType(int32_t nConvertColorType) {
-  if (nColorType == nConvertColorType)
-    return;
-
-  switch (nColorType) {
-    case COLORTYPE_TRANSPARENT:
-      break;
-    case COLORTYPE_GRAY:
-      switch (nConvertColorType) {
-        case COLORTYPE_RGB:
-          CPWL_Utils::ConvertGRAY2RGB(fColor1, fColor1, fColor2, fColor3);
-          break;
-        case COLORTYPE_CMYK:
-          CPWL_Utils::ConvertGRAY2CMYK(fColor1, fColor1, fColor2, fColor3,
-                                       fColor4);
-          break;
-      }
-      break;
-    case COLORTYPE_RGB:
-      switch (nConvertColorType) {
-        case COLORTYPE_GRAY:
-          CPWL_Utils::ConvertRGB2GRAY(fColor1, fColor2, fColor3, fColor1);
-          break;
-        case COLORTYPE_CMYK:
-          CPWL_Utils::ConvertRGB2CMYK(fColor1, fColor2, fColor3, fColor1,
-                                      fColor2, fColor3, fColor4);
-          break;
-      }
-      break;
-    case COLORTYPE_CMYK:
-      switch (nConvertColorType) {
-        case COLORTYPE_GRAY:
-          CPWL_Utils::ConvertCMYK2GRAY(fColor1, fColor2, fColor3, fColor4,
-                                       fColor1);
-          break;
-        case COLORTYPE_RGB:
-          CPWL_Utils::ConvertCMYK2RGB(fColor1, fColor2, fColor3, fColor4,
-                                      fColor1, fColor2, fColor3);
-          break;
-      }
-      break;
-  }
-  nColorType = nConvertColorType;
-}
diff --git a/fpdfsdk/pdfwindow/PWL_Utils.h b/fpdfsdk/pdfwindow/PWL_Utils.h
index f14c3c7..a4ecc19 100644
--- a/fpdfsdk/pdfwindow/PWL_Utils.h
+++ b/fpdfsdk/pdfwindow/PWL_Utils.h
@@ -11,51 +11,10 @@
 #include "fpdfsdk/pdfwindow/PWL_Wnd.h"
 
 class CFX_Edit;
-class CFX_PathData;
-
 struct CPWL_Color;
 
-template <class T>
-T PWL_MIN(const T& i, const T& j) {
-  return ((i < j) ? i : j);
-}
-template <class T>
-T PWL_MAX(const T& i, const T& j) {
-  return ((i > j) ? i : j);
-}
-
-#define PWL_PDF2WIN(color) (uint8_t(color * 255))
-#define PWL_WIN2PDF(color) ((FX_FLOAT)((FX_FLOAT)color / 255.0f))
-
 #define PWL_MAKEDWORD(low, high) \
   ((uint32_t)((uint16_t)(low) | (uint32_t)(((uint16_t)(high)) << 16)))
-#define PWL_GETLOWWORD(dword) ((uint16_t)(dword))
-#define PWL_GETHIGHWORD(dword) ((uint16_t)(dword >> 16))
-
-#define PWL_ICONTYPE_CHECKMARK 0
-#define PWL_ICONTYPE_CIRCLE 1
-#define PWL_ICONTYPE_COMMENT 2
-#define PWL_ICONTYPE_CROSS 3
-#define PWL_ICONTYPE_HELP 4
-#define PWL_ICONTYPE_INSERTTEXT 5
-#define PWL_ICONTYPE_KEY 6
-#define PWL_ICONTYPE_NEWPARAGRAPH 7
-#define PWL_ICONTYPE_TEXTNOTE 8
-#define PWL_ICONTYPE_PARAGRAPH 9
-#define PWL_ICONTYPE_RIGHTARROW 10
-#define PWL_ICONTYPE_RIGHTPOINTER 11
-#define PWL_ICONTYPE_STAR 12
-#define PWL_ICONTYPE_UPARROW 13
-#define PWL_ICONTYPE_UPLEFTARROW 14
-
-#define PWL_ICONTYPE_GRAPH 15
-#define PWL_ICONTYPE_PAPERCLIP 16
-#define PWL_ICONTYPE_ATTACHMENT 17
-#define PWL_ICONTYPE_TAG 18
-
-#define PWL_ICONTYPE_FOXIT 19
-
-#define PWL_ICONTYPE_UNKNOWN -1
 
 // checkbox & radiobutton style
 #define PCS_CHECK 0
@@ -74,60 +33,18 @@
 #define PPBL_LABELLEFTICONRIGHT 5
 #define PPBL_LABELOVERICON 6
 
-class CPWL_Point : public CFX_FloatPoint {
- public:
-  CPWL_Point() {}
-  CPWL_Point(FX_FLOAT fx, FX_FLOAT fy) : CFX_FloatPoint(fx, fy) {}
-  CPWL_Point(const CPWL_Point& point) : CFX_FloatPoint(point.x, point.y) {}
-};
-
-enum PWL_PATHDATA_TYPE {
-  PWLPT_MOVETO,
-  PWLPT_LINETO,
-  PWLPT_BEZIERTO,
-  PWLPT_UNKNOWN
-};
-
-enum PWL_PATH_TYPE { PWLPT_PATHDATA, PWLPT_STREAM };
-
-class CPWL_PathData {
- public:
-  CPWL_PathData() : point(), type(PWLPT_UNKNOWN) {}
-  CPWL_PathData(const CPWL_Point& pt, PWL_PATHDATA_TYPE tp)
-      : point(pt), type(tp) {}
-
-  CPWL_Point point;
-  PWL_PATHDATA_TYPE type;
-};
-
 class CPWL_Utils {
  public:
   static CFX_FloatRect InflateRect(const CFX_FloatRect& rcRect, FX_FLOAT fSize);
   static CFX_FloatRect DeflateRect(const CFX_FloatRect& rcRect, FX_FLOAT fSize);
-  static bool IntersectRect(const CFX_FloatRect& rect1,
-                            const CFX_FloatRect& rect2);
-  static bool ContainsRect(const CFX_FloatRect& rcParent,
-                           const CFX_FloatRect& rcChild);
-  static CFX_FloatRect ScaleRect(const CFX_FloatRect& rcRect, FX_FLOAT fScale);
+
   static CPVT_WordRange OverlapWordRange(const CPVT_WordRange& wr1,
                                          const CPVT_WordRange& wr2);
   static CFX_FloatRect GetCenterSquare(const CFX_FloatRect& rect);
-  static CPWL_Color SubstractColor(const CPWL_Color& sColor,
-                                   FX_FLOAT fColorSub);
-  static CPWL_Color DevideColor(const CPWL_Color& sColor,
-                                FX_FLOAT fColorDevide);
-  static CFX_FloatRect MaxRect(const CFX_FloatRect& rect1,
-                               const CFX_FloatRect& rect2);
+
   static CFX_FloatRect OffsetRect(const CFX_FloatRect& rect,
                                   FX_FLOAT x,
                                   FX_FLOAT y);
-  static CFX_FloatPoint OffsetPoint(const CFX_FloatPoint& point,
-                                    FX_FLOAT x,
-                                    FX_FLOAT y);
-  static FX_COLORREF PWLColorToFXColor(const CPWL_Color& color,
-                                       int32_t nTransparancy = 255);
-  static bool IsBlackOrWhite(const CPWL_Color& color);
-  static CPWL_Color GetReverseColor(const CPWL_Color& color);
 
   static CFX_ByteString GetColorAppStream(const CPWL_Color& color,
                                           const bool& bFillOrStroke = true);
@@ -150,7 +67,6 @@
                                              const CPWL_Color& color);
   static CFX_ByteString GetCircleFillAppStream(const CFX_FloatRect& rect,
                                                const CPWL_Color& color);
-
   static CFX_ByteString GetPushButtonAppStream(const CFX_FloatRect& rcBBox,
                                                IPVT_FontMap* pFontMap,
                                                CPDF_Stream* pIconStream,
@@ -165,32 +81,22 @@
   static CFX_ByteString GetRadioButtonAppStream(const CFX_FloatRect& rcBBox,
                                                 int32_t nStyle,
                                                 const CPWL_Color& crText);
-
   static CFX_ByteString GetEditAppStream(CFX_Edit* pEdit,
-                                         const CFX_FloatPoint& ptOffset,
+                                         const CFX_PointF& ptOffset,
                                          const CPVT_WordRange* pRange = nullptr,
                                          bool bContinuous = true,
                                          uint16_t SubWord = 0);
   static CFX_ByteString GetEditSelAppStream(
       CFX_Edit* pEdit,
-      const CFX_FloatPoint& ptOffset,
+      const CFX_PointF& ptOffset,
       const CPVT_WordRange* pRange = nullptr);
-  static CFX_ByteString GetTextAppStream(const CFX_FloatRect& rcBBox,
-                                         IPVT_FontMap* pFontMap,
-                                         const CFX_WideString& sText,
-                                         int32_t nAlignmentH,
-                                         int32_t nAlignmentV,
-                                         FX_FLOAT fFontSize,
-                                         bool bMultiLine,
-                                         bool bAutoReturn,
-                                         const CPWL_Color& crText);
   static CFX_ByteString GetDropButtonAppStream(const CFX_FloatRect& rcBBox);
 
   static void DrawFillRect(CFX_RenderDevice* pDevice,
                            CFX_Matrix* pUser2Device,
                            const CFX_FloatRect& rect,
                            const CPWL_Color& color,
-                           int32_t nTransparancy);
+                           int32_t nTransparency);
   static void DrawFillRect(CFX_RenderDevice* pDevice,
                            CFX_Matrix* pUser2Device,
                            const CFX_FloatRect& rect,
@@ -202,8 +108,8 @@
                              FX_FLOAT fWidth);
   static void DrawStrokeLine(CFX_RenderDevice* pDevice,
                              CFX_Matrix* pUser2Device,
-                             const CFX_FloatPoint& ptMoveTo,
-                             const CFX_FloatPoint& ptLineTo,
+                             const CFX_PointF& ptMoveTo,
+                             const CFX_PointF& ptLineTo,
                              const FX_COLORREF& color,
                              FX_FLOAT fWidth);
   static void DrawBorder(CFX_RenderDevice* pDevice,
@@ -214,10 +120,10 @@
                          const CPWL_Color& crLeftTop,
                          const CPWL_Color& crRightBottom,
                          BorderStyle nStyle,
-                         int32_t nTransparancy);
+                         int32_t nTransparency);
   static void DrawFillArea(CFX_RenderDevice* pDevice,
                            CFX_Matrix* pUser2Device,
-                           const CFX_FloatPoint* pPts,
+                           const CFX_PointF* pPts,
                            int32_t nCount,
                            const FX_COLORREF& color);
   static void DrawShadow(CFX_RenderDevice* pDevice,
@@ -225,72 +131,12 @@
                          bool bVertical,
                          bool bHorizontal,
                          CFX_FloatRect rect,
-                         int32_t nTransparancy,
+                         int32_t nTransparency,
                          int32_t nStartGray,
                          int32_t nEndGray);
 
- public:
-  static void ConvertCMYK2RGB(FX_FLOAT dC,
-                              FX_FLOAT dM,
-                              FX_FLOAT dY,
-                              FX_FLOAT dK,
-                              FX_FLOAT& dR,
-                              FX_FLOAT& dG,
-                              FX_FLOAT& dB);
-  static void ConvertRGB2CMYK(FX_FLOAT dR,
-                              FX_FLOAT dG,
-                              FX_FLOAT dB,
-                              FX_FLOAT& dC,
-                              FX_FLOAT& dM,
-                              FX_FLOAT& dY,
-                              FX_FLOAT& dK);
-
-  static void ConvertRGB2GRAY(FX_FLOAT dR,
-                              FX_FLOAT dG,
-                              FX_FLOAT dB,
-                              FX_FLOAT& dGray);
-  static void ConvertGRAY2RGB(FX_FLOAT dGray,
-                              FX_FLOAT& dR,
-                              FX_FLOAT& dG,
-                              FX_FLOAT& dB);
-
-  static void ConvertCMYK2GRAY(FX_FLOAT dC,
-                               FX_FLOAT dM,
-                               FX_FLOAT dY,
-                               FX_FLOAT dK,
-                               FX_FLOAT& dGray);
-  static void ConvertGRAY2CMYK(FX_FLOAT dGray,
-                               FX_FLOAT& dC,
-                               FX_FLOAT& dM,
-                               FX_FLOAT& dY,
-                               FX_FLOAT& dK);
-
-  static void PWLColorToARGB(const CPWL_Color& color,
-                             int32_t& alpha,
-                             FX_FLOAT& red,
-                             FX_FLOAT& green,
-                             FX_FLOAT& blue);
-
- public:
-  static CFX_ByteString GetIconAppStream(
-      int32_t nType,
-      const CFX_FloatRect& rect,
-      const CPWL_Color& crFill,
-      const CPWL_Color& crStroke = PWL_DEFAULT_BLACKCOLOR);
-  static void DrawIconAppStream(CFX_RenderDevice* pDevice,
-                                CFX_Matrix* pUser2Device,
-                                int32_t nType,
-                                const CFX_FloatRect& rect,
-                                const CPWL_Color& crFill,
-                                const CPWL_Color& crStroke,
-                                const int32_t nTransparancy);
-
  private:
-  static CFX_ByteString GetAppStreamFromArray(const CPWL_PathData* pPathData,
-                                              int32_t nCount);
-  static void GetPathDataFromArray(CFX_PathData& path,
-                                   const CPWL_PathData* pPathData,
-                                   int32_t nCount);
+  static CFX_FloatRect ScaleRect(const CFX_FloatRect& rcRect, FX_FLOAT fScale);
 
   static CFX_ByteString GetAppStream_Check(const CFX_FloatRect& rcBBox,
                                            const CPWL_Color& crText);
@@ -313,87 +159,6 @@
   static CFX_ByteString GetAP_Star(const CFX_FloatRect& crBBox);
   static CFX_ByteString GetAP_HalfCircle(const CFX_FloatRect& crBBox,
                                          FX_FLOAT fRotate);
-
-  static void GetGraphics_Checkmark(CFX_ByteString& sPathData,
-                                    CFX_PathData& path,
-                                    const CFX_FloatRect& crBBox,
-                                    const PWL_PATH_TYPE type);
-  static void GetGraphics_Circle(CFX_ByteString& sPathData,
-                                 CFX_PathData& path,
-                                 const CFX_FloatRect& crBBox,
-                                 const PWL_PATH_TYPE type);
-  static void GetGraphics_Comment(CFX_ByteString& sPathData,
-                                  CFX_PathData& path,
-                                  const CFX_FloatRect& crBBox,
-                                  const PWL_PATH_TYPE type);
-  static void GetGraphics_Cross(CFX_ByteString& sPathData,
-                                CFX_PathData& path,
-                                const CFX_FloatRect& crBBox,
-                                const PWL_PATH_TYPE type);
-  static void GetGraphics_Help(CFX_ByteString& sPathData,
-                               CFX_PathData& path,
-                               const CFX_FloatRect& crBBox,
-                               const PWL_PATH_TYPE type);
-  static void GetGraphics_InsertText(CFX_ByteString& sPathData,
-                                     CFX_PathData& path,
-                                     const CFX_FloatRect& crBBox,
-                                     const PWL_PATH_TYPE type);
-  static void GetGraphics_Key(CFX_ByteString& sPathData,
-                              CFX_PathData& path,
-                              const CFX_FloatRect& crBBox,
-                              const PWL_PATH_TYPE type);
-  static void GetGraphics_NewParagraph(CFX_ByteString& sPathData,
-                                       CFX_PathData& path,
-                                       const CFX_FloatRect& crBBox,
-                                       const PWL_PATH_TYPE type);
-  static void GetGraphics_TextNote(CFX_ByteString& sPathData,
-                                   CFX_PathData& path,
-                                   const CFX_FloatRect& crBBox,
-                                   const PWL_PATH_TYPE type);
-  static void GetGraphics_Paragraph(CFX_ByteString& sPathData,
-                                    CFX_PathData& path,
-                                    const CFX_FloatRect& crBBox,
-                                    const PWL_PATH_TYPE type);
-  static void GetGraphics_RightArrow(CFX_ByteString& sPathData,
-                                     CFX_PathData& path,
-                                     const CFX_FloatRect& crBBox,
-                                     const PWL_PATH_TYPE type);
-  static void GetGraphics_RightPointer(CFX_ByteString& sPathData,
-                                       CFX_PathData& path,
-                                       const CFX_FloatRect& crBBox,
-                                       const PWL_PATH_TYPE type);
-  static void GetGraphics_Star(CFX_ByteString& sPathData,
-                               CFX_PathData& path,
-                               const CFX_FloatRect& crBBox,
-                               const PWL_PATH_TYPE type);
-  static void GetGraphics_UpArrow(CFX_ByteString& sPathData,
-                                  CFX_PathData& path,
-                                  const CFX_FloatRect& crBBox,
-                                  const PWL_PATH_TYPE type);
-  static void GetGraphics_UpLeftArrow(CFX_ByteString& sPathData,
-                                      CFX_PathData& path,
-                                      const CFX_FloatRect& crBBox,
-                                      const PWL_PATH_TYPE type);
-  static void GetGraphics_Graph(CFX_ByteString& sPathData,
-                                CFX_PathData& path,
-                                const CFX_FloatRect& crBBox,
-                                const PWL_PATH_TYPE type);
-  static void GetGraphics_Paperclip(CFX_ByteString& sPathData,
-                                    CFX_PathData& path,
-                                    const CFX_FloatRect& crBBox,
-                                    const PWL_PATH_TYPE type);
-  static void GetGraphics_Attachment(CFX_ByteString& sPathData,
-                                     CFX_PathData& path,
-                                     const CFX_FloatRect& crBBox,
-                                     const PWL_PATH_TYPE type);
-  static void GetGraphics_Tag(CFX_ByteString& sPathData,
-                              CFX_PathData& path,
-                              const CFX_FloatRect& crBBox,
-                              const PWL_PATH_TYPE type);
-  static void GetGraphics_Foxit(CFX_ByteString& sPathData,
-                                CFX_PathData& path,
-                                const CFX_FloatRect& crBBox,
-                                const PWL_PATH_TYPE type);
 };
 
 #endif  // FPDFSDK_PDFWINDOW_PWL_UTILS_H_
diff --git a/fpdfsdk/pdfwindow/PWL_Wnd.cpp b/fpdfsdk/pdfwindow/PWL_Wnd.cpp
index 8fd7b16..14024dd 100644
--- a/fpdfsdk/pdfwindow/PWL_Wnd.cpp
+++ b/fpdfsdk/pdfwindow/PWL_Wnd.cpp
@@ -32,7 +32,6 @@
       dwBorderWidth(1),
       sBorderColor(),
       sTextColor(),
-      sTextStrokeColor(),
       nTransparency(255),
       fFontSize(PWL_DEFAULT_FONTSIZE),
       sDash(3, 0, 0),
@@ -421,13 +420,11 @@
   }
 
 PWL_IMPLEMENT_KEY_METHOD(OnKeyDown)
-PWL_IMPLEMENT_KEY_METHOD(OnKeyUp)
 PWL_IMPLEMENT_KEY_METHOD(OnChar)
 #undef PWL_IMPLEMENT_KEY_METHOD
 
 #define PWL_IMPLEMENT_MOUSE_METHOD(mouse_method_name)                          \
-  bool CPWL_Wnd::mouse_method_name(const CFX_FloatPoint& point,                \
-                                   uint32_t nFlag) {                           \
+  bool CPWL_Wnd::mouse_method_name(const CFX_PointF& point, uint32_t nFlag) {  \
     if (!IsValid() || !IsVisible() || !IsEnabled())                            \
       return false;                                                            \
     if (IsWndCaptureMouse(this)) {                                             \
@@ -453,16 +450,13 @@
 PWL_IMPLEMENT_MOUSE_METHOD(OnLButtonDblClk)
 PWL_IMPLEMENT_MOUSE_METHOD(OnLButtonDown)
 PWL_IMPLEMENT_MOUSE_METHOD(OnLButtonUp)
-PWL_IMPLEMENT_MOUSE_METHOD(OnMButtonDblClk)
-PWL_IMPLEMENT_MOUSE_METHOD(OnMButtonDown)
-PWL_IMPLEMENT_MOUSE_METHOD(OnMButtonUp)
 PWL_IMPLEMENT_MOUSE_METHOD(OnRButtonDown)
 PWL_IMPLEMENT_MOUSE_METHOD(OnRButtonUp)
 PWL_IMPLEMENT_MOUSE_METHOD(OnMouseMove)
 #undef PWL_IMPLEMENT_MOUSE_METHOD
 
 bool CPWL_Wnd::OnMouseWheel(short zDelta,
-                            const CFX_FloatPoint& point,
+                            const CFX_PointF& point,
                             uint32_t nFlag) {
   if (!IsValid() || !IsVisible() || !IsEnabled())
     return false;
@@ -534,10 +528,10 @@
   return rcWindow.Contains(rcClient) ? rcClient : CFX_FloatRect();
 }
 
-CFX_FloatPoint CPWL_Wnd::GetCenterPoint() const {
+CFX_PointF CPWL_Wnd::GetCenterPoint() const {
   CFX_FloatRect rcClient = GetClientRect();
-  return CFX_FloatPoint((rcClient.left + rcClient.right) * 0.5f,
-                        (rcClient.top + rcClient.bottom) * 0.5f);
+  return CFX_PointF((rcClient.left + rcClient.right) * 0.5f,
+                    (rcClient.top + rcClient.bottom) * 0.5f);
 }
 
 bool CPWL_Wnd::HasFlag(uint32_t dwFlags) const {
@@ -560,22 +554,10 @@
   m_sPrivateParam.sBackgroundColor = color;
 }
 
-void CPWL_Wnd::SetTextColor(const CPWL_Color& color) {
-  m_sPrivateParam.sTextColor = color;
-}
-
-void CPWL_Wnd::SetTextStrokeColor(const CPWL_Color& color) {
-  m_sPrivateParam.sTextStrokeColor = color;
-}
-
 CPWL_Color CPWL_Wnd::GetTextColor() const {
   return m_sPrivateParam.sTextColor;
 }
 
-CPWL_Color CPWL_Wnd::GetTextStrokeColor() const {
-  return m_sPrivateParam.sTextStrokeColor;
-}
-
 BorderStyle CPWL_Wnd::GetBorderStyle() const {
   return m_sPrivateParam.nBorderStyle;
 }
@@ -633,7 +615,7 @@
     scp.pParentWnd = this;
     scp.sBackgroundColor = PWL_DEFAULT_WHITECOLOR;
     scp.eCursorType = FXCT_ARROW;
-    scp.nTransparency = PWL_SCROLLBAR_TRANSPARANCY;
+    scp.nTransparency = PWL_SCROLLBAR_TRANSPARENCY;
 
     m_pVScrollBar = new CPWL_ScrollBar(SBT_VSCROLL);
     m_pVScrollBar->Create(scp);
@@ -673,12 +655,12 @@
 
 void CPWL_Wnd::OnKillFocus() {}
 
-bool CPWL_Wnd::WndHitTest(const CFX_FloatPoint& point) const {
-  return IsValid() && IsVisible() && GetWindowRect().Contains(point.x, point.y);
+bool CPWL_Wnd::WndHitTest(const CFX_PointF& point) const {
+  return IsValid() && IsVisible() && GetWindowRect().Contains(point);
 }
 
-bool CPWL_Wnd::ClientHitTest(const CFX_FloatPoint& point) const {
-  return IsValid() && IsVisible() && GetClientRect().Contains(point.x, point.y);
+bool CPWL_Wnd::ClientHitTest(const CFX_PointF& point) const {
+  return IsValid() && IsVisible() && GetClientRect().Contains(point);
 }
 
 const CPWL_Wnd* CPWL_Wnd::GetRootWnd() const {
@@ -823,7 +805,7 @@
 CPWL_Color CPWL_Wnd::GetBorderRightBottomColor(BorderStyle nBorderStyle) const {
   switch (nBorderStyle) {
     case BorderStyle::BEVELED:
-      return CPWL_Utils::DevideColor(GetBackgroundColor(), 2);
+      return GetBackgroundColor() / 2.0f;
     case BorderStyle::INSET:
       return CPWL_Color(COLORTYPE_GRAY, 0.75f);
     default:
@@ -850,16 +832,6 @@
   return mt;
 }
 
-void CPWL_Wnd::PWLtoWnd(const CFX_FloatPoint& point,
-                        int32_t& x,
-                        int32_t& y) const {
-  CFX_Matrix mt = GetWindowMatrix();
-  CFX_FloatPoint pt = point;
-  mt.Transform(pt.x, pt.y);
-  x = (int32_t)(pt.x + 0.5);
-  y = (int32_t)(pt.y + 0.5);
-}
-
 FX_RECT CPWL_Wnd::PWLtoWnd(const CFX_FloatRect& rect) const {
   CFX_FloatRect rcTemp = rect;
   CFX_Matrix mt = GetWindowMatrix();
@@ -868,35 +840,13 @@
                  (int32_t)(rcTemp.right + 0.5), (int32_t)(rcTemp.top + 0.5));
 }
 
-CFX_FloatPoint CPWL_Wnd::ChildToParent(const CFX_FloatPoint& point) const {
-  CFX_Matrix mt = GetChildMatrix();
-  if (mt.IsIdentity())
-    return point;
-
-  CFX_FloatPoint pt = point;
-  mt.Transform(pt.x, pt.y);
-  return pt;
-}
-
-CFX_FloatRect CPWL_Wnd::ChildToParent(const CFX_FloatRect& rect) const {
-  CFX_Matrix mt = GetChildMatrix();
-  if (mt.IsIdentity())
-    return rect;
-
-  CFX_FloatRect rc = rect;
-  mt.TransformRect(rc);
-  return rc;
-}
-
-CFX_FloatPoint CPWL_Wnd::ParentToChild(const CFX_FloatPoint& point) const {
+CFX_PointF CPWL_Wnd::ParentToChild(const CFX_PointF& point) const {
   CFX_Matrix mt = GetChildMatrix();
   if (mt.IsIdentity())
     return point;
 
   mt.SetReverse(mt);
-  CFX_FloatPoint pt = point;
-  mt.Transform(pt.x, pt.y);
-  return pt;
+  return mt.Transform(point);
 }
 
 CFX_FloatRect CPWL_Wnd::ParentToChild(const CFX_FloatRect& rect) const {
@@ -910,18 +860,6 @@
   return rc;
 }
 
-FX_FLOAT CPWL_Wnd::GetItemHeight(FX_FLOAT fLimitWidth) {
-  return 0;
-}
-
-FX_FLOAT CPWL_Wnd::GetItemLeftMargin() {
-  return 0;
-}
-
-FX_FLOAT CPWL_Wnd::GetItemRightMargin() {
-  return 0;
-}
-
 CFX_Matrix CPWL_Wnd::GetChildToRoot() const {
   CFX_Matrix mt(1, 0, 0, 1, 0, 0);
   if (HasFlag(PWS_CHILD)) {
@@ -959,40 +897,19 @@
       pChild->EnableWindow(bEnable);
   }
   m_bEnabled = bEnable;
-  if (bEnable)
-    OnEnabled();
-  else
-    OnDisabled();
 }
 
-bool CPWL_Wnd::IsEnabled() {
-  return m_bEnabled;
-}
-
-void CPWL_Wnd::OnEnabled() {}
-
-void CPWL_Wnd::OnDisabled() {}
-
 bool CPWL_Wnd::IsCTRLpressed(uint32_t nFlag) const {
-  if (CFX_SystemHandler* pSystemHandler = GetSystemHandler()) {
-    return pSystemHandler->IsCTRLKeyDown(nFlag);
-  }
-
-  return false;
+  CFX_SystemHandler* pSystemHandler = GetSystemHandler();
+  return pSystemHandler && pSystemHandler->IsCTRLKeyDown(nFlag);
 }
 
 bool CPWL_Wnd::IsSHIFTpressed(uint32_t nFlag) const {
-  if (CFX_SystemHandler* pSystemHandler = GetSystemHandler()) {
-    return pSystemHandler->IsSHIFTKeyDown(nFlag);
-  }
-
-  return false;
+  CFX_SystemHandler* pSystemHandler = GetSystemHandler();
+  return pSystemHandler && pSystemHandler->IsSHIFTKeyDown(nFlag);
 }
 
 bool CPWL_Wnd::IsALTpressed(uint32_t nFlag) const {
-  if (CFX_SystemHandler* pSystemHandler = GetSystemHandler()) {
-    return pSystemHandler->IsALTKeyDown(nFlag);
-  }
-
-  return false;
+  CFX_SystemHandler* pSystemHandler = GetSystemHandler();
+  return pSystemHandler && pSystemHandler->IsALTKeyDown(nFlag);
 }
diff --git a/fpdfsdk/pdfwindow/PWL_Wnd.h b/fpdfsdk/pdfwindow/PWL_Wnd.h
index dd4f321..55836d4 100644
--- a/fpdfsdk/pdfwindow/PWL_Wnd.h
+++ b/fpdfsdk/pdfwindow/PWL_Wnd.h
@@ -121,7 +121,7 @@
 #define PWL_SCROLLBAR_WIDTH 12.0f
 #define PWL_SCROLLBAR_BUTTON_WIDTH 9.0f
 #define PWL_SCROLLBAR_POSBUTTON_MINWIDTH 2.0f
-#define PWL_SCROLLBAR_TRANSPARANCY 150
+#define PWL_SCROLLBAR_TRANSPARENCY 150
 #define PWL_SCROLLBAR_BKCOLOR \
   CPWL_Color(COLORTYPE_RGB, 220.0f / 255.0f, 220.0f / 255.0f, 220.0f / 255.0f)
 #define PWL_DEFAULT_SELTEXTCOLOR CPWL_Color(COLORTYPE_RGB, 1, 1, 1)
@@ -181,7 +181,6 @@
     dwBorderWidth = 0;
     sBorderColor.Reset();
     sTextColor.Reset();
-    sTextStrokeColor.Reset();
     nTransparency = 0;
     fFontSize = 0.0f;
     sDash.Reset();
@@ -204,7 +203,6 @@
   int32_t dwBorderWidth;              // optional
   CPWL_Color sBorderColor;            // optional
   CPWL_Color sTextColor;              // optional
-  CPWL_Color sTextStrokeColor;        // optional
   int32_t nTransparency;              // optional
   FX_FLOAT fFontSize;                 // optional
   CPWL_Dash sDash;                    // optional
@@ -245,85 +243,83 @@
 };
 
 class CPWL_Wnd : public CPWL_TimerHandler {
-  friend class CPWL_MsgControl;
-
  public:
   CPWL_Wnd();
   ~CPWL_Wnd() override;
 
-  void Create(const PWL_CREATEPARAM& cp);
   virtual CFX_ByteString GetClassName() const;
-  void InvalidateFocusHandler(IPWL_FocusHandler* handler);
-  void InvalidateProvider(IPWL_Provider* provider);
-  void Destroy();
-  void Move(const CFX_FloatRect& rcNew, bool bReset, bool bRefresh);
   virtual void InvalidateRect(CFX_FloatRect* pRect = nullptr);
 
-  void DrawAppearance(CFX_RenderDevice* pDevice, CFX_Matrix* pUser2Device);
-
   virtual bool OnKeyDown(uint16_t nChar, uint32_t nFlag);
-  virtual bool OnKeyUp(uint16_t nChar, uint32_t nFlag);
   virtual bool OnChar(uint16_t nChar, uint32_t nFlag);
-  virtual bool OnLButtonDblClk(const CFX_FloatPoint& point, uint32_t nFlag);
-  virtual bool OnLButtonDown(const CFX_FloatPoint& point, uint32_t nFlag);
-  virtual bool OnLButtonUp(const CFX_FloatPoint& point, uint32_t nFlag);
-  virtual bool OnMButtonDblClk(const CFX_FloatPoint& point, uint32_t nFlag);
-  virtual bool OnMButtonDown(const CFX_FloatPoint& point, uint32_t nFlag);
-  virtual bool OnMButtonUp(const CFX_FloatPoint& point, uint32_t nFlag);
-  virtual bool OnRButtonDown(const CFX_FloatPoint& point, uint32_t nFlag);
-  virtual bool OnRButtonUp(const CFX_FloatPoint& point, uint32_t nFlag);
-  virtual bool OnMouseMove(const CFX_FloatPoint& point, uint32_t nFlag);
+  virtual bool OnLButtonDblClk(const CFX_PointF& point, uint32_t nFlag);
+  virtual bool OnLButtonDown(const CFX_PointF& point, uint32_t nFlag);
+  virtual bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag);
+  virtual bool OnRButtonDown(const CFX_PointF& point, uint32_t nFlag);
+  virtual bool OnRButtonUp(const CFX_PointF& point, uint32_t nFlag);
+  virtual bool OnMouseMove(const CFX_PointF& point, uint32_t nFlag);
   virtual bool OnMouseWheel(short zDelta,
-                            const CFX_FloatPoint& point,
+                            const CFX_PointF& point,
                             uint32_t nFlag);
-
-  virtual void SetFocus();
-  virtual void KillFocus();
-  void SetCapture();
-  void ReleaseCapture();
-
   virtual void OnNotify(CPWL_Wnd* pWnd,
                         uint32_t msg,
                         intptr_t wParam = 0,
                         intptr_t lParam = 0);
-  virtual void SetTextColor(const CPWL_Color& color);
-  virtual void SetTextStrokeColor(const CPWL_Color& color);
+  virtual void SetFocus();
+  virtual void KillFocus();
+  virtual void SetCursor();
   virtual void SetVisible(bool bVisible);
+  virtual void SetFontSize(FX_FLOAT fFontSize);
+  virtual FX_FLOAT GetFontSize() const;
 
   virtual CFX_FloatRect GetFocusRect() const;
-  virtual CPWL_Color GetBackgroundColor() const;
-  virtual CPWL_Color GetBorderColor() const;
-  virtual CPWL_Color GetTextColor() const;
-  virtual CPWL_Color GetTextStrokeColor() const;
-  virtual FX_FLOAT GetFontSize() const;
-  virtual int32_t GetInnerBorderWidth() const;
-  virtual CPWL_Color GetBorderLeftTopColor(BorderStyle nBorderStyle) const;
-  virtual CPWL_Color GetBorderRightBottomColor(BorderStyle nBorderStyle) const;
-
-  virtual void SetFontSize(FX_FLOAT fFontSize);
-
-  void SetBackgroundColor(const CPWL_Color& color);
-  void SetClipRect(const CFX_FloatRect& rect);
-  void SetBorderStyle(BorderStyle eBorderStyle);
-
-  virtual CFX_FloatRect GetWindowRect() const;
   virtual CFX_FloatRect GetClientRect() const;
-  CFX_FloatPoint GetCenterPoint() const;
+
+  void InvalidateFocusHandler(IPWL_FocusHandler* handler);
+  void InvalidateProvider(IPWL_Provider* provider);
+  void Create(const PWL_CREATEPARAM& cp);
+  void Destroy();
+  void Move(const CFX_FloatRect& rcNew, bool bReset, bool bRefresh);
+
+  void SetCapture();
+  void ReleaseCapture();
+
+  void DrawAppearance(CFX_RenderDevice* pDevice, CFX_Matrix* pUser2Device);
+
+  CPWL_Color GetBackgroundColor() const;
+  void SetBackgroundColor(const CPWL_Color& color);
+  CPWL_Color GetBorderColor() const;
+  CPWL_Color GetTextColor() const;
+  void SetTextColor(const CPWL_Color& color);
+  CPWL_Color GetBorderLeftTopColor(BorderStyle nBorderStyle) const;
+  CPWL_Color GetBorderRightBottomColor(BorderStyle nBorderStyle) const;
+
+  void SetBorderStyle(BorderStyle eBorderStyle);
+  BorderStyle GetBorderStyle() const;
+  const CPWL_Dash& GetBorderDash() const;
+
   int32_t GetBorderWidth() const;
+  int32_t GetInnerBorderWidth() const;
+  CFX_FloatRect GetWindowRect() const;
+  CFX_PointF GetCenterPoint() const;
+
   bool IsVisible() const { return m_bVisible; }
   bool HasFlag(uint32_t dwFlags) const;
   void AddFlag(uint32_t dwFlags);
   void RemoveFlag(uint32_t dwFlags);
+
+  void SetClipRect(const CFX_FloatRect& rect);
   const CFX_FloatRect& GetClipRect() const;
+
   CPWL_Wnd* GetParentWindow() const;
-  BorderStyle GetBorderStyle() const;
-  const CPWL_Dash& GetBorderDash() const;
   void* GetAttachedData() const;
 
-  bool WndHitTest(const CFX_FloatPoint& point) const;
-  bool ClientHitTest(const CFX_FloatPoint& point) const;
+  bool WndHitTest(const CFX_PointF& point) const;
+  bool ClientHitTest(const CFX_PointF& point) const;
   bool IsCaptureMouse() const;
 
+  void EnableWindow(bool bEnable);
+  bool IsEnabled() const { return m_bEnabled; }
   const CPWL_Wnd* GetFocused() const;
   bool IsFocused() const;
   bool IsReadOnly() const;
@@ -341,34 +337,18 @@
   void SetChildMatrix(const CFX_Matrix& mt);
   CFX_Matrix GetWindowMatrix() const;
 
-  virtual CFX_FloatPoint ChildToParent(const CFX_FloatPoint& point) const;
-  virtual CFX_FloatRect ChildToParent(const CFX_FloatRect& rect) const;
-  virtual CFX_FloatPoint ParentToChild(const CFX_FloatPoint& point) const;
-  virtual CFX_FloatRect ParentToChild(const CFX_FloatRect& rect) const;
-
-  // those methods only implemented by listctrl item
-  virtual FX_FLOAT GetItemHeight(FX_FLOAT fLimitWidth);
-  virtual FX_FLOAT GetItemLeftMargin();
-  virtual FX_FLOAT GetItemRightMargin();
-
-  void EnableWindow(bool bEnable);
-  bool IsEnabled();
-  virtual void SetCursor();
-
  protected:
+  friend class CPWL_MsgControl;
+
   // CPWL_TimerHandler
   CFX_SystemHandler* GetSystemHandler() const override;
 
   virtual void CreateChildWnd(const PWL_CREATEPARAM& cp);
   virtual void RePosChildWnd();
-  void GetAppearanceStream(CFX_ByteTextBuf& sAppStream);
   virtual void GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream);
-  virtual void GetChildAppearanceStream(CFX_ByteTextBuf& sAppStream);
 
   virtual void DrawThisAppearance(CFX_RenderDevice* pDevice,
                                   CFX_Matrix* pUser2Device);
-  virtual void DrawChildAppearance(CFX_RenderDevice* pDevice,
-                                   CFX_Matrix* pUser2Device);
 
   virtual void OnCreate(PWL_CREATEPARAM& cp);
   virtual void OnCreated();
@@ -377,9 +357,7 @@
   virtual void OnSetFocus();
   virtual void OnKillFocus();
 
-  virtual void OnEnabled();
-  virtual void OnDisabled();
-
+  void GetAppearanceStream(CFX_ByteTextBuf& sAppStream);
   void SetNotifyFlag(bool bNotifying = true) { m_bNotifying = bNotifying; }
 
   bool IsValid() const;
@@ -389,9 +367,6 @@
   void InvalidateRectMove(const CFX_FloatRect& rcOld,
                           const CFX_FloatRect& rcNew);
 
-  void PWLtoWnd(const CFX_FloatPoint& point, int32_t& x, int32_t& y) const;
-  FX_RECT PWLtoWnd(const CFX_FloatRect& rect) const;
-
   bool IsWndCaptureMouse(const CPWL_Wnd* pWnd) const;
   bool IsWndCaptureKeyboard(const CPWL_Wnd* pWnd) const;
   const CPWL_Wnd* GetRootWnd() const;
@@ -401,6 +376,14 @@
   bool IsALTpressed(uint32_t nFlag) const;
 
  private:
+  CFX_PointF ParentToChild(const CFX_PointF& point) const;
+  CFX_FloatRect ParentToChild(const CFX_FloatRect& rect) const;
+
+  void GetChildAppearanceStream(CFX_ByteTextBuf& sAppStream);
+  void DrawChildAppearance(CFX_RenderDevice* pDevice, CFX_Matrix* pUser2Device);
+
+  FX_RECT PWLtoWnd(const CFX_FloatRect& rect) const;
+
   void AddChild(CPWL_Wnd* pWnd);
   void RemoveChild(CPWL_Wnd* pWnd);
 
@@ -413,10 +396,7 @@
 
   CPWL_MsgControl* GetMsgControl() const;
 
- protected:
   std::vector<CPWL_Wnd*> m_Children;
-
- private:
   PWL_CREATEPARAM m_sPrivateParam;
   CPWL_ScrollBar* m_pVScrollBar;
   CFX_FloatRect m_rcWindow;
diff --git a/fpdfsdk/pdfwindow/cpwl_color.cpp b/fpdfsdk/pdfwindow/cpwl_color.cpp
new file mode 100644
index 0000000..9c9ca3e
--- /dev/null
+++ b/fpdfsdk/pdfwindow/cpwl_color.cpp
@@ -0,0 +1,179 @@
+// 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 "fpdfsdk/pdfwindow/cpwl_color.h"
+
+#include <algorithm>
+
+namespace {
+
+bool InRange(FX_FLOAT comp) {
+  return comp >= 0.0f && comp <= 1.0f;
+}
+
+CPWL_Color ConvertCMYK2GRAY(FX_FLOAT dC,
+                            FX_FLOAT dM,
+                            FX_FLOAT dY,
+                            FX_FLOAT dK) {
+  if (!InRange(dC) || !InRange(dM) || !InRange(dY) || !InRange(dK))
+    return CPWL_Color(COLORTYPE_GRAY);
+  return CPWL_Color(
+      COLORTYPE_GRAY,
+      1.0f - std::min(1.0f, 0.3f * dC + 0.59f * dM + 0.11f * dY + dK));
+}
+
+CPWL_Color ConvertGRAY2CMYK(FX_FLOAT dGray) {
+  if (!InRange(dGray))
+    return CPWL_Color(COLORTYPE_CMYK);
+  return CPWL_Color(COLORTYPE_CMYK, 0.0f, 0.0f, 0.0f, 1.0f - dGray);
+}
+
+CPWL_Color ConvertGRAY2RGB(FX_FLOAT dGray) {
+  if (!InRange(dGray))
+    return CPWL_Color(COLORTYPE_RGB);
+  return CPWL_Color(COLORTYPE_RGB, dGray, dGray, dGray);
+}
+
+CPWL_Color ConvertRGB2GRAY(FX_FLOAT dR, FX_FLOAT dG, FX_FLOAT dB) {
+  if (!InRange(dR) || !InRange(dG) || !InRange(dB))
+    return CPWL_Color(COLORTYPE_GRAY);
+  return CPWL_Color(COLORTYPE_GRAY, 0.3f * dR + 0.59f * dG + 0.11f * dB);
+}
+
+CPWL_Color ConvertCMYK2RGB(FX_FLOAT dC, FX_FLOAT dM, FX_FLOAT dY, FX_FLOAT dK) {
+  if (!InRange(dC) || !InRange(dM) || !InRange(dY) || !InRange(dK))
+    return CPWL_Color(COLORTYPE_RGB);
+  return CPWL_Color(COLORTYPE_RGB, 1.0f - std::min(1.0f, dC + dK),
+                    1.0f - std::min(1.0f, dM + dK),
+                    1.0f - std::min(1.0f, dY + dK));
+}
+
+CPWL_Color ConvertRGB2CMYK(FX_FLOAT dR, FX_FLOAT dG, FX_FLOAT dB) {
+  if (!InRange(dR) || !InRange(dG) || !InRange(dB))
+    return CPWL_Color(COLORTYPE_CMYK);
+
+  FX_FLOAT c = 1.0f - dR;
+  FX_FLOAT m = 1.0f - dG;
+  FX_FLOAT y = 1.0f - dB;
+  return CPWL_Color(COLORTYPE_CMYK, c, m, y, std::min(c, std::min(m, y)));
+}
+
+}  // namespace
+
+CPWL_Color CPWL_Color::ConvertColorType(int32_t nConvertColorType) const {
+  if (nColorType == nConvertColorType)
+    return *this;
+
+  CPWL_Color ret;
+  switch (nColorType) {
+    case COLORTYPE_TRANSPARENT:
+      ret = *this;
+      ret.nColorType = COLORTYPE_TRANSPARENT;
+      break;
+    case COLORTYPE_GRAY:
+      switch (nConvertColorType) {
+        case COLORTYPE_RGB:
+          ret = ConvertGRAY2RGB(fColor1);
+          break;
+        case COLORTYPE_CMYK:
+          ret = ConvertGRAY2CMYK(fColor1);
+          break;
+      }
+      break;
+    case COLORTYPE_RGB:
+      switch (nConvertColorType) {
+        case COLORTYPE_GRAY:
+          ret = ConvertRGB2GRAY(fColor1, fColor2, fColor3);
+          break;
+        case COLORTYPE_CMYK:
+          ret = ConvertRGB2CMYK(fColor1, fColor2, fColor3);
+          break;
+      }
+      break;
+    case COLORTYPE_CMYK:
+      switch (nConvertColorType) {
+        case COLORTYPE_GRAY:
+          ret = ConvertCMYK2GRAY(fColor1, fColor2, fColor3, fColor4);
+          break;
+        case COLORTYPE_RGB:
+          ret = ConvertCMYK2RGB(fColor1, fColor2, fColor3, fColor4);
+          break;
+      }
+      break;
+  }
+  return ret;
+}
+
+FX_COLORREF CPWL_Color::ToFXColor(int32_t nTransparency) const {
+  CPWL_Color ret;
+  switch (nColorType) {
+    case COLORTYPE_TRANSPARENT: {
+      ret = CPWL_Color(COLORTYPE_TRANSPARENT, 0, 0, 0, 0);
+      break;
+    }
+    case COLORTYPE_GRAY: {
+      ret = ConvertGRAY2RGB(fColor1);
+      ret.fColor4 = nTransparency;
+      break;
+    }
+    case COLORTYPE_RGB: {
+      ret = CPWL_Color(COLORTYPE_RGB, fColor1, fColor2, fColor3);
+      ret.fColor4 = nTransparency;
+      break;
+    }
+    case COLORTYPE_CMYK: {
+      ret = ConvertCMYK2RGB(fColor1, fColor2, fColor3, fColor4);
+      ret.fColor4 = nTransparency;
+      break;
+    }
+  }
+  return ArgbEncode(ret.fColor4, static_cast<int32_t>(ret.fColor1 * 255),
+                    static_cast<int32_t>(ret.fColor2 * 255),
+                    static_cast<int32_t>(ret.fColor3 * 255));
+}
+
+CPWL_Color CPWL_Color::operator-(FX_FLOAT fColorSub) const {
+  CPWL_Color sRet(nColorType);
+  switch (nColorType) {
+    case COLORTYPE_TRANSPARENT:
+      sRet.nColorType = COLORTYPE_RGB;
+      sRet.fColor1 = std::max(1.0f - fColorSub, 0.0f);
+      sRet.fColor2 = std::max(1.0f - fColorSub, 0.0f);
+      sRet.fColor3 = std::max(1.0f - fColorSub, 0.0f);
+      break;
+    case COLORTYPE_RGB:
+    case COLORTYPE_GRAY:
+    case COLORTYPE_CMYK:
+      sRet.fColor1 = std::max(fColor1 - fColorSub, 0.0f);
+      sRet.fColor2 = std::max(fColor2 - fColorSub, 0.0f);
+      sRet.fColor3 = std::max(fColor3 - fColorSub, 0.0f);
+      sRet.fColor4 = std::max(fColor4 - fColorSub, 0.0f);
+      break;
+  }
+  return sRet;
+}
+
+CPWL_Color CPWL_Color::operator/(FX_FLOAT fColorDivide) const {
+  CPWL_Color sRet(nColorType);
+  switch (nColorType) {
+    case COLORTYPE_TRANSPARENT:
+      sRet.nColorType = COLORTYPE_RGB;
+      sRet.fColor1 = 1.0f / fColorDivide;
+      sRet.fColor2 = 1.0f / fColorDivide;
+      sRet.fColor3 = 1.0f / fColorDivide;
+      break;
+    case COLORTYPE_RGB:
+    case COLORTYPE_GRAY:
+    case COLORTYPE_CMYK:
+      sRet = *this;
+      sRet.fColor1 /= fColorDivide;
+      sRet.fColor2 /= fColorDivide;
+      sRet.fColor3 /= fColorDivide;
+      sRet.fColor4 /= fColorDivide;
+      break;
+  }
+  return sRet;
+}
diff --git a/fpdfsdk/pdfwindow/cpwl_color.h b/fpdfsdk/pdfwindow/cpwl_color.h
index c1f9e6e..f1b34c7 100644
--- a/fpdfsdk/pdfwindow/cpwl_color.h
+++ b/fpdfsdk/pdfwindow/cpwl_color.h
@@ -28,7 +28,12 @@
         fColor3(b / 255.0f),
         fColor4(0) {}
 
-  void ConvertColorType(int32_t other_nColorType);
+  CPWL_Color operator/(FX_FLOAT fColorDivide) const;
+  CPWL_Color operator-(FX_FLOAT fColorSub) const;
+
+  CPWL_Color ConvertColorType(int32_t other_nColorType) const;
+
+  FX_COLORREF ToFXColor(int32_t nTransparency) const;
 
   void Reset() {
     nColorType = COLORTYPE_TRANSPARENT;
diff --git a/fxjs/fxjs_v8.cpp b/fxjs/fxjs_v8.cpp
index c96cc1f..b0e1a1b 100644
--- a/fxjs/fxjs_v8.cpp
+++ b/fxjs/fxjs_v8.cpp
@@ -20,12 +20,32 @@
 static size_t g_isolate_ref_count = 0;
 static FXJS_ArrayBufferAllocator* g_arrayBufferAllocator = nullptr;
 static v8::Global<v8::ObjectTemplate>* g_DefaultGlobalObjectTemplate = nullptr;
+static wchar_t kPerObjectDataTag[] = L"CFXJS_PerObjectData";
 
 class CFXJS_PerObjectData {
  public:
   explicit CFXJS_PerObjectData(int nObjDefID)
       : m_ObjDefID(nObjDefID), m_pPrivate(nullptr) {}
 
+  static void SetInObject(CFXJS_PerObjectData* pData,
+                          v8::Local<v8::Object> pObj) {
+    if (pObj->InternalFieldCount() == 2) {
+      pObj->SetAlignedPointerInInternalField(0, pData);
+      pObj->SetAlignedPointerInInternalField(
+          1, static_cast<void*>(kPerObjectDataTag));
+    }
+  }
+
+  static CFXJS_PerObjectData* GetFromObject(v8::Local<v8::Object> pObj) {
+    if (pObj.IsEmpty() || pObj->InternalFieldCount() != 2 ||
+        pObj->GetAlignedPointerFromInternalField(1) !=
+            static_cast<void*>(kPerObjectDataTag)) {
+      return nullptr;
+    }
+    return static_cast<CFXJS_PerObjectData*>(
+        pObj->GetAlignedPointerFromInternalField(0));
+  }
+
   const int m_ObjDefID;
   void* m_pPrivate;
 };
@@ -42,7 +62,7 @@
   }
 
   CFXJS_ObjDefinition(v8::Isolate* isolate,
-                      const wchar_t* sObjName,
+                      const char* sObjName,
                       FXJSOBJTYPE eObjType,
                       CFXJS_Engine::Constructor pConstructor,
                       CFXJS_Engine::Destructor pDestructor)
@@ -56,6 +76,12 @@
 
     v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
     fun->InstanceTemplate()->SetInternalFieldCount(2);
+    fun->SetCallHandler([](const v8::FunctionCallbackInfo<v8::Value>& info) {
+      v8::Local<v8::Object> holder = info.Holder();
+      ASSERT(holder->InternalFieldCount() == 2);
+      holder->SetAlignedPointerInInternalField(0, nullptr);
+      holder->SetAlignedPointerInInternalField(1, nullptr);
+    });
     if (eObjType == FXJSOBJTYPE_GLOBAL) {
       fun->InstanceTemplate()->Set(
           v8::Symbol::GetToStringTag(isolate),
@@ -86,7 +112,7 @@
     return scope.Escape(m_Signature.Get(m_pIsolate));
   }
 
-  const wchar_t* const m_ObjName;
+  const char* const m_ObjName;
   const FXJSOBJTYPE m_ObjType;
   const CFXJS_Engine::Constructor m_pConstructor;
   const CFXJS_Engine::Destructor m_pDestructor;
@@ -235,13 +261,8 @@
 
 // static
 int CFXJS_Engine::GetObjDefnID(v8::Local<v8::Object> pObj) {
-  if (pObj.IsEmpty() || !pObj->InternalFieldCount())
-    return -1;
-  CFXJS_PerObjectData* pPerObjectData = static_cast<CFXJS_PerObjectData*>(
-      pObj->GetAlignedPointerFromInternalField(0));
-  if (!pPerObjectData)
-    return -1;
-  return pPerObjectData->m_ObjDefID;
+  CFXJS_PerObjectData* pData = CFXJS_PerObjectData::GetFromObject(pObj);
+  return pData ? pData->m_ObjDefID : -1;
 }
 
 // static
@@ -251,13 +272,13 @@
 
 // static
 void CFXJS_Engine::FreeObjectPrivate(v8::Local<v8::Object> pObj) {
-  if (pObj.IsEmpty() || !pObj->InternalFieldCount())
-    return;
-  FreeObjectPrivate(pObj->GetAlignedPointerFromInternalField(0));
+  CFXJS_PerObjectData* pData = CFXJS_PerObjectData::GetFromObject(pObj);
   pObj->SetAlignedPointerInInternalField(0, nullptr);
+  pObj->SetAlignedPointerInInternalField(1, nullptr);
+  delete pData;
 }
 
-int CFXJS_Engine::DefineObj(const wchar_t* sObjName,
+int CFXJS_Engine::DefineObj(const char* sObjName,
                             FXJSOBJTYPE eObjType,
                             CFXJS_Engine::Constructor pConstructor,
                             CFXJS_Engine::Destructor pDestructor) {
@@ -270,35 +291,32 @@
 }
 
 void CFXJS_Engine::DefineObjMethod(int nObjDefnID,
-                                   const wchar_t* sMethodName,
+                                   const char* sMethodName,
                                    v8::FunctionCallback pMethodCall) {
   v8::Isolate::Scope isolate_scope(m_isolate);
   v8::HandleScope handle_scope(m_isolate);
-  CFX_ByteString bsMethodName = CFX_WideString(sMethodName).UTF8Encode();
   CFXJS_ObjDefinition* pObjDef =
       CFXJS_ObjDefinition::ForID(m_isolate, nObjDefnID);
   v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(
       m_isolate, pMethodCall, v8::Local<v8::Value>(), pObjDef->GetSignature());
   fun->RemovePrototype();
   pObjDef->GetInstanceTemplate()->Set(
-      v8::String::NewFromUtf8(m_isolate, bsMethodName.c_str(),
+      v8::String::NewFromUtf8(m_isolate, sMethodName,
                               v8::NewStringType::kNormal)
           .ToLocalChecked(),
       fun, v8::ReadOnly);
 }
 
 void CFXJS_Engine::DefineObjProperty(int nObjDefnID,
-                                     const wchar_t* sPropName,
+                                     const char* sPropName,
                                      v8::AccessorGetterCallback pPropGet,
                                      v8::AccessorSetterCallback pPropPut) {
   v8::Isolate::Scope isolate_scope(m_isolate);
   v8::HandleScope handle_scope(m_isolate);
-  CFX_ByteString bsPropertyName = CFX_WideString(sPropName).UTF8Encode();
   CFXJS_ObjDefinition* pObjDef =
       CFXJS_ObjDefinition::ForID(m_isolate, nObjDefnID);
   pObjDef->GetInstanceTemplate()->SetAccessor(
-      v8::String::NewFromUtf8(m_isolate, bsPropertyName.c_str(),
-                              v8::NewStringType::kNormal)
+      v8::String::NewFromUtf8(m_isolate, sPropName, v8::NewStringType::kNormal)
           .ToLocalChecked(),
       pPropGet, pPropPut);
 }
@@ -318,26 +336,24 @@
 }
 
 void CFXJS_Engine::DefineObjConst(int nObjDefnID,
-                                  const wchar_t* sConstName,
+                                  const char* sConstName,
                                   v8::Local<v8::Value> pDefault) {
   v8::Isolate::Scope isolate_scope(m_isolate);
   v8::HandleScope handle_scope(m_isolate);
-  CFX_ByteString bsConstName = CFX_WideString(sConstName).UTF8Encode();
   CFXJS_ObjDefinition* pObjDef =
       CFXJS_ObjDefinition::ForID(m_isolate, nObjDefnID);
-  pObjDef->GetInstanceTemplate()->Set(m_isolate, bsConstName.c_str(), pDefault);
+  pObjDef->GetInstanceTemplate()->Set(m_isolate, sConstName, pDefault);
 }
 
-void CFXJS_Engine::DefineGlobalMethod(const wchar_t* sMethodName,
+void CFXJS_Engine::DefineGlobalMethod(const char* sMethodName,
                                       v8::FunctionCallback pMethodCall) {
   v8::Isolate::Scope isolate_scope(m_isolate);
   v8::HandleScope handle_scope(m_isolate);
-  CFX_ByteString bsMethodName = CFX_WideString(sMethodName).UTF8Encode();
   v8::Local<v8::FunctionTemplate> fun =
       v8::FunctionTemplate::New(m_isolate, pMethodCall);
   fun->RemovePrototype();
   GetGlobalObjectTemplate(m_isolate)->Set(
-      v8::String::NewFromUtf8(m_isolate, bsMethodName.c_str(),
+      v8::String::NewFromUtf8(m_isolate, sMethodName,
                               v8::NewStringType::kNormal)
           .ToLocalChecked(),
       fun, v8::ReadOnly);
@@ -347,7 +363,7 @@
                                      v8::FunctionCallback pConstGetter) {
   v8::Isolate::Scope isolate_scope(m_isolate);
   v8::HandleScope handle_scope(m_isolate);
-  CFX_ByteString bsConst = CFX_WideString(sConstName).UTF8Encode();
+  CFX_ByteString bsConst = FX_UTF8Encode(CFX_WideStringC(sConstName));
   v8::Local<v8::FunctionTemplate> fun =
       v8::FunctionTemplate::New(m_isolate, pConstGetter);
   fun->RemovePrototype();
@@ -380,26 +396,26 @@
   for (int i = 0; i < maxID; ++i) {
     CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(m_isolate, i);
     if (pObjDef->m_ObjType == FXJSOBJTYPE_GLOBAL) {
-      v8Context->Global()
-          ->GetPrototype()
-          ->ToObject(v8Context)
-          .ToLocalChecked()
-          ->SetAlignedPointerInInternalField(0, new CFXJS_PerObjectData(i));
-
-      if (pObjDef->m_pConstructor)
+      CFXJS_PerObjectData::SetInObject(new CFXJS_PerObjectData(i),
+                                       v8Context->Global()
+                                           ->GetPrototype()
+                                           ->ToObject(v8Context)
+                                           .ToLocalChecked());
+      if (pObjDef->m_pConstructor) {
         pObjDef->m_pConstructor(this, v8Context->Global()
                                           ->GetPrototype()
                                           ->ToObject(v8Context)
                                           .ToLocalChecked());
+      }
     } else if (pObjDef->m_ObjType == FXJSOBJTYPE_STATIC) {
-      CFX_ByteString bs = CFX_WideString(pObjDef->m_ObjName).UTF8Encode();
-      v8::Local<v8::String> m_ObjName =
-          v8::String::NewFromUtf8(m_isolate, bs.c_str(),
-                                  v8::NewStringType::kNormal, bs.GetLength())
+      v8::Local<v8::String> pObjName =
+          v8::String::NewFromUtf8(m_isolate, pObjDef->m_ObjName,
+                                  v8::NewStringType::kNormal,
+                                  strlen(pObjDef->m_ObjName))
               .ToLocalChecked();
 
       v8::Local<v8::Object> obj = NewFxDynamicObj(i, true);
-      v8Context->Global()->Set(v8Context, m_ObjName, obj).FromJust();
+      v8Context->Global()->Set(v8Context, pObjName, obj).FromJust();
       m_StaticObjects[i] = new v8::Global<v8::Object>(m_isolate, obj);
     }
   }
@@ -499,15 +515,14 @@
   if (!pObjDef->GetInstanceTemplate()->NewInstance(context).ToLocal(&obj))
     return v8::Local<v8::Object>();
 
-  CFXJS_PerObjectData* pPerObjData = new CFXJS_PerObjectData(nObjDefnID);
-  obj->SetAlignedPointerInInternalField(0, pPerObjData);
+  CFXJS_PerObjectData* pObjData = new CFXJS_PerObjectData(nObjDefnID);
+  CFXJS_PerObjectData::SetInObject(pObjData, obj);
   if (pObjDef->m_pConstructor)
     pObjDef->m_pConstructor(this, obj);
 
-  if (!bStatic && FXJS_PerIsolateData::Get(m_isolate)->m_pDynamicObjsMap) {
-    FXJS_PerIsolateData::Get(m_isolate)->m_pDynamicObjsMap->set(pPerObjData,
-                                                                obj);
-  }
+  if (!bStatic && FXJS_PerIsolateData::Get(m_isolate)->m_pDynamicObjsMap)
+    FXJS_PerIsolateData::Get(m_isolate)->m_pDynamicObjsMap->set(pObjData, obj);
+
   return obj;
 }
 
@@ -533,43 +548,25 @@
 }
 
 void CFXJS_Engine::SetObjectPrivate(v8::Local<v8::Object> pObj, void* p) {
-  if (pObj.IsEmpty() || !pObj->InternalFieldCount())
-    return;
-  CFXJS_PerObjectData* pPerObjectData = static_cast<CFXJS_PerObjectData*>(
-      pObj->GetAlignedPointerFromInternalField(0));
+  CFXJS_PerObjectData* pPerObjectData =
+      CFXJS_PerObjectData::GetFromObject(pObj);
   if (!pPerObjectData)
     return;
   pPerObjectData->m_pPrivate = p;
 }
 
 void* CFXJS_Engine::GetObjectPrivate(v8::Local<v8::Object> pObj) {
-  if (pObj.IsEmpty())
-    return nullptr;
-  CFXJS_PerObjectData* pPerObjectData = nullptr;
-  if (pObj->InternalFieldCount()) {
-    pPerObjectData = static_cast<CFXJS_PerObjectData*>(
-        pObj->GetAlignedPointerFromInternalField(0));
-  } else {
+  CFXJS_PerObjectData* pData = CFXJS_PerObjectData::GetFromObject(pObj);
+  if (!pData && !pObj.IsEmpty()) {
     // It could be a global proxy object.
     v8::Local<v8::Value> v = pObj->GetPrototype();
     v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
     if (v->IsObject()) {
-      pPerObjectData = static_cast<CFXJS_PerObjectData*>(
-          v->ToObject(context)
-              .ToLocalChecked()
-              ->GetAlignedPointerFromInternalField(0));
+      pData = CFXJS_PerObjectData::GetFromObject(
+          v->ToObject(context).ToLocalChecked());
     }
   }
-  return pPerObjectData ? pPerObjectData->m_pPrivate : nullptr;
-}
-
-v8::Local<v8::String> CFXJS_Engine::WSToJSString(
-    const CFX_WideString& wsPropertyName) {
-  v8::Isolate* pIsolate = m_isolate ? m_isolate : v8::Isolate::GetCurrent();
-  CFX_ByteString bs = wsPropertyName.UTF8Encode();
-  return v8::String::NewFromUtf8(pIsolate, bs.c_str(),
-                                 v8::NewStringType::kNormal, bs.GetLength())
-      .ToLocalChecked();
+  return pData ? pData->m_pPrivate : nullptr;
 }
 
 v8::Local<v8::Value> CFXJS_Engine::GetObjectProperty(
@@ -578,7 +575,8 @@
   if (pObj.IsEmpty())
     return v8::Local<v8::Value>();
   v8::Local<v8::Value> val;
-  if (!pObj->Get(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName))
+  if (!pObj->Get(m_isolate->GetCurrentContext(),
+                 NewString(wsPropertyName.AsStringC()))
            .ToLocal(&val))
     return v8::Local<v8::Value>();
   return val;
@@ -607,7 +605,8 @@
                                      v8::Local<v8::Value> pPut) {
   if (pObj.IsEmpty())
     return;
-  pObj->Set(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName), pPut)
+  pObj->Set(m_isolate->GetCurrentContext(),
+            NewString(wsPropertyName.AsStringC()), pPut)
       .FromJust();
 }
 
@@ -666,8 +665,15 @@
   return v8::Boolean::New(m_isolate, b);
 }
 
-v8::Local<v8::Value> CFXJS_Engine::NewString(const CFX_WideString& str) {
-  return WSToJSString(str.c_str());
+v8::Local<v8::Value> CFXJS_Engine::NewString(const CFX_ByteStringC& str) {
+  v8::Isolate* pIsolate = m_isolate ? m_isolate : v8::Isolate::GetCurrent();
+  return v8::String::NewFromUtf8(pIsolate, str.c_str(),
+                                 v8::NewStringType::kNormal, str.GetLength())
+      .ToLocalChecked();
+}
+
+v8::Local<v8::Value> CFXJS_Engine::NewString(const CFX_WideStringC& str) {
+  return NewString(FX_UTF8Encode(str).AsStringC());
 }
 
 v8::Local<v8::Value> CFXJS_Engine::NewNull() {
diff --git a/fxjs/fxjs_v8.h b/fxjs/fxjs_v8.h
index 6cf3ca5..50b0b2c 100644
--- a/fxjs/fxjs_v8.h
+++ b/fxjs/fxjs_v8.h
@@ -33,7 +33,7 @@
 
 // FXJS_V8 places no restrictions on this class; it merely passes it
 // on to caller-provided methods.
-class IJS_Context;  // A description of the event that caused JS execution.
+class IJS_EventContext;  // A description of the event that caused JS execution.
 
 enum FXJSOBJTYPE {
   FXJSOBJTYPE_DYNAMIC = 0,  // Created by native method and returned to JS.
@@ -142,16 +142,16 @@
   v8::Isolate* GetIsolate() const { return m_isolate; }
 
   // Always returns a valid, newly-created objDefnID.
-  int DefineObj(const wchar_t* sObjName,
+  int DefineObj(const char* sObjName,
                 FXJSOBJTYPE eObjType,
                 Constructor pConstructor,
                 Destructor pDestructor);
 
   void DefineObjMethod(int nObjDefnID,
-                       const wchar_t* sMethodName,
+                       const char* sMethodName,
                        v8::FunctionCallback pMethodCall);
   void DefineObjProperty(int nObjDefnID,
-                         const wchar_t* sPropName,
+                         const char* sPropName,
                          v8::AccessorGetterCallback pPropGet,
                          v8::AccessorSetterCallback pPropPut);
   void DefineObjAllProperties(int nObjDefnID,
@@ -160,9 +160,9 @@
                               v8::NamedPropertySetterCallback pPropPut,
                               v8::NamedPropertyDeleterCallback pPropDel);
   void DefineObjConst(int nObjDefnID,
-                      const wchar_t* sConstName,
+                      const char* sConstName,
                       v8::Local<v8::Value> pDefault);
-  void DefineGlobalMethod(const wchar_t* sMethodName,
+  void DefineGlobalMethod(const char* sMethodName,
                           v8::FunctionCallback pMethodCall);
   void DefineGlobalConst(const wchar_t* sConstName,
                          v8::FunctionCallback pConstGetter);
@@ -184,7 +184,8 @@
   v8::Local<v8::Value> NewNumber(double number);
   v8::Local<v8::Value> NewNumber(float number);
   v8::Local<v8::Value> NewBoolean(bool b);
-  v8::Local<v8::Value> NewString(const CFX_WideString& str);
+  v8::Local<v8::Value> NewString(const CFX_ByteStringC& str);
+  v8::Local<v8::Value> NewString(const CFX_WideStringC& str);
   v8::Local<v8::Date> NewDate(double d);
   v8::Local<v8::Object> NewFxDynamicObj(int nObjDefnID, bool bStatic = false);
 
@@ -221,7 +222,6 @@
   void SetConstArray(const CFX_WideString& name, v8::Local<v8::Array> array);
   v8::Local<v8::Array> GetConstArray(const CFX_WideString& name);
 
-  v8::Local<v8::String> WSToJSString(const CFX_WideString& wsPropertyName);
   void Error(const CFX_WideString& message);
 
  protected:
diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg
index a621401..7062e43 100644
--- a/infra/config/cq.cfg
+++ b/infra/config/cq.cfg
@@ -14,6 +14,11 @@
 verifiers {
   reviewer_lgtm {
      committer_list: "project-pdfium-committers"
+     dry_run_access_list: "project-pdfium-tryjob-access"
+  }
+  gerrit_cq_ability {
+     committer_list: "project-pdfium-committers"
+     dry_run_access_list: "project-pdfium-tryjob-access"
   }
 
   tree_status {
@@ -41,7 +46,6 @@
       }
       builders {
         name: "linux_skia"
-        experiment_percentage: 100
       }
       builders {
         name: "linux_xfa"
@@ -60,7 +64,6 @@
       }
       builders {
         name: "mac_skia"
-        experiment_percentage: 100
       }
       builders {
         name: "mac_xfa"
@@ -76,7 +79,6 @@
       }
       builders {
         name: "win_skia"
-        experiment_percentage: 100
       }
       builders {
         name: "win_xfa"
diff --git a/pdfium.gni b/pdfium.gni
index 5737224..8ce09f9 100644
--- a/pdfium.gni
+++ b/pdfium.gni
@@ -17,6 +17,18 @@
   # Build PDFium either with or without XFA Forms support.
   pdf_enable_xfa = pdf_enable_xfa_override
 
+  # If XFA, also support bmp codec. Ignored if not XFA.
+  pdf_enable_xfa_bmp = true
+
+  # If XFA, also support gif codec. Ignored if not XFA.
+  pdf_enable_xfa_gif = true
+
+  # If XFA, also support png codec. Ignored if not XFA.
+  pdf_enable_xfa_png = true
+
+  # If XFA, also support png codec. Ignored if not XFA.
+  pdf_enable_xfa_tiff = true
+
   # Build PDFium against skia (experimental) rather than agg. Use Skia to draw everything.
   pdf_use_skia = pdf_use_skia_override
 
diff --git a/pdfium.mk b/pdfium.mk
index b81ae6d..26a14b5 100644
--- a/pdfium.mk
+++ b/pdfium.mk
@@ -63,6 +63,8 @@
     fpdfsdk/fpdfdoc.cpp \
     fpdfsdk/fpdfeditimg.cpp \
     fpdfsdk/fpdfeditpage.cpp \
+    fpdfsdk/fpdfeditpath.cpp \
+    fpdfsdk/fpdfedittext.cpp \
     fpdfsdk/fpdfformfill.cpp \
     fpdfsdk/fpdfppo.cpp \
     fpdfsdk/fpdfsave.cpp \
diff --git a/pdfiumpdfwindow.mk b/pdfiumpdfwindow.mk
index d25c8b3..4bd27ef 100644
--- a/pdfiumpdfwindow.mk
+++ b/pdfiumpdfwindow.mk
@@ -29,6 +29,7 @@
     fpdfsdk/pdfwindow/PWL_SpecialButton.cpp \
     fpdfsdk/pdfwindow/PWL_Utils.cpp \
     fpdfsdk/pdfwindow/PWL_Wnd.cpp \
+    fpdfsdk/pdfwindow/cpwl_color.cpp \
 
 LOCAL_C_INCLUDES := \
     external/pdfium \
diff --git a/public/fpdf_edit.h b/public/fpdf_edit.h
index 640d97e..3350b5c 100644
--- a/public/fpdf_edit.h
+++ b/public/fpdf_edit.h
@@ -27,6 +27,9 @@
 #define FPDF_PAGEOBJ_SHADING 4
 #define FPDF_PAGEOBJ_FORM 5
 
+#define FPDF_FILLMODE_ALTERNATE 1
+#define FPDF_FILLMODE_WINDING 2
+
 #ifdef __cplusplus
 extern "C" {
 #endif  // __cplusplus
@@ -260,6 +263,161 @@
                                                    FPDF_PAGEOBJECT image_object,
                                                    FPDF_BITMAP bitmap);
 
+// Create a new path object at an initial position.
+//
+//   x - initial horizontal position.
+//   y - initial vertical position.
+//
+// Returns a handle to a new path object.
+DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_CreateNewPath(float x, float y);
+
+// Create a closed path consisting of a rectangle.
+//
+//   x - horizontal position for the left boundary of the rectangle.
+//   y - vertical position for the bottom boundary of the rectangle.
+//   w - width of the rectangle.
+//   h - height of the rectangle.
+//
+// Returns a handle to the new path object.
+DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_CreateNewRect(float x,
+                                                            float y,
+                                                            float w,
+                                                            float h);
+
+// Set the stroke RGBA of a path. Range of values: 0 - 255.
+//
+// path   - the handle to the path object.
+// R      - the red component for the path stroke color.
+// G      - the green component for the path stroke color.
+// B      - the blue component for the path stroke color.
+// A      - the stroke alpha for the path.
+//
+// Returns TRUE on success.
+DLLEXPORT FPDF_BOOL FPDFPath_SetStrokeColor(FPDF_PAGEOBJECT path,
+                                            unsigned int R,
+                                            unsigned int G,
+                                            unsigned int B,
+                                            unsigned int A);
+
+// Set the stroke width of a path.
+//
+// path   - the handle to the path object.
+// width  - the width of the stroke.
+//
+// Returns TRUE on success
+DLLEXPORT FPDF_BOOL FPDFPath_SetStrokeWidth(FPDF_PAGEOBJECT path, float width);
+
+// Set the fill RGBA of a path. Range of values: 0 - 255.
+//
+// path   - the handle to the path object.
+// R      - the red component for the path fill color.
+// G      - the green component for the path fill color.
+// B      - the blue component for the path fill color.
+// A      - the fill alpha for the path.
+//
+// Returns TRUE on success.
+DLLEXPORT FPDF_BOOL FPDFPath_SetFillColor(FPDF_PAGEOBJECT path,
+                                          unsigned int R,
+                                          unsigned int G,
+                                          unsigned int B,
+                                          unsigned int A);
+
+// Move a path's current point.
+//
+// path   - the handle to the path object.
+// x      - the horizontal position of the new current point.
+// y      - the vertical position of the new current point.
+//
+// Note that no line will be created between the previous current point and the
+// new one.
+//
+// Returns TRUE on success
+DLLEXPORT FPDF_BOOL FPDFPath_MoveTo(FPDF_PAGEOBJECT path, float x, float y);
+
+// Add a line between the current point and a new point in the path.
+//
+// path   - the handle to the path object.
+// x      - the horizontal position of the new point.
+// y      - the vertical position of the new point.
+//
+// The path's current point is changed to (x, y).
+//
+// Returns TRUE on success
+DLLEXPORT FPDF_BOOL FPDFPath_LineTo(FPDF_PAGEOBJECT path, float x, float y);
+
+// Add a cubic Bezier curve to the given path, starting at the current point.
+//
+// path   - the handle to the path object.
+// x1     - the horizontal position of the first Bezier control point.
+// y1     - the vertical position of the first Bezier control point.
+// x2     - the horizontal position of the second Bezier control point.
+// y2     - the vertical position of the second Bezier control point.
+// x3     - the horizontal position of the ending point of the Bezier curve.
+// y3     - the vertical position of the ending point of the Bezier curve.
+//
+// Returns TRUE on success
+DLLEXPORT FPDF_BOOL FPDFPath_BezierTo(FPDF_PAGEOBJECT path,
+                                      float x1,
+                                      float y1,
+                                      float x2,
+                                      float y2,
+                                      float x3,
+                                      float y3);
+
+// Close the current subpath of a given path.
+//
+// path   - the handle to the path object.
+//
+// This will add a line between the current point and the initial point of the
+// subpath, thus terminating the current subpath.
+//
+// Returns TRUE on success
+DLLEXPORT FPDF_BOOL FPDFPath_Close(FPDF_PAGEOBJECT path);
+
+// Set the drawing mode of a path.
+//
+// path     - the handle to the path object.
+// fillmode - the filling mode to be set: 0 for no fill, 1 for alternate, 2 for
+// winding.
+// stroke   - a boolean specifying if the path should be stroked or not.
+//
+// Returns TRUE on success
+DLLEXPORT FPDF_BOOL FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path,
+                                         int fillmode,
+                                         FPDF_BOOL stroke);
+
+// Create a new text object using one of the standard PDF fonts.
+//
+// document   - handle to the document.
+// font       - string containing the font name, without spaces.
+// font_size  - the font size for the new text object.
+//
+// Returns a handle to a new text object, or NULL on failure
+DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_NewTextObj(FPDF_DOCUMENT document,
+                                                         FPDF_BYTESTRING font,
+                                                         float font_size);
+
+// Set the text for a textobject. If it had text, it will be replaced.
+//
+// text_object  - handle to the text object.
+// text         - string containing the text to be added.
+//
+// Returns TRUE on success
+DLLEXPORT FPDF_BOOL STDCALL FPDFText_SetText(FPDF_PAGEOBJECT text_object,
+                                             FPDF_BYTESTRING text);
+
+// Returns a type 1 font object loaded from a stream of data. The font is loaded
+// into the document. The caller does not need to free the returned object.
+//
+// document - handle to the document.
+// data     - the stream of data, which will be copied by the font object.
+// size     - size of the stream, in bytes.
+//
+// Returns NULL on failure
+DLLEXPORT FPDF_FONT STDCALL FPDFText_LoadType1Font(FPDF_DOCUMENT document,
+                                                   const uint8_t* data,
+                                                   uint32_t size);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif  // __cplusplus
diff --git a/public/fpdfview.h b/public/fpdfview.h
index 7378d5f..1c47a36 100644
--- a/public/fpdfview.h
+++ b/public/fpdfview.h
@@ -252,7 +252,8 @@
 //                              All other values are invalid.
 // Return value:
 //          True if successful, false if unsucessful (typically invalid input).
-DLLEXPORT FPDF_BOOL STDCALL FPDF_SetPrintPostscriptLevel(FPDF_BOOL use_gdi);
+DLLEXPORT FPDF_BOOL STDCALL
+FPDF_SetPrintPostscriptLevel(FPDF_BOOL postscript_level);
 #endif  // defined(_WIN32)
 
 // Function: FPDF_LoadDocument
diff --git a/samples/BUILD.gn b/samples/BUILD.gn
index b66554d..23f4d0c 100644
--- a/samples/BUILD.gn
+++ b/samples/BUILD.gn
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 
 import("//build/config/sanitizers/sanitizers.gni")
-import("//build_overrides/v8.gni")
 import("../pdfium.gni")
 
 group("samples") {
@@ -15,6 +14,8 @@
 }
 
 config("pdfium_samples_config") {
+  cflags = []
+  ldflags = []
   defines = [
     "PNG_PREFIX",
     "PNG_USE_READ_MACROS",
@@ -29,6 +30,17 @@
   if (pdf_use_skia) {
     defines += [ "PDF_ENABLE_SKIA" ]
   }
+  if (is_asan) {
+    defines += [ "PDF_ENABLE_ASAN" ]
+  }
+  if (use_coverage && is_clang) {
+    cflags += [
+      "--coverage",
+      "-g",
+      "-O0",
+    ]
+    ldflags += [ "--coverage" ]
+  }
 }
 
 executable("pdfium_test") {
diff --git a/samples/pdfium_test.cc b/samples/pdfium_test.cc
index 1e0a5be..a0afd4d 100644
--- a/samples/pdfium_test.cc
+++ b/samples/pdfium_test.cc
@@ -893,6 +893,11 @@
   config.append("XFA");
   maybe_comma = ",";
 #endif  // PDF_ENABLE_XFA
+#ifdef PDF_ENABLE_ASAN
+  config.append(maybe_comma);
+  config.append("ASAN");
+  maybe_comma = ",";
+#endif  // PDF_ENABLE_ASAN
   printf("%s\n", config.c_str());
 }
 
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index 178b694..723e872 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -205,6 +205,7 @@
     #pdfium
     "//third_party/skia/src/ports/SkDiscardableMemory_none.cpp",
     "//third_party/skia/src/ports/SkFontMgr_custom.cpp",
+    "//third_party/skia/src/ports/SkFontMgr_custom_empty.cpp",
     "//third_party/skia/src/ports/SkFontMgr_custom_empty_factory.cpp",
     "//third_party/skia/src/ports/SkMemory_malloc.cpp",
   ]
@@ -229,7 +230,6 @@
     "//third_party/skia/src/utils/SkDumpCanvas.cpp",
     "//third_party/skia/src/utils/SkFrontBufferedStream.cpp",
     "//third_party/skia/src/utils/SkInterpolator.cpp",
-    "//third_party/skia/src/utils/SkLayer.cpp",
     "//third_party/skia/src/utils/SkMeshUtils.cpp",
     "//third_party/skia/src/utils/SkParsePath.cpp",
   ]
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index f505c50..e09a235 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -127,9 +127,6 @@
 
 // ===== Begin Chrome-specific definitions =====
 
-#define SK_SCALAR_IS_FLOAT
-#undef SK_SCALAR_IS_FIXED
-
 #define SK_MSCALAR_IS_FLOAT
 #undef SK_MSCALAR_IS_DOUBLE
 
diff --git a/testing/SUPPRESSIONS b/testing/SUPPRESSIONS
index 2d54247..447c9fa 100644
--- a/testing/SUPPRESSIONS
+++ b/testing/SUPPRESSIONS
@@ -484,6 +484,21 @@
 zh_function_list.pdf mac * *
 zh_shared_document.pdf mac * *
 
+bug_679643.in * * noxfa
+bug_679642.in * * noxfa
+
+### TODO(dsinclair): These need to be fixed ....
+Test_DateField_locale_en_CA.pdf asan * *
+Test_DateField_locale_en_GB.pdf asan * *
+Test_DateField_locale_en_US.pdf asan * *
+Test_DateField_locale_fr_CA.pdf asan * *
+Test_DateField_locale_fr_FR.pdf asan * *
+Test_DateField_locale_nl_NL.pdf asan * *
+Test_DateField_locale_zh_CN.pdf asan * *
+Test_DateField_locale_zh_HK.pdf asan * *
+Test_PasswordField.pdf asan * *
+format_custom_format.pdf asan * *
+
 #
 # xfa_specific
 #
diff --git a/testing/libfuzzer/pdf_css_fuzzer.cc b/testing/libfuzzer/pdf_css_fuzzer.cc
index 9135b25..f02f006 100644
--- a/testing/libfuzzer/pdf_css_fuzzer.cc
+++ b/testing/libfuzzer/pdf_css_fuzzer.cc
@@ -15,8 +15,12 @@
   CFX_WideString input = CFX_WideString::FromUTF8(
       CFX_ByteStringC(data, static_cast<FX_STRSIZE>(size)));
 
+  // If we convert the input into an empty string bail out.
+  if (input.GetLength() == 0)
+    return 0;
+
   CFDE_CSSSyntaxParser parser;
-  parser.Init(input.c_str(), size);
+  parser.Init(input.c_str(), input.GetLength());
 
   FDE_CSSSyntaxStatus status;
   do {
diff --git a/testing/libfuzzer/pdf_streamparser_fuzzer.cc b/testing/libfuzzer/pdf_streamparser_fuzzer.cc
index 5cfa318..46113d4 100644
--- a/testing/libfuzzer/pdf_streamparser_fuzzer.cc
+++ b/testing/libfuzzer/pdf_streamparser_fuzzer.cc
@@ -10,7 +10,8 @@
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   CPDF_StreamParser parser(data, size);
-  while (std::unique_ptr<CPDF_Object> pObj = parser.ReadNextObject(true, 0))
+  while (std::unique_ptr<CPDF_Object> pObj =
+             parser.ReadNextObject(true, false, 0))
     continue;
 
   return 0;
diff --git a/testing/libfuzzer/xfa_codec_fuzzer.h b/testing/libfuzzer/xfa_codec_fuzzer.h
index 8608993..9a8b23e 100644
--- a/testing/libfuzzer/xfa_codec_fuzzer.h
+++ b/testing/libfuzzer/xfa_codec_fuzzer.h
@@ -7,16 +7,26 @@
 
 #include <memory>
 
+#include "core/fxcodec/codec/ccodec_bmpmodule.h"
+#include "core/fxcodec/codec/ccodec_gifmodule.h"
+#include "core/fxcodec/codec/ccodec_pngmodule.h"
 #include "core/fxcodec/codec/ccodec_progressivedecoder.h"
+#include "core/fxcodec/codec/ccodec_tiffmodule.h"
 #include "core/fxcodec/fx_codec.h"
 #include "core/fxcrt/fx_stream.h"
+#include "third_party/base/ptr_util.h"
 
 class XFACodecFuzzer {
  public:
   static int Fuzz(const uint8_t* data, size_t size, FXCODEC_IMAGE_TYPE type) {
-    std::unique_ptr<CCodec_ModuleMgr> mgr(new CCodec_ModuleMgr());
-    std::unique_ptr<CCodec_ProgressiveDecoder> decoder(
-        mgr->CreateProgressiveDecoder());
+    auto mgr = pdfium::MakeUnique<CCodec_ModuleMgr>();
+    mgr->SetBmpModule(pdfium::MakeUnique<CCodec_BmpModule>());
+    mgr->SetGifModule(pdfium::MakeUnique<CCodec_GifModule>());
+    mgr->SetPngModule(pdfium::MakeUnique<CCodec_PngModule>());
+    mgr->SetTiffModule(pdfium::MakeUnique<CCodec_TiffModule>());
+
+    std::unique_ptr<CCodec_ProgressiveDecoder> decoder =
+        mgr->CreateProgressiveDecoder();
     CFX_RetainPtr<Reader> source(new Reader(data, size));
     FXCODEC_STATUS status = decoder->LoadImageInfo(source, type, nullptr, true);
     if (status != FXCODEC_STATUS_FRAME_READY)
diff --git a/testing/resources/javascript/bug_695826.in b/testing/resources/javascript/bug_695826.in
new file mode 100644
index 0000000..b20908b
--- /dev/null
+++ b/testing/resources/javascript/bug_695826.in
@@ -0,0 +1,47 @@
+{{header}}
+{{object 1 0}} <<
+  /Type /Catalog
+  /Pages 2 0 R
+  /OpenAction 10 0 R
+>>
+endobj
+{{object 2 0}} <<
+  /Type /Pages
+  /Count 1
+  /Kids [
+    3 0 R
+  ]
+>>
+endobj
+% Page number 0.
+{{object 3 0}} <<
+  /Type /Page
+  /Parent 2 0 R
+  /Resources <<
+    /Font <</F1 15 0 R>>
+  >>
+  /Contents [21 0 R]
+  /MediaBox [0 0 612 792]
+>>
+% OpenAction action
+{{object 10 0}} <<
+  /Type /Action
+  /S /JavaScript
+  /JS 11 0 R
+>>
+endobj
+% JS program to exexute
+{{object 11 0}} <<
+>>
+stream
+var obj = new this.constructor;
+obj.author = 3;
+app.alert('Done!');
+endstream
+endobj
+{{xref}}
+trailer <<
+  /Root 1 0 R
+>>
+{{startxref}}
+%%EOF
diff --git a/testing/resources/javascript/bug_695826_expected.txt b/testing/resources/javascript/bug_695826_expected.txt
new file mode 100644
index 0000000..5bb6e85
--- /dev/null
+++ b/testing/resources/javascript/bug_695826_expected.txt
@@ -0,0 +1 @@
+Alert: Done!
diff --git a/testing/tools/common.py b/testing/tools/common.py
index a0cc946..b6e4a7d 100755
--- a/testing/tools/common.py
+++ b/testing/tools/common.py
@@ -43,38 +43,6 @@
   except subprocess.CalledProcessError as e:
     return e, None
 
-# Adjust Dr. Memory wrapper to have separate log directory for each test
-# for better error reporting.
-def DrMemoryWrapper(wrapper, pdf_name):
-  if not wrapper:
-    return []
-  # convert string to list
-  cmd_to_run = wrapper.split()
-
-  # Do nothing if using default log directory.
-  if cmd_to_run.count("-logdir") == 0:
-    return cmd_to_run
-  # Usually, we pass "-logdir" "foo\bar\spam path" args to Dr. Memory.
-  # To group reports per test, we want to put the reports for each test into a
-  # separate directory. This code can be simplified when we have
-  # https://github.com/DynamoRIO/drmemory/issues/684 fixed.
-  logdir_idx = cmd_to_run.index("-logdir")
-  old_logdir = cmd_to_run[logdir_idx + 1]
-  wrapper_pid = str(os.getpid())
-
-  # We are using the same pid of the same python process, so append the number
-  # of entries in the logdir at the end of wrapper_pid to avoid conflict.
-  wrapper_pid += "_%d" % len(glob.glob(old_logdir + "\\*"))
-
-  cmd_to_run[logdir_idx + 1] += "\\testcase.%s.logs" % wrapper_pid
-  os.makedirs(cmd_to_run[logdir_idx + 1])
-
-  f = open(old_logdir + "\\testcase.%s.name" % wrapper_pid, "w")
-  print >>f, pdf_name + ".pdf"
-  f.close()
-
-  return cmd_to_run
-
 
 class DirectoryFinder:
   '''A class for finding directories and paths under either a standalone
diff --git a/testing/tools/gold.py b/testing/tools/gold.py
index 7598caf..db3bf81 100644
--- a/testing/tools/gold.py
+++ b/testing/tools/gold.py
@@ -51,7 +51,8 @@
 # }
 #
 class GoldResults(object):
-  def __init__(self, source_type, outputDir, propertiesStr, keyStr):
+  def __init__(self, source_type, outputDir, propertiesStr, keyStr,
+               ignore_hashes_file):
     """
     source_type is the source_type (=corpus) field used for all results.
     output_dir is the directory where the resulting images are copied and
@@ -60,6 +61,8 @@
                is used to set the top level fields in the output JSON file.
     keyStr is a string with space separated key/value pairs that
                is used to set the 'key' field in the output JSON file.
+    ignore_hashes_file is a file that contains a list of image hashes
+               that should be ignored.
     """
     self._source_type = source_type
     self._properties = self._parseKeyValuePairs(propertiesStr)
@@ -71,13 +74,22 @@
     if not os.path.exists(outputDir):
       os.makedirs(outputDir)
 
+    self._ignore_hashes = set()
+    if ignore_hashes_file:
+      with open(ignore_hashes_file, 'r') as ig_file:
+        hashes=[x.strip() for x in ig_file.readlines() if x.strip()]
+        self._ignore_hashes = set(hashes)
+
   def AddTestResult(self, testName, md5Hash, outputImagePath):
-    # Copy the image to <output_dir>/<md5Hash>.<image_extension>
+    # If the hash is in the list of hashes to ignore then we don'try
+    # make a copy, but add it to the result.
     imgExt = os.path.splitext(outputImagePath)[1].lstrip(".")
-    if not imgExt:
-      raise ValueError("File %s does not have an extension" % outputImagePath)
-    newFilePath = os.path.join(self._outputDir, md5Hash + '.' + imgExt)
-    shutil.copy2(outputImagePath, newFilePath)
+    if md5Hash not in self._ignore_hashes:
+      # Copy the image to <output_dir>/<md5Hash>.<image_extension>
+      if not imgExt:
+        raise ValueError("File %s does not have an extension" % outputImagePath)
+      newFilePath = os.path.join(self._outputDir, md5Hash + '.' + imgExt)
+      shutil.copy2(outputImagePath, newFilePath)
 
     # Add an entry to the list of test results
     self._results.append({
@@ -123,7 +135,11 @@
 
   keyStr = "arch arm64 compiler Clang configuration Debug"
 
-  gr = GoldResults("pdfium", testDir, propStr, keyStr)
+  hash_file = os.path.join(testDir, "ignore_hashes.txt")
+  with open(hash_file, 'wb') as f:
+    f.write("\n".join(["hash-1","hash-4"]) + "\n")
+
+  gr = GoldResults("pdfium", testDir, propStr, keyStr, hash_file)
   gr.AddTestResult("test-1", "hash-1", os.path.join(testDir, "image1.png"))
   gr.AddTestResult("test-2", "hash-2", os.path.join(testDir, "image2.png"))
   gr.AddTestResult("test-3", "hash-3", os.path.join(testDir, "image3.png"))
diff --git a/testing/tools/suppressor.py b/testing/tools/suppressor.py
index b7629ef..86d2668 100755
--- a/testing/tools/suppressor.py
+++ b/testing/tools/suppressor.py
@@ -12,8 +12,10 @@
     feature_vector = feature_string.strip().split(",")
     self.has_v8 = "V8" in feature_vector
     self.has_xfa = "XFA" in feature_vector
+    self.is_asan = "ASAN" in feature_vector
     v8_option = "v8" if self.has_v8 else "nov8"
     xfa_option = "xfa" if self.has_xfa else "noxfa"
+
     with open(os.path.join(finder.TestingDir(), 'SUPPRESSIONS')) as f:
       self.suppression_set = set(self._FilterSuppressions(
         common.os_name(), v8_option, xfa_option, self._ExtractSuppressions(f)))
@@ -31,6 +33,8 @@
     os_column = item[1].split(",");
     js_column = item[2].split(",");
     xfa_column = item[3].split(",");
+    if self.is_asan and 'asan' in os_column:
+      return True
     return (('*' in os_column or os in os_column) and
             ('*' in js_column or js in js_column) and
             ('*' in xfa_column or xfa in xfa_column))
diff --git a/testing/tools/test_runner.py b/testing/tools/test_runner.py
index 92db911..6cd3a6c 100644
--- a/testing/tools/test_runner.py
+++ b/testing/tools/test_runner.py
@@ -107,9 +107,7 @@
     txt_path = os.path.join(self.working_dir, input_root + '.txt')
 
     with open(txt_path, 'w') as outfile:
-      # add Dr. Memory wrapper if exist
-      cmd_to_run = common.DrMemoryWrapper(self.drmem_wrapper, input_root)
-      cmd_to_run.extend([self.pdfium_test_path, pdf_path])
+      cmd_to_run = [self.pdfium_test_path, pdf_path]
       subprocess.check_call(cmd_to_run, stdout=outfile)
 
     cmd = [sys.executable, self.text_diff_path, expected_txt_path, txt_path]
@@ -117,16 +115,15 @@
 
 
   def TestPixel(self, input_root, pdf_path):
-    cmd_to_run = common.DrMemoryWrapper(self.drmem_wrapper, input_root)
-    cmd_to_run.extend([self.pdfium_test_path, '--send-events', '--png'])
+    cmd_to_run = [self.pdfium_test_path, '--send-events', '--png']
     if self.gold_results:
       cmd_to_run.append('--md5')
     cmd_to_run.append(pdf_path)
     return common.RunCommandExtractHashedFiles(cmd_to_run)
 
   def HandleResult(self, input_filename, input_path, result):
+    success, image_paths = result
     if self.gold_results:
-      success, image_paths = result
       if image_paths:
         for img_path, md5_hash in image_paths:
           # the output filename (without extension becomes the test name)
@@ -134,10 +131,10 @@
           self.gold_results.AddTestResult(test_name, md5_hash, img_path)
 
     if self.test_suppressor.IsResultSuppressed(input_filename):
-      if result:
+      if success:
         self.surprises.append(input_path)
     else:
-      if not result:
+      if not success:
         self.failures.append(input_path)
 
 
@@ -151,9 +148,6 @@
                       dest='num_workers', type='int',
                       help='run NUM_WORKERS jobs in parallel')
 
-    parser.add_option('--wrapper', default='', dest="wrapper",
-                      help='wrapper for running test under Dr. Memory')
-
     parser.add_option('--gold_properties', default='', dest="gold_properties",
                       help='Key value pairs that are written to the top level of the JSON file that is ingested by Gold.')
 
@@ -163,6 +157,9 @@
     parser.add_option('--gold_output_dir', default='', dest="gold_output_dir",
                       help='Path of where to write the JSON output to be uploaded to Gold.')
 
+    parser.add_option('--gold_ignore_hashes', default='', dest="gold_ignore_hashes",
+                      help='Path to a file with MD5 hashes we wish to ignore.')
+
     parser.add_option('--ignore_errors', action="store_true", dest="ignore_errors",
                       help='Prevents the return value from being non-zero when image comparison fails.')
 
@@ -172,8 +169,6 @@
     self.fixup_path = finder.ScriptPath('fixup_pdf_template.py')
     self.text_diff_path = finder.ScriptPath('text_diff.py')
 
-    self.drmem_wrapper = options.wrapper
-
     self.source_dir = finder.TestingDir()
     if self.test_dir != 'corpus':
       test_dir = finder.TestingDir(os.path.join('resources', self.test_dir))
@@ -227,7 +222,8 @@
       self.gold_results = gold.GoldResults("pdfium",
                                            options.gold_output_dir,
                                            options.gold_properties,
-                                           options.gold_key)
+                                           options.gold_key,
+                                           options.gold_ignore_hashes)
 
     if options.num_workers > 1 and len(test_cases) > 1:
       try:
@@ -267,6 +263,7 @@
       print '\n\nSummary of Failures:'
       for failure in self.failures:
         print failure
-        if not options.ignore_errors:
-          return 1
+
+      if not options.ignore_errors:
+        return 1
     return 0
diff --git a/third_party/agg23/agg_rasterizer_scanline_aa.cpp b/third_party/agg23/agg_rasterizer_scanline_aa.cpp
index c6b3f01..af6dd58 100644
--- a/third_party/agg23/agg_rasterizer_scanline_aa.cpp
+++ b/third_party/agg23/agg_rasterizer_scanline_aa.cpp
@@ -283,8 +283,8 @@
       incr = -1;
       dy = -dy;
     }
-    delta = safeP.ValueOrDie() / dy;
-    mod = safeP.ValueOrDie() % dy;
+    delta = (safeP / dy).ValueOrDie();
+    mod = (safeP % dy).ValueOrDie();
     if(mod < 0) {
         delta--;
         mod += dy;
@@ -298,8 +298,8 @@
       safeP *= dx;
       if (!safeP.IsValid())
         return;
-      lift = safeP.ValueOrDie() / dy;
-      rem = safeP.ValueOrDie() % dy;
+      lift = (safeP / dy).ValueOrDie();
+      rem = (safeP % dy).ValueOrDie();
       if (rem < 0) {
         lift--;
         rem += dy;
diff --git a/third_party/agg23/agg_rasterizer_scanline_aa.h b/third_party/agg23/agg_rasterizer_scanline_aa.h
index 77e04ed..fc28290 100644
--- a/third_party/agg23/agg_rasterizer_scanline_aa.h
+++ b/third_party/agg23/agg_rasterizer_scanline_aa.h
@@ -390,10 +390,12 @@
         unsigned cmd;
         vs.rewind(path_id);
         while(!is_stop(cmd = vs.vertex(&x, &y))) {
-            if (pMatrix) {
-                pMatrix->Transform(x, y);
-            }
-            add_vertex(x, y, cmd);
+          if (pMatrix) {
+            CFX_PointF ret = pMatrix->Transform(CFX_PointF(x, y));
+            x = ret.x;
+            y = ret.y;
+          }
+          add_vertex(x, y, cmd);
         }
     }
 private:
diff --git a/third_party/base/numerics/safe_conversions.h b/third_party/base/numerics/safe_conversions.h
index dd0d1e4..dc61d9c 100644
--- a/third_party/base/numerics/safe_conversions.h
+++ b/third_party/base/numerics/safe_conversions.h
@@ -2,65 +2,271 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef PDFIUM_THIRD_PARTY_BASE_SAFE_CONVERSIONS_H_
-#define PDFIUM_THIRD_PARTY_BASE_SAFE_CONVERSIONS_H_
+#ifndef PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_H_
+#define PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_H_
+
+#include <stddef.h>
 
 #include <limits>
+#include <ostream>
+#include <type_traits>
 
-#include "safe_conversions_impl.h"
-#include "third_party/base/logging.h"
+#include "third_party/base/numerics/safe_conversions_impl.h"
 
 namespace pdfium {
 namespace base {
 
+// The following are helper constexpr template functions and classes for safely
+// performing a range of conversions, assignments, and tests:
+//
+//  checked_cast<> - Analogous to static_cast<> for numeric types, except
+//      that it CHECKs that the specified numeric conversion will not overflow
+//      or underflow. NaN source will always trigger a CHECK.
+//      The default CHECK triggers a crash, but the handler can be overriden.
+//  saturated_cast<> - Analogous to static_cast<> for numeric types, except
+//      that it returns a saturated result when the specified numeric conversion
+//      would otherwise overflow or underflow. An NaN source returns 0 by
+//      default, but can be overridden to return a different result.
+//  strict_cast<> - Analogous to static_cast<> for numeric types, except that
+//      it will cause a compile failure if the destination type is not large
+//      enough to contain any value in the source type. It performs no runtime
+//      checking and thus introduces no runtime overhead.
+//  IsValueInRangeForNumericType<>() - A convenience function that returns true
+//      if the type supplied to the template parameter can represent the value
+//      passed as an argument to the function.
+//  IsValueNegative<>() - A convenience function that will accept any arithmetic
+//      type as an argument and will return whether the value is less than zero.
+//      Unsigned types always return false.
+//  SafeUnsignedAbs() - Returns the absolute value of the supplied integer
+//      parameter as an unsigned result (thus avoiding an overflow if the value
+//      is the signed, two's complement minimum).
+//  StrictNumeric<> - A wrapper type that performs assignments and copies via
+//      the strict_cast<> template, and can perform valid arithmetic comparisons
+//      across any range of arithmetic types. StrictNumeric is the return type
+//      for values extracted from a CheckedNumeric class instance. The raw
+//      arithmetic value is extracted via static_cast to the underlying type.
+//  MakeStrictNum() - Creates a new StrictNumeric from the underlying type of
+//      the supplied arithmetic or StrictNumeric type.
+
 // Convenience function that returns true if the supplied value is in range
 // for the destination type.
 template <typename Dst, typename Src>
-inline bool IsValueInRangeForNumericType(Src value) {
-  return internal::DstRangeRelationToSrcRange<Dst>(value) ==
-         internal::RANGE_VALID;
+constexpr bool IsValueInRangeForNumericType(Src value) {
+  return internal::DstRangeRelationToSrcRange<Dst>(value).IsValid();
 }
 
+// Forces a crash, like a CHECK(false). Used for numeric boundary errors.
+struct CheckOnFailure {
+  template <typename T>
+  static T HandleFailure() {
+#if defined(__GNUC__) || defined(__clang__)
+    __builtin_trap();
+#else
+    ((void)(*(volatile char*)0 = 0));
+#endif
+    return T();
+  }
+};
+
 // checked_cast<> is analogous to static_cast<> for numeric types,
 // except that it CHECKs that the specified numeric conversion will not
 // overflow or underflow. NaN source will always trigger a CHECK.
-template <typename Dst, typename Src>
-inline Dst checked_cast(Src value) {
-  CHECK(IsValueInRangeForNumericType<Dst>(value));
-  return static_cast<Dst>(value);
+template <typename Dst, class CheckHandler = CheckOnFailure, typename Src>
+constexpr Dst checked_cast(Src value) {
+  // This throws a compile-time error on evaluating the constexpr if it can be
+  // determined at compile-time as failing, otherwise it will CHECK at runtime.
+  using SrcType = typename internal::UnderlyingType<Src>::type;
+  return IsValueInRangeForNumericType<Dst, SrcType>(value)
+             ? static_cast<Dst>(static_cast<SrcType>(value))
+             : CheckHandler::template HandleFailure<Dst>();
+}
+
+// Default boundaries for integral/float: max/infinity, lowest/-infinity, 0/NaN.
+template <typename T>
+struct SaturationDefaultHandler {
+  static constexpr T NaN() {
+    return std::numeric_limits<T>::has_quiet_NaN
+               ? std::numeric_limits<T>::quiet_NaN()
+               : T();
+  }
+  static constexpr T max() { return std::numeric_limits<T>::max(); }
+  static constexpr T Overflow() {
+    return std::numeric_limits<T>::has_infinity
+               ? std::numeric_limits<T>::infinity()
+               : std::numeric_limits<T>::max();
+  }
+  static constexpr T lowest() { return std::numeric_limits<T>::lowest(); }
+  static constexpr T Underflow() {
+    return std::numeric_limits<T>::has_infinity
+               ? std::numeric_limits<T>::infinity() * -1
+               : std::numeric_limits<T>::lowest();
+  }
+};
+
+namespace internal {
+
+template <typename Dst, template <typename> class S, typename Src>
+constexpr Dst saturated_cast_impl(Src value, RangeCheck constraint) {
+  // For some reason clang generates much better code when the branch is
+  // structured exactly this way, rather than a sequence of checks.
+  return !constraint.IsOverflowFlagSet()
+             ? (!constraint.IsUnderflowFlagSet() ? static_cast<Dst>(value)
+                                                 : S<Dst>::Underflow())
+             // Skip this check for integral Src, which cannot be NaN.
+             : (std::is_integral<Src>::value || !constraint.IsUnderflowFlagSet()
+                    ? S<Dst>::Overflow()
+                    : S<Dst>::NaN());
 }
 
 // saturated_cast<> is analogous to static_cast<> for numeric types, except
-// that the specified numeric conversion will saturate rather than overflow or
-// underflow. NaN assignment to an integral will trigger a CHECK condition.
+// that the specified numeric conversion will saturate by default rather than
+// overflow or underflow, and NaN assignment to an integral will return 0.
+// All boundary condition behaviors can be overriden with a custom handler.
+template <typename Dst,
+          template <typename>
+          class SaturationHandler = SaturationDefaultHandler,
+          typename Src>
+constexpr Dst saturated_cast(Src value) {
+  using SrcType = typename UnderlyingType<Src>::type;
+  return saturated_cast_impl<Dst, SaturationHandler, SrcType>(
+      value,
+      DstRangeRelationToSrcRange<Dst, SaturationHandler, SrcType>(value));
+}
+
+// strict_cast<> is analogous to static_cast<> for numeric types, except that
+// it will cause a compile failure if the destination type is not large enough
+// to contain any value in the source type. It performs no runtime checking.
 template <typename Dst, typename Src>
-inline Dst saturated_cast(Src value) {
-  // Optimization for floating point values, which already saturate.
-  if (std::numeric_limits<Dst>::is_iec559)
-    return static_cast<Dst>(value);
+constexpr Dst strict_cast(Src value) {
+  using SrcType = typename UnderlyingType<Src>::type;
+  static_assert(UnderlyingType<Src>::is_numeric, "Argument must be numeric.");
+  static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric.");
 
-  switch (internal::DstRangeRelationToSrcRange<Dst>(value)) {
-    case internal::RANGE_VALID:
-      return static_cast<Dst>(value);
+  // If you got here from a compiler error, it's because you tried to assign
+  // from a source type to a destination type that has insufficient range.
+  // The solution may be to change the destination type you're assigning to,
+  // and use one large enough to represent the source.
+  // Alternatively, you may be better served with the checked_cast<> or
+  // saturated_cast<> template functions for your particular use case.
+  static_assert(StaticDstRangeRelationToSrcRange<Dst, SrcType>::value ==
+                    NUMERIC_RANGE_CONTAINED,
+                "The source type is out of range for the destination type. "
+                "Please see strict_cast<> comments for more information.");
 
-    case internal::RANGE_UNDERFLOW:
-      return std::numeric_limits<Dst>::min();
+  return static_cast<Dst>(static_cast<SrcType>(value));
+}
 
-    case internal::RANGE_OVERFLOW:
-      return std::numeric_limits<Dst>::max();
+// Some wrappers to statically check that a type is in range.
+template <typename Dst, typename Src, class Enable = void>
+struct IsNumericRangeContained {
+  static const bool value = false;
+};
 
-    // Should fail only on attempting to assign NaN to a saturated integer.
-    case internal::RANGE_INVALID:
-      CHECK(false);
-      return std::numeric_limits<Dst>::max();
+template <typename Dst, typename Src>
+struct IsNumericRangeContained<
+    Dst,
+    Src,
+    typename std::enable_if<ArithmeticOrUnderlyingEnum<Dst>::value &&
+                            ArithmeticOrUnderlyingEnum<Src>::value>::type> {
+  static const bool value = StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
+                            NUMERIC_RANGE_CONTAINED;
+};
+
+// StrictNumeric implements compile time range checking between numeric types by
+// wrapping assignment operations in a strict_cast. This class is intended to be
+// used for function arguments and return types, to ensure the destination type
+// can always contain the source type. This is essentially the same as enforcing
+// -Wconversion in gcc and C4302 warnings on MSVC, but it can be applied
+// incrementally at API boundaries, making it easier to convert code so that it
+// compiles cleanly with truncation warnings enabled.
+// This template should introduce no runtime overhead, but it also provides no
+// runtime checking of any of the associated mathematical operations. Use
+// CheckedNumeric for runtime range checks of the actual value being assigned.
+template <typename T>
+class StrictNumeric {
+ public:
+  using type = T;
+
+  constexpr StrictNumeric() : value_(0) {}
+
+  // Copy constructor.
+  template <typename Src>
+  constexpr StrictNumeric(const StrictNumeric<Src>& rhs)
+      : value_(strict_cast<T>(rhs.value_)) {}
+
+  // This is not an explicit constructor because we implicitly upgrade regular
+  // numerics to StrictNumerics to make them easier to use.
+  template <typename Src>
+  constexpr StrictNumeric(Src value)  // NOLINT(runtime/explicit)
+      : value_(strict_cast<T>(value)) {}
+
+  // If you got here from a compiler error, it's because you tried to assign
+  // from a source type to a destination type that has insufficient range.
+  // The solution may be to change the destination type you're assigning to,
+  // and use one large enough to represent the source.
+  // If you're assigning from a CheckedNumeric<> class, you may be able to use
+  // the AssignIfValid() member function, specify a narrower destination type to
+  // the member value functions (e.g. val.template ValueOrDie<Dst>()), use one
+  // of the value helper functions (e.g. ValueOrDieForType<Dst>(val)).
+  // If you've encountered an _ambiguous overload_ you can use a static_cast<>
+  // to explicitly cast the result to the destination type.
+  // If none of that works, you may be better served with the checked_cast<> or
+  // saturated_cast<> template functions for your particular use case.
+  template <typename Dst,
+            typename std::enable_if<
+                IsNumericRangeContained<Dst, T>::value>::type* = nullptr>
+  constexpr operator Dst() const {
+    return static_cast<typename ArithmeticOrUnderlyingEnum<Dst>::type>(value_);
   }
 
-  NOTREACHED();
-  return static_cast<Dst>(value);
+ private:
+  const T value_;
+};
+
+// Convience wrapper returns a StrictNumeric from the provided arithmetic type.
+template <typename T>
+constexpr StrictNumeric<typename UnderlyingType<T>::type> MakeStrictNum(
+    const T value) {
+  return value;
 }
 
+// Overload the ostream output operator to make logging work nicely.
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const StrictNumeric<T>& value) {
+  os << static_cast<T>(value);
+  return os;
+}
+
+#define STRICT_COMPARISON_OP(NAME, OP)                               \
+  template <typename L, typename R,                                  \
+            typename std::enable_if<                                 \
+                internal::IsStrictOp<L, R>::value>::type* = nullptr> \
+  constexpr bool operator OP(const L lhs, const R rhs) {             \
+    return SafeCompare<NAME, typename UnderlyingType<L>::type,       \
+                       typename UnderlyingType<R>::type>(lhs, rhs);  \
+  }
+
+STRICT_COMPARISON_OP(IsLess, <);
+STRICT_COMPARISON_OP(IsLessOrEqual, <=);
+STRICT_COMPARISON_OP(IsGreater, >);
+STRICT_COMPARISON_OP(IsGreaterOrEqual, >=);
+STRICT_COMPARISON_OP(IsEqual, ==);
+STRICT_COMPARISON_OP(IsNotEqual, !=);
+
+#undef STRICT_COMPARISON_OP
+};
+
+using internal::strict_cast;
+using internal::saturated_cast;
+using internal::SafeUnsignedAbs;
+using internal::StrictNumeric;
+using internal::MakeStrictNum;
+using internal::IsValueNegative;
+
+// Explicitly make a shorter size_t alias for convenience.
+using SizeT = StrictNumeric<size_t>;
+
 }  // namespace base
 }  // namespace pdfium
 
-#endif  // PDFIUM_THIRD_PARTY_BASE_SAFE_CONVERSIONS_H_
-
+#endif  // PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_H_
diff --git a/third_party/base/numerics/safe_conversions_impl.h b/third_party/base/numerics/safe_conversions_impl.h
index e1c4c3b..2a7ce14 100644
--- a/third_party/base/numerics/safe_conversions_impl.h
+++ b/third_party/base/numerics/safe_conversions_impl.h
@@ -2,29 +2,81 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef PDFIUM_THIRD_PARTY_BASE_SAFE_CONVERSIONS_IMPL_H_
-#define PDFIUM_THIRD_PARTY_BASE_SAFE_CONVERSIONS_IMPL_H_
+#ifndef PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
+#define PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
 
-#include <assert.h>
+#include <stdint.h>
+
 #include <limits>
-
-#include "third_party/base/macros.h"
+#include <type_traits>
 
 namespace pdfium {
 namespace base {
 namespace internal {
 
 // The std library doesn't provide a binary max_exponent for integers, however
-// we can compute one by adding one to the number of non-sign bits. This allows
-// for accurate range comparisons between floating point and integer types.
+// we can compute an analog using std::numeric_limits<>::digits.
 template <typename NumericType>
 struct MaxExponent {
-  static const int value = std::numeric_limits<NumericType>::is_iec559
+  static const int value = std::is_floating_point<NumericType>::value
                                ? std::numeric_limits<NumericType>::max_exponent
-                               : (sizeof(NumericType) * 8 + 1 -
-                                  std::numeric_limits<NumericType>::is_signed);
+                               : std::numeric_limits<NumericType>::digits + 1;
 };
 
+// The number of bits (including the sign) in an integer. Eliminates sizeof
+// hacks.
+template <typename NumericType>
+struct IntegerBitsPlusSign {
+  static const int value = std::numeric_limits<NumericType>::digits +
+                           std::is_signed<NumericType>::value;
+};
+
+// Helper templates for integer manipulations.
+
+template <typename Integer>
+struct PositionOfSignBit {
+  static const size_t value = IntegerBitsPlusSign<Integer>::value - 1;
+};
+
+// Determines if a numeric value is negative without throwing compiler
+// warnings on: unsigned(value) < 0.
+template <typename T,
+          typename std::enable_if<std::is_signed<T>::value>::type* = nullptr>
+constexpr bool IsValueNegative(T value) {
+  static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
+  return value < 0;
+}
+
+template <typename T,
+          typename std::enable_if<!std::is_signed<T>::value>::type* = nullptr>
+constexpr bool IsValueNegative(T) {
+  static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
+  return false;
+}
+
+// This performs a fast negation, returning a signed value. It works on unsigned
+// arguments, but probably doesn't do what you want for any unsigned value
+// larger than max / 2 + 1 (i.e. signed min cast to unsigned).
+template <typename T>
+constexpr typename std::make_signed<T>::type ConditionalNegate(
+    T x,
+    bool is_negative) {
+  static_assert(std::is_integral<T>::value, "Type must be integral");
+  using SignedT = typename std::make_signed<T>::type;
+  using UnsignedT = typename std::make_unsigned<T>::type;
+  return static_cast<SignedT>(
+      (static_cast<UnsignedT>(x) ^ -SignedT(is_negative)) + is_negative);
+}
+
+// This performs a safe, absolute value via unsigned overflow.
+template <typename T>
+constexpr typename std::make_unsigned<T>::type SafeUnsignedAbs(T value) {
+  static_assert(std::is_integral<T>::value, "Type must be integral");
+  using UnsignedT = typename std::make_unsigned<T>::type;
+  return IsValueNegative(value) ? 0 - static_cast<UnsignedT>(value)
+                                : static_cast<UnsignedT>(value);
+}
+
 enum IntegerRepresentation {
   INTEGER_REPRESENTATION_UNSIGNED,
   INTEGER_REPRESENTATION_SIGNED
@@ -32,7 +84,7 @@
 
 // A range for a given nunmeric Src type is contained for a given numeric Dst
 // type if both numeric_limits<Src>::max() <= numeric_limits<Dst>::max() and
-// numeric_limits<Src>::min() >= numeric_limits<Dst>::min() are true.
+// numeric_limits<Src>::lowest() >= numeric_limits<Dst>::lowest() are true.
 // We implement this as template specializations rather than simple static
 // comparisons to ensure type correctness in our comparisons.
 enum NumericRangeRepresentation {
@@ -43,16 +95,14 @@
 // Helper templates to statically determine if our destination type can contain
 // maximum and minimum values represented by the source type.
 
-template <
-    typename Dst,
-    typename Src,
-    IntegerRepresentation DstSign = std::numeric_limits<Dst>::is_signed
-                                            ? INTEGER_REPRESENTATION_SIGNED
-                                            : INTEGER_REPRESENTATION_UNSIGNED,
-    IntegerRepresentation SrcSign =
-        std::numeric_limits<Src>::is_signed
-            ? INTEGER_REPRESENTATION_SIGNED
-            : INTEGER_REPRESENTATION_UNSIGNED >
+template <typename Dst,
+          typename Src,
+          IntegerRepresentation DstSign = std::is_signed<Dst>::value
+                                              ? INTEGER_REPRESENTATION_SIGNED
+                                              : INTEGER_REPRESENTATION_UNSIGNED,
+          IntegerRepresentation SrcSign = std::is_signed<Src>::value
+                                              ? INTEGER_REPRESENTATION_SIGNED
+                                              : INTEGER_REPRESENTATION_UNSIGNED>
 struct StaticDstRangeRelationToSrcRange;
 
 // Same sign: Dst is guaranteed to contain Src only if its range is equal or
@@ -87,132 +137,598 @@
   static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED;
 };
 
-enum RangeConstraint {
-  RANGE_VALID = 0x0,  // Value can be represented by the destination type.
-  RANGE_UNDERFLOW = 0x1,  // Value would overflow.
-  RANGE_OVERFLOW = 0x2,  // Value would underflow.
-  RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW  // Invalid (i.e. NaN).
+// This class wraps the range constraints as separate booleans so the compiler
+// can identify constants and eliminate unused code paths.
+class RangeCheck {
+ public:
+  constexpr RangeCheck(bool is_in_lower_bound, bool is_in_upper_bound)
+      : is_underflow_(!is_in_lower_bound), is_overflow_(!is_in_upper_bound) {}
+  constexpr RangeCheck() : is_underflow_(0), is_overflow_(0) {}
+  constexpr bool IsValid() const { return !is_overflow_ && !is_underflow_; }
+  constexpr bool IsInvalid() const { return is_overflow_ && is_underflow_; }
+  constexpr bool IsOverflow() const { return is_overflow_ && !is_underflow_; }
+  constexpr bool IsUnderflow() const { return !is_overflow_ && is_underflow_; }
+  constexpr bool IsOverflowFlagSet() const { return is_overflow_; }
+  constexpr bool IsUnderflowFlagSet() const { return is_underflow_; }
+  constexpr bool operator==(const RangeCheck rhs) const {
+    return is_underflow_ == rhs.is_underflow_ &&
+           is_overflow_ == rhs.is_overflow_;
+  }
+  constexpr bool operator!=(const RangeCheck rhs) const {
+    return !(*this == rhs);
+  }
+
+ private:
+  // Do not change the order of these member variables. The integral conversion
+  // optimization depends on this exact order.
+  const bool is_underflow_;
+  const bool is_overflow_;
 };
 
-// Helper function for coercing an int back to a RangeContraint.
-inline RangeConstraint GetRangeConstraint(int integer_range_constraint) {
-  assert(integer_range_constraint >= RANGE_VALID &&
-         integer_range_constraint <= RANGE_INVALID);
-  return static_cast<RangeConstraint>(integer_range_constraint);
-}
+// The following helper template addresses a corner case in range checks for
+// conversion from a floating-point type to an integral type of smaller range
+// but larger precision (e.g. float -> unsigned). The problem is as follows:
+//   1. Integral maximum is always one less than a power of two, so it must be
+//      truncated to fit the mantissa of the floating point. The direction of
+//      rounding is implementation defined, but by default it's always IEEE
+//      floats, which round to nearest and thus result in a value of larger
+//      magnitude than the integral value.
+//      Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX
+//                                   // is 4294967295u.
+//   2. If the floating point value is equal to the promoted integral maximum
+//      value, a range check will erroneously pass.
+//      Example: (4294967296f <= 4294967295u) // This is true due to a precision
+//                                            // loss in rounding up to float.
+//   3. When the floating point value is then converted to an integral, the
+//      resulting value is out of range for the target integral type and
+//      thus is implementation defined.
+//      Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0.
+// To fix this bug we manually truncate the maximum value when the destination
+// type is an integral of larger precision than the source floating-point type,
+// such that the resulting maximum is represented exactly as a floating point.
+template <typename Dst, typename Src, template <typename> class Bounds>
+struct NarrowingRange {
+  using SrcLimits = std::numeric_limits<Src>;
+  using DstLimits = typename std::numeric_limits<Dst>;
 
-// This function creates a RangeConstraint from an upper and lower bound
-// check by taking advantage of the fact that only NaN can be out of range in
-// both directions at once.
-inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound,
-                                   bool is_in_lower_bound) {
-  return GetRangeConstraint((is_in_upper_bound ? 0 : RANGE_OVERFLOW) |
-                            (is_in_lower_bound ? 0 : RANGE_UNDERFLOW));
-}
+  // Computes the mask required to make an accurate comparison between types.
+  static const int kShift =
+      (MaxExponent<Src>::value > MaxExponent<Dst>::value &&
+       SrcLimits::digits < DstLimits::digits)
+          ? (DstLimits::digits - SrcLimits::digits)
+          : 0;
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
 
-template <
-    typename Dst,
-    typename Src,
-    IntegerRepresentation DstSign = std::numeric_limits<Dst>::is_signed
-                                            ? INTEGER_REPRESENTATION_SIGNED
-                                            : INTEGER_REPRESENTATION_UNSIGNED,
-    IntegerRepresentation SrcSign = std::numeric_limits<Src>::is_signed
-                                            ? INTEGER_REPRESENTATION_SIGNED
-                                            : INTEGER_REPRESENTATION_UNSIGNED,
-    NumericRangeRepresentation DstRange =
-        StaticDstRangeRelationToSrcRange<Dst, Src>::value >
+  // Masks out the integer bits that are beyond the precision of the
+  // intermediate type used for comparison.
+  static constexpr T Adjust(T value) {
+    static_assert(std::is_same<T, Dst>::value, "");
+    static_assert(kShift < DstLimits::digits, "");
+    return static_cast<T>(
+        ConditionalNegate(SafeUnsignedAbs(value) & ~((T(1) << kShift) - T(1)),
+                          IsValueNegative(value)));
+  }
+
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static constexpr T Adjust(T value) {
+    static_assert(std::is_same<T, Dst>::value, "");
+    static_assert(kShift == 0, "");
+    return value;
+  }
+
+  static constexpr Dst max() { return Adjust(Bounds<Dst>::max()); }
+  static constexpr Dst lowest() { return Adjust(Bounds<Dst>::lowest()); }
+};
+
+template <typename Dst,
+          typename Src,
+          template <typename> class Bounds,
+          IntegerRepresentation DstSign = std::is_signed<Dst>::value
+                                              ? INTEGER_REPRESENTATION_SIGNED
+                                              : INTEGER_REPRESENTATION_UNSIGNED,
+          IntegerRepresentation SrcSign = std::is_signed<Src>::value
+                                              ? INTEGER_REPRESENTATION_SIGNED
+                                              : INTEGER_REPRESENTATION_UNSIGNED,
+          NumericRangeRepresentation DstRange =
+              StaticDstRangeRelationToSrcRange<Dst, Src>::value>
 struct DstRangeRelationToSrcRangeImpl;
 
 // The following templates are for ranges that must be verified at runtime. We
 // split it into checks based on signedness to avoid confusing casts and
 // compiler warnings on signed an unsigned comparisons.
 
-// Dst range is statically determined to contain Src: Nothing to check.
+// Same sign narrowing: The range is contained for normal limits.
 template <typename Dst,
           typename Src,
+          template <typename> class Bounds,
           IntegerRepresentation DstSign,
           IntegerRepresentation SrcSign>
 struct DstRangeRelationToSrcRangeImpl<Dst,
                                       Src,
+                                      Bounds,
                                       DstSign,
                                       SrcSign,
                                       NUMERIC_RANGE_CONTAINED> {
-  static RangeConstraint Check(Src value) { return RANGE_VALID; }
+  static constexpr RangeCheck Check(Src value) {
+    using SrcLimits = std::numeric_limits<Src>;
+    using DstLimits = NarrowingRange<Dst, Src, Bounds>;
+    return RangeCheck(
+        static_cast<Dst>(SrcLimits::lowest()) >= DstLimits::lowest() ||
+            static_cast<Dst>(value) >= DstLimits::lowest(),
+        static_cast<Dst>(SrcLimits::max()) <= DstLimits::max() ||
+            static_cast<Dst>(value) <= DstLimits::max());
+  }
 };
 
 // Signed to signed narrowing: Both the upper and lower boundaries may be
-// exceeded.
-template <typename Dst, typename Src>
+// exceeded for standard limits.
+template <typename Dst, typename Src, template <typename> class Bounds>
 struct DstRangeRelationToSrcRangeImpl<Dst,
                                       Src,
+                                      Bounds,
                                       INTEGER_REPRESENTATION_SIGNED,
                                       INTEGER_REPRESENTATION_SIGNED,
                                       NUMERIC_RANGE_NOT_CONTAINED> {
-  static RangeConstraint Check(Src value) {
-    return std::numeric_limits<Dst>::is_iec559
-               ? GetRangeConstraint(value <= std::numeric_limits<Dst>::max(),
-                                    value >= -std::numeric_limits<Dst>::max())
-               : GetRangeConstraint(value <= std::numeric_limits<Dst>::max(),
-                                    value >= std::numeric_limits<Dst>::min());
+  static constexpr RangeCheck Check(Src value) {
+    using DstLimits = NarrowingRange<Dst, Src, Bounds>;
+    return RangeCheck(value >= DstLimits::lowest(), value <= DstLimits::max());
   }
 };
 
-// Unsigned to unsigned narrowing: Only the upper boundary can be exceeded.
-template <typename Dst, typename Src>
+// Unsigned to unsigned narrowing: Only the upper bound can be exceeded for
+// standard limits.
+template <typename Dst, typename Src, template <typename> class Bounds>
 struct DstRangeRelationToSrcRangeImpl<Dst,
                                       Src,
+                                      Bounds,
                                       INTEGER_REPRESENTATION_UNSIGNED,
                                       INTEGER_REPRESENTATION_UNSIGNED,
                                       NUMERIC_RANGE_NOT_CONTAINED> {
-  static RangeConstraint Check(Src value) {
-    return GetRangeConstraint(value <= std::numeric_limits<Dst>::max(), true);
+  static constexpr RangeCheck Check(Src value) {
+    using DstLimits = NarrowingRange<Dst, Src, Bounds>;
+    return RangeCheck(
+        DstLimits::lowest() == Dst(0) || value >= DstLimits::lowest(),
+        value <= DstLimits::max());
   }
 };
 
-// Unsigned to signed: The upper boundary may be exceeded.
-template <typename Dst, typename Src>
+// Unsigned to signed: Only the upper bound can be exceeded for standard limits.
+template <typename Dst, typename Src, template <typename> class Bounds>
 struct DstRangeRelationToSrcRangeImpl<Dst,
                                       Src,
+                                      Bounds,
                                       INTEGER_REPRESENTATION_SIGNED,
                                       INTEGER_REPRESENTATION_UNSIGNED,
                                       NUMERIC_RANGE_NOT_CONTAINED> {
-  static RangeConstraint Check(Src value) {
-    return sizeof(Dst) > sizeof(Src)
-               ? RANGE_VALID
-               : GetRangeConstraint(
-                     value <= static_cast<Src>(std::numeric_limits<Dst>::max()),
-                     true);
+  static constexpr RangeCheck Check(Src value) {
+    using DstLimits = NarrowingRange<Dst, Src, Bounds>;
+    using Promotion = decltype(Src() + Dst());
+    return RangeCheck(DstLimits::lowest() <= Dst(0) ||
+                          static_cast<Promotion>(value) >=
+                              static_cast<Promotion>(DstLimits::lowest()),
+                      static_cast<Promotion>(value) <=
+                          static_cast<Promotion>(DstLimits::max()));
   }
 };
 
 // Signed to unsigned: The upper boundary may be exceeded for a narrower Dst,
-// and any negative value exceeds the lower boundary.
-template <typename Dst, typename Src>
+// and any negative value exceeds the lower boundary for standard limits.
+template <typename Dst, typename Src, template <typename> class Bounds>
 struct DstRangeRelationToSrcRangeImpl<Dst,
                                       Src,
+                                      Bounds,
                                       INTEGER_REPRESENTATION_UNSIGNED,
                                       INTEGER_REPRESENTATION_SIGNED,
                                       NUMERIC_RANGE_NOT_CONTAINED> {
-  static RangeConstraint Check(Src value) {
-    return (MaxExponent<Dst>::value >= MaxExponent<Src>::value)
-               ? GetRangeConstraint(true, value >= static_cast<Src>(0))
-               : GetRangeConstraint(
-                     value <= static_cast<Src>(std::numeric_limits<Dst>::max()),
-                     value >= static_cast<Src>(0));
+  static constexpr RangeCheck Check(Src value) {
+    using SrcLimits = std::numeric_limits<Src>;
+    using DstLimits = NarrowingRange<Dst, Src, Bounds>;
+    using Promotion = decltype(Src() + Dst());
+    return RangeCheck(
+        value >= Src(0) && (DstLimits::lowest() == 0 ||
+                            static_cast<Dst>(value) >= DstLimits::lowest()),
+        static_cast<Promotion>(SrcLimits::max()) <=
+                static_cast<Promotion>(DstLimits::max()) ||
+            static_cast<Promotion>(value) <=
+                static_cast<Promotion>(DstLimits::max()));
   }
 };
 
-template <typename Dst, typename Src>
-inline RangeConstraint DstRangeRelationToSrcRange(Src value) {
-  COMPILE_ASSERT(std::numeric_limits<Src>::is_specialized,
-                 argument_must_be_numeric);
-  COMPILE_ASSERT(std::numeric_limits<Dst>::is_specialized,
-                 result_must_be_numeric);
-  return DstRangeRelationToSrcRangeImpl<Dst, Src>::Check(value);
+template <typename Dst,
+          template <typename> class Bounds = std::numeric_limits,
+          typename Src>
+constexpr RangeCheck DstRangeRelationToSrcRange(Src value) {
+  static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
+  static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric.");
+  static_assert(Bounds<Dst>::lowest() < Bounds<Dst>::max(), "");
+  return DstRangeRelationToSrcRangeImpl<Dst, Src, Bounds>::Check(value);
 }
 
+// Integer promotion templates used by the portable checked integer arithmetic.
+template <size_t Size, bool IsSigned>
+struct IntegerForDigitsAndSign;
+
+#define INTEGER_FOR_DIGITS_AND_SIGN(I)                          \
+  template <>                                                   \
+  struct IntegerForDigitsAndSign<IntegerBitsPlusSign<I>::value, \
+                                 std::is_signed<I>::value> {    \
+    using type = I;                                             \
+  }
+
+INTEGER_FOR_DIGITS_AND_SIGN(int8_t);
+INTEGER_FOR_DIGITS_AND_SIGN(uint8_t);
+INTEGER_FOR_DIGITS_AND_SIGN(int16_t);
+INTEGER_FOR_DIGITS_AND_SIGN(uint16_t);
+INTEGER_FOR_DIGITS_AND_SIGN(int32_t);
+INTEGER_FOR_DIGITS_AND_SIGN(uint32_t);
+INTEGER_FOR_DIGITS_AND_SIGN(int64_t);
+INTEGER_FOR_DIGITS_AND_SIGN(uint64_t);
+#undef INTEGER_FOR_DIGITS_AND_SIGN
+
+// WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to
+// support 128-bit math, then the ArithmeticPromotion template below will need
+// to be updated (or more likely replaced with a decltype expression).
+static_assert(IntegerBitsPlusSign<intmax_t>::value == 64,
+              "Max integer size not supported for this toolchain.");
+
+template <typename Integer, bool IsSigned = std::is_signed<Integer>::value>
+struct TwiceWiderInteger {
+  using type =
+      typename IntegerForDigitsAndSign<IntegerBitsPlusSign<Integer>::value * 2,
+                                       IsSigned>::type;
+};
+
+enum ArithmeticPromotionCategory {
+  LEFT_PROMOTION,  // Use the type of the left-hand argument.
+  RIGHT_PROMOTION  // Use the type of the right-hand argument.
+};
+
+// Determines the type that can represent the largest positive value.
+template <typename Lhs,
+          typename Rhs,
+          ArithmeticPromotionCategory Promotion =
+              (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
+                  ? LEFT_PROMOTION
+                  : RIGHT_PROMOTION>
+struct MaxExponentPromotion;
+
+template <typename Lhs, typename Rhs>
+struct MaxExponentPromotion<Lhs, Rhs, LEFT_PROMOTION> {
+  using type = Lhs;
+};
+
+template <typename Lhs, typename Rhs>
+struct MaxExponentPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
+  using type = Rhs;
+};
+
+// Determines the type that can represent the lowest arithmetic value.
+template <typename Lhs,
+          typename Rhs,
+          ArithmeticPromotionCategory Promotion =
+              std::is_signed<Lhs>::value
+                  ? (std::is_signed<Rhs>::value
+                         ? (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value
+                                ? LEFT_PROMOTION
+                                : RIGHT_PROMOTION)
+                         : LEFT_PROMOTION)
+                  : (std::is_signed<Rhs>::value
+                         ? RIGHT_PROMOTION
+                         : (MaxExponent<Lhs>::value < MaxExponent<Rhs>::value
+                                ? LEFT_PROMOTION
+                                : RIGHT_PROMOTION))>
+struct LowestValuePromotion;
+
+template <typename Lhs, typename Rhs>
+struct LowestValuePromotion<Lhs, Rhs, LEFT_PROMOTION> {
+  using type = Lhs;
+};
+
+template <typename Lhs, typename Rhs>
+struct LowestValuePromotion<Lhs, Rhs, RIGHT_PROMOTION> {
+  using type = Rhs;
+};
+
+// Determines the type that is best able to represent an arithmetic result.
+template <
+    typename Lhs,
+    typename Rhs = Lhs,
+    bool is_intmax_type =
+        std::is_integral<typename MaxExponentPromotion<Lhs, Rhs>::type>::value&&
+            IntegerBitsPlusSign<typename MaxExponentPromotion<Lhs, Rhs>::type>::
+                value == IntegerBitsPlusSign<intmax_t>::value,
+    bool is_max_exponent =
+        StaticDstRangeRelationToSrcRange<
+            typename MaxExponentPromotion<Lhs, Rhs>::type,
+            Lhs>::value ==
+        NUMERIC_RANGE_CONTAINED&& StaticDstRangeRelationToSrcRange<
+            typename MaxExponentPromotion<Lhs, Rhs>::type,
+            Rhs>::value == NUMERIC_RANGE_CONTAINED>
+struct BigEnoughPromotion;
+
+// The side with the max exponent is big enough.
+template <typename Lhs, typename Rhs, bool is_intmax_type>
+struct BigEnoughPromotion<Lhs, Rhs, is_intmax_type, true> {
+  using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
+  static const bool is_contained = true;
+};
+
+// We can use a twice wider type to fit.
+template <typename Lhs, typename Rhs>
+struct BigEnoughPromotion<Lhs, Rhs, false, false> {
+  using type =
+      typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type,
+                                 std::is_signed<Lhs>::value ||
+                                     std::is_signed<Rhs>::value>::type;
+  static const bool is_contained = true;
+};
+
+// No type is large enough.
+template <typename Lhs, typename Rhs>
+struct BigEnoughPromotion<Lhs, Rhs, true, false> {
+  using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
+  static const bool is_contained = false;
+};
+
+// We can statically check if operations on the provided types can wrap, so we
+// can skip the checked operations if they're not needed. So, for an integer we
+// care if the destination type preserves the sign and is twice the width of
+// the source.
+template <typename T, typename Lhs, typename Rhs = Lhs>
+struct IsIntegerArithmeticSafe {
+  static const bool value =
+      !std::is_floating_point<T>::value &&
+      !std::is_floating_point<Lhs>::value &&
+      !std::is_floating_point<Rhs>::value &&
+      std::is_signed<T>::value >= std::is_signed<Lhs>::value &&
+      IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Lhs>::value) &&
+      std::is_signed<T>::value >= std::is_signed<Rhs>::value &&
+      IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Rhs>::value);
+};
+
+// Promotes to a type that can represent any possible result of a binary
+// arithmetic operation with the source types.
+template <typename Lhs,
+          typename Rhs,
+          bool is_promotion_possible = IsIntegerArithmeticSafe<
+              typename std::conditional<std::is_signed<Lhs>::value ||
+                                            std::is_signed<Rhs>::value,
+                                        intmax_t,
+                                        uintmax_t>::type,
+              typename MaxExponentPromotion<Lhs, Rhs>::type>::value>
+struct FastIntegerArithmeticPromotion;
+
+template <typename Lhs, typename Rhs>
+struct FastIntegerArithmeticPromotion<Lhs, Rhs, true> {
+  using type =
+      typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type,
+                                 std::is_signed<Lhs>::value ||
+                                     std::is_signed<Rhs>::value>::type;
+  static_assert(IsIntegerArithmeticSafe<type, Lhs, Rhs>::value, "");
+  static const bool is_contained = true;
+};
+
+template <typename Lhs, typename Rhs>
+struct FastIntegerArithmeticPromotion<Lhs, Rhs, false> {
+  using type = typename BigEnoughPromotion<Lhs, Rhs>::type;
+  static const bool is_contained = false;
+};
+
+// This hacks around libstdc++ 4.6 missing stuff in type_traits.
+#if defined(__GLIBCXX__)
+#define PRIV_GLIBCXX_4_7_0 20120322
+#define PRIV_GLIBCXX_4_5_4 20120702
+#define PRIV_GLIBCXX_4_6_4 20121127
+#if (__GLIBCXX__ < PRIV_GLIBCXX_4_7_0 || __GLIBCXX__ == PRIV_GLIBCXX_4_5_4 || \
+     __GLIBCXX__ == PRIV_GLIBCXX_4_6_4)
+#define PRIV_USE_FALLBACKS_FOR_OLD_GLIBCXX
+#undef PRIV_GLIBCXX_4_7_0
+#undef PRIV_GLIBCXX_4_5_4
+#undef PRIV_GLIBCXX_4_6_4
+#endif
+#endif
+
+// Extracts the underlying type from an enum.
+template <typename T, bool is_enum = std::is_enum<T>::value>
+struct ArithmeticOrUnderlyingEnum;
+
+template <typename T>
+struct ArithmeticOrUnderlyingEnum<T, true> {
+#if defined(PRIV_USE_FALLBACKS_FOR_OLD_GLIBCXX)
+  using type = __underlying_type(T);
+#else
+  using type = typename std::underlying_type<T>::type;
+#endif
+  static const bool value = std::is_arithmetic<type>::value;
+};
+
+#if defined(PRIV_USE_FALLBACKS_FOR_OLD_GLIBCXX)
+#undef PRIV_USE_FALLBACKS_FOR_OLD_GLIBCXX
+#endif
+
+template <typename T>
+struct ArithmeticOrUnderlyingEnum<T, false> {
+  using type = T;
+  static const bool value = std::is_arithmetic<type>::value;
+};
+
+// The following are helper templates used in the CheckedNumeric class.
+template <typename T>
+class CheckedNumeric;
+
+template <typename T>
+class StrictNumeric;
+
+// Used to treat CheckedNumeric and arithmetic underlying types the same.
+template <typename T>
+struct UnderlyingType {
+  using type = typename ArithmeticOrUnderlyingEnum<T>::type;
+  static const bool is_numeric = std::is_arithmetic<type>::value;
+  static const bool is_checked = false;
+  static const bool is_strict = false;
+};
+
+template <typename T>
+struct UnderlyingType<CheckedNumeric<T>> {
+  using type = T;
+  static const bool is_numeric = true;
+  static const bool is_checked = true;
+  static const bool is_strict = false;
+};
+
+template <typename T>
+struct UnderlyingType<StrictNumeric<T>> {
+  using type = T;
+  static const bool is_numeric = true;
+  static const bool is_checked = false;
+  static const bool is_strict = true;
+};
+
+template <typename L, typename R>
+struct IsCheckedOp {
+  static const bool value =
+      UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
+      (UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked);
+};
+
+template <typename L, typename R>
+struct IsStrictOp {
+  static const bool value =
+      UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
+      (UnderlyingType<L>::is_strict || UnderlyingType<R>::is_strict);
+};
+
+template <typename L, typename R>
+constexpr bool IsLessImpl(const L lhs,
+                          const R rhs,
+                          const RangeCheck l_range,
+                          const RangeCheck r_range) {
+  return l_range.IsUnderflow() || r_range.IsOverflow() ||
+         (l_range == r_range &&
+          static_cast<decltype(lhs + rhs)>(lhs) <
+              static_cast<decltype(lhs + rhs)>(rhs));
+}
+
+template <typename L, typename R>
+struct IsLess {
+  static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
+                "Types must be numeric.");
+  static constexpr bool Test(const L lhs, const R rhs) {
+    return IsLessImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
+                      DstRangeRelationToSrcRange<L>(rhs));
+  }
+};
+
+template <typename L, typename R>
+constexpr bool IsLessOrEqualImpl(const L lhs,
+                                 const R rhs,
+                                 const RangeCheck l_range,
+                                 const RangeCheck r_range) {
+  return l_range.IsUnderflow() || r_range.IsOverflow() ||
+         (l_range == r_range &&
+          static_cast<decltype(lhs + rhs)>(lhs) <=
+              static_cast<decltype(lhs + rhs)>(rhs));
+}
+
+template <typename L, typename R>
+struct IsLessOrEqual {
+  static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
+                "Types must be numeric.");
+  static constexpr bool Test(const L lhs, const R rhs) {
+    return IsLessOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
+                             DstRangeRelationToSrcRange<L>(rhs));
+  }
+};
+
+template <typename L, typename R>
+constexpr bool IsGreaterImpl(const L lhs,
+                             const R rhs,
+                             const RangeCheck l_range,
+                             const RangeCheck r_range) {
+  return l_range.IsOverflow() || r_range.IsUnderflow() ||
+         (l_range == r_range &&
+          static_cast<decltype(lhs + rhs)>(lhs) >
+              static_cast<decltype(lhs + rhs)>(rhs));
+}
+
+template <typename L, typename R>
+struct IsGreater {
+  static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
+                "Types must be numeric.");
+  static constexpr bool Test(const L lhs, const R rhs) {
+    return IsGreaterImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
+                         DstRangeRelationToSrcRange<L>(rhs));
+  }
+};
+
+template <typename L, typename R>
+constexpr bool IsGreaterOrEqualImpl(const L lhs,
+                                    const R rhs,
+                                    const RangeCheck l_range,
+                                    const RangeCheck r_range) {
+  return l_range.IsOverflow() || r_range.IsUnderflow() ||
+         (l_range == r_range &&
+          static_cast<decltype(lhs + rhs)>(lhs) >=
+              static_cast<decltype(lhs + rhs)>(rhs));
+}
+
+template <typename L, typename R>
+struct IsGreaterOrEqual {
+  static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
+                "Types must be numeric.");
+  static constexpr bool Test(const L lhs, const R rhs) {
+    return IsGreaterOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
+                                DstRangeRelationToSrcRange<L>(rhs));
+  }
+};
+
+template <typename L, typename R>
+struct IsEqual {
+  static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
+                "Types must be numeric.");
+  static constexpr bool Test(const L lhs, const R rhs) {
+    return DstRangeRelationToSrcRange<R>(lhs) ==
+               DstRangeRelationToSrcRange<L>(rhs) &&
+           static_cast<decltype(lhs + rhs)>(lhs) ==
+               static_cast<decltype(lhs + rhs)>(rhs);
+  }
+};
+
+template <typename L, typename R>
+struct IsNotEqual {
+  static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
+                "Types must be numeric.");
+  static constexpr bool Test(const L lhs, const R rhs) {
+    return DstRangeRelationToSrcRange<R>(lhs) !=
+               DstRangeRelationToSrcRange<L>(rhs) ||
+           static_cast<decltype(lhs + rhs)>(lhs) !=
+               static_cast<decltype(lhs + rhs)>(rhs);
+  }
+};
+
+// These perform the actual math operations on the CheckedNumerics.
+// Binary arithmetic operations.
+template <template <typename, typename> class C, typename L, typename R>
+constexpr bool SafeCompare(const L lhs, const R rhs) {
+  static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
+                "Types must be numeric.");
+  using Promotion = BigEnoughPromotion<L, R>;
+  using BigType = typename Promotion::type;
+  return Promotion::is_contained
+             // Force to a larger type for speed if both are contained.
+             ? C<BigType, BigType>::Test(
+                   static_cast<BigType>(static_cast<L>(lhs)),
+                   static_cast<BigType>(static_cast<R>(rhs)))
+             // Let the template functions figure it out for mixed types.
+             : C<L, R>::Test(lhs, rhs);
+};
+
 }  // namespace internal
 }  // namespace base
 }  // namespace pdfium
 
-#endif  // PDFIUM_THIRD_PARTY_BASE_SAFE_CONVERSIONS_IMPL_H_
+#endif  // PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
diff --git a/third_party/base/numerics/safe_math.h b/third_party/base/numerics/safe_math.h
index 013af1e..a0c41a4 100644
--- a/third_party/base/numerics/safe_math.h
+++ b/third_party/base/numerics/safe_math.h
@@ -2,140 +2,268 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef PDFIUM_THIRD_PARTY_BASE_SAFE_MATH_H_
-#define PDFIUM_THIRD_PARTY_BASE_SAFE_MATH_H_
+#ifndef PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_H_
+#define PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_H_
 
-#include "safe_math_impl.h"
+#include <stddef.h>
+
+#include <limits>
+#include <type_traits>
+
+#include "third_party/base/numerics/safe_math_impl.h"
 
 namespace pdfium {
 namespace base {
 namespace internal {
 
-// CheckedNumeric implements all the logic and operators for detecting integer
+// CheckedNumeric<> implements all the logic and operators for detecting integer
 // boundary conditions such as overflow, underflow, and invalid conversions.
 // The CheckedNumeric type implicitly converts from floating point and integer
 // data types, and contains overloads for basic arithmetic operations (i.e.: +,
-// -, *, /, %).
+// -, *, / for all types and %, <<, >>, &, |, ^ for integers). Type promotions
+// are a slightly modified version of the standard C arithmetic rules with the
+// two differences being that there is no default promotion to int and bitwise
+// logical operations always return an unsigned of the wider type.
+//
+// You may also use one of the variadic convenience functions, which accept
+// standard arithmetic or CheckedNumeric types, perform arithmetic operations,
+// and return a CheckedNumeric result. The supported functions are:
+//  CheckAdd() - Addition.
+//  CheckSub() - Subtraction.
+//  CheckMul() - Multiplication.
+//  CheckDiv() - Division.
+//  CheckMod() - Modulous (integer only).
+//  CheckLsh() - Left integer shift (integer only).
+//  CheckRsh() - Right integer shift (integer only).
+//  CheckAnd() - Bitwise AND (integer only with unsigned result).
+//  CheckOr()  - Bitwise OR (integer only with unsigned result).
+//  CheckXor() - Bitwise XOR (integer only with unsigned result).
+//  CheckMax() - Maximum of supplied arguments.
+//  CheckMin() - Minimum of supplied arguments.
+//
+// The unary negation, increment, and decrement operators are supported, along
+// with the following unary arithmetic methods, which return a new
+// CheckedNumeric as a result of the operation:
+//  Abs() - Absolute value.
+//  UnsignedAbs() - Absolute value as an equal-width unsigned underlying type
+//          (valid for only integral types).
+//  Max() - Returns whichever is greater of the current instance or argument.
+//          The underlying return type is whichever has the greatest magnitude.
+//  Min() - Returns whichever is lowest of the current instance or argument.
+//          The underlying return type is whichever has can represent the lowest
+//          number in the smallest width (e.g. int8_t over unsigned, int over
+//          int8_t, and float over int).
 //
 // The following methods convert from CheckedNumeric to standard numeric values:
-// IsValid() - Returns true if the underlying numeric value is valid (i.e. has
-//             has not wrapped and is not the result of an invalid conversion).
-// ValueOrDie() - Returns the underlying value. If the state is not valid this
-//                call will crash on a CHECK.
-// ValueOrDefault() - Returns the current value, or the supplied default if the
-//                    state is not valid.
-// ValueFloating() - Returns the underlying floating point value (valid only
-//                   only for floating point CheckedNumeric types).
+//  AssignIfValid() - Assigns the underlying value to the supplied destination
+//          pointer if the value is currently valid and within the range
+//          supported by the destination type. Returns true on success.
+//  ****************************************************************************
+//  *  WARNING: All of the following functions return a StrictNumeric, which   *
+//  *  is valid for comparison and assignment operations, but will trigger a   *
+//  *  compile failure on attempts to assign to a type of insufficient range.  *
+//  ****************************************************************************
+//  IsValid() - Returns true if the underlying numeric value is valid (i.e. has
+//          has not wrapped and is not the result of an invalid conversion).
+//  ValueOrDie() - Returns the underlying value. If the state is not valid this
+//          call will crash on a CHECK.
+//  ValueOrDefault() - Returns the current value, or the supplied default if the
+//          state is not valid (will not trigger a CHECK).
 //
-// Bitwise operations are explicitly not supported, because correct
-// handling of some cases (e.g. sign manipulation) is ambiguous. Comparison
-// operations are explicitly not supported because they could result in a crash
-// on a CHECK condition. You should use patterns like the following for these
-// operations:
-// Bitwise operation:
-//     CheckedNumeric<int> checked_int = untrusted_input_value;
-//     int x = checked_int.ValueOrDefault(0) | kFlagValues;
-// Comparison:
-//   CheckedNumeric<size_t> checked_size;
-//   CheckedNumeric<int> checked_size = untrusted_input_value;
-//   checked_size = checked_size + HEADER LENGTH;
+// The following wrapper functions can be used to avoid the template
+// disambiguator syntax when converting a destination type.
+//   IsValidForType<>() in place of: a.template IsValid<Dst>()
+//   ValueOrDieForType<>() in place of: a.template ValueOrDie()
+//   ValueOrDefaultForType<>() in place of: a.template ValueOrDefault(default)
+//
+// The following are general utility methods that are useful for converting
+// between arithmetic types and CheckedNumeric types:
+//  CheckedNumeric::Cast<Dst>() - Instance method returning a CheckedNumeric
+//          derived from casting the current instance to a CheckedNumeric of
+//          the supplied destination type.
+//  MakeCheckedNum() - Creates a new CheckedNumeric from the underlying type of
+//          the supplied arithmetic, CheckedNumeric, or StrictNumeric type.
+//
+// Comparison operations are explicitly not supported because they could result
+// in a crash on an unexpected CHECK condition. You should use patterns like the
+// following for comparisons:
+//   CheckedNumeric<size_t> checked_size = untrusted_input_value;
+//   checked_size += HEADER LENGTH;
 //   if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size)
 //     Do stuff...
+
 template <typename T>
 class CheckedNumeric {
- public:
-  typedef T type;
+  static_assert(std::is_arithmetic<T>::value,
+                "CheckedNumeric<T>: T must be a numeric type.");
 
-  CheckedNumeric() {}
+ public:
+  using type = T;
+
+  constexpr CheckedNumeric() {}
 
   // Copy constructor.
   template <typename Src>
-  CheckedNumeric(const CheckedNumeric<Src>& rhs)
-      : state_(rhs.ValueUnsafe(), rhs.validity()) {}
+  constexpr CheckedNumeric(const CheckedNumeric<Src>& rhs)
+      : state_(rhs.state_.value(), rhs.IsValid()) {}
 
   template <typename Src>
-  CheckedNumeric(Src value, RangeConstraint validity)
-      : state_(value, validity) {}
+  friend class CheckedNumeric;
 
   // This is not an explicit constructor because we implicitly upgrade regular
   // numerics to CheckedNumerics to make them easier to use.
   template <typename Src>
-  CheckedNumeric(Src value)
+  constexpr CheckedNumeric(Src value)  // NOLINT(runtime/explicit)
       : state_(value) {
-    COMPILE_ASSERT(std::numeric_limits<Src>::is_specialized,
-                   argument_must_be_numeric);
+    static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
   }
 
-  // IsValid() is the public API to test if a CheckedNumeric is currently valid.
-  bool IsValid() const { return validity() == RANGE_VALID; }
+  // This is not an explicit constructor because we want a seamless conversion
+  // from StrictNumeric types.
+  template <typename Src>
+  constexpr CheckedNumeric(
+      StrictNumeric<Src> value)  // NOLINT(runtime/explicit)
+      : state_(static_cast<Src>(value)) {}
 
-  // ValueOrDie() The primary accessor for the underlying value. If the current
-  // state is not valid it will CHECK and crash.
-  T ValueOrDie() const {
-    CHECK(IsValid());
-    return state_.value();
+  // IsValid() - The public API to test if a CheckedNumeric is currently valid.
+  // A range checked destination type can be supplied using the Dst template
+  // parameter.
+  template <typename Dst = T>
+  constexpr bool IsValid() const {
+    return state_.is_valid() &&
+           IsValueInRangeForNumericType<Dst>(state_.value());
   }
 
-  // ValueOrDefault(T default_value) A convenience method that returns the
+  // AssignIfValid(Dst) - Assigns the underlying value if it is currently valid
+  // and is within the range supported by the destination type. Returns true if
+  // successful and false otherwise.
+  template <typename Dst>
+  constexpr bool AssignIfValid(Dst* result) const {
+    return IsValid<Dst>() ? ((*result = static_cast<Dst>(state_.value())), true)
+                          : false;
+  }
+
+  // ValueOrDie() - The primary accessor for the underlying value. If the
+  // current state is not valid it will CHECK and crash.
+  // A range checked destination type can be supplied using the Dst template
+  // parameter, which will trigger a CHECK if the value is not in bounds for
+  // the destination.
+  // The CHECK behavior can be overridden by supplying a handler as a
+  // template parameter, for test code, etc. However, the handler cannot access
+  // the underlying value, and it is not available through other means.
+  template <typename Dst = T, class CheckHandler = CheckOnFailure>
+  constexpr StrictNumeric<Dst> ValueOrDie() const {
+    return IsValid<Dst>() ? static_cast<Dst>(state_.value())
+                          : CheckHandler::template HandleFailure<Dst>();
+  }
+
+  // ValueOrDefault(T default_value) - A convenience method that returns the
   // current value if the state is valid, and the supplied default_value for
   // any other state.
-  T ValueOrDefault(T default_value) const {
-    return IsValid() ? state_.value() : default_value;
+  // A range checked destination type can be supplied using the Dst template
+  // parameter. WARNING: This function may fail to compile or CHECK at runtime
+  // if the supplied default_value is not within range of the destination type.
+  template <typename Dst = T, typename Src>
+  constexpr StrictNumeric<Dst> ValueOrDefault(const Src default_value) const {
+    return IsValid<Dst>() ? static_cast<Dst>(state_.value())
+                          : checked_cast<Dst>(default_value);
   }
 
-  // ValueFloating() - Since floating point values include their validity state,
-  // we provide an easy method for extracting them directly, without a risk of
-  // crashing on a CHECK.
-  T ValueFloating() const {
-    COMPILE_ASSERT(std::numeric_limits<T>::is_iec559, argument_must_be_float);
-    return CheckedNumeric<T>::cast(*this).ValueUnsafe();
+  // Returns a checked numeric of the specified type, cast from the current
+  // CheckedNumeric. If the current state is invalid or the destination cannot
+  // represent the result then the returned CheckedNumeric will be invalid.
+  template <typename Dst>
+  constexpr CheckedNumeric<typename UnderlyingType<Dst>::type> Cast() const {
+    return *this;
   }
 
-  // validity() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now for
-  // tests and to avoid a big matrix of friend operator overloads. But the
-  // values it returns are likely to change in the future.
-  // Returns: current validity state (i.e. valid, overflow, underflow, nan).
-  // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for
-  // saturation/wrapping so we can expose this state consistently and implement
-  // saturated arithmetic.
-  RangeConstraint validity() const { return state_.validity(); }
-
-  // ValueUnsafe() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now
-  // for tests and to avoid a big matrix of friend operator overloads. But the
-  // values it returns are likely to change in the future.
-  // Returns: the raw numeric value, regardless of the current state.
-  // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for
-  // saturation/wrapping so we can expose this state consistently and implement
-  // saturated arithmetic.
-  T ValueUnsafe() const { return state_.value(); }
+  // This friend method is available solely for providing more detailed logging
+  // in the the tests. Do not implement it in production code, because the
+  // underlying values may change at any time.
+  template <typename U>
+  friend U GetNumericValueForTest(const CheckedNumeric<U>& src);
 
   // Prototypes for the supported arithmetic operator overloads.
-  template <typename Src> CheckedNumeric& operator+=(Src rhs);
-  template <typename Src> CheckedNumeric& operator-=(Src rhs);
-  template <typename Src> CheckedNumeric& operator*=(Src rhs);
-  template <typename Src> CheckedNumeric& operator/=(Src rhs);
-  template <typename Src> CheckedNumeric& operator%=(Src rhs);
+  template <typename Src>
+  CheckedNumeric& operator+=(const Src rhs);
+  template <typename Src>
+  CheckedNumeric& operator-=(const Src rhs);
+  template <typename Src>
+  CheckedNumeric& operator*=(const Src rhs);
+  template <typename Src>
+  CheckedNumeric& operator/=(const Src rhs);
+  template <typename Src>
+  CheckedNumeric& operator%=(const Src rhs);
+  template <typename Src>
+  CheckedNumeric& operator<<=(const Src rhs);
+  template <typename Src>
+  CheckedNumeric& operator>>=(const Src rhs);
+  template <typename Src>
+  CheckedNumeric& operator&=(const Src rhs);
+  template <typename Src>
+  CheckedNumeric& operator|=(const Src rhs);
+  template <typename Src>
+  CheckedNumeric& operator^=(const Src rhs);
 
-  CheckedNumeric operator-() const {
-    RangeConstraint validity;
-    T value = CheckedNeg(state_.value(), &validity);
-    // Negation is always valid for floating point.
-    if (std::numeric_limits<T>::is_iec559)
-      return CheckedNumeric<T>(value);
-
-    validity = GetRangeConstraint(state_.validity() | validity);
-    return CheckedNumeric<T>(value, validity);
+  constexpr CheckedNumeric operator-() const {
+    return CheckedNumeric<T>(
+        NegateWrapper(state_.value()),
+        IsValid() &&
+            (!std::is_signed<T>::value || std::is_floating_point<T>::value ||
+             NegateWrapper(state_.value()) !=
+                 std::numeric_limits<T>::lowest()));
   }
 
-  CheckedNumeric Abs() const {
-    RangeConstraint validity;
-    T value = CheckedAbs(state_.value(), &validity);
-    // Absolute value is always valid for floating point.
-    if (std::numeric_limits<T>::is_iec559)
-      return CheckedNumeric<T>(value);
+  constexpr CheckedNumeric operator~() const {
+    return CheckedNumeric<decltype(InvertWrapper(T()))>(
+        InvertWrapper(state_.value()), IsValid());
+  }
 
-    validity = GetRangeConstraint(state_.validity() | validity);
-    return CheckedNumeric<T>(value, validity);
+  constexpr CheckedNumeric Abs() const {
+    return CheckedNumeric<T>(
+        AbsWrapper(state_.value()),
+        IsValid() &&
+            (!std::is_signed<T>::value || std::is_floating_point<T>::value ||
+             AbsWrapper(state_.value()) != std::numeric_limits<T>::lowest()));
+  }
+
+  template <typename U>
+  constexpr CheckedNumeric<typename MathWrapper<CheckedMaxOp, T, U>::type> Max(
+      const U rhs) const {
+    using R = typename UnderlyingType<U>::type;
+    using result_type = typename MathWrapper<CheckedMaxOp, T, U>::type;
+    // TODO(jschuh): This can be converted to the MathOp version and remain
+    // constexpr once we have C++14 support.
+    return CheckedNumeric<result_type>(
+        static_cast<result_type>(
+            IsGreater<T, R>::Test(state_.value(), Wrapper<U>::value(rhs))
+                ? state_.value()
+                : Wrapper<U>::value(rhs)),
+        state_.is_valid() && Wrapper<U>::is_valid(rhs));
+  }
+
+  template <typename U>
+  constexpr CheckedNumeric<typename MathWrapper<CheckedMinOp, T, U>::type> Min(
+      const U rhs) const {
+    using R = typename UnderlyingType<U>::type;
+    using result_type = typename MathWrapper<CheckedMinOp, T, U>::type;
+    // TODO(jschuh): This can be converted to the MathOp version and remain
+    // constexpr once we have C++14 support.
+    return CheckedNumeric<result_type>(
+        static_cast<result_type>(
+            IsLess<T, R>::Test(state_.value(), Wrapper<U>::value(rhs))
+                ? state_.value()
+                : Wrapper<U>::value(rhs)),
+        state_.is_valid() && Wrapper<U>::is_valid(rhs));
+  }
+
+  // This function is available only for integral types. It returns an unsigned
+  // integer of the same width as the source type, containing the absolute value
+  // of the source, and properly handling signed min.
+  constexpr CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>
+  UnsignedAbs() const {
+    return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>(
+        SafeUnsignedAbs(state_.value()), state_.is_valid());
   }
 
   CheckedNumeric& operator++() {
@@ -160,113 +288,223 @@
     return value;
   }
 
-  // These static methods behave like a convenience cast operator targeting
-  // the desired CheckedNumeric type. As an optimization, a reference is
-  // returned when Src is the same type as T.
-  template <typename Src>
-  static CheckedNumeric<T> cast(
-      Src u,
-      typename std::enable_if<std::numeric_limits<Src>::is_specialized,
-                              int>::type = 0) {
-    return u;
-  }
+  // These perform the actual math operations on the CheckedNumerics.
+  // Binary arithmetic operations.
+  template <template <typename, typename, typename> class M,
+            typename L,
+            typename R>
+  static CheckedNumeric MathOp(const L lhs, const R rhs) {
+    using Math = typename MathWrapper<M, L, R>::math;
+    T result = 0;
+    bool is_valid =
+        Wrapper<L>::is_valid(lhs) && Wrapper<R>::is_valid(rhs) &&
+        Math::Do(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs), &result);
+    return CheckedNumeric<T>(result, is_valid);
+  };
 
-  template <typename Src>
-  static CheckedNumeric<T> cast(
-      const CheckedNumeric<Src>& u,
-      typename std::enable_if<!std::is_same<Src, T>::value, int>::type = 0) {
-    return u;
-  }
-
-  static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; }
+  // Assignment arithmetic operations.
+  template <template <typename, typename, typename> class M, typename R>
+  CheckedNumeric& MathOp(const R rhs) {
+    using Math = typename MathWrapper<M, T, R>::math;
+    T result = 0;  // Using T as the destination saves a range check.
+    bool is_valid = state_.is_valid() && Wrapper<R>::is_valid(rhs) &&
+                    Math::Do(state_.value(), Wrapper<R>::value(rhs), &result);
+    *this = CheckedNumeric<T>(result, is_valid);
+    return *this;
+  };
 
  private:
   CheckedNumericState<T> state_;
+
+  template <typename Src>
+  constexpr CheckedNumeric(Src value, bool is_valid)
+      : state_(value, is_valid) {}
+
+  // These wrappers allow us to handle state the same way for both
+  // CheckedNumeric and POD arithmetic types.
+  template <typename Src>
+  struct Wrapper {
+    static constexpr bool is_valid(Src) { return true; }
+    static constexpr Src value(Src value) { return value; }
+  };
+
+  template <typename Src>
+  struct Wrapper<CheckedNumeric<Src>> {
+    static constexpr bool is_valid(const CheckedNumeric<Src> v) {
+      return v.IsValid();
+    }
+    static constexpr Src value(const CheckedNumeric<Src> v) {
+      return v.state_.value();
+    }
+  };
+
+  template <typename Src>
+  struct Wrapper<StrictNumeric<Src>> {
+    static constexpr bool is_valid(const StrictNumeric<Src>) { return true; }
+    static constexpr Src value(const StrictNumeric<Src> v) {
+      return static_cast<Src>(v);
+    }
+  };
 };
 
-// This is the boilerplate for the standard arithmetic operator overloads. A
-// macro isn't the prettiest solution, but it beats rewriting these five times.
-// Some details worth noting are:
-//  * We apply the standard arithmetic promotions.
-//  * We skip range checks for floating points.
-//  * We skip range checks for destination integers with sufficient range.
-// TODO(jschuh): extract these out into templates.
-#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP)              \
-  /* Binary arithmetic operator for CheckedNumerics of the same type. */      \
-  template <typename T>                                                       \
-  CheckedNumeric<typename ArithmeticPromotion<T>::type> operator OP(          \
-      const CheckedNumeric<T>& lhs, const CheckedNumeric<T>& rhs) {           \
-    typedef typename ArithmeticPromotion<T>::type Promotion;                  \
-    /* Floating point always takes the fast path */                           \
-    if (std::numeric_limits<T>::is_iec559)                                    \
-      return CheckedNumeric<T>(lhs.ValueUnsafe() OP rhs.ValueUnsafe());       \
-    if (IsIntegerArithmeticSafe<Promotion, T, T>::value)                      \
-      return CheckedNumeric<Promotion>(                                       \
-          lhs.ValueUnsafe() OP rhs.ValueUnsafe(),                             \
-          GetRangeConstraint(rhs.validity() | lhs.validity()));               \
-    RangeConstraint validity = RANGE_VALID;                                   \
-    T result = Checked##NAME(static_cast<Promotion>(lhs.ValueUnsafe()),       \
-                             static_cast<Promotion>(rhs.ValueUnsafe()),       \
-                             &validity);                                      \
-    return CheckedNumeric<Promotion>(                                         \
-        result,                                                               \
-        GetRangeConstraint(validity | lhs.validity() | rhs.validity()));      \
-  }                                                                           \
-  /* Assignment arithmetic operator implementation from CheckedNumeric. */    \
-  template <typename T>                                                       \
-  template <typename Src>                                                     \
-  CheckedNumeric<T>& CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) {       \
-    *this = CheckedNumeric<T>::cast(*this) OP CheckedNumeric<Src>::cast(rhs); \
-    return *this;                                                             \
-  }                                                                           \
-  /* Binary arithmetic operator for CheckedNumeric of different type. */      \
-  template <typename T, typename Src>                                         \
-  CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP(     \
-      const CheckedNumeric<Src>& lhs, const CheckedNumeric<T>& rhs) {         \
-    typedef typename ArithmeticPromotion<T, Src>::type Promotion;             \
-    if (IsIntegerArithmeticSafe<Promotion, T, Src>::value)                    \
-      return CheckedNumeric<Promotion>(                                       \
-          lhs.ValueUnsafe() OP rhs.ValueUnsafe(),                             \
-          GetRangeConstraint(rhs.validity() | lhs.validity()));               \
-    return CheckedNumeric<Promotion>::cast(lhs)                               \
-        OP CheckedNumeric<Promotion>::cast(rhs);                              \
-  }                                                                           \
-  /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \
-  template <typename T, typename Src>                                         \
-  CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP(     \
-      const CheckedNumeric<T>& lhs, Src rhs) {                                \
-    typedef typename ArithmeticPromotion<T, Src>::type Promotion;             \
-    if (IsIntegerArithmeticSafe<Promotion, T, Src>::value)                    \
-      return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs,              \
-                                       lhs.validity());                       \
-    return CheckedNumeric<Promotion>::cast(lhs)                               \
-        OP CheckedNumeric<Promotion>::cast(rhs);                              \
-  }                                                                           \
-  /* Binary arithmetic operator for right numeric and left CheckedNumeric. */ \
-  template <typename T, typename Src>                                         \
-  CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP(     \
-      Src lhs, const CheckedNumeric<T>& rhs) {                                \
-    typedef typename ArithmeticPromotion<T, Src>::type Promotion;             \
-    if (IsIntegerArithmeticSafe<Promotion, T, Src>::value)                    \
-      return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(),              \
-                                       rhs.validity());                       \
-    return CheckedNumeric<Promotion>::cast(lhs)                               \
-        OP CheckedNumeric<Promotion>::cast(rhs);                              \
+// Convenience functions to avoid the ugly template disambiguator syntax.
+template <typename Dst, typename Src>
+constexpr bool IsValidForType(const CheckedNumeric<Src> value) {
+  return value.template IsValid<Dst>();
+}
+
+template <typename Dst, typename Src>
+constexpr StrictNumeric<Dst> ValueOrDieForType(
+    const CheckedNumeric<Src> value) {
+  return value.template ValueOrDie<Dst>();
+}
+
+template <typename Dst, typename Src, typename Default>
+constexpr StrictNumeric<Dst> ValueOrDefaultForType(
+    const CheckedNumeric<Src> value,
+    const Default default_value) {
+  return value.template ValueOrDefault<Dst>(default_value);
+}
+
+// These variadic templates work out the return types.
+// TODO(jschuh): Rip all this out once we have C++14 non-trailing auto support.
+template <template <typename, typename, typename> class M,
+          typename L,
+          typename R,
+          typename... Args>
+struct ResultType;
+
+template <template <typename, typename, typename> class M,
+          typename L,
+          typename R>
+struct ResultType<M, L, R> {
+  using type = typename MathWrapper<M, L, R>::type;
+};
+
+template <template <typename, typename, typename> class M,
+          typename L,
+          typename R,
+          typename... Args>
+struct ResultType {
+  using type =
+      typename ResultType<M, typename ResultType<M, L, R>::type, Args...>::type;
+};
+
+// Convience wrapper to return a new CheckedNumeric from the provided arithmetic
+// or CheckedNumericType.
+template <typename T>
+constexpr CheckedNumeric<typename UnderlyingType<T>::type> MakeCheckedNum(
+    const T value) {
+  return value;
+}
+
+// These implement the variadic wrapper for the math operations.
+template <template <typename, typename, typename> class M,
+          typename L,
+          typename R>
+CheckedNumeric<typename MathWrapper<M, L, R>::type> ChkMathOp(const L lhs,
+                                                              const R rhs) {
+  using Math = typename MathWrapper<M, L, R>::math;
+  return CheckedNumeric<typename Math::result_type>::template MathOp<M>(lhs,
+                                                                        rhs);
+}
+
+// General purpose wrapper template for arithmetic operations.
+template <template <typename, typename, typename> class M,
+          typename L,
+          typename R,
+          typename... Args>
+CheckedNumeric<typename ResultType<M, L, R, Args...>::type>
+ChkMathOp(const L lhs, const R rhs, const Args... args) {
+  auto tmp = ChkMathOp<M>(lhs, rhs);
+  return tmp.IsValid() ? ChkMathOp<M>(tmp, args...)
+                       : decltype(ChkMathOp<M>(tmp, args...))(tmp);
+};
+
+// The following macros are just boilerplate for the standard arithmetic
+// operator overloads and variadic function templates. A macro isn't the nicest
+// solution, but it beats rewriting these over and over again.
+#define BASE_NUMERIC_ARITHMETIC_VARIADIC(NAME)                                \
+  template <typename L, typename R, typename... Args>                         \
+  CheckedNumeric<typename ResultType<Checked##NAME##Op, L, R, Args...>::type> \
+      Check##NAME(const L lhs, const R rhs, const Args... args) {             \
+    return ChkMathOp<Checked##NAME##Op, L, R, Args...>(lhs, rhs, args...);    \
   }
 
-BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += )
-BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= )
-BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= )
-BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= )
-BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= )
+#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP)               \
+  /* Binary arithmetic operator for all CheckedNumeric operations. */          \
+  template <typename L, typename R,                                            \
+            typename std::enable_if<IsCheckedOp<L, R>::value>::type* =         \
+                nullptr>                                                       \
+  CheckedNumeric<typename MathWrapper<Checked##NAME##Op, L, R>::type>          \
+  operator OP(const L lhs, const R rhs) {                                      \
+    return decltype(lhs OP rhs)::template MathOp<Checked##NAME##Op>(lhs, rhs); \
+  }                                                                            \
+  /* Assignment arithmetic operator implementation from CheckedNumeric. */     \
+  template <typename L>                                                        \
+  template <typename R>                                                        \
+  CheckedNumeric<L>& CheckedNumeric<L>::operator COMPOUND_OP(const R rhs) {    \
+    return MathOp<Checked##NAME##Op>(rhs);                                     \
+  }                                                                            \
+  /* Variadic arithmetic functions that return CheckedNumeric. */              \
+  BASE_NUMERIC_ARITHMETIC_VARIADIC(NAME)
 
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, +=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Lsh, <<, <<=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Rsh, >>, >>=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(And, &, &=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Or, |, |=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Xor, ^, ^=)
+BASE_NUMERIC_ARITHMETIC_VARIADIC(Max)
+BASE_NUMERIC_ARITHMETIC_VARIADIC(Min)
+
+#undef BASE_NUMERIC_ARITHMETIC_VARIADIC
 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS
 
+// These are some extra StrictNumeric operators to support simple pointer
+// arithmetic with our result types. Since wrapping on a pointer is always
+// bad, we trigger the CHECK condition here.
+template <typename L, typename R>
+L* operator+(L* lhs, const StrictNumeric<R> rhs) {
+  uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs),
+                              CheckMul(sizeof(L), static_cast<R>(rhs)))
+                         .template ValueOrDie<uintptr_t>();
+  return reinterpret_cast<L*>(result);
+}
+
+template <typename L, typename R>
+L* operator-(L* lhs, const StrictNumeric<R> rhs) {
+  uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs),
+                              CheckMul(sizeof(L), static_cast<R>(rhs)))
+                         .template ValueOrDie<uintptr_t>();
+  return reinterpret_cast<L*>(result);
+}
+
 }  // namespace internal
 
 using internal::CheckedNumeric;
+using internal::IsValidForType;
+using internal::ValueOrDieForType;
+using internal::ValueOrDefaultForType;
+using internal::MakeCheckedNum;
+using internal::CheckMax;
+using internal::CheckMin;
+using internal::CheckAdd;
+using internal::CheckSub;
+using internal::CheckMul;
+using internal::CheckDiv;
+using internal::CheckMod;
+using internal::CheckLsh;
+using internal::CheckRsh;
+using internal::CheckAnd;
+using internal::CheckOr;
+using internal::CheckXor;
 
 }  // namespace base
 }  // namespace pdfium
 
-#endif  // PDFIUM_THIRD_PARTY_BASE_SAFE_MATH_H_
+#endif  // PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_H_
diff --git a/third_party/base/numerics/safe_math_impl.h b/third_party/base/numerics/safe_math_impl.h
index f950f5d..5ad79ce 100644
--- a/third_party/base/numerics/safe_math_impl.h
+++ b/third_party/base/numerics/safe_math_impl.h
@@ -14,7 +14,6 @@
 #include <limits>
 #include <type_traits>
 
-#include "third_party/base/macros.h"
 #include "third_party/base/numerics/safe_conversions.h"
 
 namespace pdfium {
@@ -25,355 +24,486 @@
 // but it may not be fast. This code could be split based on
 // platform/architecture and replaced with potentially faster implementations.
 
-// Integer promotion templates used by the portable checked integer arithmetic.
-template <size_t Size, bool IsSigned>
-struct IntegerForSizeAndSign;
-template <>
-struct IntegerForSizeAndSign<1, true> {
-  typedef int8_t type;
-};
-template <>
-struct IntegerForSizeAndSign<1, false> {
-  typedef uint8_t type;
-};
-template <>
-struct IntegerForSizeAndSign<2, true> {
-  typedef int16_t type;
-};
-template <>
-struct IntegerForSizeAndSign<2, false> {
-  typedef uint16_t type;
-};
-template <>
-struct IntegerForSizeAndSign<4, true> {
-  typedef int32_t type;
-};
-template <>
-struct IntegerForSizeAndSign<4, false> {
-  typedef uint32_t type;
-};
-template <>
-struct IntegerForSizeAndSign<8, true> {
-  typedef int64_t type;
-};
-template <>
-struct IntegerForSizeAndSign<8, false> {
-  typedef uint64_t type;
-};
-
-// WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to
-// support 128-bit math, then the ArithmeticPromotion template below will need
-// to be updated (or more likely replaced with a decltype expression).
-
-template <typename Integer>
-struct UnsignedIntegerForSize {
-  typedef typename std::enable_if<
-      std::numeric_limits<Integer>::is_integer,
-      typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type;
-};
-
-template <typename Integer>
-struct SignedIntegerForSize {
-  typedef typename std::enable_if<
-      std::numeric_limits<Integer>::is_integer,
-      typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type;
-};
-
-template <typename Integer>
-struct TwiceWiderInteger {
-  typedef typename std::enable_if<
-      std::numeric_limits<Integer>::is_integer,
-      typename IntegerForSizeAndSign<
-          sizeof(Integer) * 2,
-          std::numeric_limits<Integer>::is_signed>::type>::type type;
-};
-
-template <typename Integer>
-struct PositionOfSignBit {
-  static const typename std::enable_if<std::numeric_limits<Integer>::is_integer,
-                                       size_t>::type value =
-      CHAR_BIT * sizeof(Integer) - 1;
-};
-
 // This is used for UnsignedAbs, where we need to support floating-point
 // template instantiations even though we don't actually support the operations.
-// However, there is no corresponding implementation of e.g. CheckedUnsignedAbs,
+// However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
 // so the float versions will not compile.
 template <typename Numeric,
-          bool IsInteger = std::numeric_limits<Numeric>::is_integer,
-          bool IsFloat = std::numeric_limits<Numeric>::is_iec559>
+          bool IsInteger = std::is_integral<Numeric>::value,
+          bool IsFloat = std::is_floating_point<Numeric>::value>
 struct UnsignedOrFloatForSize;
 
 template <typename Numeric>
 struct UnsignedOrFloatForSize<Numeric, true, false> {
-  typedef typename UnsignedIntegerForSize<Numeric>::type type;
+  using type = typename std::make_unsigned<Numeric>::type;
 };
 
 template <typename Numeric>
 struct UnsignedOrFloatForSize<Numeric, false, true> {
-  typedef Numeric type;
+  using type = Numeric;
 };
 
-// Helper templates for integer manipulations.
+// Probe for builtin math overflow support on Clang and version check on GCC.
+#if defined(__has_builtin)
+#define USE_OVERFLOW_BUILTINS (__has_builtin(__builtin_add_overflow))
+#elif defined(__GNUC__)
+#define USE_OVERFLOW_BUILTINS (__GNUC__ >= 5)
+#else
+#define USE_OVERFLOW_BUILTINS (0)
+#endif
 
 template <typename T>
-constexpr bool HasSignBit(T x) {
-  // Cast to unsigned since right shift on signed is undefined.
-  return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >>
-            PositionOfSignBit<T>::value);
-}
-
-// This wrapper undoes the standard integer promotions.
-template <typename T>
-constexpr T BinaryComplement(T x) {
-  return static_cast<T>(~x);
-}
-
-// Here are the actual portable checked integer math implementations.
-// TODO(jschuh): Break this code out from the enable_if pattern and find a clean
-// way to coalesce things into the CheckedNumericState specializations below.
-
-template <typename T>
-typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
-CheckedAdd(T x, T y, RangeConstraint* validity) {
+bool CheckedAddImpl(T x, T y, T* result) {
+  static_assert(std::is_integral<T>::value, "Type must be integral");
   // Since the value of x+y is undefined if we have a signed type, we compute
   // it using the unsigned type of the same size.
-  typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
+  using UnsignedDst = typename std::make_unsigned<T>::type;
+  using SignedDst = typename std::make_signed<T>::type;
   UnsignedDst ux = static_cast<UnsignedDst>(x);
   UnsignedDst uy = static_cast<UnsignedDst>(y);
   UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy);
+  *result = static_cast<T>(uresult);
   // Addition is valid if the sign of (x + y) is equal to either that of x or
   // that of y.
-  if (std::numeric_limits<T>::is_signed) {
-    if (HasSignBit(BinaryComplement(
-            static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy))))) {
-      *validity = RANGE_VALID;
-    } else {  // Direction of wrap is inverse of result sign.
-      *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
-    }
-  } else {  // Unsigned is either valid or overflow.
-    *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW;
-  }
-  return static_cast<T>(uresult);
+  return (std::is_signed<T>::value)
+             ? static_cast<SignedDst>((uresult ^ ux) & (uresult ^ uy)) >= 0
+             : uresult >= uy;  // Unsigned is either valid or underflow.
 }
 
+template <typename T, typename U, class Enable = void>
+struct CheckedAddOp {};
+
+template <typename T, typename U>
+struct CheckedAddOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = typename MaxExponentPromotion<T, U>::type;
+  template <typename V>
+  static bool Do(T x, U y, V* result) {
+#if USE_OVERFLOW_BUILTINS
+    return !__builtin_add_overflow(x, y, result);
+#else
+    using Promotion = typename BigEnoughPromotion<T, U>::type;
+    Promotion presult;
+    // Fail if either operand is out of range for the promoted type.
+    // TODO(jschuh): This could be made to work for a broader range of values.
+    bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
+                    IsValueInRangeForNumericType<Promotion>(y);
+
+    if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
+      presult = static_cast<Promotion>(x) + static_cast<Promotion>(y);
+    } else {
+      is_valid &= CheckedAddImpl(static_cast<Promotion>(x),
+                                 static_cast<Promotion>(y), &presult);
+    }
+    *result = static_cast<V>(presult);
+    return is_valid && IsValueInRangeForNumericType<V>(presult);
+#endif
+  }
+};
+
 template <typename T>
-typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
-CheckedSub(T x, T y, RangeConstraint* validity) {
+bool CheckedSubImpl(T x, T y, T* result) {
+  static_assert(std::is_integral<T>::value, "Type must be integral");
   // Since the value of x+y is undefined if we have a signed type, we compute
   // it using the unsigned type of the same size.
-  typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
+  using UnsignedDst = typename std::make_unsigned<T>::type;
+  using SignedDst = typename std::make_signed<T>::type;
   UnsignedDst ux = static_cast<UnsignedDst>(x);
   UnsignedDst uy = static_cast<UnsignedDst>(y);
   UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy);
+  *result = static_cast<T>(uresult);
   // Subtraction is valid if either x and y have same sign, or (x-y) and x have
   // the same sign.
-  if (std::numeric_limits<T>::is_signed) {
-    if (HasSignBit(BinaryComplement(
-            static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy))))) {
-      *validity = RANGE_VALID;
-    } else {  // Direction of wrap is inverse of result sign.
-      *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
-    }
-  } else {  // Unsigned is either valid or underflow.
-    *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW;
-  }
-  return static_cast<T>(uresult);
+  return (std::is_signed<T>::value)
+             ? static_cast<SignedDst>((uresult ^ ux) & (ux ^ uy)) >= 0
+             : x >= y;
 }
 
-// Integer multiplication is a bit complicated. In the fast case we just
-// we just promote to a twice wider type, and range check the result. In the
-// slow case we need to manually check that the result won't be truncated by
-// checking with division against the appropriate bound.
-template <typename T>
-typename std::enable_if<std::numeric_limits<T>::is_integer &&
-                            sizeof(T) * 2 <= sizeof(uintmax_t),
-                        T>::type
-CheckedMul(T x, T y, RangeConstraint* validity) {
-  typedef typename TwiceWiderInteger<T>::type IntermediateType;
-  IntermediateType tmp =
-      static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y);
-  *validity = DstRangeRelationToSrcRange<T>(tmp);
-  return static_cast<T>(tmp);
-}
+template <typename T, typename U, class Enable = void>
+struct CheckedSubOp {};
 
-template <typename T>
-typename std::enable_if<std::numeric_limits<T>::is_integer &&
-                            std::numeric_limits<T>::is_signed &&
-                            (sizeof(T) * 2 > sizeof(uintmax_t)),
-                        T>::type
-CheckedMul(T x, T y, RangeConstraint* validity) {
-  // If either side is zero then the result will be zero.
-  if (!x || !y) {
-    *validity = RANGE_VALID;
-    return static_cast<T>(0);
-  }
-  if (x > 0) {
-    if (y > 0) {
-      *validity =
-          x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW;
+template <typename T, typename U>
+struct CheckedSubOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = typename MaxExponentPromotion<T, U>::type;
+  template <typename V>
+  static bool Do(T x, U y, V* result) {
+#if USE_OVERFLOW_BUILTINS
+    return !__builtin_sub_overflow(x, y, result);
+#else
+    using Promotion = typename BigEnoughPromotion<T, U>::type;
+    Promotion presult;
+    // Fail if either operand is out of range for the promoted type.
+    // TODO(jschuh): This could be made to work for a broader range of values.
+    bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
+                    IsValueInRangeForNumericType<Promotion>(y);
+
+    if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
+      presult = static_cast<Promotion>(x) - static_cast<Promotion>(y);
     } else {
-      *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID
-                                                         : RANGE_UNDERFLOW;
+      is_valid &= CheckedSubImpl(static_cast<Promotion>(x),
+                                 static_cast<Promotion>(y), &presult);
     }
-  } else {
-    if (y > 0) {
-      *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID
-                                                         : RANGE_UNDERFLOW;
-    } else {
-      *validity =
-          y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW;
-    }
+    *result = static_cast<V>(presult);
+    return is_valid && IsValueInRangeForNumericType<V>(presult);
+#endif
   }
-  return static_cast<T>(*validity == RANGE_VALID ? x * y : 0);
-}
+};
 
 template <typename T>
-typename std::enable_if<std::numeric_limits<T>::is_integer &&
-                            !std::numeric_limits<T>::is_signed &&
-                            (sizeof(T) * 2 > sizeof(uintmax_t)),
-                        T>::type
-CheckedMul(T x, T y, RangeConstraint* validity) {
-  *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y)
-                  ? RANGE_VALID
-                  : RANGE_OVERFLOW;
-  return static_cast<T>(*validity == RANGE_VALID ? x * y : 0);
+bool CheckedMulImpl(T x, T y, T* result) {
+  static_assert(std::is_integral<T>::value, "Type must be integral");
+  // Since the value of x*y is potentially undefined if we have a signed type,
+  // we compute it using the unsigned type of the same size.
+  using UnsignedDst = typename std::make_unsigned<T>::type;
+  using SignedDst = typename std::make_signed<T>::type;
+  const UnsignedDst ux = SafeUnsignedAbs(x);
+  const UnsignedDst uy = SafeUnsignedAbs(y);
+  UnsignedDst uresult = static_cast<UnsignedDst>(ux * uy);
+  const bool is_negative =
+      std::is_signed<T>::value && static_cast<SignedDst>(x ^ y) < 0;
+  *result = is_negative ? 0 - uresult : uresult;
+  // We have a fast out for unsigned identity or zero on the second operand.
+  // After that it's an unsigned overflow check on the absolute value, with
+  // a +1 bound for a negative result.
+  return uy <= UnsignedDst(!std::is_signed<T>::value || is_negative) ||
+         ux <= (std::numeric_limits<T>::max() + UnsignedDst(is_negative)) / uy;
 }
 
+template <typename T, typename U, class Enable = void>
+struct CheckedMulOp {};
+
+template <typename T, typename U>
+struct CheckedMulOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = typename MaxExponentPromotion<T, U>::type;
+  template <typename V>
+  static bool Do(T x, U y, V* result) {
+#if USE_OVERFLOW_BUILTINS
+#if defined(__clang__)
+    // TODO(jschuh): Get the Clang runtime library issues sorted out so we can
+    // support full-width, mixed-sign multiply builtins.
+    // https://crbug.com/613003
+    static const bool kUseMaxInt =
+        // Narrower type than uintptr_t is always safe.
+        std::numeric_limits<__typeof__(x * y)>::digits <
+            std::numeric_limits<intptr_t>::digits ||
+        // Safe for intptr_t and uintptr_t if the sign matches.
+        (IntegerBitsPlusSign<__typeof__(x * y)>::value ==
+             IntegerBitsPlusSign<intptr_t>::value &&
+         std::is_signed<T>::value == std::is_signed<U>::value);
+#else
+    static const bool kUseMaxInt = true;
+#endif
+    if (kUseMaxInt)
+      return !__builtin_mul_overflow(x, y, result);
+#endif
+    using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
+    Promotion presult;
+    // Fail if either operand is out of range for the promoted type.
+    // TODO(jschuh): This could be made to work for a broader range of values.
+    bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
+                    IsValueInRangeForNumericType<Promotion>(y);
+
+    if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
+      presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
+    } else {
+      is_valid &= CheckedMulImpl(static_cast<Promotion>(x),
+                                 static_cast<Promotion>(y), &presult);
+    }
+    *result = static_cast<V>(presult);
+    return is_valid && IsValueInRangeForNumericType<V>(presult);
+  }
+};
+
+// Avoid poluting the namespace once we're done with the macro.
+#undef USE_OVERFLOW_BUILTINS
+
 // Division just requires a check for a zero denominator or an invalid negation
 // on signed min/-1.
 template <typename T>
-T CheckedDiv(T x,
-             T y,
-             RangeConstraint* validity,
-             typename std::enable_if<std::numeric_limits<T>::is_integer,
-                                     int>::type = 0) {
-  if (y == 0) {
-    *validity = RANGE_INVALID;
-    return static_cast<T>(0);
+bool CheckedDivImpl(T x, T y, T* result) {
+  static_assert(std::is_integral<T>::value, "Type must be integral");
+  if (y && (!std::is_signed<T>::value ||
+            x != std::numeric_limits<T>::lowest() || y != static_cast<T>(-1))) {
+    *result = x / y;
+    return true;
   }
-  if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() &&
-      y == static_cast<T>(-1)) {
-    *validity = RANGE_OVERFLOW;
-    return std::numeric_limits<T>::min();
+  return false;
+}
+
+template <typename T, typename U, class Enable = void>
+struct CheckedDivOp {};
+
+template <typename T, typename U>
+struct CheckedDivOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = typename MaxExponentPromotion<T, U>::type;
+  template <typename V>
+  static bool Do(T x, U y, V* result) {
+    using Promotion = typename BigEnoughPromotion<T, U>::type;
+    Promotion presult;
+    // Fail if either operand is out of range for the promoted type.
+    // TODO(jschuh): This could be made to work for a broader range of values.
+    bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
+                    IsValueInRangeForNumericType<Promotion>(y);
+    is_valid &= CheckedDivImpl(static_cast<Promotion>(x),
+                               static_cast<Promotion>(y), &presult);
+    *result = static_cast<V>(presult);
+    return is_valid && IsValueInRangeForNumericType<V>(presult);
   }
-
-  *validity = RANGE_VALID;
-  return static_cast<T>(x / y);
-}
+};
 
 template <typename T>
-typename std::enable_if<std::numeric_limits<T>::is_integer &&
-                            std::numeric_limits<T>::is_signed,
-                        T>::type
-CheckedMod(T x, T y, RangeConstraint* validity) {
-  *validity = y > 0 ? RANGE_VALID : RANGE_INVALID;
-  return static_cast<T>(*validity == RANGE_VALID ? x % y : 0);
-}
-
-template <typename T>
-typename std::enable_if<std::numeric_limits<T>::is_integer &&
-                            !std::numeric_limits<T>::is_signed,
-                        T>::type
-CheckedMod(T x, T y, RangeConstraint* validity) {
-  *validity = y != 0 ? RANGE_VALID : RANGE_INVALID;
-  return static_cast<T>(*validity == RANGE_VALID ? x % y : 0);
-}
-
-template <typename T>
-typename std::enable_if<std::numeric_limits<T>::is_integer &&
-                            std::numeric_limits<T>::is_signed,
-                        T>::type
-CheckedNeg(T value, RangeConstraint* validity) {
-  *validity =
-      value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
-  // The negation of signed min is min, so catch that one.
-  return static_cast<T>(*validity == RANGE_VALID ? -value : 0);
-}
-
-template <typename T>
-typename std::enable_if<std::numeric_limits<T>::is_integer &&
-                            !std::numeric_limits<T>::is_signed,
-                        T>::type
-CheckedNeg(T value, RangeConstraint* validity) {
-  // The only legal unsigned negation is zero.
-  *validity = value ? RANGE_UNDERFLOW : RANGE_VALID;
-  return static_cast<T>(
-      *validity == RANGE_VALID
-          ? -static_cast<typename SignedIntegerForSize<T>::type>(value)
-          : 0);
-}
-
-template <typename T>
-typename std::enable_if<std::numeric_limits<T>::is_integer &&
-                            std::numeric_limits<T>::is_signed,
-                        T>::type
-CheckedAbs(T value, RangeConstraint* validity) {
-  *validity =
-      value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
-  return static_cast<T>(*validity == RANGE_VALID ? std::abs(value) : 0);
-}
-
-template <typename T>
-typename std::enable_if<std::numeric_limits<T>::is_integer &&
-                            !std::numeric_limits<T>::is_signed,
-                        T>::type
-CheckedAbs(T value, RangeConstraint* validity) {
-  // T is unsigned, so |value| must already be positive.
-  *validity = RANGE_VALID;
-  return value;
-}
-
-template <typename T>
-typename std::enable_if<std::numeric_limits<T>::is_integer &&
-                            std::numeric_limits<T>::is_signed,
-                        typename UnsignedIntegerForSize<T>::type>::type
-CheckedUnsignedAbs(T value) {
-  typedef typename UnsignedIntegerForSize<T>::type UnsignedT;
-  return value == std::numeric_limits<T>::min()
-             ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1
-             : static_cast<UnsignedT>(std::abs(value));
-}
-
-template <typename T>
-typename std::enable_if<std::numeric_limits<T>::is_integer &&
-                            !std::numeric_limits<T>::is_signed,
-                        T>::type
-CheckedUnsignedAbs(T value) {
-  // T is unsigned, so |value| must already be positive.
-  return static_cast<T>(value);
-}
-
-// These are the floating point stubs that the compiler needs to see. Only the
-// negation operation is ever called.
-#define BASE_FLOAT_ARITHMETIC_STUBS(NAME)                             \
-  template <typename T>                                               \
-  typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \
-      Checked##NAME(T, T, RangeConstraint*) {                         \
-    NOTREACHED();                                                     \
-    return static_cast<T>(0);                                         \
+bool CheckedModImpl(T x, T y, T* result) {
+  static_assert(std::is_integral<T>::value, "Type must be integral");
+  if (y > 0) {
+    *result = static_cast<T>(x % y);
+    return true;
   }
-
-BASE_FLOAT_ARITHMETIC_STUBS(Add)
-BASE_FLOAT_ARITHMETIC_STUBS(Sub)
-BASE_FLOAT_ARITHMETIC_STUBS(Mul)
-BASE_FLOAT_ARITHMETIC_STUBS(Div)
-BASE_FLOAT_ARITHMETIC_STUBS(Mod)
-
-#undef BASE_FLOAT_ARITHMETIC_STUBS
-
-template <typename T>
-typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
-    T value,
-    RangeConstraint*) {
-  return static_cast<T>(-value);
+  return false;
 }
 
-template <typename T>
-typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
-    T value,
-    RangeConstraint*) {
-  return static_cast<T>(std::abs(value));
+template <typename T, typename U, class Enable = void>
+struct CheckedModOp {};
+
+template <typename T, typename U>
+struct CheckedModOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = typename MaxExponentPromotion<T, U>::type;
+  template <typename V>
+  static bool Do(T x, U y, V* result) {
+    using Promotion = typename BigEnoughPromotion<T, U>::type;
+    Promotion presult;
+    bool is_valid = CheckedModImpl(static_cast<Promotion>(x),
+                                   static_cast<Promotion>(y), &presult);
+    *result = static_cast<V>(presult);
+    return is_valid && IsValueInRangeForNumericType<V>(presult);
+  }
+};
+
+template <typename T, typename U, class Enable = void>
+struct CheckedLshOp {};
+
+// Left shift. Shifts less than 0 or greater than or equal to the number
+// of bits in the promoted type are undefined. Shifts of negative values
+// are undefined. Otherwise it is defined when the result fits.
+template <typename T, typename U>
+struct CheckedLshOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = T;
+  template <typename V>
+  static bool Do(T x, U shift, V* result) {
+    using ShiftType = typename std::make_unsigned<T>::type;
+    static const ShiftType kBitWidth = IntegerBitsPlusSign<T>::value;
+    const ShiftType real_shift = static_cast<ShiftType>(shift);
+    // Signed shift is not legal on negative values.
+    if (!IsValueNegative(x) && real_shift < kBitWidth) {
+      // Just use a multiplication because it's easy.
+      // TODO(jschuh): This could probably be made more efficient.
+      if (!std::is_signed<T>::value || real_shift != kBitWidth - 1)
+        return CheckedMulOp<T, T>::Do(x, static_cast<T>(1) << shift, result);
+      return !x;  // Special case zero for a full width signed shift.
+    }
+    return false;
+  }
+};
+
+template <typename T, typename U, class Enable = void>
+struct CheckedRshOp {};
+
+// Right shift. Shifts less than 0 or greater than or equal to the number
+// of bits in the promoted type are undefined. Otherwise, it is always defined,
+// but a right shift of a negative value is implementation-dependent.
+template <typename T, typename U>
+struct CheckedRshOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = T;
+  template <typename V = result_type>
+  static bool Do(T x, U shift, V* result) {
+    // Use the type conversion push negative values out of range.
+    using ShiftType = typename std::make_unsigned<T>::type;
+    if (static_cast<ShiftType>(shift) < IntegerBitsPlusSign<T>::value) {
+      T tmp = x >> shift;
+      *result = static_cast<V>(tmp);
+      return IsValueInRangeForNumericType<V>(tmp);
+    }
+    return false;
+  }
+};
+
+template <typename T, typename U, class Enable = void>
+struct CheckedAndOp {};
+
+// For simplicity we support only unsigned integer results.
+template <typename T, typename U>
+struct CheckedAndOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = typename std::make_unsigned<
+      typename MaxExponentPromotion<T, U>::type>::type;
+  template <typename V = result_type>
+  static bool Do(T x, U y, V* result) {
+    result_type tmp = static_cast<result_type>(x) & static_cast<result_type>(y);
+    *result = static_cast<V>(tmp);
+    return IsValueInRangeForNumericType<V>(tmp);
+  }
+};
+
+template <typename T, typename U, class Enable = void>
+struct CheckedOrOp {};
+
+// For simplicity we support only unsigned integers.
+template <typename T, typename U>
+struct CheckedOrOp<T,
+                   U,
+                   typename std::enable_if<std::is_integral<T>::value &&
+                                           std::is_integral<U>::value>::type> {
+  using result_type = typename std::make_unsigned<
+      typename MaxExponentPromotion<T, U>::type>::type;
+  template <typename V = result_type>
+  static bool Do(T x, U y, V* result) {
+    result_type tmp = static_cast<result_type>(x) | static_cast<result_type>(y);
+    *result = static_cast<V>(tmp);
+    return IsValueInRangeForNumericType<V>(tmp);
+  }
+};
+
+template <typename T, typename U, class Enable = void>
+struct CheckedXorOp {};
+
+// For simplicity we support only unsigned integers.
+template <typename T, typename U>
+struct CheckedXorOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = typename std::make_unsigned<
+      typename MaxExponentPromotion<T, U>::type>::type;
+  template <typename V = result_type>
+  static bool Do(T x, U y, V* result) {
+    result_type tmp = static_cast<result_type>(x) ^ static_cast<result_type>(y);
+    *result = static_cast<V>(tmp);
+    return IsValueInRangeForNumericType<V>(tmp);
+  }
+};
+
+// Max doesn't really need to be implemented this way because it can't fail,
+// but it makes the code much cleaner to use the MathOp wrappers.
+template <typename T, typename U, class Enable = void>
+struct CheckedMaxOp {};
+
+template <typename T, typename U>
+struct CheckedMaxOp<
+    T,
+    U,
+    typename std::enable_if<std::is_arithmetic<T>::value &&
+                            std::is_arithmetic<U>::value>::type> {
+  using result_type = typename MaxExponentPromotion<T, U>::type;
+  template <typename V = result_type>
+  static bool Do(T x, U y, V* result) {
+    *result = IsGreater<T, U>::Test(x, y) ? static_cast<result_type>(x)
+                                          : static_cast<result_type>(y);
+    return true;
+  }
+};
+
+// Min doesn't really need to be implemented this way because it can't fail,
+// but it makes the code much cleaner to use the MathOp wrappers.
+template <typename T, typename U, class Enable = void>
+struct CheckedMinOp {};
+
+template <typename T, typename U>
+struct CheckedMinOp<
+    T,
+    U,
+    typename std::enable_if<std::is_arithmetic<T>::value &&
+                            std::is_arithmetic<U>::value>::type> {
+  using result_type = typename LowestValuePromotion<T, U>::type;
+  template <typename V = result_type>
+  static bool Do(T x, U y, V* result) {
+    *result = IsLess<T, U>::Test(x, y) ? static_cast<result_type>(x)
+                                       : static_cast<result_type>(y);
+    return true;
+  }
+};
+
+// This is just boilerplate that wraps the standard floating point arithmetic.
+// A macro isn't the nicest solution, but it beats rewriting these repeatedly.
+#define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP)                                    \
+  template <typename T, typename U>                                            \
+  struct Checked##NAME##Op<                                                    \
+      T, U, typename std::enable_if<std::is_floating_point<T>::value ||        \
+                                    std::is_floating_point<U>::value>::type> { \
+    using result_type = typename MaxExponentPromotion<T, U>::type;             \
+    template <typename V>                                                      \
+    static bool Do(T x, U y, V* result) {                                      \
+      using Promotion = typename MaxExponentPromotion<T, U>::type;             \
+      Promotion presult = x OP y;                                              \
+      *result = static_cast<V>(presult);                                       \
+      return IsValueInRangeForNumericType<V>(presult);                         \
+    }                                                                          \
+  };
+
+BASE_FLOAT_ARITHMETIC_OPS(Add, +)
+BASE_FLOAT_ARITHMETIC_OPS(Sub, -)
+BASE_FLOAT_ARITHMETIC_OPS(Mul, *)
+BASE_FLOAT_ARITHMETIC_OPS(Div, /)
+
+#undef BASE_FLOAT_ARITHMETIC_OPS
+
+// Wrap the unary operations to allow SFINAE when instantiating integrals versus
+// floating points. These don't perform any overflow checking. Rather, they
+// exhibit well-defined overflow semantics and rely on the caller to detect
+// if an overflow occured.
+
+template <typename T,
+          typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+constexpr T NegateWrapper(T value) {
+  using UnsignedT = typename std::make_unsigned<T>::type;
+  // This will compile to a NEG on Intel, and is normal negation on ARM.
+  return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
+}
+
+template <
+    typename T,
+    typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
+constexpr T NegateWrapper(T value) {
+  return -value;
+}
+
+template <typename T,
+          typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
+  return ~value;
+}
+
+template <typename T,
+          typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+constexpr T AbsWrapper(T value) {
+  return static_cast<T>(SafeUnsignedAbs(value));
+}
+
+template <
+    typename T,
+    typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
+constexpr T AbsWrapper(T value) {
+  return value < 0 ? -value : value;
 }
 
 // Floats carry around their validity state with them, but integers do not. So,
@@ -388,10 +518,10 @@
 template <typename NumericType>
 struct GetNumericRepresentation {
   static const NumericRepresentation value =
-      std::numeric_limits<NumericType>::is_integer
+      std::is_integral<NumericType>::value
           ? NUMERIC_INTEGER
-          : (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING
-                                                         : NUMERIC_UNKNOWN);
+          : (std::is_floating_point<NumericType>::value ? NUMERIC_FLOATING
+                                                        : NUMERIC_UNKNOWN);
 };
 
 template <typename T, NumericRepresentation type =
@@ -402,41 +532,48 @@
 template <typename T>
 class CheckedNumericState<T, NUMERIC_INTEGER> {
  private:
+  // is_valid_ precedes value_ because member intializers in the constructors
+  // are evaluated in field order, and is_valid_ must be read when initializing
+  // value_.
+  bool is_valid_;
   T value_;
-  RangeConstraint validity_ : CHAR_BIT;  // Actually requires only two bits.
+
+  // Ensures that a type conversion does not trigger undefined behavior.
+  template <typename Src>
+  static constexpr T WellDefinedConversionOrZero(const Src value,
+                                                 const bool is_valid) {
+    using SrcType = typename internal::UnderlyingType<Src>::type;
+    return (std::is_integral<SrcType>::value || is_valid)
+               ? static_cast<T>(value)
+               : static_cast<T>(0);
+  }
 
  public:
   template <typename Src, NumericRepresentation type>
   friend class CheckedNumericState;
 
-  CheckedNumericState() : value_(0), validity_(RANGE_VALID) {}
+  constexpr CheckedNumericState() : is_valid_(true), value_(0) {}
 
   template <typename Src>
-  CheckedNumericState(Src value, RangeConstraint validity)
-      : value_(static_cast<T>(value)),
-        validity_(GetRangeConstraint(validity |
-                                     DstRangeRelationToSrcRange<T>(value))) {
-    static_assert(std::numeric_limits<Src>::is_specialized,
-                  "Argument must be numeric.");
+  constexpr CheckedNumericState(Src value, bool is_valid)
+      : is_valid_(is_valid && IsValueInRangeForNumericType<T>(value)),
+        value_(WellDefinedConversionOrZero(value, is_valid_)) {
+    static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
   }
 
   // Copy constructor.
   template <typename Src>
-  CheckedNumericState(const CheckedNumericState<Src>& rhs)
-      : value_(static_cast<T>(rhs.value())),
-        validity_(GetRangeConstraint(
-            rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {}
+  constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
+      : is_valid_(rhs.IsValid()),
+        value_(WellDefinedConversionOrZero(rhs.value(), is_valid_)) {}
 
   template <typename Src>
-  explicit CheckedNumericState(
-      Src value,
-      typename std::enable_if<std::numeric_limits<Src>::is_specialized,
-                              int>::type = 0)
-      : value_(static_cast<T>(value)),
-        validity_(DstRangeRelationToSrcRange<T>(value)) {}
+  constexpr explicit CheckedNumericState(Src value)
+      : is_valid_(IsValueInRangeForNumericType<T>(value)),
+        value_(WellDefinedConversionOrZero(value, is_valid_)) {}
 
-  RangeConstraint validity() const { return validity_; }
-  T value() const { return value_; }
+  constexpr bool is_valid() const { return is_valid_; }
+  constexpr T value() const { return value_; }
 };
 
 // Floating points maintain their own validity, but need translation wrappers.
@@ -445,94 +582,58 @@
  private:
   T value_;
 
+  // Ensures that a type conversion does not trigger undefined behavior.
+  template <typename Src>
+  static constexpr T WellDefinedConversionOrNaN(const Src value,
+                                                const bool is_valid) {
+    using SrcType = typename internal::UnderlyingType<Src>::type;
+    return (StaticDstRangeRelationToSrcRange<T, SrcType>::value ==
+                NUMERIC_RANGE_CONTAINED ||
+            is_valid)
+               ? static_cast<T>(value)
+               : std::numeric_limits<T>::quiet_NaN();
+  }
+
  public:
   template <typename Src, NumericRepresentation type>
   friend class CheckedNumericState;
 
-  CheckedNumericState() : value_(0.0) {}
+  constexpr CheckedNumericState() : value_(0.0) {}
 
   template <typename Src>
-  CheckedNumericState(
-      Src value,
-      RangeConstraint validity,
-      typename std::enable_if<std::numeric_limits<Src>::is_integer, int>::type =
-          0) {
-    switch (DstRangeRelationToSrcRange<T>(value)) {
-      case RANGE_VALID:
-        value_ = static_cast<T>(value);
-        break;
-
-      case RANGE_UNDERFLOW:
-        value_ = -std::numeric_limits<T>::infinity();
-        break;
-
-      case RANGE_OVERFLOW:
-        value_ = std::numeric_limits<T>::infinity();
-        break;
-
-      case RANGE_INVALID:
-        value_ = std::numeric_limits<T>::quiet_NaN();
-        break;
-
-      default:
-        NOTREACHED();
-    }
-  }
+  constexpr CheckedNumericState(Src value, bool is_valid)
+      : value_(WellDefinedConversionOrNaN(value, is_valid)) {}
 
   template <typename Src>
-  explicit CheckedNumericState(
-      Src value,
-      typename std::enable_if<std::numeric_limits<Src>::is_specialized,
-                              int>::type = 0)
-      : value_(static_cast<T>(value)) {}
+  constexpr explicit CheckedNumericState(Src value)
+      : value_(WellDefinedConversionOrNaN(
+            value,
+            IsValueInRangeForNumericType<T>(value))) {}
 
   // Copy constructor.
   template <typename Src>
-  CheckedNumericState(const CheckedNumericState<Src>& rhs)
-      : value_(static_cast<T>(rhs.value())) {}
+  constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
+      : value_(WellDefinedConversionOrNaN(
+            rhs.value(),
+            rhs.is_valid() && IsValueInRangeForNumericType<T>(rhs.value()))) {}
 
-  RangeConstraint validity() const {
-    return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(),
-                              value_ >= -std::numeric_limits<T>::max());
+  constexpr bool is_valid() const {
+    // Written this way because std::isfinite is not reliably constexpr.
+    // TODO(jschuh): Fix this if the libraries ever get fixed.
+    return value_ <= std::numeric_limits<T>::max() &&
+           value_ >= std::numeric_limits<T>::lowest();
   }
-  T value() const { return value_; }
+  constexpr T value() const { return value_; }
 };
 
-// For integers less than 128-bit and floats 32-bit or larger, we have the type
-// with the larger maximum exponent take precedence.
-enum ArithmeticPromotionCategory { LEFT_PROMOTION, RIGHT_PROMOTION };
-
-template <typename Lhs,
-          typename Rhs = Lhs,
-          ArithmeticPromotionCategory Promotion =
-              (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
-                  ? LEFT_PROMOTION
-                  : RIGHT_PROMOTION>
-struct ArithmeticPromotion;
-
-template <typename Lhs, typename Rhs>
-struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> {
-  typedef Lhs type;
-};
-
-template <typename Lhs, typename Rhs>
-struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
-  typedef Rhs type;
-};
-
-// We can statically check if operations on the provided types can wrap, so we
-// can skip the checked operations if they're not needed. So, for an integer we
-// care if the destination type preserves the sign and is twice the width of
-// the source.
-template <typename T, typename Lhs, typename Rhs>
-struct IsIntegerArithmeticSafe {
-  static const bool value = !std::numeric_limits<T>::is_iec559 &&
-                            StaticDstRangeRelationToSrcRange<T, Lhs>::value ==
-                                NUMERIC_RANGE_CONTAINED &&
-                            sizeof(T) >= (2 * sizeof(Lhs)) &&
-                            StaticDstRangeRelationToSrcRange<T, Rhs>::value !=
-                                NUMERIC_RANGE_CONTAINED &&
-                            sizeof(T) >= (2 * sizeof(Rhs));
+template <template <typename, typename, typename> class M,
+          typename L,
+          typename R>
+struct MathWrapper {
+  using math = M<typename UnderlyingType<L>::type,
+                 typename UnderlyingType<R>::type,
+                 void>;
+  using type = typename math::result_type;
 };
 
 }  // namespace internal
diff --git a/third_party/lcms2-2.6/0016-check-LUT-and-MPE.patch b/third_party/lcms2-2.6/0016-check-LUT-and-MPE.patch
new file mode 100644
index 0000000..bfa84e2
--- /dev/null
+++ b/third_party/lcms2-2.6/0016-check-LUT-and-MPE.patch
@@ -0,0 +1,170 @@
+diff --git a/third_party/lcms2-2.6/src/cmslut.c b/third_party/lcms2-2.6/src/cmslut.c
+index 9b0eb4b54..19d43361f 100644
+--- a/third_party/lcms2-2.6/src/cmslut.c
++++ b/third_party/lcms2-2.6/src/cmslut.c
+@@ -1255,21 +1255,39 @@ cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe)
+ // ***********************************************************************************************************
+ 
+ // This function sets up the channel count
+-
+ static
+-void BlessLUT(cmsPipeline* lut)
++cmsBool BlessLUT(cmsPipeline* lut)
+ {
+     // We can set the input/ouput channels only if we have elements.
+     if (lut ->Elements != NULL) {
+ 
+-        cmsStage *First, *Last;
++        cmsStage* prev;
++        cmsStage* next;
++        cmsStage* First;
++        cmsStage* Last;
+ 
+         First  = cmsPipelineGetPtrToFirstStage(lut);
+         Last   = cmsPipelineGetPtrToLastStage(lut);
+ 
+-        if (First != NULL)lut ->InputChannels = First ->InputChannels;
+-        if (Last != NULL) lut ->OutputChannels = Last ->OutputChannels;
++        if (First == NULL || Last == NULL) return FALSE;
++
++        lut->InputChannels = First->InputChannels;
++        lut->OutputChannels = Last->OutputChannels;
++
++        // Check chain consistency
++        prev = First;
++        next = prev->Next;
++
++        while (next != NULL)
++        {
++            if (next->InputChannels != prev->OutputChannels)
++                return FALSE;
++
++            next = next->Next;
++            prev = prev->Next;
++        }
+     }
++    return TRUE;    
+ }
+ 
+ 
+@@ -1331,6 +1349,7 @@ cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number In
+ {
+        cmsPipeline* NewLUT;
+ 
++       // A value of zero in channels is allowed as placeholder
+        if (InputChannels >= cmsMAXCHANNELS ||
+            OutputChannels >= cmsMAXCHANNELS) return NULL;
+ 
+@@ -1348,7 +1367,11 @@ cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number In
+        NewLUT ->Data        = NewLUT;
+        NewLUT ->ContextID   = ContextID;
+ 
+-       BlessLUT(NewLUT);
++       if (!BlessLUT(NewLUT))
++       {
++           _cmsFree(ContextID, NewLUT);
++           return NULL;
++       }
+ 
+        return NewLUT;
+ }
+@@ -1454,7 +1477,12 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut)
+ 
+     NewLUT ->SaveAs8Bits    = lut ->SaveAs8Bits;
+ 
+-    BlessLUT(NewLUT);
++    if (!BlessLUT(NewLUT))
++    {
++        _cmsFree(lut->ContextID, NewLUT);
++        return NULL;
++    }
++
+     return NewLUT;
+ }
+ 
+@@ -1491,8 +1519,7 @@ int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage
+             return FALSE;
+     }
+ 
+-    BlessLUT(lut);
+-    return TRUE;
++    return BlessLUT(lut);    
+ }
+ 
+ // Unlink an element and return the pointer to it
+@@ -1547,6 +1574,7 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag
+     else
+         cmsStageFree(Unlinked);
+ 
++    // May fail, but we ignore it
+     BlessLUT(lut);
+ }
+ 
+@@ -1573,8 +1601,7 @@ cmsBool  CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2)
+                 return FALSE;
+     }
+ 
+-    BlessLUT(l1);
+-    return TRUE;
++    return BlessLUT(l1);    
+ }
+ 
+ 
+diff --git a/third_party/lcms2-2.6/src/cmstypes.c b/third_party/lcms2-2.6/src/cmstypes.c
+index e5ed06c33..0256e247b 100644
+--- a/third_party/lcms2-2.6/src/cmstypes.c
++++ b/third_party/lcms2-2.6/src/cmstypes.c
+@@ -1755,8 +1755,8 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms
+     if (!_cmsReadUInt8Number(io, NULL)) goto Error;
+ 
+     // Do some checking
+-    if (InputChannels > cmsMAXCHANNELS)  goto Error;
+-    if (OutputChannels > cmsMAXCHANNELS) goto Error;
++    if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS)  goto Error;
++    if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error;
+ 
+    // Allocates an empty Pipeline
+     NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
+@@ -2048,8 +2048,8 @@ void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm
+     if (!_cmsReadUInt8Number(io, NULL)) return NULL;
+ 
+     // Do some checking
+-    if (InputChannels > cmsMAXCHANNELS)  goto Error;
+-    if (OutputChannels > cmsMAXCHANNELS) goto Error;
++    if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS)  goto Error;
++    if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error;
+ 
+     // Allocates an empty LUT
+     NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
+@@ -2486,7 +2486,10 @@ void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c
+     if (!_cmsReadUInt32Number(io, &offsetC)) return NULL;
+     if (!_cmsReadUInt32Number(io, &offsetA)) return NULL;
+ 
+-   // Allocates an empty LUT
++    if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL;
++    if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL;
++
++    // Allocates an empty LUT
+     NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan);
+     if (NewLUT == NULL) return NULL;
+ 
+@@ -2794,6 +2797,9 @@ void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c
+     if (!_cmsReadUInt8Number(io, &inputChan)) return NULL;
+     if (!_cmsReadUInt8Number(io, &outputChan)) return NULL;
+ 
++    if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL;
++    if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL;
++
+     // Padding
+     if (!_cmsReadUInt16Number(io, NULL)) return NULL;
+ 
+@@ -4443,6 +4449,9 @@ void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU
+     if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
+     if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
+ 
++    if (InputChans == 0 || InputChans >= cmsMAXCHANNELS) return NULL;
++    if (OutputChans == 0 || OutputChans >= cmsMAXCHANNELS) return NULL;
++
+     // Allocates an empty LUT
+     NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans);
+     if (NewLUT == NULL) return NULL;
diff --git a/third_party/lcms2-2.6/0017-upstream-integer-overflow-MPEmatrix_Read.patch b/third_party/lcms2-2.6/0017-upstream-integer-overflow-MPEmatrix_Read.patch
new file mode 100644
index 0000000..47df7a8
--- /dev/null
+++ b/third_party/lcms2-2.6/0017-upstream-integer-overflow-MPEmatrix_Read.patch
@@ -0,0 +1,85 @@
+diff --git a/third_party/lcms2-2.6/src/cmscgats.c b/third_party/lcms2-2.6/src/cmscgats.c
+index 5720c66a7..cce4cedba 100644
+--- a/third_party/lcms2-2.6/src/cmscgats.c
++++ b/third_party/lcms2-2.6/src/cmscgats.c
+@@ -150,23 +150,24 @@ typedef struct {
+         SUBALLOCATOR   Allocator;             // String suballocator -- just to keep it fast
+ 
+         // Parser state machine
+-        SYMBOL         sy;                    // Current symbol
+-        int            ch;                    // Current character
++        SYMBOL             sy;                // Current symbol
++        int                ch;                // Current character
++
++        cmsInt32Number     inum;              // integer value
++        cmsFloat64Number   dnum;              // real value
+ 
+-        int            inum;                  // integer value
+-        cmsFloat64Number         dnum;                  // real value
+         char           id[MAXID];             // identifier
+         char           str[MAXSTR];           // string
+ 
+         // Allowed keywords & datasets. They have visibility on whole stream
+-        KEYVALUE*     ValidKeywords;
+-        KEYVALUE*     ValidSampleID;
++        KEYVALUE*      ValidKeywords;
++        KEYVALUE*      ValidSampleID;
+ 
+         char*          Source;                // Points to loc. being parsed
+-        int            lineno;                // line counter for error reporting
++        cmsInt32Number lineno;                // line counter for error reporting
+ 
+         FILECTX*       FileStack[MAXINCLUDE]; // Stack of files being parsed
+-        int            IncludeSP;             // Include Stack Pointer
++        cmsInt32Number IncludeSP;             // Include Stack Pointer
+ 
+         char*          MemoryBlock;           // The stream if holded in memory
+ 
+@@ -568,8 +569,8 @@ void ReadReal(cmsIT8* it8, int inum)
+     // Exponent, example 34.00E+20
+     if (toupper(it8->ch) == 'E') {
+ 
+-        int e;
+-        int sgn;
++        cmsInt32Number e;
++        cmsInt32Number sgn;
+ 
+         NextCh(it8); sgn = 1;
+ 
+@@ -587,7 +588,7 @@ void ReadReal(cmsIT8* it8, int inum)
+             e = 0;
+             while (isdigit(it8->ch)) {
+ 
+-                if ((cmsFloat64Number) e * 10L < INT_MAX)
++                if ((cmsFloat64Number) e * 10L < (cmsFloat64Number) +2147483647.0)
+                     e = e * 10 + (it8->ch - '0');
+ 
+                 NextCh(it8);
+@@ -777,7 +778,7 @@ void InSymbol(cmsIT8* it8)
+ 
+                 while (isdigit(it8->ch)) {
+ 
+-                    if ((long) it8->inum * 10L > (long) INT_MAX) {
++                    if ((cmsFloat64Number) it8->inum * 10L > (cmsFloat64Number) +2147483647.0) {
+                         ReadReal(it8, it8->inum);
+                         it8->sy = SDNUM;
+                         it8->dnum *= sign;
+diff --git a/third_party/lcms2-2.6/src/cmstypes.c b/third_party/lcms2-2.6/src/cmstypes.c
+index 0256e247b..75f1fae32 100644
+--- a/third_party/lcms2-2.6/src/cmstypes.c
++++ b/third_party/lcms2-2.6/src/cmstypes.c
+@@ -4199,9 +4199,13 @@ void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io
+     if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
+ 
+ 
++    // Input and output chans may be ANY (up to 0xffff), 
++    // but we choose to limit to 16 channels for now
++    if (InputChans >= cmsMAXCHANNELS) return NULL;
++    if (OutputChans >= cmsMAXCHANNELS) return NULL;
++
+     nElems = InputChans * OutputChans;
+ 
+-    // Input and output chans may be ANY (up to 0xffff)
+     Matrix = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, nElems, sizeof(cmsFloat64Number));
+     if (Matrix == NULL) return NULL;
+ 
diff --git a/third_party/lcms2-2.6/README.pdfium b/third_party/lcms2-2.6/README.pdfium
index c775609..6504298 100644
--- a/third_party/lcms2-2.6/README.pdfium
+++ b/third_party/lcms2-2.6/README.pdfium
@@ -27,4 +27,6 @@
 0014-avoid-fixed-inf.patch: Avoid fixed number LUT optimization on inf values.
 0015-sanitize-float-read.patch: Sanitize floating point read. Partially backport
     from upstream https://github.com/mm2/Little-CMS/commit/4011a6e3
+0016-check-LUT-and-MPE.patch: check LUT consistency and sanitize MPE profiles.
+0017-upstream-integer-overflow-MPEmatrix_Read.patch: fix some integer overflows.
 TODO(ochang): List other patches.
diff --git a/third_party/lcms2-2.6/src/cmscgats.c b/third_party/lcms2-2.6/src/cmscgats.c
index 5720c66..cce4ced 100644
--- a/third_party/lcms2-2.6/src/cmscgats.c
+++ b/third_party/lcms2-2.6/src/cmscgats.c
@@ -150,23 +150,24 @@
         SUBALLOCATOR   Allocator;             // String suballocator -- just to keep it fast
 
         // Parser state machine
-        SYMBOL         sy;                    // Current symbol
-        int            ch;                    // Current character
+        SYMBOL             sy;                // Current symbol
+        int                ch;                // Current character
 
-        int            inum;                  // integer value
-        cmsFloat64Number         dnum;                  // real value
+        cmsInt32Number     inum;              // integer value
+        cmsFloat64Number   dnum;              // real value
+
         char           id[MAXID];             // identifier
         char           str[MAXSTR];           // string
 
         // Allowed keywords & datasets. They have visibility on whole stream
-        KEYVALUE*     ValidKeywords;
-        KEYVALUE*     ValidSampleID;
+        KEYVALUE*      ValidKeywords;
+        KEYVALUE*      ValidSampleID;
 
         char*          Source;                // Points to loc. being parsed
-        int            lineno;                // line counter for error reporting
+        cmsInt32Number lineno;                // line counter for error reporting
 
         FILECTX*       FileStack[MAXINCLUDE]; // Stack of files being parsed
-        int            IncludeSP;             // Include Stack Pointer
+        cmsInt32Number IncludeSP;             // Include Stack Pointer
 
         char*          MemoryBlock;           // The stream if holded in memory
 
@@ -568,8 +569,8 @@
     // Exponent, example 34.00E+20
     if (toupper(it8->ch) == 'E') {
 
-        int e;
-        int sgn;
+        cmsInt32Number e;
+        cmsInt32Number sgn;
 
         NextCh(it8); sgn = 1;
 
@@ -587,7 +588,7 @@
             e = 0;
             while (isdigit(it8->ch)) {
 
-                if ((cmsFloat64Number) e * 10L < INT_MAX)
+                if ((cmsFloat64Number) e * 10L < (cmsFloat64Number) +2147483647.0)
                     e = e * 10 + (it8->ch - '0');
 
                 NextCh(it8);
@@ -777,7 +778,7 @@
 
                 while (isdigit(it8->ch)) {
 
-                    if ((long) it8->inum * 10L > (long) INT_MAX) {
+                    if ((cmsFloat64Number) it8->inum * 10L > (cmsFloat64Number) +2147483647.0) {
                         ReadReal(it8, it8->inum);
                         it8->sy = SDNUM;
                         it8->dnum *= sign;
diff --git a/third_party/lcms2-2.6/src/cmslut.c b/third_party/lcms2-2.6/src/cmslut.c
index 9b0eb4b..19d4336 100644
--- a/third_party/lcms2-2.6/src/cmslut.c
+++ b/third_party/lcms2-2.6/src/cmslut.c
@@ -1255,21 +1255,39 @@
 // ***********************************************************************************************************
 
 // This function sets up the channel count
-
 static
-void BlessLUT(cmsPipeline* lut)
+cmsBool BlessLUT(cmsPipeline* lut)
 {
     // We can set the input/ouput channels only if we have elements.
     if (lut ->Elements != NULL) {
 
-        cmsStage *First, *Last;
+        cmsStage* prev;
+        cmsStage* next;
+        cmsStage* First;
+        cmsStage* Last;
 
         First  = cmsPipelineGetPtrToFirstStage(lut);
         Last   = cmsPipelineGetPtrToLastStage(lut);
 
-        if (First != NULL)lut ->InputChannels = First ->InputChannels;
-        if (Last != NULL) lut ->OutputChannels = Last ->OutputChannels;
+        if (First == NULL || Last == NULL) return FALSE;
+
+        lut->InputChannels = First->InputChannels;
+        lut->OutputChannels = Last->OutputChannels;
+
+        // Check chain consistency
+        prev = First;
+        next = prev->Next;
+
+        while (next != NULL)
+        {
+            if (next->InputChannels != prev->OutputChannels)
+                return FALSE;
+
+            next = next->Next;
+            prev = prev->Next;
+        }
     }
+    return TRUE;    
 }
 
 
@@ -1331,6 +1349,7 @@
 {
        cmsPipeline* NewLUT;
 
+       // A value of zero in channels is allowed as placeholder
        if (InputChannels >= cmsMAXCHANNELS ||
            OutputChannels >= cmsMAXCHANNELS) return NULL;
 
@@ -1348,7 +1367,11 @@
        NewLUT ->Data        = NewLUT;
        NewLUT ->ContextID   = ContextID;
 
-       BlessLUT(NewLUT);
+       if (!BlessLUT(NewLUT))
+       {
+           _cmsFree(ContextID, NewLUT);
+           return NULL;
+       }
 
        return NewLUT;
 }
@@ -1454,7 +1477,12 @@
 
     NewLUT ->SaveAs8Bits    = lut ->SaveAs8Bits;
 
-    BlessLUT(NewLUT);
+    if (!BlessLUT(NewLUT))
+    {
+        _cmsFree(lut->ContextID, NewLUT);
+        return NULL;
+    }
+
     return NewLUT;
 }
 
@@ -1491,8 +1519,7 @@
             return FALSE;
     }
 
-    BlessLUT(lut);
-    return TRUE;
+    return BlessLUT(lut);    
 }
 
 // Unlink an element and return the pointer to it
@@ -1547,6 +1574,7 @@
     else
         cmsStageFree(Unlinked);
 
+    // May fail, but we ignore it
     BlessLUT(lut);
 }
 
@@ -1573,8 +1601,7 @@
                 return FALSE;
     }
 
-    BlessLUT(l1);
-    return TRUE;
+    return BlessLUT(l1);    
 }
 
 
diff --git a/third_party/lcms2-2.6/src/cmstypes.c b/third_party/lcms2-2.6/src/cmstypes.c
index e5ed06c..75f1fae 100644
--- a/third_party/lcms2-2.6/src/cmstypes.c
+++ b/third_party/lcms2-2.6/src/cmstypes.c
@@ -1755,8 +1755,8 @@
     if (!_cmsReadUInt8Number(io, NULL)) goto Error;
 
     // Do some checking
-    if (InputChannels > cmsMAXCHANNELS)  goto Error;
-    if (OutputChannels > cmsMAXCHANNELS) goto Error;
+    if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS)  goto Error;
+    if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error;
 
    // Allocates an empty Pipeline
     NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
@@ -2048,8 +2048,8 @@
     if (!_cmsReadUInt8Number(io, NULL)) return NULL;
 
     // Do some checking
-    if (InputChannels > cmsMAXCHANNELS)  goto Error;
-    if (OutputChannels > cmsMAXCHANNELS) goto Error;
+    if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS)  goto Error;
+    if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error;
 
     // Allocates an empty LUT
     NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
@@ -2486,7 +2486,10 @@
     if (!_cmsReadUInt32Number(io, &offsetC)) return NULL;
     if (!_cmsReadUInt32Number(io, &offsetA)) return NULL;
 
-   // Allocates an empty LUT
+    if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL;
+    if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL;
+
+    // Allocates an empty LUT
     NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan);
     if (NewLUT == NULL) return NULL;
 
@@ -2794,6 +2797,9 @@
     if (!_cmsReadUInt8Number(io, &inputChan)) return NULL;
     if (!_cmsReadUInt8Number(io, &outputChan)) return NULL;
 
+    if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL;
+    if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL;
+
     // Padding
     if (!_cmsReadUInt16Number(io, NULL)) return NULL;
 
@@ -4193,9 +4199,13 @@
     if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
 
 
+    // Input and output chans may be ANY (up to 0xffff), 
+    // but we choose to limit to 16 channels for now
+    if (InputChans >= cmsMAXCHANNELS) return NULL;
+    if (OutputChans >= cmsMAXCHANNELS) return NULL;
+
     nElems = InputChans * OutputChans;
 
-    // Input and output chans may be ANY (up to 0xffff)
     Matrix = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, nElems, sizeof(cmsFloat64Number));
     if (Matrix == NULL) return NULL;
 
@@ -4443,6 +4453,9 @@
     if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
     if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
 
+    if (InputChans == 0 || InputChans >= cmsMAXCHANNELS) return NULL;
+    if (OutputChans == 0 || OutputChans >= cmsMAXCHANNELS) return NULL;
+
     // Allocates an empty LUT
     NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans);
     if (NewLUT == NULL) return NULL;
diff --git a/third_party/libopenjpeg20/0025-opj_j2k_add_mct_null_data.patch b/third_party/libopenjpeg20/0025-opj_j2k_add_mct_null_data.patch
new file mode 100644
index 0000000..4a371e5
--- /dev/null
+++ b/third_party/libopenjpeg20/0025-opj_j2k_add_mct_null_data.patch
@@ -0,0 +1,22 @@
+diff --git a/third_party/libopenjpeg20/j2k.c b/third_party/libopenjpeg20/j2k.c
+index 5de89cf0e..400ca8098 100644
+--- a/third_party/libopenjpeg20/j2k.c
++++ b/third_party/libopenjpeg20/j2k.c
+@@ -5715,7 +5715,7 @@ static OPJ_BOOL opj_j2k_add_mct(opj_tcp_t * p_tcp, opj_image_t * p_image, OPJ_UI
+ 
+         if (l_deco_array) {
+                 l_data_size = MCT_ELEMENT_SIZE[l_deco_array->m_element_type] * p_image->numcomps * p_image->numcomps;
+-                if (l_deco_array->m_data_size != l_data_size) {
++                if (l_deco_array->m_data_size != l_data_size || ! l_deco_array->m_data) {
+                         return OPJ_FALSE;
+                 }
+ 
+@@ -5734,7 +5734,7 @@ static OPJ_BOOL opj_j2k_add_mct(opj_tcp_t * p_tcp, opj_image_t * p_image, OPJ_UI
+ 
+         if (l_offset_array) {
+                 l_data_size = MCT_ELEMENT_SIZE[l_offset_array->m_element_type] * p_image->numcomps;
+-                if (l_offset_array->m_data_size != l_data_size) {
++                if (l_offset_array->m_data_size != l_data_size || ! l_offset_array->m_data) {
+                         return OPJ_FALSE;
+                 }
+ 
diff --git a/third_party/libopenjpeg20/0026-use_opj_uint_ceildiv.patch b/third_party/libopenjpeg20/0026-use_opj_uint_ceildiv.patch
new file mode 100644
index 0000000..a196a44
--- /dev/null
+++ b/third_party/libopenjpeg20/0026-use_opj_uint_ceildiv.patch
@@ -0,0 +1,70 @@
+diff --git a/third_party/libopenjpeg20/j2k.c b/third_party/libopenjpeg20/j2k.c
+index 400ca8098..e77edd22b 100644
+--- a/third_party/libopenjpeg20/j2k.c
++++ b/third_party/libopenjpeg20/j2k.c
+@@ -2155,8 +2155,8 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
+         }
+ 
+         /* Compute the number of tiles */
+-        l_cp->tw = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(l_image->x1 - l_cp->tx0), (OPJ_INT32)l_cp->tdx);
+-        l_cp->th = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(l_image->y1 - l_cp->ty0), (OPJ_INT32)l_cp->tdy);
++        l_cp->tw = opj_uint_ceildiv(l_image->x1 - l_cp->tx0, l_cp->tdx);
++        l_cp->th = opj_uint_ceildiv(l_image->y1 - l_cp->ty0, l_cp->tdy);
+ 
+         /* Check that the number of tiles is valid */
+         if (l_cp->tw == 0 || l_cp->th == 0 || l_cp->tw > 65535 / l_cp->th) {
+@@ -2171,8 +2171,8 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
+         if (p_j2k->m_specific_param.m_decoder.m_discard_tiles) {
+                 p_j2k->m_specific_param.m_decoder.m_start_tile_x = (p_j2k->m_specific_param.m_decoder.m_start_tile_x - l_cp->tx0) / l_cp->tdx;
+                 p_j2k->m_specific_param.m_decoder.m_start_tile_y = (p_j2k->m_specific_param.m_decoder.m_start_tile_y - l_cp->ty0) / l_cp->tdy;
+-                p_j2k->m_specific_param.m_decoder.m_end_tile_x = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(p_j2k->m_specific_param.m_decoder.m_end_tile_x - l_cp->tx0), (OPJ_INT32)l_cp->tdx);
+-                p_j2k->m_specific_param.m_decoder.m_end_tile_y = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(p_j2k->m_specific_param.m_decoder.m_end_tile_y - l_cp->ty0), (OPJ_INT32)l_cp->tdy);
++                p_j2k->m_specific_param.m_decoder.m_end_tile_x = opj_uint_ceildiv(p_j2k->m_specific_param.m_decoder.m_end_tile_x - l_cp->tx0, l_cp->tdx);
++                p_j2k->m_specific_param.m_decoder.m_end_tile_y = opj_uint_ceildiv(p_j2k->m_specific_param.m_decoder.m_end_tile_y - l_cp->ty0, l_cp->tdy);
+         }
+         else {
+                 p_j2k->m_specific_param.m_decoder.m_start_tile_x = 0;
+@@ -6354,8 +6354,8 @@ OPJ_BOOL opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
+         */
+ 
+         if (parameters->tile_size_on) {
+-                cp->tw = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(image->x1 - cp->tx0), (OPJ_INT32)cp->tdx);
+-                cp->th = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(image->y1 - cp->ty0), (OPJ_INT32)cp->tdy);
++                cp->tw = opj_uint_ceildiv(image->x1 - cp->tx0, cp->tdx);
++                cp->th = opj_uint_ceildiv(image->y1 - cp->ty0, cp->tdy);
+         } else {
+                 cp->tdx = image->x1 - cp->tx0;
+                 cp->tdy = image->y1 - cp->ty0;
+@@ -8529,8 +8529,8 @@ OPJ_BOOL opj_j2k_set_decode_area(       opj_j2k_t *p_j2k,
+         {
+                 OPJ_INT32 l_h,l_w;
+ 
+-                l_img_comp->x0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->x0, (OPJ_INT32)l_img_comp->dx);
+-                l_img_comp->y0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->y0, (OPJ_INT32)l_img_comp->dy);
++                l_img_comp->x0 = opj_uint_ceildiv(p_image->x0, l_img_comp->dx);
++                l_img_comp->y0 = opj_uint_ceildiv(p_image->y0, l_img_comp->dy);
+                 l_comp_x1 = opj_int_ceildiv((OPJ_INT32)p_image->x1, (OPJ_INT32)l_img_comp->dx);
+                 l_comp_y1 = opj_int_ceildiv((OPJ_INT32)p_image->y1, (OPJ_INT32)l_img_comp->dy);
+ 
+@@ -9887,8 +9887,8 @@ OPJ_BOOL opj_j2k_get_tile(      opj_j2k_t *p_j2k,
+ 
+                 l_img_comp->factor = p_j2k->m_private_image->comps[compno].factor;
+ 
+-                l_img_comp->x0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->x0, (OPJ_INT32)l_img_comp->dx);
+-                l_img_comp->y0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->y0, (OPJ_INT32)l_img_comp->dy);
++                l_img_comp->x0 = opj_uint_ceildiv(p_image->x0, l_img_comp->dx);
++                l_img_comp->y0 = opj_uint_ceildiv(p_image->y0, l_img_comp->dy);
+                 l_comp_x1 = opj_int_ceildiv((OPJ_INT32)p_image->x1, (OPJ_INT32)l_img_comp->dx);
+                 l_comp_y1 = opj_int_ceildiv((OPJ_INT32)p_image->y1, (OPJ_INT32)l_img_comp->dy);
+ 
+@@ -10169,8 +10169,8 @@ static void opj_get_tile_dimensions(opj_image_t * l_image,
+ 
+        *l_width  = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0);
+        *l_height = (OPJ_UINT32)(l_tilec->y1 - l_tilec->y0);
+-       *l_offset_x = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->x0, (OPJ_INT32)l_img_comp->dx);
+-       *l_offset_y = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->y0, (OPJ_INT32)l_img_comp->dy);
++       *l_offset_x = opj_uint_ceildiv(l_image->x0, l_img_comp->dx);
++       *l_offset_y = opj_uint_ceildiv(l_image->y0, l_img_comp->dy);
+        *l_image_width = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->x1 - (OPJ_INT32)l_image->x0, (OPJ_INT32)l_img_comp->dx);
+        *l_stride = *l_image_width - *l_width;
+        *l_tile_offset = ((OPJ_UINT32)l_tilec->x0 - *l_offset_x) + ((OPJ_UINT32)l_tilec->y0 - *l_offset_y) * *l_image_width;
diff --git a/third_party/libopenjpeg20/0027-undefined-shift-opj_t1_decode_cblk.patch b/third_party/libopenjpeg20/0027-undefined-shift-opj_t1_decode_cblk.patch
new file mode 100644
index 0000000..7ba877a
--- /dev/null
+++ b/third_party/libopenjpeg20/0027-undefined-shift-opj_t1_decode_cblk.patch
@@ -0,0 +1,13 @@
+diff --git a/third_party/libopenjpeg20/t1.c b/third_party/libopenjpeg20/t1.c
+index a119db1f7..1ad850c77 100644
+--- a/third_party/libopenjpeg20/t1.c
++++ b/third_party/libopenjpeg20/t1.c
+@@ -1411,7 +1411,7 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1,
+             }
+                }
+ 
+-               for (passno = 0; passno < seg->real_num_passes; ++passno) {
++               for (passno = 0; (passno < seg->real_num_passes) && (bpno_plus_one >= 1); ++passno) {
+             switch (passtype) {
+                 case 0:
+                     if (type == T1_TYPE_RAW) {
diff --git a/third_party/libopenjpeg20/0028-upstream-check-size-in-opj_j2k_read_siz.patch b/third_party/libopenjpeg20/0028-upstream-check-size-in-opj_j2k_read_siz.patch
new file mode 100644
index 0000000..22d5562
--- /dev/null
+++ b/third_party/libopenjpeg20/0028-upstream-check-size-in-opj_j2k_read_siz.patch
@@ -0,0 +1,22 @@
+diff --git a/third_party/libopenjpeg20/j2k.c b/third_party/libopenjpeg20/j2k.c
+index e77edd22b..cb5a28373 100644
+--- a/third_party/libopenjpeg20/j2k.c
++++ b/third_party/libopenjpeg20/j2k.c
+@@ -2117,10 +2117,16 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
+                 if( l_img_comp->dx < 1 || l_img_comp->dx > 255 ||
+                     l_img_comp->dy < 1 || l_img_comp->dy > 255 ) {
+                     opj_event_msg(p_manager, EVT_ERROR,
+-                                  "Invalid values for comp = %d : dx=%u dy=%u\n (should be between 1 and 255 according the JPEG2000 norm)",
++                                  "Invalid values for comp = %d : dx=%u dy=%u (should be between 1 and 255 according to the JPEG2000 norm)\n",
+                                   i, l_img_comp->dx, l_img_comp->dy);
+                     return OPJ_FALSE;
+                 }
++                if( l_img_comp->prec > 38) { /* TODO openjpeg won't handle more than ? */
++                    opj_event_msg(p_manager, EVT_ERROR,
++                                  "Invalid values for comp = %d : prec=%u (should be between 1 and 38 according to the JPEG2000 norm)\n",
++                                  i, l_img_comp->prec);
++                    return OPJ_FALSE;
++                }
+ 
+ #ifdef USE_JPWL
+                 if (l_cp->correct) {
diff --git a/third_party/libopenjpeg20/README.pdfium b/third_party/libopenjpeg20/README.pdfium
index 0f45337..6c2a3c7 100644
--- a/third_party/libopenjpeg20/README.pdfium
+++ b/third_party/libopenjpeg20/README.pdfium
@@ -34,4 +34,8 @@
 0022-jp2_apply_pclr_overflow.patch: Prevent integer overflow in opj_jp2_apply_pclr.
 0023-opj_j2k_read_mct_records.patch: Fix opj_j2k_read to prevent heap-use-after-free.
 0024-l_marker_size_check.patch: Return error before overflow in opj_j2k_read_header_procedure.
+0025-opj_j2k_add_mct_null_data.patch: Check m_data != null before trying to read from it.
+0026-use_opj_uint_ceildiv.patch: Remove (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)a, (OPJ_INT32) b).
+0027-undefined-shift-opj_t1_decode_cblk.patch: upstream fix for a ubsan bug.
+0028-upstream-check-size-in-opj_j2k_read_siz.patch: upstream patch in j2k.c.
 TODO(thestig): List all the other patches.
diff --git a/third_party/libopenjpeg20/j2k.c b/third_party/libopenjpeg20/j2k.c
index 5de89cf..cb5a283 100644
--- a/third_party/libopenjpeg20/j2k.c
+++ b/third_party/libopenjpeg20/j2k.c
@@ -2117,10 +2117,16 @@
                 if( l_img_comp->dx < 1 || l_img_comp->dx > 255 ||
                     l_img_comp->dy < 1 || l_img_comp->dy > 255 ) {
                     opj_event_msg(p_manager, EVT_ERROR,
-                                  "Invalid values for comp = %d : dx=%u dy=%u\n (should be between 1 and 255 according the JPEG2000 norm)",
+                                  "Invalid values for comp = %d : dx=%u dy=%u (should be between 1 and 255 according to the JPEG2000 norm)\n",
                                   i, l_img_comp->dx, l_img_comp->dy);
                     return OPJ_FALSE;
                 }
+                if( l_img_comp->prec > 38) { /* TODO openjpeg won't handle more than ? */
+                    opj_event_msg(p_manager, EVT_ERROR,
+                                  "Invalid values for comp = %d : prec=%u (should be between 1 and 38 according to the JPEG2000 norm)\n",
+                                  i, l_img_comp->prec);
+                    return OPJ_FALSE;
+                }
 
 #ifdef USE_JPWL
                 if (l_cp->correct) {
@@ -2155,8 +2161,8 @@
         }
 
         /* Compute the number of tiles */
-        l_cp->tw = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(l_image->x1 - l_cp->tx0), (OPJ_INT32)l_cp->tdx);
-        l_cp->th = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(l_image->y1 - l_cp->ty0), (OPJ_INT32)l_cp->tdy);
+        l_cp->tw = opj_uint_ceildiv(l_image->x1 - l_cp->tx0, l_cp->tdx);
+        l_cp->th = opj_uint_ceildiv(l_image->y1 - l_cp->ty0, l_cp->tdy);
 
         /* Check that the number of tiles is valid */
         if (l_cp->tw == 0 || l_cp->th == 0 || l_cp->tw > 65535 / l_cp->th) {
@@ -2171,8 +2177,8 @@
         if (p_j2k->m_specific_param.m_decoder.m_discard_tiles) {
                 p_j2k->m_specific_param.m_decoder.m_start_tile_x = (p_j2k->m_specific_param.m_decoder.m_start_tile_x - l_cp->tx0) / l_cp->tdx;
                 p_j2k->m_specific_param.m_decoder.m_start_tile_y = (p_j2k->m_specific_param.m_decoder.m_start_tile_y - l_cp->ty0) / l_cp->tdy;
-                p_j2k->m_specific_param.m_decoder.m_end_tile_x = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(p_j2k->m_specific_param.m_decoder.m_end_tile_x - l_cp->tx0), (OPJ_INT32)l_cp->tdx);
-                p_j2k->m_specific_param.m_decoder.m_end_tile_y = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(p_j2k->m_specific_param.m_decoder.m_end_tile_y - l_cp->ty0), (OPJ_INT32)l_cp->tdy);
+                p_j2k->m_specific_param.m_decoder.m_end_tile_x = opj_uint_ceildiv(p_j2k->m_specific_param.m_decoder.m_end_tile_x - l_cp->tx0, l_cp->tdx);
+                p_j2k->m_specific_param.m_decoder.m_end_tile_y = opj_uint_ceildiv(p_j2k->m_specific_param.m_decoder.m_end_tile_y - l_cp->ty0, l_cp->tdy);
         }
         else {
                 p_j2k->m_specific_param.m_decoder.m_start_tile_x = 0;
@@ -5715,7 +5721,7 @@
 
         if (l_deco_array) {
                 l_data_size = MCT_ELEMENT_SIZE[l_deco_array->m_element_type] * p_image->numcomps * p_image->numcomps;
-                if (l_deco_array->m_data_size != l_data_size) {
+                if (l_deco_array->m_data_size != l_data_size || ! l_deco_array->m_data) {
                         return OPJ_FALSE;
                 }
 
@@ -5734,7 +5740,7 @@
 
         if (l_offset_array) {
                 l_data_size = MCT_ELEMENT_SIZE[l_offset_array->m_element_type] * p_image->numcomps;
-                if (l_offset_array->m_data_size != l_data_size) {
+                if (l_offset_array->m_data_size != l_data_size || ! l_offset_array->m_data) {
                         return OPJ_FALSE;
                 }
 
@@ -6354,8 +6360,8 @@
         */
 
         if (parameters->tile_size_on) {
-                cp->tw = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(image->x1 - cp->tx0), (OPJ_INT32)cp->tdx);
-                cp->th = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(image->y1 - cp->ty0), (OPJ_INT32)cp->tdy);
+                cp->tw = opj_uint_ceildiv(image->x1 - cp->tx0, cp->tdx);
+                cp->th = opj_uint_ceildiv(image->y1 - cp->ty0, cp->tdy);
         } else {
                 cp->tdx = image->x1 - cp->tx0;
                 cp->tdy = image->y1 - cp->ty0;
@@ -8529,8 +8535,8 @@
         {
                 OPJ_INT32 l_h,l_w;
 
-                l_img_comp->x0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->x0, (OPJ_INT32)l_img_comp->dx);
-                l_img_comp->y0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->y0, (OPJ_INT32)l_img_comp->dy);
+                l_img_comp->x0 = opj_uint_ceildiv(p_image->x0, l_img_comp->dx);
+                l_img_comp->y0 = opj_uint_ceildiv(p_image->y0, l_img_comp->dy);
                 l_comp_x1 = opj_int_ceildiv((OPJ_INT32)p_image->x1, (OPJ_INT32)l_img_comp->dx);
                 l_comp_y1 = opj_int_ceildiv((OPJ_INT32)p_image->y1, (OPJ_INT32)l_img_comp->dy);
 
@@ -9887,8 +9893,8 @@
 
                 l_img_comp->factor = p_j2k->m_private_image->comps[compno].factor;
 
-                l_img_comp->x0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->x0, (OPJ_INT32)l_img_comp->dx);
-                l_img_comp->y0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->y0, (OPJ_INT32)l_img_comp->dy);
+                l_img_comp->x0 = opj_uint_ceildiv(p_image->x0, l_img_comp->dx);
+                l_img_comp->y0 = opj_uint_ceildiv(p_image->y0, l_img_comp->dy);
                 l_comp_x1 = opj_int_ceildiv((OPJ_INT32)p_image->x1, (OPJ_INT32)l_img_comp->dx);
                 l_comp_y1 = opj_int_ceildiv((OPJ_INT32)p_image->y1, (OPJ_INT32)l_img_comp->dy);
 
@@ -10169,8 +10175,8 @@
 
 	*l_width  = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0);
 	*l_height = (OPJ_UINT32)(l_tilec->y1 - l_tilec->y0);
-	*l_offset_x = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->x0, (OPJ_INT32)l_img_comp->dx);
-	*l_offset_y = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->y0, (OPJ_INT32)l_img_comp->dy);
+	*l_offset_x = opj_uint_ceildiv(l_image->x0, l_img_comp->dx);
+	*l_offset_y = opj_uint_ceildiv(l_image->y0, l_img_comp->dy);
 	*l_image_width = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->x1 - (OPJ_INT32)l_image->x0, (OPJ_INT32)l_img_comp->dx);
 	*l_stride = *l_image_width - *l_width;
 	*l_tile_offset = ((OPJ_UINT32)l_tilec->x0 - *l_offset_x) + ((OPJ_UINT32)l_tilec->y0 - *l_offset_y) * *l_image_width;
diff --git a/third_party/libopenjpeg20/t1.c b/third_party/libopenjpeg20/t1.c
index a119db1..1ad850c 100644
--- a/third_party/libopenjpeg20/t1.c
+++ b/third_party/libopenjpeg20/t1.c
@@ -1411,7 +1411,7 @@
             }
 		}
 
-		for (passno = 0; passno < seg->real_num_passes; ++passno) {
+		for (passno = 0; (passno < seg->real_num_passes) && (bpno_plus_one >= 1); ++passno) {
             switch (passtype) {
                 case 0:
                     if (type == T1_TYPE_RAW) {
diff --git a/third_party/libtiff/0017-safe_skews_in_gtTileContig.patch b/third_party/libtiff/0017-safe_skews_in_gtTileContig.patch
new file mode 100644
index 0000000..10c5077
--- /dev/null
+++ b/third_party/libtiff/0017-safe_skews_in_gtTileContig.patch
@@ -0,0 +1,88 @@
+diff --git a/third_party/libtiff/tif_getimage.c b/third_party/libtiff/tif_getimage.c
+index 2861cdd1e..5ed1b7a37 100644
+--- a/third_party/libtiff/tif_getimage.c
++++ b/third_party/libtiff/tif_getimage.c
+@@ -31,6 +31,7 @@
+  */
+ #include "tiffiop.h"
+ #include <stdio.h>
++#include <limits.h>
+ 
+ static int gtTileContig(TIFFRGBAImage*, uint32*, uint32, uint32);
+ static int gtTileSeparate(TIFFRGBAImage*, uint32*, uint32, uint32);
+@@ -612,6 +613,7 @@ gtTileContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
+     uint32 tw, th;
+     unsigned char* buf;
+     int32 fromskew, toskew;
++    int64 safeskew;
+     uint32 nrow;
+     int ret = 1, flip;
+     uint32 this_tw, tocol;
+@@ -631,19 +633,37 @@ gtTileContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
+     flip = setorientation(img);
+     if (flip & FLIP_VERTICALLY) {
+            y = h - 1;
+-           toskew = -(int32)(tw + w);
++           safeskew = 0;
++           safeskew -= tw;
++           safeskew -= w;
+     }
+     else {
+            y = 0;
+-           toskew = -(int32)(tw - w);
++           safeskew = 0;
++           safeskew -= tw;
++           safeskew +=w;
+     }
++    if(safeskew > INT_MAX || safeskew < INT_MIN){
++       _TIFFfree(buf);
++       TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", "Invalid skew");
++       return (0);
++    }
++    toskew = safeskew;
++
+      
+     /*
+      * Leftmost tile is clipped on left side if col_offset > 0.
+      */
+     leftmost_fromskew = img->col_offset % tw;
+     leftmost_tw = tw - leftmost_fromskew;
+-    leftmost_toskew = toskew + leftmost_fromskew;
++    safeskew = toskew;
++    safeskew += leftmost_fromskew;
++    if(safeskew > INT_MAX || safeskew < INT_MIN){
++       _TIFFfree(buf);
++       TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", "Invalid skew");
++       return (0);
++    }
++    leftmost_toskew = safeskew;
+     for (row = 0; row < h; row += nrow)
+     {
+         rowstoread = th - (row + img->row_offset) % th;
+@@ -668,9 +688,24 @@ gtTileContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
+                /*
+                 * Rightmost tile is clipped on right side.
+                 */
+-               fromskew = tw - (w - tocol);
++               safeskew = tw;
++               safeskew -= w;
++               safeskew += tocol;
++               if(safeskew > INT_MAX || safeskew < INT_MIN){
++                       _TIFFfree(buf);
++                       TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", "Invalid skew");
++                       return (0);
++               }
++               fromskew = safeskew;
+                this_tw = tw - fromskew;
+-               this_toskew = toskew + fromskew;
++               safeskew = toskew;
++               safeskew += fromskew;
++               if(safeskew > INT_MAX || safeskew < INT_MIN){
++                       _TIFFfree(buf);
++                       TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", "Invalid skew");
++                       return (0);
++               }
++               this_toskew = safeskew;
+            }
+            (*put)(img, raster+y*w+tocol, tocol, y, this_tw, nrow, fromskew, this_toskew, buf + pos);
+            tocol += this_tw;
diff --git a/third_party/libtiff/0018-fix-leak-in-PredictorSetupDecode.patch b/third_party/libtiff/0018-fix-leak-in-PredictorSetupDecode.patch
new file mode 100644
index 0000000..a18df77
--- /dev/null
+++ b/third_party/libtiff/0018-fix-leak-in-PredictorSetupDecode.patch
@@ -0,0 +1,39 @@
+diff --git a/third_party/libtiff/tif_pixarlog.c b/third_party/libtiff/tif_pixarlog.c
+index 80006d5b1..29535d31e 100644
+--- a/third_party/libtiff/tif_pixarlog.c
++++ b/third_party/libtiff/tif_pixarlog.c
+@@ -697,9 +697,6 @@ PixarLogSetupDecode(TIFF* tif)
+        if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN)
+                sp->user_datafmt = PixarLogGuessDataFmt(td);
+        if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) {
+-               _TIFFfree(sp->tbuf);
+-               sp->tbuf = NULL;
+-               sp->tbuf_size = 0;
+                TIFFErrorExt(tif->tif_clientdata, module,
+                        "PixarLog compression can't handle bits depth/data format combination (depth: %d)", 
+                        td->td_bitspersample);
+@@ -707,9 +704,6 @@ PixarLogSetupDecode(TIFF* tif)
+        }
+ 
+        if (inflateInit(&sp->stream) != Z_OK) {
+-               _TIFFfree(sp->tbuf);
+-               sp->tbuf = NULL;
+-               sp->tbuf_size = 0;
+                TIFFErrorExt(tif->tif_clientdata, module, "%s", sp->stream.msg);
+                return (0);
+        } else {
+diff --git a/third_party/libtiff/tif_predict.c b/third_party/libtiff/tif_predict.c
+index 1388dde59..8975672ae 100644
+--- a/third_party/libtiff/tif_predict.c
++++ b/third_party/libtiff/tif_predict.c
+@@ -109,7 +109,10 @@ PredictorSetupDecode(TIFF* tif)
+        TIFFDirectory* td = &tif->tif_dir;
+ 
+        if (!(*sp->setupdecode)(tif) || !PredictorSetup(tif))
++       {
++               (*tif->tif_cleanup)(tif);
+                return 0;
++       }
+ 
+        if (sp->predictor == 2) {
+                switch (td->td_bitspersample) {
diff --git a/third_party/libtiff/0019-fix-invalid-reads-TIFFFetchNormalTag.patch b/third_party/libtiff/0019-fix-invalid-reads-TIFFFetchNormalTag.patch
new file mode 100644
index 0000000..9ebb7ef
--- /dev/null
+++ b/third_party/libtiff/0019-fix-invalid-reads-TIFFFetchNormalTag.patch
@@ -0,0 +1,28 @@
+diff --git a/third_party/libtiff/tif_dirread.c b/third_party/libtiff/tif_dirread.c
+index bc4102184..0e3f8ccd4 100644
+--- a/third_party/libtiff/tif_dirread.c
++++ b/third_party/libtiff/tif_dirread.c
+@@ -4983,6 +4983,11 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
+                                        if (err==TIFFReadDirEntryErrOk)
+                                        {
+                                                int m;
++                                               if( dp->tdir_count > 0 && data[dp->tdir_count-1] != '\0' )
++                        {
++                            TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte. Forcing it to be null",fip->field_name);
++                            data[dp->tdir_count-1] = '\0';
++                        }
+                                                m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data);
+                                                if (data!=0)
+                                                        _TIFFfree(data);
+@@ -5155,6 +5160,11 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
+                                if (err==TIFFReadDirEntryErrOk)
+                                {
+                                        int m;
++                                       if( dp->tdir_count > 0 && data[dp->tdir_count-1] != '\0' )
++                    {
++                        TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte. Forcing it to be null",fip->field_name);
++                        data[dp->tdir_count-1] = '\0';
++                    }
+                                        m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+                                        if (data!=0)
+                                                _TIFFfree(data);
diff --git a/third_party/libtiff/0020-unreasonable-td-bitspersample.patch b/third_party/libtiff/0020-unreasonable-td-bitspersample.patch
new file mode 100644
index 0000000..1ad5e34
--- /dev/null
+++ b/third_party/libtiff/0020-unreasonable-td-bitspersample.patch
@@ -0,0 +1,22 @@
+diff --git a/third_party/libtiff/tif_dirread.c b/third_party/libtiff/tif_dirread.c
+index 0e3f8ccd4..e0403aef3 100644
+--- a/third_party/libtiff/tif_dirread.c
++++ b/third_party/libtiff/tif_dirread.c
+@@ -3754,6 +3754,17 @@ TIFFReadDirectory(TIFF* tif)
+                                        fip ? fip->field_name : "unknown tagname");
+                         continue;
+                     }
++                                       /* ColorMap or TransferFunction for high bit */
++                                       /* depths do not make much sense and could be */
++                                       /* used as a denial of service vector */
++                                       if (tif->tif_dir.td_bitspersample > 24)
++                                       {
++                                           TIFFWarningExt(tif->tif_clientdata,module,
++                                               "Ignoring %s because BitsPerSample=%d>24",
++                                               fip ? fip->field_name : "unknown tagname",
++                                               tif->tif_dir.td_bitspersample);
++                                           continue;
++                                       }
+                                        countpersample=(1L<<tif->tif_dir.td_bitspersample);
+                                        if ((dp->tdir_tag==TIFFTAG_TRANSFERFUNCTION)&&(dp->tdir_count==(uint64)countpersample))
+                                        {
diff --git a/third_party/libtiff/0021-fix-leaks-ojpegreaderinfosectables.patch b/third_party/libtiff/0021-fix-leaks-ojpegreaderinfosectables.patch
new file mode 100644
index 0000000..e3b4bd8
--- /dev/null
+++ b/third_party/libtiff/0021-fix-leaks-ojpegreaderinfosectables.patch
@@ -0,0 +1,31 @@
+diff --git a/third_party/libtiff/tif_ojpeg.c b/third_party/libtiff/tif_ojpeg.c
+index f69b00148..276d562df 100644
+--- a/third_party/libtiff/tif_ojpeg.c
++++ b/third_party/libtiff/tif_ojpeg.c
+@@ -1794,6 +1794,8 @@ OJPEGReadHeaderInfoSecTablesQTable(TIFF* tif)
+                                _TIFFfree(ob);
+                                return(0);
+                        }
++                       if (sp->qtable[m]!=0)
++                               _TIFFfree(sp->qtable[m]);
+                        sp->qtable[m]=ob;
+                        sp->sof_tq[m]=m;
+                }
+@@ -1861,6 +1863,8 @@ OJPEGReadHeaderInfoSecTablesDcTable(TIFF* tif)
+                                _TIFFfree(rb);
+                                return(0);
+                        }
++                       if (sp->dctable[m]!=0)
++                               _TIFFfree(sp->dctable[m]);
+                        sp->dctable[m]=rb;
+                        sp->sos_tda[m]=(m<<4);
+                }
+@@ -1928,6 +1932,8 @@ OJPEGReadHeaderInfoSecTablesAcTable(TIFF* tif)
+                                _TIFFfree(rb);
+                                return(0);
+                        }
++                       if (sp->actable[m])
++                               _TIFFfree(sp->actable[m]);
+                        sp->actable[m]=rb;
+                        sp->sos_tda[m]=(sp->sos_tda[m]|m);
+                }
diff --git a/third_party/libtiff/README.pdfium b/third_party/libtiff/README.pdfium
index 23c8450..e4436d2 100644
--- a/third_party/libtiff/README.pdfium
+++ b/third_party/libtiff/README.pdfium
@@ -26,3 +26,8 @@
 0014-cast-to-unsigned-in-putagreytile.patch: casting to avoid undefined shifts.
 0015-fix-leaks-in-tif_ojpeg.patch: fix direct leaks in tif_ojpeg.c methods
 0016-fix-leak-in-pixarlogsetupdecode.patch: Free sp->tbuf if setup fails
+0017-safe_skews_in_gtTileContig.patch: return error if to/from skews overflow from int32.
+0018-fix-leak-in-PredictorSetupDecode.patch: call tif->tif_cleanup if the setup fails.
+0019-fix-invalid-reads-TIFFFetchNormalTag.patch: upstream security fix in tif_dirread.
+0020-unreasonable-td-bitspersample.patch: upstream patch ignoring large td_bitspersample.
+0021-fix-leaks-ojpegreaderinfosectables.patch: more direct leak fixes in tif_ojpeg.c.
diff --git a/third_party/libtiff/tif_dirread.c b/third_party/libtiff/tif_dirread.c
index bc41021..e0403ae 100644
--- a/third_party/libtiff/tif_dirread.c
+++ b/third_party/libtiff/tif_dirread.c
@@ -3754,6 +3754,17 @@
                                        fip ? fip->field_name : "unknown tagname");
                         continue;
                     }
+					/* ColorMap or TransferFunction for high bit */
+					/* depths do not make much sense and could be */
+					/* used as a denial of service vector */
+					if (tif->tif_dir.td_bitspersample > 24)
+					{
+					    TIFFWarningExt(tif->tif_clientdata,module,
+						"Ignoring %s because BitsPerSample=%d>24",
+						fip ? fip->field_name : "unknown tagname",
+						tif->tif_dir.td_bitspersample);
+					    continue;
+					}
 					countpersample=(1L<<tif->tif_dir.td_bitspersample);
 					if ((dp->tdir_tag==TIFFTAG_TRANSFERFUNCTION)&&(dp->tdir_count==(uint64)countpersample))
 					{
@@ -4983,6 +4994,11 @@
 					if (err==TIFFReadDirEntryErrOk)
 					{
 						int m;
+						if( dp->tdir_count > 0 && data[dp->tdir_count-1] != '\0' )
+                        {
+                            TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte. Forcing it to be null",fip->field_name);
+                            data[dp->tdir_count-1] = '\0';
+                        }
 						m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data);
 						if (data!=0)
 							_TIFFfree(data);
@@ -5155,6 +5171,11 @@
 				if (err==TIFFReadDirEntryErrOk)
 				{
 					int m;
+					if( dp->tdir_count > 0 && data[dp->tdir_count-1] != '\0' )
+                    {
+                        TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte. Forcing it to be null",fip->field_name);
+                        data[dp->tdir_count-1] = '\0';
+                    }
 					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
 					if (data!=0)
 						_TIFFfree(data);
diff --git a/third_party/libtiff/tif_getimage.c b/third_party/libtiff/tif_getimage.c
index 2861cdd..5ed1b7a 100644
--- a/third_party/libtiff/tif_getimage.c
+++ b/third_party/libtiff/tif_getimage.c
@@ -31,6 +31,7 @@
  */
 #include "tiffiop.h"
 #include <stdio.h>
+#include <limits.h>
 
 static int gtTileContig(TIFFRGBAImage*, uint32*, uint32, uint32);
 static int gtTileSeparate(TIFFRGBAImage*, uint32*, uint32, uint32);
@@ -612,6 +613,7 @@
     uint32 tw, th;
     unsigned char* buf;
     int32 fromskew, toskew;
+    int64 safeskew;
     uint32 nrow;
     int ret = 1, flip;
     uint32 this_tw, tocol;
@@ -631,19 +633,37 @@
     flip = setorientation(img);
     if (flip & FLIP_VERTICALLY) {
 	    y = h - 1;
-	    toskew = -(int32)(tw + w);
+	    safeskew = 0;
+	    safeskew -= tw;
+	    safeskew -= w;
     }
     else {
 	    y = 0;
-	    toskew = -(int32)(tw - w);
+	    safeskew = 0;
+	    safeskew -= tw;
+	    safeskew +=w;
     }
+    if(safeskew > INT_MAX || safeskew < INT_MIN){
+    	_TIFFfree(buf);
+    	TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", "Invalid skew");
+    	return (0);
+    }
+    toskew = safeskew;
+
      
     /*
      *	Leftmost tile is clipped on left side if col_offset > 0.
      */
     leftmost_fromskew = img->col_offset % tw;
     leftmost_tw = tw - leftmost_fromskew;
-    leftmost_toskew = toskew + leftmost_fromskew;
+    safeskew = toskew;
+    safeskew += leftmost_fromskew;
+    if(safeskew > INT_MAX || safeskew < INT_MIN){
+    	_TIFFfree(buf);
+    	TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", "Invalid skew");
+    	return (0);
+    }
+    leftmost_toskew = safeskew;
     for (row = 0; row < h; row += nrow)
     {
         rowstoread = th - (row + img->row_offset) % th;
@@ -668,9 +688,24 @@
 		/*
 		 * Rightmost tile is clipped on right side.
 		 */
-		fromskew = tw - (w - tocol);
+		safeskew = tw;
+		safeskew -= w;
+		safeskew += tocol;
+		if(safeskew > INT_MAX || safeskew < INT_MIN){
+			_TIFFfree(buf);
+			TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", "Invalid skew");
+			return (0);
+		}
+		fromskew = safeskew;
 		this_tw = tw - fromskew;
-		this_toskew = toskew + fromskew;
+		safeskew = toskew;
+		safeskew += fromskew;
+		if(safeskew > INT_MAX || safeskew < INT_MIN){
+			_TIFFfree(buf);
+			TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", "Invalid skew");
+			return (0);
+		}
+		this_toskew = safeskew;
 	    }
 	    (*put)(img, raster+y*w+tocol, tocol, y, this_tw, nrow, fromskew, this_toskew, buf + pos);
 	    tocol += this_tw;
diff --git a/third_party/libtiff/tif_ojpeg.c b/third_party/libtiff/tif_ojpeg.c
index f69b001..276d562 100644
--- a/third_party/libtiff/tif_ojpeg.c
+++ b/third_party/libtiff/tif_ojpeg.c
@@ -1794,6 +1794,8 @@
 				_TIFFfree(ob);
 				return(0);
 			}
+			if (sp->qtable[m]!=0)
+				_TIFFfree(sp->qtable[m]);
 			sp->qtable[m]=ob;
 			sp->sof_tq[m]=m;
 		}
@@ -1861,6 +1863,8 @@
 				_TIFFfree(rb);
 				return(0);
 			}
+			if (sp->dctable[m]!=0)
+				_TIFFfree(sp->dctable[m]);
 			sp->dctable[m]=rb;
 			sp->sos_tda[m]=(m<<4);
 		}
@@ -1928,6 +1932,8 @@
 				_TIFFfree(rb);
 				return(0);
 			}
+			if (sp->actable[m])
+				_TIFFfree(sp->actable[m]);
 			sp->actable[m]=rb;
 			sp->sos_tda[m]=(sp->sos_tda[m]|m);
 		}
diff --git a/third_party/libtiff/tif_pixarlog.c b/third_party/libtiff/tif_pixarlog.c
index 80006d5..29535d3 100644
--- a/third_party/libtiff/tif_pixarlog.c
+++ b/third_party/libtiff/tif_pixarlog.c
@@ -697,9 +697,6 @@
 	if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN)
 		sp->user_datafmt = PixarLogGuessDataFmt(td);
 	if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) {
-		_TIFFfree(sp->tbuf);
-		sp->tbuf = NULL;
-		sp->tbuf_size = 0;
 		TIFFErrorExt(tif->tif_clientdata, module,
 			"PixarLog compression can't handle bits depth/data format combination (depth: %d)", 
 			td->td_bitspersample);
@@ -707,9 +704,6 @@
 	}
 
 	if (inflateInit(&sp->stream) != Z_OK) {
-		_TIFFfree(sp->tbuf);
-		sp->tbuf = NULL;
-		sp->tbuf_size = 0;
 		TIFFErrorExt(tif->tif_clientdata, module, "%s", sp->stream.msg);
 		return (0);
 	} else {
diff --git a/third_party/libtiff/tif_predict.c b/third_party/libtiff/tif_predict.c
index 1388dde..8975672 100644
--- a/third_party/libtiff/tif_predict.c
+++ b/third_party/libtiff/tif_predict.c
@@ -109,7 +109,10 @@
 	TIFFDirectory* td = &tif->tif_dir;
 
 	if (!(*sp->setupdecode)(tif) || !PredictorSetup(tif))
+	{
+		(*tif->tif_cleanup)(tif);
 		return 0;
+	}
 
 	if (sp->predictor == 2) {
 		switch (td->td_bitspersample) {
diff --git a/tools/drmemory/DrMemory-Windows-sfx.exe b/tools/drmemory/DrMemory-Windows-sfx.exe
deleted file mode 100644
index cd3992b..0000000
--- a/tools/drmemory/DrMemory-Windows-sfx.exe
+++ /dev/null
Binary files differ
diff --git a/tools/drmemory/README b/tools/drmemory/README
deleted file mode 100644
index 1db5410..0000000
--- a/tools/drmemory/README
+++ /dev/null
@@ -1,86 +0,0 @@
-
-# Dr. Memory
-
-Dr. Memory (www.drmemory.org) is an open-source dynamic memory
-monitoring tool for Windows, Linux, and Mac.
-
-## About Dr. Memory
-
-Dr. Memory operates on unmodified application binaries running on
-Windows, Linux, or Mac on commodity x86 and ARM32 (forthcoming) hardware.
-It is capable of identifying memory-related programming errors including:
-  * accesses of uninitialized memory
-  * accesses to unaddressable memory (heap underflow and overflow)
-  * accesses to freed memory
-  * double frees
-  * memory leaks
-  * handle leaks (on Windows)
-  * GDI API usage errors (on Windows)
-  * accesses to un-reserved thread local storage slots (on Windows)
-
-## Using Dr. Memory (Windows only)
-
-Build your application with debug information and then run it under
-Dr. Memory.  Errors found are printed to the screen, and a summary is
-shown at the end of the run.
-
-### Obtain Dr. Memory
-
-The Dr. Memory package is provided as a self-extracting archive
-(DrMemory-Windows-sfx.exe) in tools/drmemory directory, which can be
-extracted by running command 'DrMemory-Windows-sfx.exe -ounpacked -y'.
-
-The Dr. Memory release package can be downloaded from
-https://github.com/DynamoRIO/drmemory/wiki/Downloads.
-
-Nightly builds can be downloaded from
-https://build.chromium.org/p/client.drmemory/builds/.
-
-The Dr. Memory source code can be found at
-https://github.com/DynamoRIO/drmemory.
-
-### Run your application with Dr. Memory
-
-To run your application with Dr. Memory, simply put 'drmemory.exe --'
-before the command that invokes the application.
-
-  * Running pdfium_unittests with Dr. Memory:
-    tools\drmemory\unpaced\bin\drmemory.exe -- out\Debug\pdfium_unittests.exe
-
-  * Running pdfium_tests with Dr. Memory:
-    tools\drmemory\unpaced\bin\drmemory.exe -- out\Debug\pdfium_tests.exe --png YourInputPDF.pdf
-
-### Run test suite with Dr. Memory
-
-A set of scripts are provided to run PDFium test suite with Dr. Memory
-on buildbots, which can also be used for running test suite locally.
-
-  * Running pdfium_unittests with Dr. Memory:
-    tools\drmemory\scripts\pdfium_tests.bat -t pdfium_unittests
-
-  * Running pixel test suite with Dr. Memory:
-    tools\drmemory\scripts\pdfium_tests.bat -t pdfium_pixel
-
-## Documentation
-
-Command 'drmemory.exe -help' prints a list of Dr. Memory runtime
-options with short description.
-
-To view the full documention, point your web browser at
-http://drmemory.org/docs/.
-
-
-## Contact
-
-This project is provided as-is, with no official support.
-Use the Dr. Memory Users group at
-http://groups.google.com/group/drmemory-users/ to ask questions and
-seek help on using Dr. Memory.
-
-Dr. Memory's source code and issue tracker live at
-https://github.com/DynamoRIO/drmemory
-
-If you would like to submit a patch, you will need to first sign a
-Contributor License Agreement.
-See https://github.com/DynamoRIO/drmemory/wiki/Contributing for more
-information.
diff --git a/tools/drmemory/scripts/common.py b/tools/drmemory/scripts/common.py
deleted file mode 100644
index 7e163e3..0000000
--- a/tools/drmemory/scripts/common.py
+++ /dev/null
@@ -1,252 +0,0 @@
-# Copyright (c) 2012 The Chromium 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 logging
-import platform
-import os
-import signal
-import subprocess
-import sys
-import time
-
-
-class NotImplementedError(Exception):
-  pass
-
-
-class TimeoutError(Exception):
-  pass
-
-
-def RunSubprocessInBackground(proc):
-  """Runs a subprocess in the background. Returns a handle to the process."""
-  logging.info("running %s in the background" % " ".join(proc))
-  return subprocess.Popen(proc)
-
-
-def RunSubprocess(proc, timeout=0):
-  """ Runs a subprocess, until it finishes or |timeout| is exceeded and the
-  process is killed with taskkill.  A |timeout| <= 0  means no timeout.
-
-  Args:
-    proc: list of process components (exe + args)
-    timeout: how long to wait before killing, <= 0 means wait forever
-  """
-
-  logging.info("running %s, timeout %d sec" % (" ".join(proc), timeout))
-  sys.stdout.flush()
-  sys.stderr.flush()
-
-  # Manually read and print out stdout and stderr.
-  # By default, the subprocess is supposed to inherit these from its parent,
-  # however when run under buildbot, it seems unable to read data from a
-  # grandchild process, so we have to read the child and print the data as if
-  # it came from us for buildbot to read it.  We're not sure why this is
-  # necessary.
-  # TODO(erikkay): should we buffer stderr and stdout separately?
-  p = subprocess.Popen(proc, universal_newlines=True,
-                       bufsize=0,  # unbuffered
-                       stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-
-  logging.info("started subprocess")
-
-  did_timeout = False
-  if timeout > 0:
-    wait_until = time.time() + timeout
-  while p.poll() is None and not did_timeout:
-    # Have to use readline rather than readlines() or "for line in p.stdout:",
-    # otherwise we get buffered even with bufsize=0.
-    line = p.stdout.readline()
-    while line and not did_timeout:
-      sys.stdout.write(line)
-      sys.stdout.flush()
-      line = p.stdout.readline()
-      if timeout > 0:
-        did_timeout = time.time() > wait_until
-
-  if did_timeout:
-    logging.info("process timed out")
-  else:
-    logging.info("process ended, did not time out")
-
-  if did_timeout:
-    if IsWindows():
-      subprocess.call(["taskkill", "/T", "/F", "/PID", str(p.pid)])
-    else:
-      # Does this kill all children, too?
-      os.kill(p.pid, signal.SIGINT)
-    logging.error("KILLED %d" % p.pid)
-    # Give the process a chance to actually die before continuing
-    # so that cleanup can happen safely.
-    time.sleep(1.0)
-    logging.error("TIMEOUT waiting for %s" % proc[0])
-    raise TimeoutError(proc[0])
-  else:
-    for line in p.stdout:
-      sys.stdout.write(line)
-    if not IsMac():   # stdout flush fails on Mac
-      logging.info("flushing stdout")
-      sys.stdout.flush()
-
-  logging.info("collecting result code")
-  result = p.poll()
-  if result:
-    logging.error("%s exited with non-zero result code %d" % (proc[0], result))
-  return result
-
-
-def IsLinux():
-  return sys.platform.startswith('linux')
-
-
-def IsMac():
-  return sys.platform.startswith('darwin')
-
-
-def IsWindows():
-  return sys.platform == 'cygwin' or sys.platform.startswith('win')
-
-
-def WindowsVersionName():
-  """Returns the name of the Windows version if it is known, or None.
-
-  Possible return values are: xp, vista, 7, 8, or None
-  """
-  if sys.platform == 'cygwin':
-    # Windows version number is hiding in system name.  Looks like:
-    # CYGWIN_NT-6.1-WOW64
-    try:
-      version_str = platform.uname()[0].split('-')[1]
-    except:
-      return None
-  elif sys.platform.startswith('win'):
-    # Normal Windows version string.  Mine: 6.1.7601
-    version_str = platform.version()
-  else:
-    return None
-
-  parts = version_str.split('.')
-  try:
-    major = int(parts[0])
-    minor = int(parts[1])
-  except:
-    return None  # Can't parse, unknown version.
-
-  if major == 5:
-    return 'xp'
-  elif major == 6 and minor == 0:
-    return 'vista'
-  elif major == 6 and minor == 1:
-    return '7'
-  elif major == 6 and minor == 2:
-    return '8'  # Future proof.  ;)
-  return None
-
-
-def PlatformNames():
-  """Return an array of string to be used in paths for the platform
-  (e.g. suppressions, gtest filters, ignore files etc.)
-  The first element of the array describes the 'main' platform
-  """
-  if IsLinux():
-    return ['linux']
-  if IsMac():
-    return ['mac']
-  if IsWindows():
-    names = ['win32']
-    version_name = WindowsVersionName()
-    if version_name is not None:
-      names.append('win-%s' % version_name)
-    return names
-  raise NotImplementedError('Unknown platform "%s".' % sys.platform)
-
-
-def PutEnvAndLog(env_name, env_value):
-  os.putenv(env_name, env_value)
-  logging.info('export %s=%s', env_name, env_value)
-
-def BoringCallers(mangled, use_re_wildcards):
-  """Return a list of 'boring' function names (optinally mangled)
-  with */? wildcards (optionally .*/.).
-  Boring = we drop off the bottom of stack traces below such functions.
-  """
-
-  need_mangling = [
-    # Don't show our testing framework:
-    ("testing::Test::Run",     "_ZN7testing4Test3RunEv"),
-    ("testing::TestInfo::Run", "_ZN7testing8TestInfo3RunEv"),
-    ("testing::internal::Handle*ExceptionsInMethodIfSupported*",
-     "_ZN7testing8internal3?Handle*ExceptionsInMethodIfSupported*"),
-
-    # Depend on scheduling:
-    ("MessageLoop::Run",     "_ZN11MessageLoop3RunEv"),
-    ("MessageLoop::RunTask", "_ZN11MessageLoop7RunTask*"),
-    ("RunnableMethod*",      "_ZN14RunnableMethod*"),
-    ("DispatchToMethod*",    "_Z*16DispatchToMethod*"),
-    ("base::internal::Invoker*::DoInvoke*",
-     "_ZN4base8internal8Invoker*DoInvoke*"),  # Invoker{1,2,3}
-    ("base::internal::RunnableAdapter*::Run*",
-     "_ZN4base8internal15RunnableAdapter*Run*"),
-  ]
-
-  ret = []
-  for pair in need_mangling:
-    ret.append(pair[1 if mangled else 0])
-
-  ret += [
-    # Also don't show the internals of libc/pthread.
-    "start_thread",
-    "main",
-    "BaseThreadInitThunk",
-  ]
-
-  if use_re_wildcards:
-    for i in range(0, len(ret)):
-      ret[i] = ret[i].replace('*', '.*').replace('?', '.')
-
-  return ret
-
-def NormalizeWindowsPath(path):
-  """If we're using Cygwin Python, turn the path into a Windows path.
-
-  Don't turn forward slashes into backslashes for easier copy-pasting and
-  escaping.
-
-  TODO(rnk): If we ever want to cut out the subprocess invocation, we can use
-  _winreg to get the root Cygwin directory from the registry key:
-  HKEY_LOCAL_MACHINE\SOFTWARE\Cygwin\setup\rootdir.
-  """
-  if sys.platform.startswith("cygwin"):
-    p = subprocess.Popen(["cygpath", "-m", path],
-                         stdout=subprocess.PIPE,
-                         stderr=subprocess.PIPE)
-    (out, err) = p.communicate()
-    if err:
-      logging.warning("WARNING: cygpath error: %s", err)
-    return out.strip()
-  else:
-    return path
-
-############################
-# Common output format code
-
-def PrintUsedSuppressionsList(suppcounts):
-  """ Prints out the list of used suppressions in a format common to all the
-      memory tools. If the list is empty, prints nothing and returns False,
-      otherwise True.
-
-      suppcounts: a dictionary of used suppression counts,
-                  Key -> name, Value -> count.
-  """
-  if not suppcounts:
-    return False
-
-  print "-----------------------------------------------------"
-  print "Suppressions used:"
-  print "  count name"
-  for (name, count) in sorted(suppcounts.items(), key=lambda (k,v): (v,k)):
-    print "%7d %s" % (count, name)
-  print "-----------------------------------------------------"
-  sys.stdout.flush()
-  return True
diff --git a/tools/drmemory/scripts/drmemory_analyze.py b/tools/drmemory/scripts/drmemory_analyze.py
deleted file mode 100644
index 29fc0ed..0000000
--- a/tools/drmemory/scripts/drmemory_analyze.py
+++ /dev/null
@@ -1,202 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# drmemory_analyze.py
-
-''' Given a Dr. Memory output file, parses errors and uniques them.'''
-
-from collections import defaultdict
-import common
-import hashlib
-import logging
-import optparse
-import os
-import re
-import subprocess
-import sys
-import time
-
-class DrMemoryError:
-  def __init__(self, report, suppression, testcase):
-    self._report = report
-    self._testcase = testcase
-
-    # Chromium-specific transformations of the suppressions:
-    # Replace 'any_test.exe' and 'chrome.dll' with '*', then remove the
-    # Dr.Memory-generated error ids from the name= lines as they don't
-    # make sense in a multiprocess report.
-    supp_lines = suppression.split("\n")
-    for l in xrange(len(supp_lines)):
-      if supp_lines[l].startswith("name="):
-        supp_lines[l] = "name=<insert_a_suppression_name_here>"
-      if supp_lines[l].startswith("chrome.dll!"):
-        supp_lines[l] = supp_lines[l].replace("chrome.dll!", "*!")
-      bang_index = supp_lines[l].find("!")
-      d_exe_index = supp_lines[l].find(".exe!")
-      if bang_index >= 4 and d_exe_index + 4 == bang_index:
-        supp_lines[l] = "*" + supp_lines[l][bang_index:]
-    self._suppression = "\n".join(supp_lines)
-
-  def __str__(self):
-    output = ""
-    output += "### BEGIN MEMORY TOOL REPORT (error hash=#%016X#)\n" % \
-        self.ErrorHash()
-    output += self._report + "\n"
-    if self._testcase:
-      output += "The report came from the `%s` test.\n" % self._testcase
-    output += "Suppression (error hash=#%016X#):\n" % self.ErrorHash()
-    output += ("  For more info on using suppressions see "
-        "http://dev.chromium.org/developers/how-tos/using-drmemory#TOC-Suppressing-error-reports-from-the-\n")
-    output += "{\n%s\n}\n" % self._suppression
-    output += "### END MEMORY TOOL REPORT (error hash=#%016X#)\n" % \
-        self.ErrorHash()
-    return output
-
-  # This is a device-independent hash identifying the suppression.
-  # By printing out this hash we can find duplicate reports between tests and
-  # different shards running on multiple buildbots
-  def ErrorHash(self):
-    return int(hashlib.md5(self._suppression).hexdigest()[:16], 16)
-
-  def __hash__(self):
-    return hash(self._suppression)
-
-  def __eq__(self, rhs):
-    return self._suppression == rhs
-
-
-class DrMemoryAnalyzer:
-  ''' Given a set of Dr.Memory output files, parse all the errors out of
-  them, unique them and output the results.'''
-
-  def __init__(self):
-    self.known_errors = set()
-    self.error_count = 0;
-
-  def ReadLine(self):
-    self.line_ = self.cur_fd_.readline()
-
-  def ReadSection(self):
-    result = [self.line_]
-    self.ReadLine()
-    while len(self.line_.strip()) > 0:
-      result.append(self.line_)
-      self.ReadLine()
-    return result
-
-  def ParseReportFile(self, filename, testcase):
-    ret = []
-
-    # First, read the generated suppressions file so we can easily lookup a
-    # suppression for a given error.
-    supp_fd = open(filename.replace("results", "suppress"), 'r')
-    generated_suppressions = {}  # Key -> Error #, Value -> Suppression text.
-    for line in supp_fd:
-      # NOTE: this regexp looks fragile. Might break if the generated
-      # suppression format slightly changes.
-      m = re.search("# Suppression for Error #([0-9]+)", line.strip())
-      if not m:
-        continue
-      error_id = int(m.groups()[0])
-      assert error_id not in generated_suppressions
-      # OK, now read the next suppression:
-      cur_supp = ""
-      for supp_line in supp_fd:
-        if supp_line.startswith("#") or supp_line.strip() == "":
-          break
-        cur_supp += supp_line
-      generated_suppressions[error_id] = cur_supp.strip()
-    supp_fd.close()
-
-    self.cur_fd_ = open(filename, 'r')
-    while True:
-      self.ReadLine()
-      if (self.line_ == ''): break
-
-      match = re.search("^Error #([0-9]+): (.*)", self.line_)
-      if match:
-        error_id = int(match.groups()[0])
-        self.line_ = match.groups()[1].strip() + "\n"
-        report = "".join(self.ReadSection()).strip()
-        suppression = generated_suppressions[error_id]
-        ret.append(DrMemoryError(report, suppression, testcase))
-
-      if re.search("SUPPRESSIONS USED:", self.line_):
-        self.ReadLine()
-        while self.line_.strip() != "":
-          line = self.line_.strip()
-          (count, name) = re.match(" *([0-9\?]+)x(?: \(.*?\))?: (.*)",
-                                   line).groups()
-          if (count == "?"):
-            # Whole-module have no count available: assume 1
-            count = 1
-          else:
-            count = int(count)
-          self.used_suppressions[name] += count
-          self.ReadLine()
-
-      if self.line_.startswith("ASSERT FAILURE"):
-        ret.append(self.line_.strip())
-
-    self.cur_fd_.close()
-    return ret
-
-  def Report(self, filenames, testcase, check_sanity):
-    sys.stdout.flush()
-    # TODO(timurrrr): support positive tests / check_sanity==True
-    self.used_suppressions = defaultdict(int)
-
-    to_report = []
-    reports_for_this_test = set()
-    for f in filenames:
-      cur_reports = self.ParseReportFile(f, testcase)
-
-      # Filter out the reports that were there in previous tests.
-      for r in cur_reports:
-        if r in reports_for_this_test:
-          # A similar report is about to be printed for this test.
-          pass
-        elif r in self.known_errors:
-          # A similar report has already been printed in one of the prev tests.
-          to_report.append("This error was already printed in some "
-                           "other test, see 'hash=#%016X#'" % r.ErrorHash())
-          reports_for_this_test.add(r)
-        else:
-          self.known_errors.add(r)
-          reports_for_this_test.add(r)
-          to_report.append(r)
-
-    common.PrintUsedSuppressionsList(self.used_suppressions)
-
-    if not to_report:
-      logging.info("PASS: No error reports found")
-      return 0
-
-    sys.stdout.flush()
-    sys.stderr.flush()
-    logging.info("Found %i error reports" % len(to_report))
-    for report in to_report:
-      self.error_count += 1
-      logging.info("Report #%d\n%s" % (self.error_count, report))
-    logging.info("Total: %i error reports" % len(to_report))
-    sys.stdout.flush()
-    return -1
-
-
-def main():
-  '''For testing only. The DrMemoryAnalyze class should be imported instead.'''
-  parser = optparse.OptionParser("usage: %prog <files to analyze>")
-
-  (options, args) = parser.parse_args()
-  if len(args) == 0:
-    parser.error("no filename specified")
-  filenames = args
-
-  logging.getLogger().setLevel(logging.INFO)
-  return DrMemoryAnalyzer().Report(filenames, None, False)
-
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/tools/drmemory/scripts/logging_utils.py b/tools/drmemory/scripts/logging_utils.py
deleted file mode 100644
index ef2d674..0000000
--- a/tools/drmemory/scripts/logging_utils.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# Copyright (c) 2011 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-''' Utility functions and objects for logging.
-'''
-
-import logging
-import sys
-
-class StdoutStderrHandler(logging.Handler):
-  ''' Subclass of logging.Handler which outputs to either stdout or stderr
-  based on a threshold level.
-  '''
-
-  def __init__(self, threshold=logging.WARNING, err=sys.stderr, out=sys.stdout):
-    ''' Args:
-          threshold: below this logging level messages are sent to stdout,
-            otherwise they are sent to stderr
-          err: a stream object that error messages are sent to, defaults to
-            sys.stderr
-          out: a stream object that non-error messages are sent to, defaults to
-            sys.stdout
-    '''
-    logging.Handler.__init__(self)
-    self._err = logging.StreamHandler(err)
-    self._out = logging.StreamHandler(out)
-    self._threshold = threshold
-    self._last_was_err = False
-
-  def setLevel(self, lvl):
-    logging.Handler.setLevel(self, lvl)
-    self._err.setLevel(lvl)
-    self._out.setLevel(lvl)
-
-  def setFormatter(self, formatter):
-    logging.Handler.setFormatter(self, formatter)
-    self._err.setFormatter(formatter)
-    self._out.setFormatter(formatter)
-
-  def emit(self, record):
-    if record.levelno < self._threshold:
-      self._out.emit(record)
-      self._last_was_err = False
-    else:
-      self._err.emit(record)
-      self._last_was_err = False
-
-  def flush(self):
-    # preserve order on the flushing, the stalest stream gets flushed first
-    if self._last_was_err:
-      self._out.flush()
-      self._err.flush()
-    else:
-      self._err.flush()
-      self._out.flush()
-
-
-FORMAT = "%(asctime)s %(filename)s [%(levelname)s] %(message)s"
-DATEFMT = "%H:%M:%S"
-
-def config_root(level=logging.INFO, threshold=logging.WARNING, format=FORMAT,
-         datefmt=DATEFMT):
-  ''' Configure the root logger to use a StdoutStderrHandler and some default
-  formatting.
-    Args:
-      level: messages below this level are ignored
-      threshold: below this logging level messages are sent to stdout,
-        otherwise they are sent to stderr
-      format: format for log messages, see logger.Format
-      datefmt: format for date in log messages
-
-  '''
-  # to set the handler of the root logging object, we need to do setup
-  # manually rather than using basicConfig
-  root = logging.getLogger()
-  root.setLevel(level)
-  formatter = logging.Formatter(format, datefmt)
-  handler = StdoutStderrHandler(threshold=threshold)
-  handler.setLevel(level)
-  handler.setFormatter(formatter)
-  root.addHandler(handler)
diff --git a/tools/drmemory/scripts/path_utils.py b/tools/drmemory/scripts/path_utils.py
deleted file mode 100644
index 6ab4312..0000000
--- a/tools/drmemory/scripts/path_utils.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# Copyright (c) 2011 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Some utility methods for getting and manipulating paths."""
-
-# TODO(pamg): Have the buildbot use these, too.
-
-
-import errno
-import os
-import sys
-
-class PathNotFound(Exception): pass
-
-def ScriptDir():
-  """Get the full path to the directory containing the current script."""
-  script_filename = os.path.abspath(sys.argv[0])
-  return os.path.dirname(script_filename)
-
-def FindAncestor(start_dir, ancestor):
-  """Finds an ancestor dir in a path.
-
-  For example, FindAncestor('c:\foo\bar\baz', 'bar') would return
-  'c:\foo\bar'.  Unlike FindUpward*, this only looks at direct path ancestors.
-  """
-  start_dir = os.path.abspath(start_dir)
-  path = start_dir
-  while True:
-    (parent, tail) = os.path.split(path)
-    if tail == ancestor:
-      return path
-    if not tail:
-      break
-    path = parent
-  raise PathNotFound("Unable to find ancestor %s in %s" % (ancestor, start_dir))
-
-def FindUpwardParent(start_dir, *desired_list):
-  """Finds the desired object's parent, searching upward from the start_dir.
-
-  Searches start_dir and all its parents looking for the desired directory
-  or file, which may be given in one or more path components. Returns the
-  first directory in which the top desired path component was found, or raises
-  PathNotFound if it wasn't.
-  """
-  desired_path = os.path.join(*desired_list)
-  last_dir = ''
-  cur_dir = start_dir
-  found_path = os.path.join(cur_dir, desired_path)
-  while not os.path.exists(found_path):
-    last_dir = cur_dir
-    cur_dir = os.path.dirname(cur_dir)
-    if last_dir == cur_dir:
-      raise PathNotFound('Unable to find %s above %s' %
-                         (desired_path, start_dir))
-    found_path = os.path.join(cur_dir, desired_path)
-  # Strip the entire original desired path from the end of the one found
-  # and remove a trailing path separator, if present.
-  found_path = found_path[:len(found_path) - len(desired_path)]
-  if found_path.endswith(os.sep):
-    found_path = found_path[:len(found_path) - 1]
-  return found_path
-
-
-def FindUpward(start_dir, *desired_list):
-  """Returns a path to the desired directory or file, searching upward.
-
-  Searches start_dir and all its parents looking for the desired directory
-  or file, which may be given in one or more path components. Returns the full
-  path to the desired object, or raises PathNotFound if it wasn't found.
-  """
-  parent = FindUpwardParent(start_dir, *desired_list)
-  return os.path.join(parent, *desired_list)
-
-
-def MaybeMakeDirectory(*path):
-  """Creates an entire path, if it doesn't already exist."""
-  file_path = os.path.join(*path)
-  try:
-    os.makedirs(file_path)
-  except OSError, e:
-    # errno.EEXIST is "File exists".  If we see another error, re-raise.
-    if e.errno != errno.EEXIST:
-      raise
diff --git a/tools/drmemory/scripts/pdfium_tests.bat b/tools/drmemory/scripts/pdfium_tests.bat
deleted file mode 100644
index 4618a0e..0000000
--- a/tools/drmemory/scripts/pdfium_tests.bat
+++ /dev/null
@@ -1,24 +0,0 @@
-@echo off

-:: Copyright (c) 2011 The Chromium Authors. All rights reserved.

-:: Use of this source code is governed by a BSD-style license that can be

-:: found in the LICENSE file.

-

-set THISDIR=%~dp0

-set TOOL_NAME="drmemory_full"

-

-:: Set up DRMEMORY_COMMAND to invoke Dr. Memory {{{1

-set DRMEMORY_PATH=%THISDIR%..

-set DRMEMORY_SFX=%DRMEMORY_PATH%\drmemory-windows-sfx.exe

-if EXIST %DRMEMORY_SFX% GOTO DRMEMORY_BINARY_OK

-echo "Can't find Dr. Memory executables."

-echo "See http://www.chromium.org/developers/how-tos/using-valgrind/dr-memory"

-echo "for the instructions on how to get them."

-exit /B 1

-

-:DRMEMORY_BINARY_OK

-%DRMEMORY_SFX% -o%DRMEMORY_PATH%\unpacked -y

-set DRMEMORY_COMMAND=%DRMEMORY_PATH%\unpacked\bin\drmemory.exe

-:: }}}

-

-:RUN_TESTS

-python %THISDIR%/pdfium_tests.py %*

diff --git a/tools/drmemory/scripts/pdfium_tests.py b/tools/drmemory/scripts/pdfium_tests.py
deleted file mode 100644
index f1d5308..0000000
--- a/tools/drmemory/scripts/pdfium_tests.py
+++ /dev/null
@@ -1,399 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-''' Runs various chrome tests through valgrind_test.py.'''
-
-import glob
-import logging
-import optparse
-import os
-import subprocess
-import sys
-
-import logging_utils
-import path_utils
-
-import common
-import valgrind_test
-
-class TestNotFound(Exception): pass
-
-class MultipleGTestFiltersSpecified(Exception): pass
-
-class BuildDirNotFound(Exception): pass
-
-class BuildDirAmbiguous(Exception): pass
-
-class ExecutableNotFound(Exception): pass
-
-class BadBinary(Exception): pass
-
-class ChromeTests:
-  SLOW_TOOLS = ["drmemory"]
-
-  def __init__(self, options, args, test):
-    if ':' in test:
-      (self._test, self._gtest_filter) = test.split(':', 1)
-    else:
-      self._test = test
-      self._gtest_filter = options.gtest_filter
-
-    if self._test not in self._test_list:
-      raise TestNotFound("Unknown test: %s" % test)
-
-    if options.gtest_filter and options.gtest_filter != self._gtest_filter:
-      raise MultipleGTestFiltersSpecified("Can not specify both --gtest_filter "
-                                          "and --test %s" % test)
-
-    self._options = options
-    self._args = args
-
-    # Compute the top of the tree (the "source dir") from the script dir
-    # (where this script lives).  We assume that the script dir is in
-    # tools/drmemory/scripts relative to the top of the tree.
-    script_dir = os.path.dirname(path_utils.ScriptDir())
-    self._source_dir = os.path.dirname(os.path.dirname(script_dir))
-    # Setup Dr. Memory if it's not set up yet.
-    drmem_cmd = os.getenv("DRMEMORY_COMMAND")
-    if not drmem_cmd:
-      drmem_sfx = os.path.join(script_dir, "drmemory-windows-sfx.exe")
-      if not os.path.isfile(drmem_sfx):
-        raise RuntimeError, "Cannot find drmemory-windows-sfx.exe"
-      drmem_dir = os.path.join(script_dir, "unpacked")
-      subprocess.call([drmem_sfx, "-o" + drmem_dir, "-y"], 0)
-      drmem_cmd = os.path.join(drmem_dir, "bin", "drmemory.exe")
-      os.environ["DRMEMORY_COMMAND"] = drmem_cmd
-    # since this path is used for string matching, make sure it's always
-    # an absolute Unix-style path
-    self._source_dir = os.path.abspath(self._source_dir).replace('\\', '/')
-    self._command_preamble = ["--source-dir=%s" % (self._source_dir)]
-
-    if not self._options.build_dir:
-      dirs = [
-        os.path.join(self._source_dir, "xcodebuild", "Debug"),
-        os.path.join(self._source_dir, "out", "Debug"),
-        os.path.join(self._source_dir, "build", "Debug"),
-      ]
-      build_dir = [d for d in dirs if os.path.isdir(d)]
-      if len(build_dir) > 1:
-        raise BuildDirAmbiguous("Found more than one suitable build dir:\n"
-                                "%s\nPlease specify just one "
-                                "using --build-dir" % ", ".join(build_dir))
-      elif build_dir:
-        self._options.build_dir = build_dir[0]
-      else:
-        self._options.build_dir = None
-
-    if self._options.build_dir:
-      build_dir = os.path.abspath(self._options.build_dir)
-      self._command_preamble += ["--build-dir=%s" % (self._options.build_dir)]
-
-  def _EnsureBuildDirFound(self):
-    if not self._options.build_dir:
-      raise BuildDirNotFound("Oops, couldn't find a build dir, please "
-                             "specify it manually using --build-dir")
-
-  def _DefaultCommand(self, tool, exe=None, valgrind_test_args=None):
-    '''Generates the default command array that most tests will use.'''
-    if exe and common.IsWindows():
-      exe += '.exe'
-
-    cmd = list(self._command_preamble)
-
-    # Find all suppressions matching the following pattern:
-    # tools/valgrind/TOOL/suppressions[_PLATFORM].txt
-    # and list them with --suppressions= prefix.
-    script_dir = path_utils.ScriptDir()
-    suppression_file = os.path.join(script_dir, "..", "suppressions.txt")
-    if os.path.exists(suppression_file):
-      cmd.append("--suppressions=%s" % suppression_file)
-    # Platform-specific suppression
-    for platform in common.PlatformNames():
-      platform_suppression_file = \
-          os.path.join(script_dir, "..", 'suppressions_%s.txt' % platform)
-      if os.path.exists(platform_suppression_file):
-        cmd.append("--suppressions=%s" % platform_suppression_file)
-
-    if self._options.valgrind_tool_flags:
-      cmd += self._options.valgrind_tool_flags.split(" ")
-    if self._options.keep_logs:
-      cmd += ["--keep_logs"]
-    if valgrind_test_args != None:
-      for arg in valgrind_test_args:
-        cmd.append(arg)
-    if exe:
-      self._EnsureBuildDirFound()
-      exe_path = os.path.join(self._options.build_dir, exe)
-      if not os.path.exists(exe_path):
-        raise ExecutableNotFound("Couldn't find '%s'" % exe_path)
-
-      cmd.append(exe_path)
-      # Valgrind runs tests slowly, so slow tests hurt more; show elapased time
-      # so we can find the slowpokes.
-      cmd.append("--gtest_print_time")
-      # Built-in test launcher for gtest-based executables runs tests using
-      # multiple process by default. Force the single-process mode back.
-      cmd.append("--single-process-tests")
-    if self._options.gtest_repeat:
-      cmd.append("--gtest_repeat=%s" % self._options.gtest_repeat)
-    if self._options.gtest_shuffle:
-      cmd.append("--gtest_shuffle")
-    if self._options.gtest_break_on_failure:
-      cmd.append("--gtest_break_on_failure")
-    if self._options.test_launcher_bot_mode:
-      cmd.append("--test-launcher-bot-mode")
-    if self._options.test_launcher_total_shards is not None:
-      cmd.append("--test-launcher-total-shards=%d" % self._options.test_launcher_total_shards)
-    if self._options.test_launcher_shard_index is not None:
-      cmd.append("--test-launcher-shard-index=%d" % self._options.test_launcher_shard_index)
-    return cmd
-
-  def Run(self):
-    ''' Runs the test specified by command-line argument --test '''
-    logging.info("running test %s" % (self._test))
-    return self._test_list[self._test](self)
-
-  def _AppendGtestFilter(self, tool, name, cmd):
-    '''Append an appropriate --gtest_filter flag to the googletest binary
-       invocation.
-       If the user passed his own filter mentioning only one test, just use it.
-       Othewise, filter out tests listed in the appropriate gtest_exclude files.
-    '''
-    if (self._gtest_filter and
-        ":" not in self._gtest_filter and
-        "?" not in self._gtest_filter and
-        "*" not in self._gtest_filter):
-      cmd.append("--gtest_filter=%s" % self._gtest_filter)
-      return
-
-    filters = []
-    gtest_files_dir = os.path.join(path_utils.ScriptDir(), "gtest_exclude")
-
-    gtest_filter_files = [
-        os.path.join(gtest_files_dir, name + ".gtest-%s.txt" % tool.ToolName())]
-    # Use ".gtest.txt" files only for slow tools, as they now contain
-    # Valgrind- and Dr.Memory-specific filters.
-    # TODO(glider): rename the files to ".gtest_slow.txt"
-    if tool.ToolName() in ChromeTests.SLOW_TOOLS:
-      gtest_filter_files += [os.path.join(gtest_files_dir, name + ".gtest.txt")]
-    for platform_suffix in common.PlatformNames():
-      gtest_filter_files += [
-        os.path.join(gtest_files_dir, name + ".gtest_%s.txt" % platform_suffix),
-        os.path.join(gtest_files_dir, name + ".gtest-%s_%s.txt" % \
-            (tool.ToolName(), platform_suffix))]
-    logging.info("Reading gtest exclude filter files:")
-    for filename in gtest_filter_files:
-      # strip the leading absolute path (may be very long on the bot)
-      # and the following / or \.
-      readable_filename = filename.replace("\\", "/")  # '\' on Windows
-      readable_filename = readable_filename.replace(self._source_dir, "")[1:]
-      if not os.path.exists(filename):
-        logging.info("  \"%s\" - not found" % readable_filename)
-        continue
-      logging.info("  \"%s\" - OK" % readable_filename)
-      f = open(filename, 'r')
-      for line in f.readlines():
-        if line.startswith("#") or line.startswith("//") or line.isspace():
-          continue
-        line = line.rstrip()
-        test_prefixes = ["FLAKY", "FAILS"]
-        for p in test_prefixes:
-          # Strip prefixes from the test names.
-          line = line.replace(".%s_" % p, ".")
-        # Exclude the original test name.
-        filters.append(line)
-        if line[-2:] != ".*":
-          # List all possible prefixes if line doesn't end with ".*".
-          for p in test_prefixes:
-            filters.append(line.replace(".", ".%s_" % p))
-    # Get rid of duplicates.
-    filters = set(filters)
-    gtest_filter = self._gtest_filter
-    if len(filters):
-      if gtest_filter:
-        gtest_filter += ":"
-        if gtest_filter.find("-") < 0:
-          gtest_filter += "-"
-      else:
-        gtest_filter = "-"
-      gtest_filter += ":".join(filters)
-    if gtest_filter:
-      cmd.append("--gtest_filter=%s" % gtest_filter)
-
-  @staticmethod
-  def ShowTests():
-    test_to_names = {}
-    for name, test_function in ChromeTests._test_list.iteritems():
-      test_to_names.setdefault(test_function, []).append(name)
-
-    name_to_aliases = {}
-    for names in test_to_names.itervalues():
-      names.sort(key=lambda name: len(name))
-      name_to_aliases[names[0]] = names[1:]
-
-    print
-    print "Available tests:"
-    print "----------------"
-    for name, aliases in sorted(name_to_aliases.iteritems()):
-      if aliases:
-        print "   {} (aka {})".format(name, ', '.join(aliases))
-      else:
-        print "   {}".format(name)
-
-  def SetupLdPath(self, requires_build_dir):
-    if requires_build_dir:
-      self._EnsureBuildDirFound()
-    elif not self._options.build_dir:
-      return
-
-    # Append build_dir to LD_LIBRARY_PATH so external libraries can be loaded.
-    if (os.getenv("LD_LIBRARY_PATH")):
-      os.putenv("LD_LIBRARY_PATH", "%s:%s" % (os.getenv("LD_LIBRARY_PATH"),
-                                              self._options.build_dir))
-    else:
-      os.putenv("LD_LIBRARY_PATH", self._options.build_dir)
-
-  def SimpleTest(self, module, name, valgrind_test_args=None, cmd_args=None):
-    tool = valgrind_test.CreateTool(self._options.valgrind_tool)
-    cmd = self._DefaultCommand(tool, name, valgrind_test_args)
-    self._AppendGtestFilter(tool, name, cmd)
-    cmd.extend(['--test-tiny-timeout=1000'])
-    if cmd_args:
-      cmd.extend(cmd_args)
-
-    self.SetupLdPath(True)
-    return tool.Run(cmd, module)
-
-  def RunCmdLine(self):
-    tool = valgrind_test.CreateTool(self._options.valgrind_tool)
-    cmd = self._DefaultCommand(tool, None, self._args)
-    self.SetupLdPath(False)
-    return tool.Run(cmd, None)
-
-  def TestPDFiumUnitTests(self):
-    return self.SimpleTest("pdfium_unittests", "pdfium_unittests")
-
-  def TestPDFiumEmbedderTests(self):
-    return self.SimpleTest("pdfium_embeddertests", "pdfium_embeddertests")
-
-  def TestPDFiumTest(self, script_name):
-    # Build the command line in 'cmd'.
-    # It's going to be roughly
-    #  python valgrind_test.py ...
-    # but we'll use the --indirect_pdfium_test flag to valgrind_test.py
-    # to avoid valgrinding python.
-
-    # Start by building the valgrind_test.py commandline.
-    tool = valgrind_test.CreateTool(self._options.valgrind_tool)
-    cmd = self._DefaultCommand(tool)
-    cmd.append("--trace_children")
-    cmd.append("--indirect_pdfium_test")
-    cmd.append("--ignore_exit_code")
-    # Now build script_cmd, the run_corpus_tests commandline.
-    script = os.path.join(self._source_dir, "testing", "tools", script_name)
-    script_cmd = ["python", script]
-    if self._options.build_dir:
-      script_cmd.extend(["--build-dir", self._options.build_dir])
-    # Now run script_cmd with the wrapper in cmd
-    cmd.append("--")
-    cmd.extend(script_cmd)
-
-    ret = tool.Run(cmd, "layout", min_runtime_in_seconds=0)
-    return ret
-
-  def TestPDFiumJavascript(self):
-    return self.TestPDFiumTest("run_javascript_tests.py")
-
-  def TestPDFiumPixel(self):
-    return self.TestPDFiumTest("run_pixel_tests.py")
-
-  def TestPDFiumCorpus(self):
-    return self.TestPDFiumTest("run_corpus_tests.py")
-
-  # The known list of tests.
-  _test_list = {
-    "cmdline" :             RunCmdLine,
-    "pdfium_corpus":        TestPDFiumCorpus,
-    "pdfium_embeddertests": TestPDFiumEmbedderTests,
-    "pdfium_javascript":    TestPDFiumJavascript,
-    "pdfium_pixel":         TestPDFiumPixel,
-    "pdfium_unittests":     TestPDFiumUnitTests,
-  }
-
-
-def _main():
-  parser = optparse.OptionParser("usage: %prog -b <dir> -t <test> "
-                                 "[-t <test> ...]")
-
-  parser.add_option("--help-tests", dest="help_tests", action="store_true",
-                    default=False, help="List all available tests")
-  parser.add_option("-b", "--build-dir",
-                    help="the location of the compiler output")
-  parser.add_option("--target", help="Debug or Release")
-  parser.add_option("-t", "--test", action="append", default=[],
-                    help="which test to run, supports test:gtest_filter format "
-                         "as well.")
-  parser.add_option("--gtest_filter",
-                    help="additional arguments to --gtest_filter")
-  parser.add_option("--gtest_repeat", help="argument for --gtest_repeat")
-  parser.add_option("--gtest_shuffle", action="store_true", default=False,
-                    help="Randomize tests' orders on every iteration.")
-  parser.add_option("--gtest_break_on_failure", action="store_true",
-                    default=False,
-                    help="Drop in to debugger on assertion failure. Also "
-                         "useful for forcing tests to exit with a stack dump "
-                         "on the first assertion failure when running with "
-                         "--gtest_repeat=-1")
-  parser.add_option("-v", "--verbose", action="store_true", default=False,
-                    help="verbose output - enable debug log messages")
-  parser.add_option("--tool", dest="valgrind_tool", default="drmemory_full",
-                    help="specify a valgrind tool to run the tests under")
-  parser.add_option("--tool_flags", dest="valgrind_tool_flags", default="",
-                    help="specify custom flags for the selected valgrind tool")
-  parser.add_option("--keep_logs", action="store_true", default=False,
-                    help="store memory tool logs in the <tool>.logs directory "
-                         "instead of /tmp.\nThis can be useful for tool "
-                         "developers/maintainers.\nPlease note that the <tool>"
-                         ".logs directory will be clobbered on tool startup.")
-  parser.add_option("--test-launcher-bot-mode", action="store_true",
-                    help="run the tests with --test-launcher-bot-mode")
-  parser.add_option("--test-launcher-total-shards", type=int,
-                    help="run the tests with --test-launcher-total-shards")
-  parser.add_option("--test-launcher-shard-index", type=int,
-                    help="run the tests with --test-launcher-shard-index")
-
-  options, args = parser.parse_args()
-
-  # Bake target into build_dir.
-  if options.target and options.build_dir:
-    assert (options.target !=
-            os.path.basename(os.path.dirname(options.build_dir)))
-    options.build_dir = os.path.join(os.path.abspath(options.build_dir),
-                                     options.target)
-
-  if options.verbose:
-    logging_utils.config_root(logging.DEBUG)
-  else:
-    logging_utils.config_root()
-
-  if options.help_tests:
-    ChromeTests.ShowTests()
-    return 0
-
-  if not options.test:
-    parser.error("--test not specified")
-
-  if len(options.test) != 1 and options.gtest_filter:
-    parser.error("--gtest_filter and multiple tests don't make sense together")
-
-  for t in options.test:
-    tests = ChromeTests(options, args, t)
-    ret = tests.Run()
-    if ret: return ret
-  return 0
-
-
-if __name__ == "__main__":
-  sys.exit(_main())
diff --git a/tools/drmemory/scripts/valgrind_test.py b/tools/drmemory/scripts/valgrind_test.py
deleted file mode 100644
index 92960c7..0000000
--- a/tools/drmemory/scripts/valgrind_test.py
+++ /dev/null
@@ -1,487 +0,0 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Runs an exe through Valgrind and puts the intermediate files in a
-directory.
-"""
-
-import datetime
-import glob
-import logging
-import optparse
-import os
-import re
-import shutil
-import stat
-import subprocess
-import sys
-import tempfile
-
-import common
-
-import drmemory_analyze
-
-class BaseTool(object):
-  """Abstract class for running dynamic error detection tools.
-
-  Always subclass this and implement ToolCommand with framework- and
-  tool-specific stuff.
-  """
-
-  def __init__(self):
-    temp_parent_dir = None
-    self.log_parent_dir = ""
-    if common.IsWindows():
-      # gpu process on Windows Vista+ runs at Low Integrity and can only
-      # write to certain directories (http://crbug.com/119131)
-      #
-      # TODO(bruening): if scripts die in middle and don't clean up temp
-      # dir, we'll accumulate files in profile dir.  should remove
-      # really old files automatically.
-      profile = os.getenv("USERPROFILE")
-      if profile:
-        self.log_parent_dir = profile + "\\AppData\\LocalLow\\"
-        if os.path.exists(self.log_parent_dir):
-          self.log_parent_dir = common.NormalizeWindowsPath(self.log_parent_dir)
-          temp_parent_dir = self.log_parent_dir
-    # Generated every time (even when overridden)
-    self.temp_dir = tempfile.mkdtemp(prefix="vg_logs_", dir=temp_parent_dir)
-    self.log_dir = self.temp_dir # overridable by --keep_logs
-    self.option_parser_hooks = []
-    # TODO(glider): we may not need some of the env vars on some of the
-    # platforms.
-    self._env = {
-      "G_SLICE" : "always-malloc",
-      "NSS_DISABLE_UNLOAD" : "1",
-      "NSS_DISABLE_ARENA_FREE_LIST" : "1",
-      "GTEST_DEATH_TEST_USE_FORK": "1",
-    }
-
-  def ToolName(self):
-    raise NotImplementedError, "This method should be implemented " \
-                               "in the tool-specific subclass"
-
-  def Analyze(self, check_sanity=False):
-    raise NotImplementedError, "This method should be implemented " \
-                               "in the tool-specific subclass"
-
-  def RegisterOptionParserHook(self, hook):
-    # Frameworks and tools can add their own flags to the parser.
-    self.option_parser_hooks.append(hook)
-
-  def CreateOptionParser(self):
-    # Defines Chromium-specific flags.
-    self._parser = optparse.OptionParser("usage: %prog [options] <program to "
-                                         "test>")
-    self._parser.disable_interspersed_args()
-    self._parser.add_option("-t", "--timeout",
-                      dest="timeout", metavar="TIMEOUT", default=100000,
-                      help="timeout in seconds for the run (default 100000)")
-    self._parser.add_option("", "--build-dir",
-                            help="the location of the compiler output")
-    self._parser.add_option("", "--source-dir",
-                            help="path to top of source tree for this build"
-                                 "(used to normalize source paths in baseline)")
-    self._parser.add_option("", "--gtest_filter", default="",
-                            help="which test case to run")
-    self._parser.add_option("", "--gtest_repeat",
-                            help="how many times to run each test")
-    self._parser.add_option("", "--gtest_print_time", action="store_true",
-                            default=False,
-                            help="show how long each test takes")
-    self._parser.add_option("", "--ignore_exit_code", action="store_true",
-                            default=False,
-                            help="ignore exit code of the test "
-                                 "(e.g. test failures)")
-    self._parser.add_option("", "--keep_logs", action="store_true",
-                            default=False,
-                            help="store memory tool logs in the <tool>.logs "
-                                 "directory instead of /tmp.\nThis can be "
-                                 "useful for tool developers/maintainers.\n"
-                                 "Please note that the <tool>.logs directory "
-                                 "will be clobbered on tool startup.")
-
-    # To add framework- or tool-specific flags, please add a hook using
-    # RegisterOptionParserHook in the corresponding subclass.
-    # See ValgrindTool for an example.
-    for hook in self.option_parser_hooks:
-      hook(self, self._parser)
-
-  def ParseArgv(self, args):
-    self.CreateOptionParser()
-
-    # self._tool_flags will store those tool flags which we don't parse
-    # manually in this script.
-    self._tool_flags = []
-    known_args = []
-
-    """ We assume that the first argument not starting with "-" is a program
-    name and all the following flags should be passed to the program.
-    TODO(timurrrr): customize optparse instead
-    """
-    while len(args) > 0 and args[0][:1] == "-":
-      arg = args[0]
-      if (arg == "--"):
-        break
-      if self._parser.has_option(arg.split("=")[0]):
-        known_args += [arg]
-      else:
-        self._tool_flags += [arg]
-      args = args[1:]
-
-    if len(args) > 0:
-      known_args += args
-
-    self._options, self._args = self._parser.parse_args(known_args)
-
-    self._timeout = int(self._options.timeout)
-    self._source_dir = self._options.source_dir
-    if self._options.keep_logs:
-      # log_parent_dir has trailing slash if non-empty
-      self.log_dir = self.log_parent_dir + "%s.logs" % self.ToolName()
-      if os.path.exists(self.log_dir):
-        shutil.rmtree(self.log_dir)
-      os.mkdir(self.log_dir)
-      logging.info("Logs are in " + self.log_dir)
-
-    self._ignore_exit_code = self._options.ignore_exit_code
-    if self._options.gtest_filter != "":
-      self._args.append("--gtest_filter=%s" % self._options.gtest_filter)
-    if self._options.gtest_repeat:
-      self._args.append("--gtest_repeat=%s" % self._options.gtest_repeat)
-    if self._options.gtest_print_time:
-      self._args.append("--gtest_print_time")
-
-    return True
-
-  def Setup(self, args):
-    return self.ParseArgv(args)
-
-  def ToolCommand(self):
-    raise NotImplementedError, "This method should be implemented " \
-                               "in the tool-specific subclass"
-
-  def Cleanup(self):
-    # You may override it in the tool-specific subclass
-    pass
-
-  def Execute(self):
-    """ Execute the app to be tested after successful instrumentation.
-    Full execution command-line provided by subclassers via proc."""
-    logging.info("starting execution...")
-    proc = self.ToolCommand()
-    for var in self._env:
-      common.PutEnvAndLog(var, self._env[var])
-    return common.RunSubprocess(proc, self._timeout)
-
-  def RunTestsAndAnalyze(self, check_sanity):
-    exec_retcode = self.Execute()
-    analyze_retcode = self.Analyze(check_sanity)
-
-    if analyze_retcode:
-      logging.error("Analyze failed.")
-      logging.info("Search the log for '[ERROR]' to see the error reports.")
-      return analyze_retcode
-
-    if exec_retcode:
-      if self._ignore_exit_code:
-        logging.info("Test execution failed, but the exit code is ignored.")
-      else:
-        logging.error("Test execution failed.")
-        return exec_retcode
-    else:
-      logging.info("Test execution completed successfully.")
-
-    if not analyze_retcode:
-      logging.info("Analysis completed successfully.")
-
-    return 0
-
-  def Main(self, args, check_sanity, min_runtime_in_seconds):
-    """Call this to run through the whole process: Setup, Execute, Analyze"""
-    start_time = datetime.datetime.now()
-    retcode = -1
-    if self.Setup(args):
-      retcode = self.RunTestsAndAnalyze(check_sanity)
-      shutil.rmtree(self.temp_dir, ignore_errors=True)
-      self.Cleanup()
-    else:
-      logging.error("Setup failed")
-    end_time = datetime.datetime.now()
-    runtime_in_seconds = (end_time - start_time).seconds
-    hours = runtime_in_seconds / 3600
-    seconds = runtime_in_seconds % 3600
-    minutes = seconds / 60
-    seconds = seconds % 60
-    logging.info("elapsed time: %02d:%02d:%02d" % (hours, minutes, seconds))
-    if (min_runtime_in_seconds > 0 and
-        runtime_in_seconds < min_runtime_in_seconds):
-      logging.error("Layout tests finished too quickly. "
-                    "It should have taken at least %d seconds. "
-                    "Something went wrong?" % min_runtime_in_seconds)
-      retcode = -1
-    return retcode
-
-  def Run(self, args, module, min_runtime_in_seconds=0):
-    MODULES_TO_SANITY_CHECK = ["base"]
-
-    check_sanity = module in MODULES_TO_SANITY_CHECK
-    return self.Main(args, check_sanity, min_runtime_in_seconds)
-
-
-class DrMemory(BaseTool):
-  """Dr.Memory
-  Dynamic memory error detector for Windows.
-
-  http://dev.chromium.org/developers/how-tos/using-drmemory
-  It is not very mature at the moment, some things might not work properly.
-  """
-
-  def __init__(self, full_mode, pattern_mode):
-    super(DrMemory, self).__init__()
-    self.full_mode = full_mode
-    self.pattern_mode = pattern_mode
-    self.RegisterOptionParserHook(DrMemory.ExtendOptionParser)
-
-  def ToolName(self):
-    return "drmemory"
-
-  def ExtendOptionParser(self, parser):
-    parser.add_option("", "--suppressions", default=[],
-                      action="append",
-                      help="path to a drmemory suppression file")
-    parser.add_option("", "--follow_python", action="store_true",
-                      default=False, dest="follow_python",
-                      help="Monitor python child processes.  If off, neither "
-                      "python children nor any children of python children "
-                      "will be monitored.")
-    parser.add_option("", "--indirect_pdfium_test", action="store_true",
-                      default=False,
-                      help="set --wrapper rather than running Dr. Memory "
-                      "directly.")
-    parser.add_option("", "--use_debug", action="store_true",
-                      default=False, dest="use_debug",
-                      help="Run Dr. Memory debug build")
-    parser.add_option("", "--trace_children", action="store_true",
-                            default=True,
-                            help="TODO: default value differs from Valgrind")
-
-  def ToolCommand(self):
-    """Get the tool command to run."""
-    # WINHEAP is what Dr. Memory supports as there are issues w/ both
-    # jemalloc (https://github.com/DynamoRIO/drmemory/issues/320) and
-    # tcmalloc (https://github.com/DynamoRIO/drmemory/issues/314)
-    add_env = {
-      "CHROME_ALLOCATOR" : "WINHEAP",
-      "JSIMD_FORCEMMX"   : "1",  # https://github.com/DynamoRIO/drmemory/issues/540
-    }
-    for k,v in add_env.iteritems():
-      logging.info("export %s=%s", k, v)
-      os.putenv(k, v)
-
-    drmem_cmd = os.getenv("DRMEMORY_COMMAND")
-    if not drmem_cmd:
-      raise RuntimeError, "Please set DRMEMORY_COMMAND environment variable " \
-                          "with the path to drmemory.exe"
-    proc = drmem_cmd.split(" ")
-
-    # By default, don't run python (this will exclude python's children as well)
-    # to reduce runtime.  We're not really interested in spending time finding
-    # bugs in the python implementation.
-    # With file-based config we must update the file every time, and
-    # it will affect simultaneous drmem uses by this user.  While file-based
-    # config has many advantages, here we may want this-instance-only
-    # (https://github.com/DynamoRIO/drmemory/issues/334).
-    drconfig_cmd = [ proc[0].replace("drmemory.exe", "drconfig.exe") ]
-    drconfig_cmd += ["-quiet"] # suppress errors about no 64-bit libs
-    run_drconfig = True
-    if self._options.follow_python:
-      logging.info("Following python children")
-      # -unreg fails if not already registered so query for that first
-      query_cmd = drconfig_cmd + ["-isreg", "python.exe"]
-      query_proc = subprocess.Popen(query_cmd, stdout=subprocess.PIPE,
-                                    shell=True)
-      (query_out, query_err) = query_proc.communicate()
-      if re.search("exe not registered", query_out):
-        run_drconfig = False # all set
-      else:
-        drconfig_cmd += ["-unreg", "python.exe"]
-    else:
-      logging.info("Excluding python children")
-      drconfig_cmd += ["-reg", "python.exe", "-norun"]
-    if run_drconfig:
-      drconfig_retcode = common.RunSubprocess(drconfig_cmd, self._timeout)
-      if drconfig_retcode:
-        logging.error("Configuring whether to follow python children failed " \
-                      "with %d.", drconfig_retcode)
-        raise RuntimeError, "Configuring python children failed "
-
-    suppression_count = 0
-    supp_files = self._options.suppressions
-    if self.full_mode:
-      supp_files += [s.replace(".txt", "_full.txt") for s in supp_files]
-    for suppression_file in supp_files:
-      if os.path.exists(suppression_file):
-        suppression_count += 1
-        proc += ["-suppress", common.NormalizeWindowsPath(suppression_file)]
-
-    if not suppression_count:
-      logging.warning("WARNING: NOT USING SUPPRESSIONS!")
-
-    # Un-comment to dump Dr.Memory events on error
-    #proc += ["-dr_ops", "-dumpcore_mask", "-dr_ops", "0x8bff"]
-
-    # Un-comment and comment next line to debug Dr.Memory
-    #proc += ["-dr_ops", "-no_hide"]
-    #proc += ["-dr_ops", "-msgbox_mask", "-dr_ops", "15"]
-    #Proc += ["-dr_ops", "-stderr_mask", "-dr_ops", "15"]
-    # Ensure we see messages about Dr. Memory crashing!
-    proc += ["-dr_ops", "-stderr_mask", "-dr_ops", "12"]
-
-    if self._options.use_debug:
-      proc += ["-debug"]
-
-    proc += ["-logdir", common.NormalizeWindowsPath(self.log_dir)]
-
-    if self.log_parent_dir:
-      # gpu process on Windows Vista+ runs at Low Integrity and can only
-      # write to certain directories (http://crbug.com/119131)
-      symcache_dir = os.path.join(self.log_parent_dir, "drmemory.symcache")
-    elif self._options.build_dir:
-      # The other case is only possible with -t cmdline.
-      # Anyways, if we omit -symcache_dir the -logdir's value is used which
-      # should be fine.
-      symcache_dir = os.path.join(self._options.build_dir, "drmemory.symcache")
-    if symcache_dir:
-      if not os.path.exists(symcache_dir):
-        try:
-          os.mkdir(symcache_dir)
-        except OSError:
-          logging.warning("Can't create symcache dir?")
-      if os.path.exists(symcache_dir):
-        proc += ["-symcache_dir", common.NormalizeWindowsPath(symcache_dir)]
-
-    # Use -no_summary to suppress DrMemory's summary and init-time
-    # notifications.  We generate our own with drmemory_analyze.py.
-    proc += ["-batch", "-no_summary"]
-
-    # Un-comment to disable interleaved output.  Will also suppress error
-    # messages normally printed to stderr.
-    #proc += ["-quiet", "-no_results_to_stderr"]
-
-    proc += ["-callstack_max_frames", "40"]
-
-    # disable leak scan for now
-    proc += ["-no_count_leaks", "-no_leak_scan"]
-
-    # disable warnings about unaddressable prefetches
-    proc += ["-no_check_prefetch"]
-
-    # crbug.com/413215, no heap mismatch check for Windows release build binary
-    if common.IsWindows() and "Release" in self._options.build_dir:
-        proc += ["-no_check_delete_mismatch"]
-
-    # make callstacks easier to read
-    proc += ["-callstack_srcfile_prefix",
-             "build\\src,chromium\\src,crt_build\\self_x86"]
-    proc += ["-callstack_modname_hide",
-             "*drmemory*,chrome.dll"]
-
-    boring_callers = common.BoringCallers(mangled=False, use_re_wildcards=False)
-    # TODO(timurrrr): In fact, we want "starting from .." instead of "below .."
-    proc += ["-callstack_truncate_below", ",".join(boring_callers)]
-
-    if self.pattern_mode:
-      proc += ["-pattern", "0xf1fd", "-no_count_leaks", "-redzone_size", "0x20"]
-    elif not self.full_mode:
-      proc += ["-light"]
-
-    proc += self._tool_flags
-
-    # Dr.Memory requires -- to separate tool flags from the executable name.
-    proc += ["--"]
-
-    if self._options.indirect_pdfium_test:
-      wrapper = " ".join(proc)
-      logging.info("pdfium wrapper = " + wrapper)
-      proc = self._args
-      proc += ["--wrapper", wrapper]
-      return proc
-
-    # Note that self._args begins with the name of the exe to be run.
-    self._args[0] = common.NormalizeWindowsPath(self._args[0])
-    proc += self._args
-    return proc
-
-  def CreateBrowserWrapper(self, command):
-    os.putenv("BROWSER_WRAPPER", command)
-
-  def Analyze(self, check_sanity=False):
-    # Use one analyzer for all the log files to avoid printing duplicate reports
-    #
-    # TODO(timurrrr): unify this with Valgrind and other tools when we have
-    # https://github.com/DynamoRIO/drmemory/issues/684
-    analyzer = drmemory_analyze.DrMemoryAnalyzer()
-
-    ret = 0
-    if not self._options.indirect_pdfium_test:
-      filenames = glob.glob(self.log_dir + "/*/results.txt")
-
-      ret = analyzer.Report(filenames, None, check_sanity)
-    else:
-      testcases = glob.glob(self.log_dir + "/testcase.*.logs")
-      # If we have browser wrapper, the per-test logdirs are named as
-      # "testcase.wrapper_PID.name".
-      # Let's extract the list of wrapper_PIDs and name it ppids.
-      # NOTE: ppids may contain '_', i.e. they are not ints!
-      ppids = set([f.split(".")[-2] for f in testcases])
-
-      for ppid in ppids:
-        testcase_name = None
-        try:
-          f = open("%s/testcase.%s.name" % (self.log_dir, ppid))
-          testcase_name = f.read().strip()
-          f.close()
-        except IOError:
-          pass
-        print "====================================================="
-        print " Below is the report for drmemory wrapper PID=%s." % ppid
-        if testcase_name:
-          print " It was used while running the `%s` test." % testcase_name
-        else:
-          # TODO(timurrrr): hm, the PID line is suppressed on Windows...
-          print " You can find the corresponding test"
-          print " by searching the above log for 'PID=%s'" % ppid
-        sys.stdout.flush()
-        ppid_filenames = glob.glob("%s/testcase.%s.logs/*/results.txt" %
-                                   (self.log_dir, ppid))
-        ret |= analyzer.Report(ppid_filenames, testcase_name, False)
-        print "====================================================="
-        sys.stdout.flush()
-
-    logging.info("Please see http://dev.chromium.org/developers/how-tos/"
-                 "using-drmemory for the info on Dr. Memory")
-    return ret
-
-
-class ToolFactory:
-  def Create(self, tool_name):
-    if tool_name == "drmemory" or tool_name == "drmemory_light":
-      # TODO(timurrrr): remove support for "drmemory" when buildbots are
-      # switched to drmemory_light OR make drmemory==drmemory_full the default
-      # mode when the tool is mature enough.
-      return DrMemory(False, False)
-    if tool_name == "drmemory_full":
-      return DrMemory(True, False)
-    if tool_name == "drmemory_pattern":
-      return DrMemory(False, True)
-    try:
-      platform_name = common.PlatformNames()[0]
-    except common.NotImplementedError:
-      platform_name = sys.platform + "(Unknown)"
-    raise RuntimeError, "Unknown tool (tool=%s, platform=%s)" % (tool_name,
-                                                                 platform_name)
-
-def CreateTool(tool):
-  return ToolFactory().Create(tool)
diff --git a/tools/drmemory/suppressions.txt b/tools/drmemory/suppressions.txt
deleted file mode 100644
index 2ad8236..0000000
--- a/tools/drmemory/suppressions.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-# This file contains suppressions for the Dr.Memory tool, see
-# http://dev.chromium.org/developers/how-tos/using-drmemory
-
-
-# Intended alloc failure
-WARNING
-name=unittests:fxcrt.FX_AllocOverflow
-drmemorylib.dll!replace_calloc
-...
-*!fxcrt_FX_*AllocOverflow*_Test::TestBody
-
-# DrMem-i#471: simple floating register copy without meaningful usage
-UNINITIALIZED READ
-name=embeddertests:DrM-i#471
-*!v8::internal::RegisterValues::GetDoubleRegister
-*!v8::internal::FrameDescription::GetDoubleRegister
-*!v8::internal::Deoptimizer::CopyDoubleRegisters
-*!v8::internal::Deoptimizer::DoComputeCompiledStubFrame
-*!v8::internal::Deoptimizer::DoComputeOutputFrames
-*!v8::internal::Deoptimizer::ComputeOutputFrames
-*!v8::internal::`anonymous namespace'::Invoke
-*!v8::internal::Execution::Call
-
-# PDFium-i#287: new/delete[] mismatch
-INVALID HEAP ARGUMENT
-name=i#287:new-delete-array-mismatch
-drmemorylib.dll!replace_operator_delete_array
-*!NumberlikeArray<>::~NumberlikeArray<>
diff --git a/xfa/fde/cfde_path.cpp b/xfa/fde/cfde_path.cpp
index 23aad50..5e6cf5c 100644
--- a/xfa/fde/cfde_path.cpp
+++ b/xfa/fde/cfde_path.cpp
@@ -6,70 +6,32 @@
 
 #include "xfa/fde/cfde_path.h"
 
+#include "third_party/base/stl_util.h"
 #include "xfa/fde/fde_object.h"
 
-bool CFDE_Path::StartFigure() {
-  return CloseFigure();
-}
-
-bool CFDE_Path::CloseFigure() {
-  FX_PATHPOINT* pPoint = GetLastPoint();
-  if (pPoint)
-    pPoint->m_Flag |= FXPT_CLOSEFIGURE;
-  return true;
-}
-
-FX_PATHPOINT* CFDE_Path::GetLastPoint(int32_t iCount) const {
-  if (iCount < 1)
-    return nullptr;
-
-  int32_t iPoints = m_Path.GetPointCount();
-  if (iCount > iPoints)
-    return nullptr;
-  return m_Path.GetPoints() + iPoints - iCount;
+void CFDE_Path::CloseFigure() {
+  m_Path.ClosePath();
 }
 
 bool CFDE_Path::FigureClosed() const {
-  FX_PATHPOINT* pPoint = GetLastPoint();
-  return pPoint ? (pPoint->m_Flag & FXPT_CLOSEFIGURE) : true;
+  const std::vector<FX_PATHPOINT>& points = m_Path.GetPoints();
+  return points.empty() ? true : points.back().m_CloseFigure;
 }
 
-FX_PATHPOINT* CFDE_Path::AddPoints(int32_t iCount) {
-  if (iCount < 1)
-    return nullptr;
-
-  int32_t iPoints = m_Path.GetPointCount();
-  m_Path.AddPointCount(iCount);
-  return m_Path.GetPoints() + iPoints;
+void CFDE_Path::MoveTo(const CFX_PointF& point) {
+  m_Path.AppendPoint(point, FXPT_TYPE::MoveTo, false);
 }
 
-void CFDE_Path::MoveTo(FX_FLOAT fx, FX_FLOAT fy) {
-  FX_PATHPOINT* pPoint = AddPoints(1);
-  pPoint->m_PointX = fx;
-  pPoint->m_PointY = fy;
-  pPoint->m_Flag = FXPT_MOVETO;
-}
-
-void CFDE_Path::LineTo(FX_FLOAT fx, FX_FLOAT fy) {
-  FX_PATHPOINT* pPoint = AddPoints(1);
-  pPoint->m_PointX = fx;
-  pPoint->m_PointY = fy;
-  pPoint->m_Flag = FXPT_LINETO;
+void CFDE_Path::LineTo(const CFX_PointF& point) {
+  m_Path.AppendPoint(point, FXPT_TYPE::LineTo, false);
 }
 
 void CFDE_Path::BezierTo(const CFX_PointF& p1,
                          const CFX_PointF& p2,
                          const CFX_PointF& p3) {
-  FX_PATHPOINT* p = AddPoints(3);
-  p[0].m_PointX = p1.x;
-  p[0].m_PointY = p1.y;
-  p[0].m_Flag = FXPT_BEZIERTO;
-  p[1].m_PointX = p2.x;
-  p[1].m_PointY = p2.y;
-  p[1].m_Flag = FXPT_BEZIERTO;
-  p[2].m_PointX = p3.x;
-  p[2].m_PointY = p3.y;
-  p[2].m_Flag = FXPT_BEZIERTO;
+  m_Path.AppendPoint(p1, FXPT_TYPE::BezierTo, false);
+  m_Path.AppendPoint(p2, FXPT_TYPE::BezierTo, false);
+  m_Path.AppendPoint(p3, FXPT_TYPE::BezierTo, false);
 }
 
 void CFDE_Path::ArcTo(bool bStart,
@@ -90,6 +52,7 @@
     else
       alpha -= 2 * FX_PI;
   }
+
   FX_FLOAT half_delta = (beta - alpha) / 2;
   FX_FLOAT bcp = 4.0f / 3 * (1 - FXSYS_cos(half_delta)) / FXSYS_sin(half_delta);
   FX_FLOAT sin_alpha = FXSYS_sin(alpha);
@@ -106,39 +69,38 @@
            CFX_PointF(cx + rx * cos_beta, cy + ry * sin_beta));
 }
 
-void CFDE_Path::AddBezier(const CFX_PointsF& points) {
-  if (points.GetSize() != 4)
+void CFDE_Path::AddBezier(const std::vector<CFX_PointF>& points) {
+  if (points.size() != 4)
     return;
 
-  const CFX_PointF* p = points.GetData();
-  MoveTo(p[0]);
-  BezierTo(p[1], p[2], p[3]);
+  MoveTo(points[0]);
+  BezierTo(points[1], points[2], points[3]);
 }
 
-void CFDE_Path::AddBeziers(const CFX_PointsF& points) {
-  int32_t iCount = points.GetSize();
+void CFDE_Path::AddBeziers(const std::vector<CFX_PointF>& points) {
+  int32_t iCount = points.size();
   if (iCount < 4)
     return;
 
-  const CFX_PointF* p = points.GetData();
+  const CFX_PointF* p = points.data();
   const CFX_PointF* pEnd = p + iCount;
   MoveTo(p[0]);
   for (++p; p <= pEnd - 3; p += 3)
     BezierTo(p[0], p[1], p[2]);
 }
 
-void CFDE_Path::GetCurveTangents(const CFX_PointsF& points,
-                                 CFX_PointsF& tangents,
+void CFDE_Path::GetCurveTangents(const std::vector<CFX_PointF>& points,
+                                 std::vector<CFX_PointF>* tangents,
                                  bool bClosed,
                                  FX_FLOAT fTension) const {
-  int32_t iCount = points.GetSize();
-  tangents.SetSize(iCount);
+  int32_t iCount = pdfium::CollectionSize<int32_t>(points);
+  tangents->resize(iCount);
   if (iCount < 3)
     return;
 
   FX_FLOAT fCoefficient = fTension / 3.0f;
-  const CFX_PointF* pPoints = points.GetData();
-  CFX_PointF* pTangents = tangents.GetData();
+  const CFX_PointF* pPoints = points.data();
+  CFX_PointF* pTangents = tangents->data();
   for (int32_t i = 0; i < iCount; ++i) {
     int32_t r = i + 1;
     int32_t s = i - 1;
@@ -152,17 +114,17 @@
   }
 }
 
-void CFDE_Path::AddCurve(const CFX_PointsF& points,
+void CFDE_Path::AddCurve(const std::vector<CFX_PointF>& points,
                          bool bClosed,
                          FX_FLOAT fTension) {
-  int32_t iLast = points.GetUpperBound();
+  int32_t iLast = pdfium::CollectionSize<int32_t>(points) - 1;
   if (iLast < 1)
     return;
 
-  CFX_PointsF tangents;
-  GetCurveTangents(points, tangents, bClosed, fTension);
-  const CFX_PointF* pPoints = points.GetData();
-  CFX_PointF* pTangents = tangents.GetData();
+  std::vector<CFX_PointF> tangents;
+  GetCurveTangents(points, &tangents, bClosed, fTension);
+  const CFX_PointF* pPoints = points.data();
+  CFX_PointF* pTangents = tangents.data();
   MoveTo(pPoints[0]);
   for (int32_t i = 0; i < iLast; ++i) {
     BezierTo(CFX_PointF(pPoints[i].x + pTangents[i].x,
@@ -193,9 +155,9 @@
 }
 
 void CFDE_Path::AddLine(const CFX_PointF& pt1, const CFX_PointF& pt2) {
-  FX_PATHPOINT* pLast = GetLastPoint();
-  if (!pLast || FXSYS_fabs(pLast->m_PointX - pt1.x) > 0.001 ||
-      FXSYS_fabs(pLast->m_PointY - pt1.y) > 0.001) {
+  std::vector<FX_PATHPOINT>& points = m_Path.GetPoints();
+  if (points.empty() || FXSYS_fabs(points.back().m_Point.x - pt1.x) > 0.001 ||
+      FXSYS_fabs(points.back().m_Point.y - pt1.y) > 0.001) {
     MoveTo(pt1);
   }
   LineTo(pt2);
@@ -205,22 +167,21 @@
   if (!pSrc)
     return;
 
-  int32_t iCount = pSrc->m_Path.GetPointCount();
-  if (iCount < 1)
+  if (pSrc->m_Path.GetPoints().empty())
     return;
   if (bConnect)
-    LineTo(pSrc->m_Path.GetPointX(0), pSrc->m_Path.GetPointY(0));
+    LineTo(pSrc->m_Path.GetPoint(0));
 
   m_Path.Append(&pSrc->m_Path, nullptr);
 }
 
-void CFDE_Path::AddPolygon(const CFX_PointsF& points) {
-  int32_t iCount = points.GetSize();
+void CFDE_Path::AddPolygon(const std::vector<CFX_PointF>& points) {
+  size_t iCount = points.size();
   if (iCount < 2)
     return;
 
   AddLines(points);
-  const CFX_PointF* p = points.GetData();
+  const CFX_PointF* p = points.data();
   if (FXSYS_fabs(p[0].x - p[iCount - 1].x) < 0.01f ||
       FXSYS_fabs(p[0].y - p[iCount - 1].y) < 0.01f) {
     LineTo(p[0]);
@@ -228,12 +189,12 @@
   CloseFigure();
 }
 
-void CFDE_Path::AddLines(const CFX_PointsF& points) {
-  int32_t iCount = points.GetSize();
+void CFDE_Path::AddLines(const std::vector<CFX_PointF>& points) {
+  size_t iCount = points.size();
   if (iCount < 2)
     return;
 
-  const CFX_PointF* p = points.GetData();
+  const CFX_PointF* p = points.data();
   const CFX_PointF* pEnd = p + iCount;
   MoveTo(p[0]);
   for (++p; p < pEnd; ++p)
@@ -248,16 +209,16 @@
   CloseFigure();
 }
 
-void CFDE_Path::GetBBox(CFX_RectF& bbox) const {
+CFX_RectF CFDE_Path::GetBBox() const {
   CFX_FloatRect rect = m_Path.GetBoundingBox();
-  bbox.Set(rect.left, rect.top, rect.Width(), rect.Height());
+  CFX_RectF bbox = CFX_RectF(rect.left, rect.top, rect.Width(), rect.Height());
   bbox.Normalize();
+  return bbox;
 }
 
-void CFDE_Path::GetBBox(CFX_RectF& bbox,
-                        FX_FLOAT fLineWidth,
-                        FX_FLOAT fMiterLimit) const {
+CFX_RectF CFDE_Path::GetBBox(FX_FLOAT fLineWidth, FX_FLOAT fMiterLimit) const {
   CFX_FloatRect rect = m_Path.GetBoundingBox(fLineWidth, fMiterLimit);
-  bbox.Set(rect.left, rect.top, rect.Width(), rect.Height());
+  CFX_RectF bbox = CFX_RectF(rect.left, rect.top, rect.Width(), rect.Height());
   bbox.Normalize();
+  return bbox;
 }
diff --git a/xfa/fde/cfde_path.h b/xfa/fde/cfde_path.h
index 936a5c8..99ff4d3 100644
--- a/xfa/fde/cfde_path.h
+++ b/xfa/fde/cfde_path.h
@@ -7,34 +7,31 @@
 #ifndef XFA_FDE_CFDE_PATH_H_
 #define XFA_FDE_CFDE_PATH_H_
 
+#include <vector>
+
 #include "core/fxge/cfx_pathdata.h"
 #include "core/fxge/cfx_renderdevice.h"
 
 class CFDE_Path {
  public:
-  bool StartFigure();
-  bool CloseFigure();
+  void CloseFigure();
 
-  void AddBezier(const CFX_PointsF& points);
-  void AddBeziers(const CFX_PointsF& points);
-  void AddCurve(const CFX_PointsF& points,
+  void AddBezier(const std::vector<CFX_PointF>& points);
+  void AddBeziers(const std::vector<CFX_PointF>& points);
+  void AddCurve(const std::vector<CFX_PointF>& points,
                 bool bClosed,
                 FX_FLOAT fTension = 0.5f);
   void AddEllipse(const CFX_RectF& rect);
-  void AddLines(const CFX_PointsF& points);
+  void AddLines(const std::vector<CFX_PointF>& points);
   void AddLine(const CFX_PointF& pt1, const CFX_PointF& pt2);
   void AddPath(const CFDE_Path* pSrc, bool bConnect);
-  void AddPolygon(const CFX_PointsF& points);
+  void AddPolygon(const std::vector<CFX_PointF>& points);
   void AddRectangle(const CFX_RectF& rect);
-  void GetBBox(CFX_RectF& bbox) const;
-  void GetBBox(CFX_RectF& bbox,
-               FX_FLOAT fLineWidth,
-               FX_FLOAT fMiterLimit) const;
-  FX_PATHPOINT* AddPoints(int32_t iCount);
-  FX_PATHPOINT* GetLastPoint(int32_t iCount = 1) const;
+
+  CFX_RectF GetBBox() const;
+  CFX_RectF GetBBox(FX_FLOAT fLineWidth, FX_FLOAT fMiterLimit) const;
+
   bool FigureClosed() const;
-  void MoveTo(FX_FLOAT fx, FX_FLOAT fy);
-  void LineTo(FX_FLOAT fx, FX_FLOAT fy);
   void BezierTo(const CFX_PointF& p1,
                 const CFX_PointF& p2,
                 const CFX_PointF& p3);
@@ -42,10 +39,11 @@
              const CFX_RectF& rect,
              FX_FLOAT startAngle,
              FX_FLOAT endAngle);
-  void MoveTo(const CFX_PointF& p0) { MoveTo(p0.x, p0.y); }
-  void LineTo(const CFX_PointF& p1) { LineTo(p1.x, p1.y); }
-  void GetCurveTangents(const CFX_PointsF& points,
-                        CFX_PointsF& tangents,
+  void MoveTo(const CFX_PointF& p);
+  void LineTo(const CFX_PointF& p);
+
+  void GetCurveTangents(const std::vector<CFX_PointF>& points,
+                        std::vector<CFX_PointF>* tangents,
                         bool bClosed,
                         FX_FLOAT fTension) const;
   CFX_PathData m_Path;
diff --git a/xfa/fde/cfde_txtedtengine.cpp b/xfa/fde/cfde_txtedtengine.cpp
index 7ef6b3f..a61f6ab 100644
--- a/xfa/fde/cfde_txtedtengine.cpp
+++ b/xfa/fde/cfde_txtedtengine.cpp
@@ -69,7 +69,6 @@
       m_nFirstLineEnd(FDE_TXTEDIT_LINEEND_Auto),
       m_bAutoLineEnd(true),
       m_wLineEnd(kUnicodeParagraphSeparator) {
-  FXSYS_memset(&m_rtCaret, 0, sizeof(CFX_RectF));
   m_bAutoLineEnd = (m_Param.nLineEnd == FDE_TXTEDIT_LINEEND_Auto);
 }
 
@@ -663,14 +662,14 @@
 void CFDE_TxtEdtEngine::EndLayout() {
   UpdatePages();
   int32_t nLength = GetTextLength();
-  if (m_nCaret > nLength) {
+  if (m_nCaret > nLength)
     m_nCaret = nLength;
-  }
+
   int32_t nIndex = m_nCaret;
-  if (!m_bBefore) {
+  if (!m_bBefore)
     nIndex--;
-  }
-  m_rtCaret.Set(0, 0, 1, m_Param.fFontSize);
+
+  m_rtCaret = CFX_RectF(0, 0, 1, m_Param.fFontSize);
   Unlock();
 }
 
@@ -1381,12 +1380,11 @@
   pTextOut->SetLineSpace(m_Param.fLineSpace);
   pTextOut->SetFont(m_Param.pFont);
   pTextOut->SetFontSize(m_Param.fFontSize);
-  CFX_RectF rcText;
-  FXSYS_memset(&rcText, 0, sizeof(rcText));
   uint32_t dwStyle = 0;
   if (!(m_Param.dwMode & FDE_TEXTEDITMODE_MultiLines))
     dwStyle |= FDE_TTOSTYLE_SingleLine;
 
+  CFX_RectF rcText;
   if (m_Param.dwMode & FDE_TEXTEDITMODE_AutoLineWrap) {
     dwStyle |= FDE_TTOSTYLE_LineWrap;
     rcText.width = m_Param.fPlateWidth;
diff --git a/xfa/fde/cfde_txtedtpage.cpp b/xfa/fde/cfde_txtedtpage.cpp
index 238dba2..8b58b2b 100644
--- a/xfa/fde/cfde_txtedtpage.cpp
+++ b/xfa/fde/cfde_txtedtpage.cpp
@@ -9,6 +9,7 @@
 #include <algorithm>
 
 #include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
 #include "xfa/fde/cfde_txtedtbuf.h"
 #include "xfa/fde/cfde_txtedtengine.h"
 #include "xfa/fde/cfde_txtedtparag.h"
@@ -30,7 +31,6 @@
 
 CFDE_TxtEdtPage::CFDE_TxtEdtPage(CFDE_TxtEdtEngine* pEngine, int32_t nPageIndex)
     : m_pEditEngine(pEngine),
-      m_PieceMassArr(100),
       m_pBgnParag(nullptr),
       m_pEndParag(nullptr),
       m_nRefCount(0),
@@ -38,15 +38,9 @@
       m_nCharCount(0),
       m_nPageIndex(nPageIndex),
       m_bLoaded(false) {
-  FXSYS_memset(&m_rtPage, 0, sizeof(CFX_RectF));
-  FXSYS_memset(&m_rtPageMargin, 0, sizeof(CFX_RectF));
-  FXSYS_memset(&m_rtPageContents, 0, sizeof(CFX_RectF));
-  FXSYS_memset(&m_rtPageCanvas, 0, sizeof(CFX_RectF));
 }
 
-CFDE_TxtEdtPage::~CFDE_TxtEdtPage() {
-  m_PieceMassArr.RemoveAll(true);
-}
+CFDE_TxtEdtPage::~CFDE_TxtEdtPage() {}
 
 CFDE_TxtEdtEngine* CFDE_TxtEdtPage::GetEngine() const {
   return m_pEditEngine;
@@ -56,25 +50,23 @@
   return FDE_VISUALOBJ_Text;
 }
 
-void CFDE_TxtEdtPage::GetRect(FDE_TEXTEDITPIECE* hVisualObj, CFX_RectF& rt) {}
+CFX_RectF CFDE_TxtEdtPage::GetRect(const FDE_TEXTEDITPIECE& hVisualObj) {
+  return CFX_RectF();
+}
 
 int32_t CFDE_TxtEdtPage::GetCharRect(int32_t nIndex,
                                      CFX_RectF& rect,
                                      bool bBBox) const {
   ASSERT(m_nRefCount > 0);
   ASSERT(nIndex >= 0 && nIndex < m_nCharCount);
-  if (m_nRefCount < 1) {
+  if (m_nRefCount < 1)
     return 0;
-  }
-  int32_t nCount = m_PieceMassArr.GetSize();
-  for (int32_t i = 0; i < nCount; i++) {
-    const FDE_TEXTEDITPIECE* pPiece = m_PieceMassArr.GetPtrAt(i);
-    if (nIndex >= pPiece->nStart &&
-        nIndex < (pPiece->nStart + pPiece->nCount)) {
-      CFX_RectFArray rectArr;
-      m_pTextSet->GetCharRects(pPiece, rectArr, bBBox);
-      rect = rectArr[nIndex - pPiece->nStart];
-      return pPiece->nBidiLevel;
+
+  for (const auto& piece : m_Pieces) {
+    if (nIndex >= piece.nStart && nIndex < piece.nStart + piece.nCount) {
+      std::vector<CFX_RectF> rectArr = m_pTextSet->GetCharRects(&piece, bBBox);
+      rect = rectArr[nIndex - piece.nStart];
+      return piece.nBidiLevel;
     }
   }
   ASSERT(0);
@@ -84,14 +76,14 @@
 int32_t CFDE_TxtEdtPage::GetCharIndex(const CFX_PointF& fPoint, bool& bBefore) {
   CFX_PointF ptF = fPoint;
   NormalizePt2Rect(ptF, m_rtPageContents, kTolerance);
-  int32_t nCount = m_PieceMassArr.GetSize();
+  int32_t nCount = pdfium::CollectionSize<int32_t>(m_Pieces);
   CFX_RectF rtLine;
   int32_t nBgn = 0;
   int32_t nEnd = 0;
   bool bInLine = false;
   int32_t i = 0;
   for (i = 0; i < nCount; i++) {
-    const FDE_TEXTEDITPIECE* pPiece = m_PieceMassArr.GetPtrAt(i);
+    const FDE_TEXTEDITPIECE* pPiece = &m_Pieces[i];
     if (!bInLine &&
         (pPiece->rtPiece.top <= ptF.y && pPiece->rtPiece.bottom() > ptF.y)) {
       nBgn = nEnd = i;
@@ -110,12 +102,11 @@
   int32_t nCaret = 0;
   FDE_TEXTEDITPIECE* pPiece = nullptr;
   for (i = nBgn; i <= nEnd; i++) {
-    pPiece = m_PieceMassArr.GetPtrAt(i);
+    pPiece = &m_Pieces[i];
     nCaret = m_nPageStart + pPiece->nStart;
     if (pPiece->rtPiece.Contains(ptF)) {
-      CFX_RectFArray rectArr;
-      m_pTextSet->GetCharRects(pPiece, rectArr, false);
-      int32_t nRtCount = rectArr.GetSize();
+      std::vector<CFX_RectF> rectArr = m_pTextSet->GetCharRects(pPiece, false);
+      int32_t nRtCount = pdfium::CollectionSize<int32_t>(rectArr);
       for (int32_t j = 0; j < nRtCount; j++) {
         if (rectArr[j].Contains(ptF)) {
           nCaret = m_nPageStart + pPiece->nStart + j;
@@ -161,17 +152,12 @@
                                        CFX_RectF* pBBox) const {
   pCharPos = FX_Alloc(FXTEXT_CHARPOS, m_nCharCount);
   int32_t nCharPosCount = 0;
-  FDE_TEXTEDITPIECE* pPiece = nullptr;
-  int32_t nVisualObjCount = m_PieceMassArr.GetSize();
   FXTEXT_CHARPOS* pos = pCharPos;
-  CFX_RectF rtObj;
-  for (int32_t i = 0; i < nVisualObjCount; i++) {
-    pPiece = m_PieceMassArr.GetPtrAt(i);
-    m_pTextSet->GetRect(pPiece, rtObj);
-    if (!rtClip.IntersectWith(rtObj)) {
+  for (const auto& piece : m_Pieces) {
+    if (!rtClip.IntersectWith(m_pTextSet->GetRect(piece)))
       continue;
-    }
-    int32_t nCount = m_pTextSet->GetDisplayPos(pPiece, pos, false);
+
+    int32_t nCount = m_pTextSet->GetDisplayPos(piece, pos, false);
     nCharPosCount += nCount;
     pos += nCount;
   }
@@ -184,42 +170,39 @@
   return nCharPosCount;
 }
 
-void CFDE_TxtEdtPage::CalcRangeRectArray(int32_t nStart,
-                                         int32_t nCount,
-                                         CFX_RectFArray& RectFArr) const {
-  int32_t nPieceCount = m_PieceMassArr.GetSize();
+void CFDE_TxtEdtPage::CalcRangeRectArray(
+    int32_t nStart,
+    int32_t nCount,
+    std::vector<CFX_RectF>* pRectFArr) const {
   int32_t nEnd = nStart + nCount - 1;
   bool bInRange = false;
-  for (int32_t i = 0; i < nPieceCount; i++) {
-    FDE_TEXTEDITPIECE* piece = m_PieceMassArr.GetPtrAt(i);
+  for (const auto& piece : m_Pieces) {
     if (!bInRange) {
-      if (nStart >= piece->nStart && nStart < (piece->nStart + piece->nCount)) {
-        int32_t nRangeEnd = piece->nCount - 1;
+      if (nStart >= piece.nStart && nStart < piece.nStart + piece.nCount) {
+        int32_t nRangeEnd = piece.nCount - 1;
         bool bEnd = false;
-        if (nEnd >= piece->nStart && nEnd < (piece->nStart + piece->nCount)) {
-          nRangeEnd = nEnd - piece->nStart;
+        if (nEnd >= piece.nStart && nEnd < piece.nStart + piece.nCount) {
+          nRangeEnd = nEnd - piece.nStart;
           bEnd = true;
         }
-        CFX_RectFArray rcArr;
-        m_pTextSet->GetCharRects(piece, rcArr, false);
-        CFX_RectF rectPiece = rcArr[nStart - piece->nStart];
+        std::vector<CFX_RectF> rcArr = m_pTextSet->GetCharRects(&piece, false);
+        CFX_RectF rectPiece = rcArr[nStart - piece.nStart];
         rectPiece.Union(rcArr[nRangeEnd]);
-        RectFArr.Add(rectPiece);
-        if (bEnd) {
+        pRectFArr->push_back(rectPiece);
+        if (bEnd)
           return;
-        }
+
         bInRange = true;
       }
     } else {
-      if (nEnd >= piece->nStart && nEnd < (piece->nStart + piece->nCount)) {
-        CFX_RectFArray rcArr;
-        m_pTextSet->GetCharRects(piece, rcArr, false);
+      if (nEnd >= piece.nStart && nEnd < piece.nStart + piece.nCount) {
+        std::vector<CFX_RectF> rcArr = m_pTextSet->GetCharRects(&piece, false);
         CFX_RectF rectPiece = rcArr[0];
-        rectPiece.Union(rcArr[nEnd - piece->nStart]);
-        RectFArr.Add(rectPiece);
+        rectPiece.Union(rcArr[nEnd - piece.nStart]);
+        pRectFArr->push_back(rectPiece);
         return;
       }
-      RectFArr.Add(piece->rtPiece);
+      pRectFArr->push_back(piece.rtPiece);
     }
   }
 }
@@ -290,7 +273,7 @@
   if (!m_pTextSet)
     m_pTextSet = pdfium::MakeUnique<CFDE_TxtEdtTextSet>(this);
 
-  m_PieceMassArr.RemoveAll(true);
+  m_Pieces.clear();
   uint32_t dwBreakStatus = FX_TXTBREAK_None;
   int32_t nPieceStart = 0;
 
@@ -364,7 +347,7 @@
           m_rtPageContents.Union(TxtEdtPiece.rtPiece);
         }
         nPieceStart += TxtEdtPiece.nCount;
-        m_PieceMassArr.Add(TxtEdtPiece);
+        m_Pieces.push_back(TxtEdtPiece);
         for (int32_t k = 0; k < TxtEdtPiece.nCount; k++) {
           CFX_Char* ptc = pPiece->GetCharPtr(k);
           m_CharWidths[TxtEdtPiece.nStart + k] = ptc->m_iCharWidth;
@@ -395,19 +378,15 @@
       }
     }
     FX_FLOAT fOffset = m_rtPageContents.left - fDelta;
-    int32_t nCount = m_PieceMassArr.GetSize();
-    for (int32_t i = 0; i < nCount; i++) {
-      FDE_TEXTEDITPIECE* pPiece = m_PieceMassArr.GetPtrAt(i);
-      pPiece->rtPiece.Offset(-fOffset, 0.0f);
-    }
+    for (auto& piece : m_Pieces)
+      piece.rtPiece.Offset(-fOffset, 0.0f);
+
     m_rtPageContents.Offset(-fOffset, 0.0f);
   }
   if (m_pEditEngine->GetEditParams()->dwLayoutStyles &
       FDE_TEXTEDITLAYOUT_LastLineHeight) {
     m_rtPageContents.height -= pParams->fLineSpace - pParams->fFontSize;
-    int32_t nCount = m_PieceMassArr.GetSize();
-    FDE_TEXTEDITPIECE* pPiece = m_PieceMassArr.GetPtrAt(nCount - 1);
-    pPiece->rtPiece.height = pParams->fFontSize;
+    m_Pieces.back().rtPiece.height = pParams->fFontSize;
   }
   m_nRefCount = 1;
   m_bLoaded = true;
@@ -420,7 +399,7 @@
   if (m_nRefCount != 0)
     return;
 
-  m_PieceMassArr.RemoveAll(false);
+  m_Pieces.clear();
   m_pTextSet.reset();
   m_CharWidths.clear();
   if (m_pBgnParag) {
@@ -439,7 +418,7 @@
 }
 
 FX_POSITION CFDE_TxtEdtPage::GetFirstPosition() {
-  if (m_PieceMassArr.GetSize() < 1)
+  if (m_Pieces.empty())
     return nullptr;
   return (FX_POSITION)1;
 }
@@ -452,20 +431,20 @@
   }
   int32_t nPos = (int32_t)(uintptr_t)pos;
   pVisualSet = m_pTextSet.get();
-  if (nPos + 1 > m_PieceMassArr.GetSize()) {
+  if (nPos + 1 > pdfium::CollectionSize<int32_t>(m_Pieces))
     pos = nullptr;
-  } else {
+  else
     pos = (FX_POSITION)(uintptr_t)(nPos + 1);
-  }
-  return m_PieceMassArr.GetPtrAt(nPos - 1);
+
+  return &m_Pieces[nPos - 1];
 }
 
 FX_WCHAR CFDE_TxtEdtPage::GetChar(const FDE_TEXTEDITPIECE* pIdentity,
                                   int32_t index) const {
   int32_t nIndex = m_nPageStart + pIdentity->nStart + index;
-  if (nIndex != m_pIter->GetAt()) {
+  if (nIndex != m_pIter->GetAt())
     m_pIter->SetAt(nIndex);
-  }
+
   FX_WCHAR wChar = m_pIter->GetChar();
   m_pIter->Next();
   return wChar;
@@ -480,17 +459,15 @@
 void CFDE_TxtEdtPage::NormalizePt2Rect(CFX_PointF& ptF,
                                        const CFX_RectF& rtF,
                                        FX_FLOAT fTolerance) const {
-  if (rtF.Contains(ptF.x, ptF.y)) {
+  if (rtF.Contains(ptF))
     return;
-  }
-  if (ptF.x < rtF.left) {
+  if (ptF.x < rtF.left)
     ptF.x = rtF.left;
-  } else if (ptF.x >= rtF.right()) {
+  else if (ptF.x >= rtF.right())
     ptF.x = rtF.right() - fTolerance;
-  }
-  if (ptF.y < rtF.top) {
+
+  if (ptF.y < rtF.top)
     ptF.y = rtF.top;
-  } else if (ptF.y >= rtF.bottom()) {
+  else if (ptF.y >= rtF.bottom())
     ptF.y = rtF.bottom() - fTolerance;
-  }
 }
diff --git a/xfa/fde/cfde_txtedtpage.h b/xfa/fde/cfde_txtedtpage.h
index 5cb4501..63ec7e7 100644
--- a/xfa/fde/cfde_txtedtpage.h
+++ b/xfa/fde/cfde_txtedtpage.h
@@ -7,6 +7,7 @@
 #ifndef XFA_FDE_CFDE_TXTEDTPAGE_H_
 #define XFA_FDE_CFDE_TXTEDTPAGE_H_
 
+#include <deque>
 #include <memory>
 #include <vector>
 
@@ -30,7 +31,7 @@
   int32_t GetCharIndex(const CFX_PointF& fPoint, bool& bBefore) override;
   void CalcRangeRectArray(int32_t nStart,
                           int32_t nCount,
-                          CFX_RectFArray& RectFArr) const override;
+                          std::vector<CFX_RectF>* RectFArr) const override;
   int32_t SelectWord(const CFX_PointF& fPoint, int32_t& nCount) override;
   int32_t GetCharStart() const override;
   int32_t GetCharCount() const override;
@@ -44,7 +45,7 @@
 
   // IFDE_VisualSet:
   FDE_VISUALOBJTYPE GetType() override;
-  void GetRect(FDE_TEXTEDITPIECE* pPiece, CFX_RectF& rt) override;
+  CFX_RectF GetRect(const FDE_TEXTEDITPIECE& pPiece) override;
 
   // IFDE_CanvasSet:
   FX_POSITION GetFirstPosition() override;
@@ -65,7 +66,7 @@
   std::unique_ptr<IFX_CharIter> m_pIter;
   std::unique_ptr<CFDE_TxtEdtTextSet> m_pTextSet;
   CFDE_TxtEdtEngine* const m_pEditEngine;
-  CFX_MassArrayTemplate<FDE_TEXTEDITPIECE> m_PieceMassArr;
+  std::deque<FDE_TEXTEDITPIECE> m_Pieces;
   CFDE_TxtEdtParag* m_pBgnParag;
   CFDE_TxtEdtParag* m_pEndParag;
   int32_t m_nRefCount;
diff --git a/xfa/fde/cfde_txtedttextset.cpp b/xfa/fde/cfde_txtedttextset.cpp
index 4149a6d..8d32f75 100644
--- a/xfa/fde/cfde_txtedttextset.cpp
+++ b/xfa/fde/cfde_txtedttextset.cpp
@@ -19,8 +19,8 @@
   return FDE_VISUALOBJ_Text;
 }
 
-void CFDE_TxtEdtTextSet::GetRect(FDE_TEXTEDITPIECE* pPiece, CFX_RectF& rt) {
-  rt = pPiece->rtPiece;
+CFX_RectF CFDE_TxtEdtTextSet::GetRect(const FDE_TEXTEDITPIECE& pPiece) {
+  return pPiece.rtPiece;
 }
 
 int32_t CFDE_TxtEdtTextSet::GetString(FDE_TEXTEDITPIECE* pPiece,
@@ -45,14 +45,11 @@
   return m_pPage->GetEngine()->GetEditParams()->dwFontColor;
 }
 
-int32_t CFDE_TxtEdtTextSet::GetDisplayPos(FDE_TEXTEDITPIECE* pPiece,
+int32_t CFDE_TxtEdtTextSet::GetDisplayPos(const FDE_TEXTEDITPIECE& piece,
                                           FXTEXT_CHARPOS* pCharPos,
                                           bool bCharCode,
                                           CFX_WideString* pWSForms) {
-  if (!pPiece)
-    return 0;
-
-  int32_t nLength = pPiece->nCount;
+  int32_t nLength = piece.nCount;
   if (nLength < 1)
     return 0;
 
@@ -63,42 +60,37 @@
   uint32_t dwLayoutStyle = pBreak->GetLayoutStyles();
   FX_TXTRUN tr;
   tr.pAccess = m_pPage;
-  tr.pIdentity = pPiece;
+  tr.pIdentity = &piece;
   tr.iLength = nLength;
   tr.pFont = pTextParams->pFont;
   tr.fFontSize = pTextParams->fFontSize;
   tr.dwStyles = dwLayoutStyle;
   tr.iCharRotation = pTextParams->nCharRotation;
-  tr.dwCharStyles = pPiece->dwCharStyles;
-  tr.pRect = &(pPiece->rtPiece);
+  tr.dwCharStyles = piece.dwCharStyles;
+  tr.pRect = &piece.rtPiece;
   tr.wLineBreakChar = pTextParams->wLineBreakChar;
   return pBreak->GetDisplayPos(&tr, pCharPos, bCharCode, pWSForms);
 }
 
-int32_t CFDE_TxtEdtTextSet::GetCharRects(const FDE_TEXTEDITPIECE* pPiece,
-                                         CFX_RectFArray& rtArray,
-                                         bool bBBox) {
-  if (!pPiece)
-    return 0;
+std::vector<CFX_RectF> CFDE_TxtEdtTextSet::GetCharRects(
+    const FDE_TEXTEDITPIECE* pPiece,
+    bool bBBox) {
+  if (!pPiece || pPiece->nCount < 1)
+    return std::vector<CFX_RectF>();
 
-  CFDE_TxtEdtEngine* pEngine =
-      static_cast<CFDE_TxtEdtEngine*>(m_pPage->GetEngine());
-  int32_t nLength = pPiece->nCount;
-  if (nLength < 1)
-    return 0;
-
+  auto pEngine = static_cast<CFDE_TxtEdtEngine*>(m_pPage->GetEngine());
   const FDE_TXTEDTPARAMS* pTextParams = pEngine->GetEditParams();
   uint32_t dwLayoutStyle = pEngine->GetTextBreak()->GetLayoutStyles();
   FX_TXTRUN tr;
   tr.pAccess = m_pPage;
   tr.pIdentity = pPiece;
-  tr.iLength = nLength;
+  tr.iLength = pPiece->nCount;
   tr.pFont = pTextParams->pFont;
   tr.fFontSize = pTextParams->fFontSize;
   tr.dwStyles = dwLayoutStyle;
   tr.iCharRotation = pTextParams->nCharRotation;
   tr.dwCharStyles = pPiece->dwCharStyles;
-  tr.pRect = &(pPiece->rtPiece);
+  tr.pRect = &pPiece->rtPiece;
   tr.wLineBreakChar = pTextParams->wLineBreakChar;
-  return pEngine->GetTextBreak()->GetCharRects(&tr, rtArray, bBBox);
+  return pEngine->GetTextBreak()->GetCharRects(&tr, bBBox);
 }
diff --git a/xfa/fde/cfde_txtedttextset.h b/xfa/fde/cfde_txtedttextset.h
index 6c62666..8ab6578 100644
--- a/xfa/fde/cfde_txtedttextset.h
+++ b/xfa/fde/cfde_txtedttextset.h
@@ -7,6 +7,8 @@
 #ifndef XFA_FDE_CFDE_TXTEDTTEXTSET_H_
 #define XFA_FDE_CFDE_TXTEDTTEXTSET_H_
 
+#include <vector>
+
 #include "xfa/fde/fde_visualset.h"
 
 class CFDE_TxtEdtPage;
@@ -18,20 +20,19 @@
 
   // IFDE_VisualSet
   FDE_VISUALOBJTYPE GetType() override;
-  void GetRect(FDE_TEXTEDITPIECE* hVisualObj, CFX_RectF& rt) override;
+  CFX_RectF GetRect(const FDE_TEXTEDITPIECE& hVisualObj) override;
 
   // IFDE_TextSet
   int32_t GetString(FDE_TEXTEDITPIECE* pPiece, CFX_WideString& wsText) override;
   CFX_RetainPtr<CFGAS_GEFont> GetFont() override;
   FX_FLOAT GetFontSize() override;
   FX_ARGB GetFontColor() override;
-  int32_t GetDisplayPos(FDE_TEXTEDITPIECE* pPiece,
+  int32_t GetDisplayPos(const FDE_TEXTEDITPIECE& pPiece,
                         FXTEXT_CHARPOS* pCharPos,
                         bool bCharCode = false,
                         CFX_WideString* pWSForms = nullptr) override;
-  int32_t GetCharRects(const FDE_TEXTEDITPIECE* pPiece,
-                       CFX_RectFArray& rtArray,
-                       bool bBBox) override;
+  std::vector<CFX_RectF> GetCharRects(const FDE_TEXTEDITPIECE* pPiece,
+                                      bool bBBox) override;
 
  private:
   CFDE_TxtEdtPage* const m_pPage;
diff --git a/xfa/fde/css/cfde_cssaccelerator.cpp b/xfa/fde/css/cfde_cssaccelerator.cpp
deleted file mode 100644
index 40fa13e..0000000
--- a/xfa/fde/css/cfde_cssaccelerator.cpp
+++ /dev/null
@@ -1,23 +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/fde/css/cfde_cssaccelerator.h"
-
-#include "third_party/base/ptr_util.h"
-
-CFDE_CSSAccelerator::CFDE_CSSAccelerator() {}
-
-CFDE_CSSAccelerator::~CFDE_CSSAccelerator() {}
-
-void CFDE_CSSAccelerator::OnEnterTag(CXFA_CSSTagProvider* pTag) {
-  stack_.push(pdfium::MakeUnique<CFDE_CSSTagCache>(top(), pTag));
-}
-
-void CFDE_CSSAccelerator::OnLeaveTag(CXFA_CSSTagProvider* pTag) {
-  ASSERT(!stack_.empty());
-  ASSERT(stack_.top()->GetTag() == pTag);
-  stack_.pop();
-}
diff --git a/xfa/fde/css/cfde_cssaccelerator.h b/xfa/fde/css/cfde_cssaccelerator.h
deleted file mode 100644
index 4ef493d..0000000
--- a/xfa/fde/css/cfde_cssaccelerator.h
+++ /dev/null
@@ -1,40 +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_FDE_CSS_CFDE_CSSACCELERATOR_H_
-#define XFA_FDE_CSS_CFDE_CSSACCELERATOR_H_
-
-#include <memory>
-#include <stack>
-
-#include "xfa/fde/css/cfde_csstagcache.h"
-
-class CXFA_CSSTagProvider;
-
-class CFDE_CSSAccelerator {
- public:
-  CFDE_CSSAccelerator();
-  ~CFDE_CSSAccelerator();
-
-  void OnEnterTag(CXFA_CSSTagProvider* pTag);
-  void OnLeaveTag(CXFA_CSSTagProvider* pTag);
-
-  void Clear() {
-    std::stack<std::unique_ptr<CFDE_CSSTagCache>> tmp;
-    stack_.swap(tmp);
-  }
-
-  CFDE_CSSTagCache* top() const {
-    if (stack_.empty())
-      return nullptr;
-    return stack_.top().get();
-  }
-
- private:
-  std::stack<std::unique_ptr<CFDE_CSSTagCache>> stack_;
-};
-
-#endif  // XFA_FDE_CSS_CFDE_CSSACCELERATOR_H_
diff --git a/xfa/fde/css/cfde_csscomputedstyle.cpp b/xfa/fde/css/cfde_csscomputedstyle.cpp
index 010f573..01872d1 100644
--- a/xfa/fde/css/cfde_csscomputedstyle.cpp
+++ b/xfa/fde/css/cfde_csscomputedstyle.cpp
@@ -10,27 +10,16 @@
 #include "xfa/fde/css/cfde_cssstringvalue.h"
 #include "xfa/fde/css/cfde_cssvaluelist.h"
 
-CFDE_CSSComputedStyle::CFDE_CSSComputedStyle() : m_dwRefCount(1) {}
+CFDE_CSSComputedStyle::CFDE_CSSComputedStyle() {}
 
 CFDE_CSSComputedStyle::~CFDE_CSSComputedStyle() {}
 
-uint32_t CFDE_CSSComputedStyle::Retain() {
-  return ++m_dwRefCount;
-}
-
-uint32_t CFDE_CSSComputedStyle::Release() {
-  uint32_t dwRefCount = --m_dwRefCount;
-  if (dwRefCount == 0)
-    delete this;
-  return dwRefCount;
-}
-
-bool CFDE_CSSComputedStyle::GetCustomStyle(const CFX_WideStringC& wsName,
+bool CFDE_CSSComputedStyle::GetCustomStyle(const CFX_WideString& wsName,
                                            CFX_WideString& wsValue) const {
-  for (int32_t i = pdfium::CollectionSize<int32_t>(m_CustomProperties) - 2;
-       i > -1; i -= 2) {
-    if (wsName == m_CustomProperties[i]) {
-      wsValue = m_CustomProperties[i + 1];
+  for (auto iter = m_CustomProperties.rbegin();
+       iter != m_CustomProperties.rend(); iter++) {
+    if (wsName == iter->name()) {
+      wsValue = iter->value();
       return true;
     }
   }
@@ -44,8 +33,8 @@
 }
 
 const CFX_WideString CFDE_CSSComputedStyle::GetFontFamily(int32_t index) const {
-  return static_cast<CFDE_CSSStringValue*>(
-             m_InheritedData.m_pFontFamily->GetValue(index))
+  return m_InheritedData.m_pFontFamily->GetValue(index)
+      .As<CFDE_CSSStringValue>()
       ->Value();
 }
 
@@ -172,10 +161,10 @@
   m_InheritedData.m_LetterSpacing = letterSpacing;
 }
 
-void CFDE_CSSComputedStyle::AddCustomStyle(const CFX_WideString& wsName,
-                                           const CFX_WideString& wsValue) {
-  m_CustomProperties.push_back(wsName);
-  m_CustomProperties.push_back(wsValue);
+void CFDE_CSSComputedStyle::AddCustomStyle(const CFDE_CSSCustomProperty& prop) {
+  // Force the property to be copied so we aren't dependent on the lifetime
+  // of whatever currently owns it.
+  m_CustomProperties.push_back(prop);
 }
 
 CFDE_CSSComputedStyle::InheritedData::InheritedData()
@@ -191,6 +180,8 @@
       m_eFontStyle(FDE_CSSFontStyle::Normal),
       m_eTextAlign(FDE_CSSTextAlign::Left) {}
 
+CFDE_CSSComputedStyle::InheritedData::~InheritedData() {}
+
 CFDE_CSSComputedStyle::NonInheritedData::NonInheritedData()
     : m_MarginWidth(FDE_CSSLengthUnit::Point, 0),
       m_BorderWidth(FDE_CSSLengthUnit::Point, 0),
diff --git a/xfa/fde/css/cfde_csscomputedstyle.h b/xfa/fde/css/cfde_csscomputedstyle.h
index 73eb996..bba4ccb 100644
--- a/xfa/fde/css/cfde_csscomputedstyle.h
+++ b/xfa/fde/css/cfde_csscomputedstyle.h
@@ -11,20 +11,22 @@
 
 #include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_string.h"
+#include "xfa/fde/css/cfde_csscustomproperty.h"
 #include "xfa/fde/css/fde_css.h"
 
 class CFDE_CSSValueList;
 
-class CFDE_CSSComputedStyle : public IFX_Retainable {
+class CFDE_CSSComputedStyle : public CFX_Retainable {
  public:
   class InheritedData {
    public:
     InheritedData();
+    ~InheritedData();
 
     FDE_CSSLength m_LetterSpacing;
     FDE_CSSLength m_WordSpacing;
     FDE_CSSLength m_TextIndent;
-    CFDE_CSSValueList* m_pFontFamily;
+    CFX_RetainPtr<CFDE_CSSValueList> m_pFontFamily;
     FX_FLOAT m_fFontSize;
     FX_FLOAT m_fLineHeight;
     FX_ARGB m_dwFontColor;
@@ -54,13 +56,6 @@
     bool m_bHasPadding;
   };
 
-  CFDE_CSSComputedStyle();
-  ~CFDE_CSSComputedStyle() override;
-
-  // IFX_Retainable
-  uint32_t Retain() override;
-  uint32_t Release() override;
-
   int32_t CountFontFamilies() const;
   const CFX_WideString GetFontFamily(int32_t index) const;
   uint16_t GetFontWeight() const;
@@ -95,18 +90,22 @@
   void SetNumberVerticalAlign(FX_FLOAT fAlign);
   void SetTextDecoration(uint32_t dwTextDecoration);
   void SetLetterSpacing(const FDE_CSSLength& letterSpacing);
-  void AddCustomStyle(const CFX_WideString& wsName,
-                      const CFX_WideString& wsValue);
+  void AddCustomStyle(const CFDE_CSSCustomProperty& prop);
 
-  bool GetCustomStyle(const CFX_WideStringC& wsName,
+  bool GetCustomStyle(const CFX_WideString& wsName,
                       CFX_WideString& wsValue) const;
 
   InheritedData m_InheritedData;
   NonInheritedData m_NonInheritedData;
 
  private:
-  uint32_t m_dwRefCount;
-  std::vector<CFX_WideString> m_CustomProperties;
+  template <typename T, typename... Args>
+  friend CFX_RetainPtr<T> pdfium::MakeRetain(Args&&... args);
+
+  CFDE_CSSComputedStyle();
+  ~CFDE_CSSComputedStyle() override;
+
+  std::vector<CFDE_CSSCustomProperty> m_CustomProperties;
 };
 
 #endif  // XFA_FDE_CSS_CFDE_CSSCOMPUTEDSTYLE_H_
diff --git a/xfa/fde/css/cfde_csscustomproperty.cpp b/xfa/fde/css/cfde_csscustomproperty.cpp
new file mode 100644
index 0000000..92b288e
--- /dev/null
+++ b/xfa/fde/css/cfde_csscustomproperty.cpp
@@ -0,0 +1,15 @@
+// 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/fde/css/cfde_csscustomproperty.h"
+
+CFDE_CSSCustomProperty::CFDE_CSSCustomProperty(const CFX_WideString& name,
+                                               const CFX_WideString& value)
+    : name_(name), value_(value) {}
+
+CFDE_CSSCustomProperty::CFDE_CSSCustomProperty(
+    const CFDE_CSSCustomProperty& prop)
+    : name_(prop.name_), value_(prop.value_) {}
+
+CFDE_CSSCustomProperty::~CFDE_CSSCustomProperty() {}
diff --git a/xfa/fde/css/cfde_csscustomproperty.h b/xfa/fde/css/cfde_csscustomproperty.h
index 6e99630..6970d49 100644
--- a/xfa/fde/css/cfde_csscustomproperty.h
+++ b/xfa/fde/css/cfde_csscustomproperty.h
@@ -11,8 +11,17 @@
 
 class CFDE_CSSCustomProperty {
  public:
-  const FX_WCHAR* pwsName;
-  const FX_WCHAR* pwsValue;
+  CFDE_CSSCustomProperty(const CFX_WideString& name,
+                         const CFX_WideString& value);
+  CFDE_CSSCustomProperty(const CFDE_CSSCustomProperty& prop);
+  ~CFDE_CSSCustomProperty();
+
+  CFX_WideString name() const { return name_; }
+  CFX_WideString value() const { return value_; }
+
+ private:
+  CFX_WideString name_;
+  CFX_WideString value_;
 };
 
 #endif  // XFA_FDE_CSS_CFDE_CSSCUSTOMPROPERTY_H_
diff --git a/xfa/fde/css/cfde_cssdeclaration.cpp b/xfa/fde/css/cfde_cssdeclaration.cpp
index 4ed20eb..3c776ca 100644
--- a/xfa/fde/css/cfde_cssdeclaration.cpp
+++ b/xfa/fde/css/cfde_cssdeclaration.cpp
@@ -133,39 +133,18 @@
 
 CFDE_CSSDeclaration::~CFDE_CSSDeclaration() {}
 
-CFDE_CSSValue* CFDE_CSSDeclaration::GetProperty(FDE_CSSProperty eProperty,
-                                                bool& bImportant) const {
+CFX_RetainPtr<CFDE_CSSValue> CFDE_CSSDeclaration::GetProperty(
+    FDE_CSSProperty eProperty,
+    bool* bImportant) const {
   for (const auto& p : properties_) {
     if (p->eProperty == eProperty) {
-      bImportant = p->bImportant;
-      return p->pValue.Get();
+      *bImportant = p->bImportant;
+      return p->pValue;
     }
   }
   return nullptr;
 }
 
-const FX_WCHAR* CFDE_CSSDeclaration::CopyToLocal(
-    const FDE_CSSPropertyArgs* pArgs,
-    const FX_WCHAR* pszValue,
-    int32_t iValueLen) {
-  ASSERT(iValueLen > 0);
-  std::unordered_map<uint32_t, FX_WCHAR*>* pCache = pArgs->pStringCache;
-  uint32_t key = 0;
-  if (pCache) {
-    key = FX_HashCode_GetW(CFX_WideStringC(pszValue, iValueLen), false);
-    auto it = pCache->find(key);
-    if (it != pCache->end())
-      return it->second;
-  }
-  FX_WCHAR* psz = FX_Alloc(FX_WCHAR, iValueLen + 1);
-  FXSYS_wcsncpy(psz, pszValue, iValueLen);
-  psz[iValueLen] = '\0';
-  if (pCache)
-    (*pCache)[key] = psz;
-
-  return psz;
-}
-
 void CFDE_CSSDeclaration::AddPropertyHolder(FDE_CSSProperty eProperty,
                                             CFX_RetainPtr<CFDE_CSSValue> pValue,
                                             bool bImportant) {
@@ -176,10 +155,13 @@
   properties_.push_back(std::move(pHolder));
 }
 
-void CFDE_CSSDeclaration::AddProperty(const FDE_CSSPropertyArgs* pArgs,
-                                      const FX_WCHAR* pszValue,
-                                      int32_t iValueLen) {
-  ASSERT(iValueLen > 0);
+void CFDE_CSSDeclaration::AddProperty(const FDE_CSSPropertyTable* pTable,
+                                      const CFX_WideStringC& value) {
+  ASSERT(!value.IsEmpty());
+
+  const FX_WCHAR* pszValue = value.c_str();
+  int32_t iValueLen = value.GetLength();
+
   bool bImportant = false;
   if (iValueLen >= 10 && pszValue[iValueLen - 10] == '!' &&
       FXSYS_wcsnicmp(L"important", pszValue + iValueLen - 9, 9) == 0) {
@@ -188,7 +170,7 @@
 
     bImportant = true;
   }
-  const uint32_t dwType = pArgs->pProperty->dwType;
+  const uint32_t dwType = pTable->dwType;
   switch (dwType & 0x0F) {
     case FDE_CSSVALUETYPE_Primitive: {
       static const uint32_t g_ValueGuessOrder[] = {
@@ -205,22 +187,22 @@
         CFX_RetainPtr<CFDE_CSSValue> pCSSValue;
         switch (dwMatch) {
           case FDE_CSSVALUETYPE_MaybeNumber:
-            pCSSValue = ParseNumber(pArgs, pszValue, iValueLen);
+            pCSSValue = ParseNumber(pszValue, iValueLen);
             break;
           case FDE_CSSVALUETYPE_MaybeEnum:
-            pCSSValue = ParseEnum(pArgs, pszValue, iValueLen);
+            pCSSValue = ParseEnum(pszValue, iValueLen);
             break;
           case FDE_CSSVALUETYPE_MaybeColor:
-            pCSSValue = ParseColor(pArgs, pszValue, iValueLen);
+            pCSSValue = ParseColor(pszValue, iValueLen);
             break;
           case FDE_CSSVALUETYPE_MaybeString:
-            pCSSValue = ParseString(pArgs, pszValue, iValueLen);
+            pCSSValue = ParseString(pszValue, iValueLen);
             break;
           default:
             break;
         }
         if (pCSSValue) {
-          AddPropertyHolder(pArgs->pProperty->eName, pCSSValue, bImportant);
+          AddPropertyHolder(pTable->eName, pCSSValue, bImportant);
           return;
         }
         if (FDE_IsOnlyValue(dwType, g_ValueGuessOrder[i]))
@@ -230,9 +212,9 @@
     }
     case FDE_CSSVALUETYPE_Shorthand: {
       CFX_RetainPtr<CFDE_CSSValue> pWidth;
-      switch (pArgs->pProperty->eName) {
+      switch (pTable->eName) {
         case FDE_CSSProperty::Font:
-          ParseFontProperty(pArgs, pszValue, iValueLen, bImportant);
+          ParseFontProperty(pszValue, iValueLen, bImportant);
           return;
         case FDE_CSSProperty::Border:
           if (ParseBorderProperty(pszValue, iValueLen, pWidth)) {
@@ -280,7 +262,7 @@
       }
     } break;
     case FDE_CSSVALUETYPE_List:
-      ParseValueListProperty(pArgs, pszValue, iValueLen, bImportant);
+      ParseValueListProperty(pTable, pszValue, iValueLen, bImportant);
       return;
     default:
       ASSERT(false);
@@ -288,19 +270,13 @@
   }
 }
 
-void CFDE_CSSDeclaration::AddProperty(const FDE_CSSPropertyArgs* pArgs,
-                                      const FX_WCHAR* pszName,
-                                      int32_t iNameLen,
-                                      const FX_WCHAR* pszValue,
-                                      int32_t iValueLen) {
-  auto pProperty = pdfium::MakeUnique<CFDE_CSSCustomProperty>();
-  pProperty->pwsName = CopyToLocal(pArgs, pszName, iNameLen);
-  pProperty->pwsValue = CopyToLocal(pArgs, pszValue, iValueLen);
-  custom_properties_.push_back(std::move(pProperty));
+void CFDE_CSSDeclaration::AddProperty(const CFX_WideString& prop,
+                                      const CFX_WideString& value) {
+  custom_properties_.push_back(
+      pdfium::MakeUnique<CFDE_CSSCustomProperty>(prop, value));
 }
 
 CFX_RetainPtr<CFDE_CSSValue> CFDE_CSSDeclaration::ParseNumber(
-    const FDE_CSSPropertyArgs* pArgs,
     const FX_WCHAR* pszValue,
     int32_t iValueLen) {
   FX_FLOAT fValue;
@@ -311,7 +287,6 @@
 }
 
 CFX_RetainPtr<CFDE_CSSValue> CFDE_CSSDeclaration::ParseEnum(
-    const FDE_CSSPropertyArgs* pArgs,
     const FX_WCHAR* pszValue,
     int32_t iValueLen) {
   const FDE_CSSPropertyValueTable* pValue =
@@ -321,7 +296,6 @@
 }
 
 CFX_RetainPtr<CFDE_CSSValue> CFDE_CSSDeclaration::ParseColor(
-    const FDE_CSSPropertyArgs* pArgs,
     const FX_WCHAR* pszValue,
     int32_t iValueLen) {
   FX_ARGB dwColor;
@@ -331,7 +305,6 @@
 }
 
 CFX_RetainPtr<CFDE_CSSValue> CFDE_CSSDeclaration::ParseString(
-    const FDE_CSSPropertyArgs* pArgs,
     const FX_WCHAR* pszValue,
     int32_t iValueLen) {
   int32_t iOffset;
@@ -341,20 +314,20 @@
   if (iValueLen <= 0)
     return nullptr;
 
-  pszValue = CopyToLocal(pArgs, pszValue + iOffset, iValueLen);
-  return pszValue ? pdfium::MakeRetain<CFDE_CSSStringValue>(pszValue) : nullptr;
+  return pdfium::MakeRetain<CFDE_CSSStringValue>(
+      CFX_WideString(pszValue + iOffset, iValueLen));
 }
 
 void CFDE_CSSDeclaration::ParseValueListProperty(
-    const FDE_CSSPropertyArgs* pArgs,
+    const FDE_CSSPropertyTable* pTable,
     const FX_WCHAR* pszValue,
     int32_t iValueLen,
     bool bImportant) {
   FX_WCHAR separator =
-      (pArgs->pProperty->eName == FDE_CSSProperty::FontFamily) ? ',' : ' ';
+      (pTable->eName == FDE_CSSProperty::FontFamily) ? ',' : ' ';
   CFDE_CSSValueListParser parser(pszValue, iValueLen, separator);
 
-  const uint32_t dwType = pArgs->pProperty->dwType;
+  const uint32_t dwType = pTable->dwType;
   FDE_CSSPrimitiveType eType;
   std::vector<CFX_RetainPtr<CFDE_CSSValue>> list;
   while (parser.NextValue(eType, pszValue, iValueLen)) {
@@ -387,8 +360,8 @@
           }
         }
         if (dwType & FDE_CSSVALUETYPE_MaybeString) {
-          pszValue = CopyToLocal(pArgs, pszValue, iValueLen);
-          list.push_back(pdfium::MakeRetain<CFDE_CSSStringValue>(pszValue));
+          list.push_back(pdfium::MakeRetain<CFDE_CSSStringValue>(
+              CFX_WideString(pszValue, iValueLen)));
         }
         break;
       case FDE_CSSPrimitiveType::RGB:
@@ -406,7 +379,7 @@
   if (list.empty())
     return;
 
-  switch (pArgs->pProperty->eName) {
+  switch (pTable->eName) {
     case FDE_CSSProperty::BorderWidth:
       Add4ValuesProperty(list, bImportant, FDE_CSSProperty::BorderLeftWidth,
                          FDE_CSSProperty::BorderTopWidth,
@@ -427,7 +400,7 @@
       return;
     default: {
       auto pList = pdfium::MakeRetain<CFDE_CSSValueList>(list);
-      AddPropertyHolder(pArgs->pProperty->eName, pList, bImportant);
+      AddPropertyHolder(pTable->eName, pList, bImportant);
       return;
     }
   }
@@ -524,8 +497,7 @@
   return true;
 }
 
-void CFDE_CSSDeclaration::ParseFontProperty(const FDE_CSSPropertyArgs* pArgs,
-                                            const FX_WCHAR* pszValue,
+void CFDE_CSSDeclaration::ParseFontProperty(const FX_WCHAR* pszValue,
                                             int32_t iValueLen,
                                             bool bImportant) {
   CFDE_CSSValueListParser parser(pszValue, iValueLen, '/');
@@ -591,7 +563,7 @@
         }
         if (pFontSize) {
           familyList.push_back(pdfium::MakeRetain<CFDE_CSSStringValue>(
-              CopyToLocal(pArgs, pszValue, iValueLen)));
+              CFX_WideString(pszValue, iValueLen)));
         }
         parser.m_Separator = ',';
         break;
@@ -630,21 +602,26 @@
     }
   }
 
-  if (!pStyle)
+  if (!pStyle) {
     pStyle =
         pdfium::MakeRetain<CFDE_CSSEnumValue>(FDE_CSSPropertyValue::Normal);
-  if (!pVariant)
+  }
+  if (!pVariant) {
     pVariant =
         pdfium::MakeRetain<CFDE_CSSEnumValue>(FDE_CSSPropertyValue::Normal);
-  if (!pWeight)
+  }
+  if (!pWeight) {
     pWeight =
         pdfium::MakeRetain<CFDE_CSSEnumValue>(FDE_CSSPropertyValue::Normal);
-  if (!pFontSize)
+  }
+  if (!pFontSize) {
     pFontSize =
         pdfium::MakeRetain<CFDE_CSSEnumValue>(FDE_CSSPropertyValue::Medium);
-  if (!pLineHeight)
+  }
+  if (!pLineHeight) {
     pLineHeight =
         pdfium::MakeRetain<CFDE_CSSEnumValue>(FDE_CSSPropertyValue::Normal);
+  }
 
   AddPropertyHolder(FDE_CSSProperty::FontStyle, pStyle, bImportant);
   AddPropertyHolder(FDE_CSSProperty::FontVariant, pVariant, bImportant);
diff --git a/xfa/fde/css/cfde_cssdeclaration.h b/xfa/fde/css/cfde_cssdeclaration.h
index 777864e..eb28730 100644
--- a/xfa/fde/css/cfde_cssdeclaration.h
+++ b/xfa/fde/css/cfde_cssdeclaration.h
@@ -8,17 +8,11 @@
 #define XFA_FDE_CSS_CFDE_CSSDECLARATION_H_
 
 #include <memory>
-#include <unordered_map>
 #include <utility>
 #include <vector>
 
 #include "xfa/fde/css/fde_cssdatatable.h"
 
-struct FDE_CSSPropertyArgs {
-  std::unordered_map<uint32_t, FX_WCHAR*>* pStringCache;
-  const FDE_CSSPropertyTable* pProperty;
-};
-
 class CFDE_CSSPropertyHolder;
 class CFDE_CSSCustomProperty;
 
@@ -40,7 +34,8 @@
   CFDE_CSSDeclaration();
   ~CFDE_CSSDeclaration();
 
-  CFDE_CSSValue* GetProperty(FDE_CSSProperty eProperty, bool& bImportant) const;
+  CFX_RetainPtr<CFDE_CSSValue> GetProperty(FDE_CSSProperty eProperty,
+                                           bool* bImportant) const;
 
   const_prop_iterator begin() const { return properties_.begin(); }
   const_prop_iterator end() const { return properties_.end(); }
@@ -52,14 +47,9 @@
 
   bool empty() const { return properties_.empty(); }
 
-  void AddProperty(const FDE_CSSPropertyArgs* pArgs,
-                   const FX_WCHAR* pszValue,
-                   int32_t iValueLen);
-  void AddProperty(const FDE_CSSPropertyArgs* pArgs,
-                   const FX_WCHAR* pszName,
-                   int32_t iNameLen,
-                   const FX_WCHAR* pszValue,
-                   int32_t iValueLen);
+  void AddProperty(const FDE_CSSPropertyTable* pTable,
+                   const CFX_WideStringC& value);
+  void AddProperty(const CFX_WideString& prop, const CFX_WideString& value);
 
   size_t PropertyCountForTesting() const;
 
@@ -68,14 +58,13 @@
                             FX_ARGB* dwColor) const;
 
  private:
-  void ParseFontProperty(const FDE_CSSPropertyArgs* pArgs,
-                         const FX_WCHAR* pszValue,
+  void ParseFontProperty(const FX_WCHAR* pszValue,
                          int32_t iValueLen,
                          bool bImportant);
   bool ParseBorderProperty(const FX_WCHAR* pszValue,
                            int32_t iValueLen,
                            CFX_RetainPtr<CFDE_CSSValue>& pWidth) const;
-  void ParseValueListProperty(const FDE_CSSPropertyArgs* pArgs,
+  void ParseValueListProperty(const FDE_CSSPropertyTable* pTable,
                               const FX_WCHAR* pszValue,
                               int32_t iValueLen,
                               bool bImportant);
@@ -85,21 +74,14 @@
                           FDE_CSSProperty eTop,
                           FDE_CSSProperty eRight,
                           FDE_CSSProperty eBottom);
-  CFX_RetainPtr<CFDE_CSSValue> ParseNumber(const FDE_CSSPropertyArgs* pArgs,
-                                           const FX_WCHAR* pszValue,
+  CFX_RetainPtr<CFDE_CSSValue> ParseNumber(const FX_WCHAR* pszValue,
                                            int32_t iValueLen);
-  CFX_RetainPtr<CFDE_CSSValue> ParseEnum(const FDE_CSSPropertyArgs* pArgs,
-                                         const FX_WCHAR* pszValue,
+  CFX_RetainPtr<CFDE_CSSValue> ParseEnum(const FX_WCHAR* pszValue,
                                          int32_t iValueLen);
-  CFX_RetainPtr<CFDE_CSSValue> ParseColor(const FDE_CSSPropertyArgs* pArgs,
-                                          const FX_WCHAR* pszValue,
+  CFX_RetainPtr<CFDE_CSSValue> ParseColor(const FX_WCHAR* pszValue,
                                           int32_t iValueLen);
-  CFX_RetainPtr<CFDE_CSSValue> ParseString(const FDE_CSSPropertyArgs* pArgs,
-                                           const FX_WCHAR* pszValue,
+  CFX_RetainPtr<CFDE_CSSValue> ParseString(const FX_WCHAR* pszValue,
                                            int32_t iValueLen);
-  const FX_WCHAR* CopyToLocal(const FDE_CSSPropertyArgs* pArgs,
-                              const FX_WCHAR* pszValue,
-                              int32_t iValueLen);
   void AddPropertyHolder(FDE_CSSProperty eProperty,
                          CFX_RetainPtr<CFDE_CSSValue> pValue,
                          bool bImportant);
diff --git a/xfa/fde/css/cfde_cssfontfacerule.cpp b/xfa/fde/css/cfde_cssfontfacerule.cpp
deleted file mode 100644
index 5d56eb8..0000000
--- a/xfa/fde/css/cfde_cssfontfacerule.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/fde/css/cfde_cssfontfacerule.h"
-
-CFDE_CSSFontFaceRule::CFDE_CSSFontFaceRule()
-    : CFDE_CSSRule(FDE_CSSRuleType::FontFace) {}
-
-CFDE_CSSFontFaceRule::~CFDE_CSSFontFaceRule() {}
diff --git a/xfa/fde/css/cfde_cssfontfacerule.h b/xfa/fde/css/cfde_cssfontfacerule.h
deleted file mode 100644
index e5249cc..0000000
--- a/xfa/fde/css/cfde_cssfontfacerule.h
+++ /dev/null
@@ -1,24 +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_FDE_CSS_CFDE_CSSFONTFACERULE_H_
-#define XFA_FDE_CSS_CFDE_CSSFONTFACERULE_H_
-
-#include "xfa/fde/css/cfde_cssdeclaration.h"
-#include "xfa/fde/css/cfde_cssrule.h"
-
-class CFDE_CSSFontFaceRule : public CFDE_CSSRule {
- public:
-  CFDE_CSSFontFaceRule();
-  ~CFDE_CSSFontFaceRule() override;
-
-  CFDE_CSSDeclaration* GetDeclaration() { return &m_Declaration; }
-
- private:
-  CFDE_CSSDeclaration m_Declaration;
-};
-
-#endif  // XFA_FDE_CSS_CFDE_CSSFONTFACERULE_H_
diff --git a/xfa/fde/css/cfde_cssmediarule.cpp b/xfa/fde/css/cfde_cssmediarule.cpp
deleted file mode 100644
index 751f9d9..0000000
--- a/xfa/fde/css/cfde_cssmediarule.cpp
+++ /dev/null
@@ -1,26 +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/fde/css/cfde_cssmediarule.h"
-
-#include "third_party/base/stl_util.h"
-
-CFDE_CSSMediaRule::CFDE_CSSMediaRule(uint32_t dwMediaList)
-    : CFDE_CSSRule(FDE_CSSRuleType::Media), m_dwMediaList(dwMediaList) {}
-
-CFDE_CSSMediaRule::~CFDE_CSSMediaRule() {}
-
-uint32_t CFDE_CSSMediaRule::GetMediaList() const {
-  return m_dwMediaList;
-}
-
-int32_t CFDE_CSSMediaRule::CountRules() const {
-  return pdfium::CollectionSize<int32_t>(m_RuleArray);
-}
-
-CFDE_CSSRule* CFDE_CSSMediaRule::GetRule(int32_t index) {
-  return m_RuleArray[index].get();
-}
diff --git a/xfa/fde/css/cfde_cssmediarule.h b/xfa/fde/css/cfde_cssmediarule.h
deleted file mode 100644
index 59febb2..0000000
--- a/xfa/fde/css/cfde_cssmediarule.h
+++ /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
-
-#ifndef XFA_FDE_CSS_CFDE_CSSMEDIARULE_H_
-#define XFA_FDE_CSS_CFDE_CSSMEDIARULE_H_
-
-#include <memory>
-#include <vector>
-
-#include "xfa/fde/css/cfde_cssrule.h"
-
-class CFDE_CSSMediaRule : public CFDE_CSSRule {
- public:
-  explicit CFDE_CSSMediaRule(uint32_t dwMediaList);
-  ~CFDE_CSSMediaRule() override;
-
-  uint32_t GetMediaList() const;
-  int32_t CountRules() const;
-  CFDE_CSSRule* GetRule(int32_t index);
-
-  std::vector<std::unique_ptr<CFDE_CSSRule>>& GetArray() { return m_RuleArray; }
-
- protected:
-  uint32_t m_dwMediaList;
-  std::vector<std::unique_ptr<CFDE_CSSRule>> m_RuleArray;
-};
-
-#endif  // XFA_FDE_CSS_CFDE_CSSMEDIARULE_H_
diff --git a/xfa/fde/css/cfde_cssrule.cpp b/xfa/fde/css/cfde_cssrule.cpp
deleted file mode 100644
index 7a46703..0000000
--- a/xfa/fde/css/cfde_cssrule.cpp
+++ /dev/null
@@ -1,11 +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/fde/css/cfde_cssrule.h"
-
-CFDE_CSSRule::CFDE_CSSRule(FDE_CSSRuleType type) : m_type(type) {}
-
-CFDE_CSSRule::~CFDE_CSSRule() {}
diff --git a/xfa/fde/css/cfde_cssrule.h b/xfa/fde/css/cfde_cssrule.h
deleted file mode 100644
index 9461321..0000000
--- a/xfa/fde/css/cfde_cssrule.h
+++ /dev/null
@@ -1,25 +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_FDE_CSS_CFDE_CSSRULE_H_
-#define XFA_FDE_CSS_CFDE_CSSRULE_H_
-
-#include "xfa/fde/css/fde_css.h"
-
-class CFDE_CSSRule {
- public:
-  virtual ~CFDE_CSSRule();
-
-  FDE_CSSRuleType GetType() const { return m_type; }
-
- protected:
-  explicit CFDE_CSSRule(FDE_CSSRuleType type);
-
- private:
-  FDE_CSSRuleType m_type;
-};
-
-#endif  // XFA_FDE_CSS_CFDE_CSSRULE_H_
diff --git a/xfa/fde/css/cfde_cssrulecollection.cpp b/xfa/fde/css/cfde_cssrulecollection.cpp
index 286f619..e318651 100644
--- a/xfa/fde/css/cfde_cssrulecollection.cpp
+++ b/xfa/fde/css/cfde_cssrulecollection.cpp
@@ -7,152 +7,52 @@
 #include "xfa/fde/css/cfde_cssrulecollection.h"
 
 #include <algorithm>
-#include <map>
-#include <memory>
+#include <utility>
 
+#include "third_party/base/ptr_util.h"
 #include "xfa/fde/css/cfde_cssdeclaration.h"
-#include "xfa/fde/css/cfde_cssmediarule.h"
-#include "xfa/fde/css/cfde_cssrule.h"
 #include "xfa/fde/css/cfde_cssselector.h"
 #include "xfa/fde/css/cfde_cssstylerule.h"
 #include "xfa/fde/css/cfde_cssstylesheet.h"
 #include "xfa/fde/css/cfde_csssyntaxparser.h"
-#include "xfa/fde/css/cfde_csstagcache.h"
 
-#define FDE_CSSUNIVERSALHASH ('*')
-
-void CFDE_CSSRuleCollection::Clear() {
-  m_IDRules.clear();
-  m_TagRules.clear();
-  m_ClassRules.clear();
-  m_pUniversalRules = nullptr;
-  m_iSelectors = 0;
-}
-
-CFDE_CSSRuleCollection::CFDE_CSSRuleCollection()
-    : m_pUniversalRules(nullptr), m_pPseudoRules(nullptr), m_iSelectors(0) {}
+CFDE_CSSRuleCollection::CFDE_CSSRuleCollection() : m_iSelectors(0) {}
 
 CFDE_CSSRuleCollection::~CFDE_CSSRuleCollection() {
   Clear();
 }
 
-void CFDE_CSSRuleCollection::AddRulesFrom(
-    const CFX_ArrayTemplate<CFDE_CSSStyleSheet*>& sheets,
-    uint32_t dwMediaList,
-    CFGAS_FontMgr* pFontMgr) {
-  int32_t iSheets = sheets.GetSize();
-  for (int32_t i = 0; i < iSheets; ++i) {
-    CFDE_CSSStyleSheet* pSheet = sheets.GetAt(i);
-    if (uint32_t dwMatchMedia = pSheet->GetMediaList() & dwMediaList) {
-      int32_t iRules = pSheet->CountRules();
-      for (int32_t j = 0; j < iRules; j++) {
-        AddRulesFrom(pSheet, pSheet->GetRule(j), dwMatchMedia, pFontMgr);
-      }
-    }
-  }
+void CFDE_CSSRuleCollection::Clear() {
+  m_TagRules.clear();
+  m_iSelectors = 0;
 }
 
-void CFDE_CSSRuleCollection::AddRulesFrom(CFDE_CSSStyleSheet* pStyleSheet,
-                                          CFDE_CSSRule* pRule,
-                                          uint32_t dwMediaList,
+const std::vector<std::unique_ptr<CFDE_CSSRuleCollection::Data>>*
+CFDE_CSSRuleCollection::GetTagRuleData(const CFX_WideString& tagname) const {
+  auto it = m_TagRules.find(FX_HashCode_GetW(tagname.c_str(), true));
+  return it != m_TagRules.end() ? &it->second : nullptr;
+}
+
+void CFDE_CSSRuleCollection::AddRulesFrom(const CFDE_CSSStyleSheet* sheet,
                                           CFGAS_FontMgr* pFontMgr) {
-  switch (pRule->GetType()) {
-    case FDE_CSSRuleType::Style: {
-      CFDE_CSSStyleRule* pStyleRule = static_cast<CFDE_CSSStyleRule*>(pRule);
-      CFDE_CSSDeclaration* pDeclaration = pStyleRule->GetDeclaration();
-      int32_t iSelectors = pStyleRule->CountSelectorLists();
-      for (int32_t i = 0; i < iSelectors; ++i) {
-        CFDE_CSSSelector* pSelector = pStyleRule->GetSelectorList(i);
-        if (pSelector->GetType() == FDE_CSSSelectorType::Pseudo) {
-          Data* pData = NewRuleData(pSelector, pDeclaration);
-          AddRuleTo(&m_pPseudoRules, pData);
-          continue;
-        }
-        if (pSelector->GetNameHash() != FDE_CSSUNIVERSALHASH) {
-          AddRuleTo(&m_TagRules, pSelector->GetNameHash(), pSelector,
-                    pDeclaration);
-          continue;
-        }
-        CFDE_CSSSelector* pNext = pSelector->GetNextSelector();
-        if (!pNext) {
-          Data* pData = NewRuleData(pSelector, pDeclaration);
-          AddRuleTo(&m_pUniversalRules, pData);
-          continue;
-        }
-        switch (pNext->GetType()) {
-          case FDE_CSSSelectorType::ID:
-            AddRuleTo(&m_IDRules, pNext->GetNameHash(), pSelector,
-                      pDeclaration);
-            break;
-          case FDE_CSSSelectorType::Class:
-            AddRuleTo(&m_ClassRules, pNext->GetNameHash(), pSelector,
-                      pDeclaration);
-            break;
-          case FDE_CSSSelectorType::Descendant:
-          case FDE_CSSSelectorType::Element:
-            AddRuleTo(&m_pUniversalRules, NewRuleData(pSelector, pDeclaration));
-            break;
-          default:
-            ASSERT(false);
-            break;
-        }
-      }
-    } break;
-    case FDE_CSSRuleType::Media: {
-      CFDE_CSSMediaRule* pMediaRule = static_cast<CFDE_CSSMediaRule*>(pRule);
-      if (pMediaRule->GetMediaList() & dwMediaList) {
-        int32_t iRules = pMediaRule->CountRules();
-        for (int32_t i = 0; i < iRules; ++i) {
-          AddRulesFrom(pStyleSheet, pMediaRule->GetRule(i), dwMediaList,
-                       pFontMgr);
-        }
-      }
-    } break;
-    default:
-      break;
-  }
+  int32_t iRules = sheet->CountRules();
+  for (int32_t j = 0; j < iRules; j++)
+    AddRulesFrom(sheet, sheet->GetRule(j), pFontMgr);
 }
 
-void CFDE_CSSRuleCollection::AddRuleTo(std::map<uint32_t, Data*>* pMap,
-                                       uint32_t dwKey,
-                                       CFDE_CSSSelector* pSel,
-                                       CFDE_CSSDeclaration* pDecl) {
-  Data* pData = NewRuleData(pSel, pDecl);
-  Data* pList = (*pMap)[dwKey];
-  if (!pList) {
-    (*pMap)[dwKey] = pData;
-  } else if (AddRuleTo(&pList, pData)) {
-    (*pMap)[dwKey] = pList;
+void CFDE_CSSRuleCollection::AddRulesFrom(const CFDE_CSSStyleSheet* pStyleSheet,
+                                          CFDE_CSSStyleRule* pStyleRule,
+                                          CFGAS_FontMgr* pFontMgr) {
+  CFDE_CSSDeclaration* pDeclaration = pStyleRule->GetDeclaration();
+  int32_t iSelectors = pStyleRule->CountSelectorLists();
+  for (int32_t i = 0; i < iSelectors; ++i) {
+    CFDE_CSSSelector* pSelector = pStyleRule->GetSelectorList(i);
+    m_TagRules[pSelector->GetNameHash()].push_back(
+        pdfium::MakeUnique<Data>(pSelector, pDeclaration));
+    m_iSelectors++;
   }
 }
 
-bool CFDE_CSSRuleCollection::AddRuleTo(Data** pList, Data* pData) {
-  if (*pList) {
-    pData->pNext = (*pList)->pNext;
-    (*pList)->pNext = pData;
-    return false;
-  }
-  *pList = pData;
-  return true;
-}
-
-CFDE_CSSRuleCollection::Data* CFDE_CSSRuleCollection::NewRuleData(
-    CFDE_CSSSelector* pSel,
-    CFDE_CSSDeclaration* pDecl) {
-  return new Data(pSel, pDecl, ++m_iSelectors);
-}
-
 CFDE_CSSRuleCollection::Data::Data(CFDE_CSSSelector* pSel,
-                                   CFDE_CSSDeclaration* pDecl,
-                                   uint32_t dwPos)
-    : pSelector(pSel), pDeclaration(pDecl), dwPriority(dwPos), pNext(nullptr) {
-  static const uint32_t s_Specific[5] = {0x00010000, 0x00010000, 0x00100000,
-                                         0x00100000, 0x01000000};
-  for (; pSel; pSel = pSel->GetNextSelector()) {
-    FDE_CSSSelectorType eType = pSel->GetType();
-    if (eType > FDE_CSSSelectorType::Descendant ||
-        pSel->GetNameHash() != FDE_CSSUNIVERSALHASH) {
-      dwPriority += s_Specific[static_cast<int>(eType)];
-    }
-  }
-}
+                                   CFDE_CSSDeclaration* pDecl)
+    : pSelector(pSel), pDeclaration(pDecl) {}
diff --git a/xfa/fde/css/cfde_cssrulecollection.h b/xfa/fde/css/cfde_cssrulecollection.h
index 1433a5a..5d49922 100644
--- a/xfa/fde/css/cfde_cssrulecollection.h
+++ b/xfa/fde/css/cfde_cssrulecollection.h
@@ -8,12 +8,14 @@
 #define XFA_FDE_CSS_CFDE_CSSRULECOLLECTION_H_
 
 #include <map>
+#include <memory>
+#include <vector>
 
 #include "core/fxcrt/fx_basic.h"
 
 class CFDE_CSSDeclaration;
-class CFDE_CSSRule;
 class CFDE_CSSSelector;
+class CFDE_CSSStyleRule;
 class CFDE_CSSStyleSheet;
 class CFGAS_FontMgr;
 
@@ -21,58 +23,28 @@
  public:
   class Data {
    public:
-    Data(CFDE_CSSSelector* pSel, CFDE_CSSDeclaration* pDecl, uint32_t dwPos);
+    Data(CFDE_CSSSelector* pSel, CFDE_CSSDeclaration* pDecl);
 
     CFDE_CSSSelector* const pSelector;
     CFDE_CSSDeclaration* const pDeclaration;
-    uint32_t dwPriority;
-    Data* pNext;
   };
 
   CFDE_CSSRuleCollection();
   ~CFDE_CSSRuleCollection();
 
-  void AddRulesFrom(const CFX_ArrayTemplate<CFDE_CSSStyleSheet*>& sheets,
-                    uint32_t dwMediaList,
-                    CFGAS_FontMgr* pFontMgr);
+  void AddRulesFrom(const CFDE_CSSStyleSheet* sheet, CFGAS_FontMgr* pFontMgr);
   void Clear();
   int32_t CountSelectors() const { return m_iSelectors; }
 
-  Data* GetIDRuleData(uint32_t dwIDHash) {
-    auto it = m_IDRules.find(dwIDHash);
-    return it != m_IDRules.end() ? it->second : nullptr;
-  }
+  const std::vector<std::unique_ptr<Data>>* GetTagRuleData(
+      const CFX_WideString& tagname) const;
 
-  Data* GetTagRuleData(uint32_t dwTagHash) {
-    auto it = m_TagRules.find(dwTagHash);
-    return it != m_TagRules.end() ? it->second : nullptr;
-  }
-
-  Data* GetClassRuleData(uint32_t dwIDHash) {
-    auto it = m_ClassRules.find(dwIDHash);
-    return it != m_ClassRules.end() ? it->second : nullptr;
-  }
-
-  Data* GetUniversalRuleData() { return m_pUniversalRules; }
-  Data* GetPseudoRuleData() { return m_pPseudoRules; }
-
- protected:
-  void AddRulesFrom(CFDE_CSSStyleSheet* pStyleSheet,
-                    CFDE_CSSRule* pRule,
-                    uint32_t dwMediaList,
+ private:
+  void AddRulesFrom(const CFDE_CSSStyleSheet* pStyleSheet,
+                    CFDE_CSSStyleRule* pRule,
                     CFGAS_FontMgr* pFontMgr);
-  void AddRuleTo(std::map<uint32_t, Data*>* pMap,
-                 uint32_t dwKey,
-                 CFDE_CSSSelector* pSel,
-                 CFDE_CSSDeclaration* pDecl);
-  bool AddRuleTo(Data** pList, Data* pData);
-  Data* NewRuleData(CFDE_CSSSelector* pSel, CFDE_CSSDeclaration* pDecl);
 
-  std::map<uint32_t, Data*> m_IDRules;
-  std::map<uint32_t, Data*> m_TagRules;
-  std::map<uint32_t, Data*> m_ClassRules;
-  Data* m_pUniversalRules;
-  Data* m_pPseudoRules;
+  std::map<uint32_t, std::vector<std::unique_ptr<Data>>> m_TagRules;
   int32_t m_iSelectors;
 };
 
diff --git a/xfa/fde/css/cfde_cssselector.cpp b/xfa/fde/css/cfde_cssselector.cpp
index 4d32bd1..0358023 100644
--- a/xfa/fde/css/cfde_cssselector.cpp
+++ b/xfa/fde/css/cfde_cssselector.cpp
@@ -16,19 +16,6 @@
   return (wch >= 'a' && wch <= 'z') || (wch >= 'A' && wch <= 'Z');
 }
 
-int32_t GetCSSPseudoLen(const FX_WCHAR* psz, const FX_WCHAR* pEnd) {
-  ASSERT(*psz == ':');
-  const FX_WCHAR* pStart = psz;
-  while (psz < pEnd) {
-    FX_WCHAR wch = *psz;
-    if (IsCSSChar(wch) || wch == ':')
-      ++psz;
-    else
-      break;
-  }
-  return psz - pStart;
-}
-
 int32_t GetCSSNameLen(const FX_WCHAR* psz, const FX_WCHAR* pEnd) {
   const FX_WCHAR* pStart = psz;
   while (psz < pEnd) {
@@ -66,17 +53,14 @@
   return m_pNext.get();
 }
 
-std::unique_ptr<CFDE_CSSSelector> CFDE_CSSSelector::ReleaseNextSelector() {
-  return std::move(m_pNext);
-}
-
+// static.
 std::unique_ptr<CFDE_CSSSelector> CFDE_CSSSelector::FromString(
-    const FX_WCHAR* psz,
-    int32_t iLen) {
-  ASSERT(psz && iLen > 0);
+    const CFX_WideStringC& str) {
+  ASSERT(!str.IsEmpty());
 
+  const FX_WCHAR* psz = str.c_str();
   const FX_WCHAR* pStart = psz;
-  const FX_WCHAR* pEnd = psz + iLen;
+  const FX_WCHAR* pEnd = psz + str.GetLength();
   for (; psz < pEnd; ++psz) {
     switch (*psz) {
       case '>':
@@ -87,44 +71,10 @@
   }
 
   std::unique_ptr<CFDE_CSSSelector> pFirst = nullptr;
-  CFDE_CSSSelector* pLast = nullptr;
-  std::unique_ptr<CFDE_CSSSelector> pPseudoFirst = nullptr;
-  CFDE_CSSSelector* pPseudoLast = nullptr;
-
   for (psz = pStart; psz < pEnd;) {
     FX_WCHAR wch = *psz;
-    if (wch == '.' || wch == '#') {
-      if (psz == pStart || psz[-1] == ' ') {
-        auto p = pdfium::MakeUnique<CFDE_CSSSelector>(
-            FDE_CSSSelectorType::Element, L"*", 1, true);
-
-        if (pFirst) {
-          pFirst->SetType(FDE_CSSSelectorType::Descendant);
-          p->SetNext(std::move(pFirst));
-        }
-        pFirst = std::move(p);
-        pLast = pFirst.get();
-      }
-      ASSERT(pLast);
-
-      int32_t iNameLen = GetCSSNameLen(++psz, pEnd);
-      if (iNameLen == 0)
-        return nullptr;
-
-      FDE_CSSSelectorType eType =
-          wch == '.' ? FDE_CSSSelectorType::Class : FDE_CSSSelectorType::ID;
-      auto p =
-          pdfium::MakeUnique<CFDE_CSSSelector>(eType, psz, iNameLen, false);
-
-      p->SetNext(pLast->ReleaseNextSelector());
-      pLast->SetNext(std::move(p));
-      pLast = pLast->GetNextSelector();
-      psz += iNameLen;
-    } else if (IsCSSChar(wch) || wch == '*') {
+    if (IsCSSChar(wch) || wch == '*') {
       int32_t iNameLen = wch == '*' ? 1 : GetCSSNameLen(psz, pEnd);
-      if (iNameLen == 0)
-        return nullptr;
-
       auto p = pdfium::MakeUnique<CFDE_CSSSelector>(
           FDE_CSSSelectorType::Element, psz, iNameLen, true);
       if (pFirst) {
@@ -132,21 +82,6 @@
         p->SetNext(std::move(pFirst));
       }
       pFirst = std::move(p);
-      pLast = pFirst.get();
-      psz += iNameLen;
-    } else if (wch == ':') {
-      int32_t iNameLen = GetCSSPseudoLen(psz, pEnd);
-      if (iNameLen == 0)
-        return nullptr;
-
-      auto p = pdfium::MakeUnique<CFDE_CSSSelector>(FDE_CSSSelectorType::Pseudo,
-                                                    psz, iNameLen, true);
-      CFDE_CSSSelector* ptr = p.get();
-      if (pPseudoFirst)
-        pPseudoLast->SetNext(std::move(p));
-      else
-        pPseudoFirst = std::move(p);
-      pPseudoLast = ptr;
       psz += iNameLen;
     } else if (wch == ' ') {
       psz++;
@@ -154,9 +89,5 @@
       return nullptr;
     }
   }
-  if (!pPseudoFirst)
-    return pFirst;
-
-  pPseudoLast->SetNext(std::move(pFirst));
-  return pPseudoFirst;
+  return pFirst;
 }
diff --git a/xfa/fde/css/cfde_cssselector.h b/xfa/fde/css/cfde_cssselector.h
index 18a7c34..d585b3f 100644
--- a/xfa/fde/css/cfde_cssselector.h
+++ b/xfa/fde/css/cfde_cssselector.h
@@ -15,8 +15,8 @@
 
 class CFDE_CSSSelector {
  public:
-  static std::unique_ptr<CFDE_CSSSelector> FromString(const FX_WCHAR* psz,
-                                                      int32_t iLen);
+  static std::unique_ptr<CFDE_CSSSelector> FromString(
+      const CFX_WideStringC& str);
 
   CFDE_CSSSelector(FDE_CSSSelectorType eType,
                    const FX_WCHAR* psz,
@@ -27,7 +27,6 @@
   FDE_CSSSelectorType GetType() const;
   uint32_t GetNameHash() const;
   CFDE_CSSSelector* GetNextSelector() const;
-  std::unique_ptr<CFDE_CSSSelector> ReleaseNextSelector();
 
   void SetNext(std::unique_ptr<CFDE_CSSSelector> pNext) {
     m_pNext = std::move(pNext);
diff --git a/xfa/fde/css/cfde_cssstylerule.cpp b/xfa/fde/css/cfde_cssstylerule.cpp
index 09c4a43..04f6cff 100644
--- a/xfa/fde/css/cfde_cssstylerule.cpp
+++ b/xfa/fde/css/cfde_cssstylerule.cpp
@@ -6,7 +6,7 @@
 
 #include "xfa/fde/css/cfde_cssstylerule.h"
 
-CFDE_CSSStyleRule::CFDE_CSSStyleRule() : CFDE_CSSRule(FDE_CSSRuleType::Style) {}
+CFDE_CSSStyleRule::CFDE_CSSStyleRule() {}
 
 CFDE_CSSStyleRule::~CFDE_CSSStyleRule() {}
 
diff --git a/xfa/fde/css/cfde_cssstylerule.h b/xfa/fde/css/cfde_cssstylerule.h
index bed0a5e..075ab8d 100644
--- a/xfa/fde/css/cfde_cssstylerule.h
+++ b/xfa/fde/css/cfde_cssstylerule.h
@@ -11,13 +11,12 @@
 #include <vector>
 
 #include "xfa/fde/css/cfde_cssdeclaration.h"
-#include "xfa/fde/css/cfde_cssrule.h"
 #include "xfa/fde/css/cfde_cssselector.h"
 
-class CFDE_CSSStyleRule : public CFDE_CSSRule {
+class CFDE_CSSStyleRule {
  public:
   CFDE_CSSStyleRule();
-  ~CFDE_CSSStyleRule() override;
+  ~CFDE_CSSStyleRule();
 
   size_t CountSelectorLists() const;
   CFDE_CSSSelector* GetSelectorList(int32_t index) const;
diff --git a/xfa/fde/css/cfde_cssstyleselector.cpp b/xfa/fde/css/cfde_cssstyleselector.cpp
index 1539894..5a7aa1b 100644
--- a/xfa/fde/css/cfde_cssstyleselector.cpp
+++ b/xfa/fde/css/cfde_cssstyleselector.cpp
@@ -7,9 +7,9 @@
 #include "xfa/fde/css/cfde_cssstyleselector.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "third_party/base/ptr_util.h"
-#include "xfa/fde/css/cfde_cssaccelerator.h"
 #include "xfa/fde/css/cfde_csscolorvalue.h"
 #include "xfa/fde/css/cfde_csscomputedstyle.h"
 #include "xfa/fde/css/cfde_csscustomproperty.h"
@@ -17,361 +17,152 @@
 #include "xfa/fde/css/cfde_cssenumvalue.h"
 #include "xfa/fde/css/cfde_csspropertyholder.h"
 #include "xfa/fde/css/cfde_cssselector.h"
+#include "xfa/fde/css/cfde_cssstylesheet.h"
 #include "xfa/fde/css/cfde_csssyntaxparser.h"
-#include "xfa/fde/css/cfde_csstagcache.h"
 #include "xfa/fde/css/cfde_cssvaluelist.h"
 #include "xfa/fxfa/app/cxfa_csstagprovider.h"
 
-namespace {
-
-template <class T>
-T* ToValue(CFDE_CSSValue* val) {
-  return static_cast<T*>(val);
-}
-
-template <class T>
-const T* ToValue(const CFDE_CSSValue* val) {
-  return static_cast<T*>(val);
-}
-
-}  // namespace
-
-#define FDE_CSSUNIVERSALHASH ('*')
-
 CFDE_CSSStyleSelector::CFDE_CSSStyleSelector(CFGAS_FontMgr* pFontMgr)
-    : m_pFontMgr(pFontMgr), m_fDefFontSize(12.0f) {
-  m_ePriorities[static_cast<int32_t>(FDE_CSSStyleSheetPriority::High)] =
-      FDE_CSSStyleSheetGroup::Author;
-  m_ePriorities[static_cast<int32_t>(FDE_CSSStyleSheetPriority::Mid)] =
-      FDE_CSSStyleSheetGroup::User;
-  m_ePriorities[static_cast<int32_t>(FDE_CSSStyleSheetPriority::Low)] =
-      FDE_CSSStyleSheetGroup::UserAgent;
-}
+    : m_pFontMgr(pFontMgr), m_fDefFontSize(12.0f) {}
 
-CFDE_CSSStyleSelector::~CFDE_CSSStyleSelector() {
-  Reset();
-}
+CFDE_CSSStyleSelector::~CFDE_CSSStyleSelector() {}
 
 void CFDE_CSSStyleSelector::SetDefFontSize(FX_FLOAT fFontSize) {
   ASSERT(fFontSize > 0);
   m_fDefFontSize = fFontSize;
 }
 
-CFDE_CSSAccelerator* CFDE_CSSStyleSelector::InitAccelerator() {
-  if (!m_pAccelerator)
-    m_pAccelerator = pdfium::MakeUnique<CFDE_CSSAccelerator>();
-  m_pAccelerator->Clear();
-  return m_pAccelerator.get();
-}
-
-CFDE_CSSComputedStyle* CFDE_CSSStyleSelector::CreateComputedStyle(
+CFX_RetainPtr<CFDE_CSSComputedStyle> CFDE_CSSStyleSelector::CreateComputedStyle(
     CFDE_CSSComputedStyle* pParentStyle) {
-  CFDE_CSSComputedStyle* pStyle = new CFDE_CSSComputedStyle();
+  auto pStyle = pdfium::MakeRetain<CFDE_CSSComputedStyle>();
   if (pParentStyle)
     pStyle->m_InheritedData = pParentStyle->m_InheritedData;
   return pStyle;
 }
 
-bool CFDE_CSSStyleSelector::SetStyleSheet(FDE_CSSStyleSheetGroup eType,
-                                          CFDE_CSSStyleSheet* pSheet) {
-  CFX_ArrayTemplate<CFDE_CSSStyleSheet*>& dest =
-      m_SheetGroups[static_cast<int32_t>(eType)];
-  dest.RemoveAt(0, dest.GetSize());
-  if (pSheet)
-    dest.Add(pSheet);
-  return true;
+void CFDE_CSSStyleSelector::SetUAStyleSheet(
+    std::unique_ptr<CFDE_CSSStyleSheet> pSheet) {
+  m_UAStyles = std::move(pSheet);
 }
 
-bool CFDE_CSSStyleSelector::SetStyleSheets(
-    FDE_CSSStyleSheetGroup eType,
-    const CFX_ArrayTemplate<CFDE_CSSStyleSheet*>* pArray) {
-  CFX_ArrayTemplate<CFDE_CSSStyleSheet*>& dest =
-      m_SheetGroups[static_cast<int32_t>(eType)];
-  if (pArray)
-    dest.Copy(*pArray);
-  else
-    dest.RemoveAt(0, dest.GetSize());
-  return true;
+void CFDE_CSSStyleSelector::UpdateStyleIndex() {
+  m_UARules.Clear();
+  m_UARules.AddRulesFrom(m_UAStyles.get(), m_pFontMgr);
 }
 
-void CFDE_CSSStyleSelector::SetStylePriority(
-    FDE_CSSStyleSheetGroup eType,
-    FDE_CSSStyleSheetPriority ePriority) {
-  m_ePriorities[static_cast<int32_t>(ePriority)] = eType;
-}
+std::vector<const CFDE_CSSDeclaration*>
+CFDE_CSSStyleSelector::MatchDeclarations(const CFX_WideString& tagname) {
+  std::vector<const CFDE_CSSDeclaration*> matchedDecls;
+  if (m_UARules.CountSelectors() == 0 || tagname.IsEmpty())
+    return matchedDecls;
 
-void CFDE_CSSStyleSelector::UpdateStyleIndex(uint32_t dwMediaList) {
-  Reset();
+  auto rules = m_UARules.GetTagRuleData(tagname);
+  if (!rules)
+    return matchedDecls;
 
-  // TODO(dsinclair): Hard coded size bad. This should probably just be a map.
-  for (int32_t iGroup = 0; iGroup < 3; ++iGroup) {
-    CFDE_CSSRuleCollection& rules = m_RuleCollection[iGroup];
-    rules.AddRulesFrom(m_SheetGroups[iGroup], dwMediaList, m_pFontMgr);
+  for (const auto& d : *rules) {
+    if (MatchSelector(tagname, d->pSelector))
+      matchedDecls.push_back(d->pDeclaration);
   }
+  return matchedDecls;
 }
 
-void CFDE_CSSStyleSelector::Reset() {
-  // TODO(dsinclair): Hard coded size bad. This should probably just be a map.
-  for (int32_t iGroup = 0; iGroup < 3; ++iGroup) {
-    m_RuleCollection[iGroup].Clear();
+bool CFDE_CSSStyleSelector::MatchSelector(const CFX_WideString& tagname,
+                                          CFDE_CSSSelector* pSel) {
+  // TODO(dsinclair): The code only supports a single level of selector at this
+  // point. None of the code using selectors required the complexity so lets
+  // just say we don't support them to simplify the code for now.
+  if (!pSel || pSel->GetNextSelector() ||
+      pSel->GetType() == FDE_CSSSelectorType::Descendant) {
+    return false;
   }
-}
-
-int32_t CFDE_CSSStyleSelector::MatchDeclarations(
-    CXFA_CSSTagProvider* pTag,
-    CFX_ArrayTemplate<CFDE_CSSDeclaration*>& matchedDecls,
-    FDE_CSSPseudo ePseudoType) {
-  ASSERT(pTag);
-  CFDE_CSSTagCache* pCache = m_pAccelerator->top();
-  ASSERT(pCache && pCache->GetTag() == pTag);
-
-  matchedDecls.RemoveAt(0, matchedDecls.GetSize());
-  // TODO(dsinclair): Hard coded size bad ...
-  for (int32_t ePriority = 2; ePriority >= 0; --ePriority) {
-    FDE_CSSStyleSheetGroup eGroup = m_ePriorities[ePriority];
-    CFDE_CSSRuleCollection& rules =
-        m_RuleCollection[static_cast<int32_t>(eGroup)];
-    if (rules.CountSelectors() == 0)
-      continue;
-
-    if (ePseudoType == FDE_CSSPseudo::NONE) {
-      MatchRules(pCache, rules.GetUniversalRuleData(), ePseudoType);
-      if (pCache->HashTag()) {
-        MatchRules(pCache, rules.GetTagRuleData(pCache->HashTag()),
-                   ePseudoType);
-      }
-      int32_t iCount = pCache->CountHashClass();
-      for (int32_t i = 0; i < iCount; i++) {
-        pCache->SetClassIndex(i);
-        MatchRules(pCache, rules.GetClassRuleData(pCache->HashClass()),
-                   ePseudoType);
-      }
-    } else {
-      MatchRules(pCache, rules.GetPseudoRuleData(), ePseudoType);
-    }
-
-    std::sort(m_MatchedRules.begin(), m_MatchedRules.end(),
-              [](const CFDE_CSSRuleCollection::Data* p1,
-                 const CFDE_CSSRuleCollection::Data* p2) {
-                return p1->dwPriority < p2->dwPriority;
-              });
-    for (const auto& rule : m_MatchedRules)
-      matchedDecls.Add(rule->pDeclaration);
-    m_MatchedRules.clear();
-  }
-  return matchedDecls.GetSize();
-}
-
-void CFDE_CSSStyleSelector::MatchRules(CFDE_CSSTagCache* pCache,
-                                       CFDE_CSSRuleCollection::Data* pList,
-                                       FDE_CSSPseudo ePseudoType) {
-  while (pList) {
-    if (MatchSelector(pCache, pList->pSelector, ePseudoType))
-      m_MatchedRules.push_back(pList);
-    pList = pList->pNext;
-  }
-}
-
-bool CFDE_CSSStyleSelector::MatchSelector(CFDE_CSSTagCache* pCache,
-                                          CFDE_CSSSelector* pSel,
-                                          FDE_CSSPseudo ePseudoType) {
-  uint32_t dwHash;
-  while (pSel && pCache) {
-    switch (pSel->GetType()) {
-      case FDE_CSSSelectorType::Descendant:
-        dwHash = pSel->GetNameHash();
-        while ((pCache = pCache->GetParent()) != nullptr) {
-          if (dwHash != FDE_CSSUNIVERSALHASH && dwHash != pCache->HashTag()) {
-            continue;
-          }
-          if (MatchSelector(pCache, pSel->GetNextSelector(), ePseudoType)) {
-            return true;
-          }
-        }
-        return false;
-      case FDE_CSSSelectorType::ID:
-        dwHash = pCache->HashID();
-        if (dwHash != pSel->GetNameHash()) {
-          return false;
-        }
-        break;
-      case FDE_CSSSelectorType::Class:
-        dwHash = pCache->HashClass();
-        if (dwHash != pSel->GetNameHash()) {
-          return false;
-        }
-        break;
-      case FDE_CSSSelectorType::Element:
-        dwHash = pSel->GetNameHash();
-        if (dwHash != FDE_CSSUNIVERSALHASH && dwHash != pCache->HashTag()) {
-          return false;
-        }
-        break;
-      case FDE_CSSSelectorType::Pseudo:
-        dwHash = FDE_GetCSSPseudoByEnum(ePseudoType)->dwHash;
-        if (dwHash != pSel->GetNameHash()) {
-          return false;
-        }
-        break;
-      default:
-        ASSERT(false);
-        break;
-    }
-    pSel = pSel->GetNextSelector();
-  }
-  return !pSel && pCache;
+  return pSel->GetNameHash() == FX_HashCode_GetW(tagname.c_str(), true);
 }
 
 void CFDE_CSSStyleSelector::ComputeStyle(
-    CXFA_CSSTagProvider* pTag,
-    const CFDE_CSSDeclaration** ppDeclArray,
-    int32_t iDeclCount,
-    CFDE_CSSComputedStyle* pDestStyle) {
-  ASSERT(iDeclCount >= 0);
-  ASSERT(pDestStyle);
+    const std::vector<const CFDE_CSSDeclaration*>& declArray,
+    const CFX_WideString& styleString,
+    const CFX_WideString& alignString,
+    CFDE_CSSComputedStyle* pDest) {
+  std::unique_ptr<CFDE_CSSDeclaration> pDecl;
+  if (!styleString.IsEmpty() || !alignString.IsEmpty()) {
+    pDecl = pdfium::MakeUnique<CFDE_CSSDeclaration>();
 
-  static const uint32_t s_dwStyleHash = FX_HashCode_GetW(L"style", true);
-  static const uint32_t s_dwAlignHash = FX_HashCode_GetW(L"align", true);
-
-  if (!pTag->empty()) {
-    CFDE_CSSDeclaration* pDecl = nullptr;
-    for (auto it : *pTag) {
-      CFX_WideString wsAttri = it.first;
-      CFX_WideString wsValue = it.second;
-      uint32_t dwAttriHash = FX_HashCode_GetW(wsAttri.AsStringC(), true);
-      if (dwAttriHash == s_dwStyleHash) {
-        if (!pDecl)
-          pDecl = new CFDE_CSSDeclaration;
-
-        AppendInlineStyle(pDecl, wsValue.c_str(), wsValue.GetLength());
-      } else if (dwAttriHash == s_dwAlignHash) {
-        if (!pDecl)
-          pDecl = new CFDE_CSSDeclaration;
-
-        FDE_CSSPropertyArgs args;
-        args.pStringCache = nullptr;
-        args.pProperty = FDE_GetCSSPropertyByEnum(FDE_CSSProperty::TextAlign);
-        pDecl->AddProperty(&args, wsValue.c_str(), wsValue.GetLength());
-      }
-    }
-
-    if (pDecl) {
-      CFX_ArrayTemplate<CFDE_CSSDeclaration*> decls;
-      decls.SetSize(iDeclCount + 1);
-      CFDE_CSSDeclaration** ppInline = decls.GetData();
-      FXSYS_memcpy(ppInline, ppDeclArray,
-                   iDeclCount * sizeof(CFDE_CSSDeclaration*));
-      ppInline[iDeclCount++] = pDecl;
-      ApplyDeclarations(true, const_cast<const CFDE_CSSDeclaration**>(ppInline),
-                        iDeclCount, pDestStyle);
-      ApplyDeclarations(false,
-                        const_cast<const CFDE_CSSDeclaration**>(ppInline),
-                        iDeclCount, pDestStyle);
-      return;
+    if (!styleString.IsEmpty())
+      AppendInlineStyle(pDecl.get(), styleString);
+    if (!alignString.IsEmpty()) {
+      pDecl->AddProperty(FDE_GetCSSPropertyByEnum(FDE_CSSProperty::TextAlign),
+                         alignString.AsStringC());
     }
   }
-
-  if (iDeclCount > 0) {
-    ASSERT(ppDeclArray);
-
-    ApplyDeclarations(true, ppDeclArray, iDeclCount, pDestStyle);
-    ApplyDeclarations(false, ppDeclArray, iDeclCount, pDestStyle);
-  }
+  ApplyDeclarations(declArray, pDecl.get(), pDest);
 }
 
 void CFDE_CSSStyleSelector::ApplyDeclarations(
-    bool bPriority,
-    const CFDE_CSSDeclaration** ppDeclArray,
-    int32_t iDeclCount,
-    CFDE_CSSComputedStyle* pDestStyle) {
-  CFDE_CSSComputedStyle* pComputedStyle = pDestStyle;
+    const std::vector<const CFDE_CSSDeclaration*>& declArray,
+    const CFDE_CSSDeclaration* extraDecl,
+    CFDE_CSSComputedStyle* pComputedStyle) {
+  std::vector<const CFDE_CSSPropertyHolder*> importants;
+  std::vector<const CFDE_CSSPropertyHolder*> normals;
+  std::vector<const CFDE_CSSCustomProperty*> customs;
 
-  int32_t i;
-  if (bPriority) {
-    CFDE_CSSValue* pLastest = nullptr;
-    CFDE_CSSValue* pImportant = nullptr;
-    for (i = 0; i < iDeclCount; ++i) {
-      bool bImportant;
-      CFDE_CSSValue* pVal =
-          ppDeclArray[i]->GetProperty(FDE_CSSProperty::FontSize, bImportant);
-      if (!pVal)
-        continue;
+  for (auto& decl : declArray)
+    ExtractValues(decl, &importants, &normals, &customs);
 
-      if (bImportant)
-        pImportant = pVal;
-      else
-        pLastest = pVal;
-    }
-    if (pImportant) {
-      ApplyProperty(FDE_CSSProperty::FontSize, pImportant, pComputedStyle);
-    } else if (pLastest) {
-      ApplyProperty(FDE_CSSProperty::FontSize, pLastest, pComputedStyle);
-    }
-  } else {
-    CFX_ArrayTemplate<CFDE_CSSDeclaration*> importants;
-    const CFDE_CSSDeclaration* pDecl = nullptr;
+  if (extraDecl)
+    ExtractValues(extraDecl, &importants, &normals, &customs);
 
-    for (i = 0; i < iDeclCount; ++i) {
-      pDecl = ppDeclArray[i];
-      for (auto it = pDecl->begin(); it != pDecl->end(); it++) {
-        if ((*it)->eProperty == FDE_CSSProperty::FontSize)
-          continue;
-        if (!(*it)->bImportant) {
-          ApplyProperty((*it)->eProperty, (*it)->pValue.Get(), pComputedStyle);
-        } else if (importants.GetSize() == 0 ||
-                   importants[importants.GetUpperBound()] != pDecl) {
-          importants.Add(const_cast<CFDE_CSSDeclaration*>(pDecl));
-        }
-      }
-    }
+  for (auto& prop : normals)
+    ApplyProperty(prop->eProperty, prop->pValue, pComputedStyle);
 
-    iDeclCount = importants.GetSize();
-    for (i = 0; i < iDeclCount; ++i) {
-      pDecl = importants[i];
+  for (auto& prop : customs)
+    pComputedStyle->AddCustomStyle(*prop);
 
-      for (auto it = pDecl->begin(); it != pDecl->end(); it++) {
-        if ((*it)->bImportant && (*it)->eProperty != FDE_CSSProperty::FontSize)
-          ApplyProperty((*it)->eProperty, (*it)->pValue.Get(), pComputedStyle);
-      }
-    }
+  for (auto& prop : importants)
+    ApplyProperty(prop->eProperty, prop->pValue, pComputedStyle);
+}
 
-    for (auto it = pDecl->custom_begin(); it != pDecl->custom_end(); it++) {
-      pComputedStyle->AddCustomStyle((*it)->pwsName, (*it)->pwsValue);
-    }
+void CFDE_CSSStyleSelector::ExtractValues(
+    const CFDE_CSSDeclaration* decl,
+    std::vector<const CFDE_CSSPropertyHolder*>* importants,
+    std::vector<const CFDE_CSSPropertyHolder*>* normals,
+    std::vector<const CFDE_CSSCustomProperty*>* custom) {
+  for (const auto& holder : *decl) {
+    if (holder->bImportant)
+      importants->push_back(holder.get());
+    else
+      normals->push_back(holder.get());
   }
+  for (auto it = decl->custom_begin(); it != decl->custom_end(); it++)
+    custom->push_back(it->get());
 }
 
 void CFDE_CSSStyleSelector::AppendInlineStyle(CFDE_CSSDeclaration* pDecl,
-                                              const FX_WCHAR* psz,
-                                              int32_t iLen) {
-  ASSERT(pDecl && psz && iLen > 0);
+                                              const CFX_WideString& style) {
+  ASSERT(pDecl && !style.IsEmpty());
+
   auto pSyntax = pdfium::MakeUnique<CFDE_CSSSyntaxParser>();
-  if (!pSyntax->Init(psz, iLen, 32, true))
+  if (!pSyntax->Init(style.c_str(), style.GetLength(), 32, true))
     return;
 
   int32_t iLen2 = 0;
-  const FX_WCHAR* psz2;
-  FDE_CSSPropertyArgs args;
-  args.pStringCache = nullptr;
-  args.pProperty = nullptr;
+  const FDE_CSSPropertyTable* table = nullptr;
   CFX_WideString wsName;
   while (1) {
     FDE_CSSSyntaxStatus eStatus = pSyntax->DoSyntaxParse();
     if (eStatus == FDE_CSSSyntaxStatus::PropertyName) {
-      psz2 = pSyntax->GetCurrentString(iLen2);
-      args.pProperty = FDE_GetCSSPropertyByName(CFX_WideStringC(psz2, iLen2));
-      if (!args.pProperty)
-        wsName = CFX_WideStringC(psz2, iLen2);
+      CFX_WideStringC strValue = pSyntax->GetCurrentString();
+      table = FDE_GetCSSPropertyByName(strValue);
+      if (!table)
+        wsName = CFX_WideString(strValue);
     } else if (eStatus == FDE_CSSSyntaxStatus::PropertyValue) {
-      if (args.pProperty) {
-        psz2 = pSyntax->GetCurrentString(iLen2);
-        if (iLen2 > 0)
-          pDecl->AddProperty(&args, psz2, iLen2);
-      } else if (iLen2 > 0) {
-        psz2 = pSyntax->GetCurrentString(iLen2);
-        if (iLen2 > 0) {
-          pDecl->AddProperty(&args, wsName.c_str(), wsName.GetLength(), psz2,
-                             iLen2);
+      if (table || iLen2 > 0) {
+        CFX_WideStringC strValue = pSyntax->GetCurrentString();
+        if (!strValue.IsEmpty()) {
+          if (table)
+            pDecl->AddProperty(table, strValue);
+          else if (iLen2 > 0)
+            pDecl->AddProperty(wsName, CFX_WideString(strValue));
         }
       }
     } else {
@@ -382,7 +173,7 @@
 
 void CFDE_CSSStyleSelector::ApplyProperty(
     FDE_CSSProperty eProperty,
-    CFDE_CSSValue* pValue,
+    const CFX_RetainPtr<CFDE_CSSValue>& pValue,
     CFDE_CSSComputedStyle* pComputedStyle) {
   if (pValue->GetType() != FDE_CSSPrimitiveType::List) {
     FDE_CSSPrimitiveType eType = pValue->GetType();
@@ -390,21 +181,22 @@
       case FDE_CSSProperty::Display:
         if (eType == FDE_CSSPrimitiveType::Enum) {
           pComputedStyle->m_NonInheritedData.m_eDisplay =
-              ToDisplay(ToValue<CFDE_CSSEnumValue>(pValue)->Value());
+              ToDisplay(pValue.As<CFDE_CSSEnumValue>()->Value());
         }
         break;
       case FDE_CSSProperty::FontSize: {
         FX_FLOAT& fFontSize = pComputedStyle->m_InheritedData.m_fFontSize;
         if (eType == FDE_CSSPrimitiveType::Number) {
-          fFontSize = ToValue<CFDE_CSSNumberValue>(pValue)->Apply(fFontSize);
+          fFontSize = pValue.As<CFDE_CSSNumberValue>()->Apply(fFontSize);
         } else if (eType == FDE_CSSPrimitiveType::Enum) {
-          fFontSize = ToFontSize(ToValue<CFDE_CSSEnumValue>(pValue)->Value(),
-                                 fFontSize);
+          fFontSize =
+              ToFontSize(pValue.As<CFDE_CSSEnumValue>()->Value(), fFontSize);
         }
       } break;
       case FDE_CSSProperty::LineHeight:
         if (eType == FDE_CSSPrimitiveType::Number) {
-          const CFDE_CSSNumberValue* v = ToValue<CFDE_CSSNumberValue>(pValue);
+          CFX_RetainPtr<CFDE_CSSNumberValue> v =
+              pValue.As<CFDE_CSSNumberValue>();
           if (v->Kind() == FDE_CSSNumberType::Number) {
             pComputedStyle->m_InheritedData.m_fLineHeight =
                 v->Value() * pComputedStyle->m_InheritedData.m_fFontSize;
@@ -417,7 +209,7 @@
       case FDE_CSSProperty::TextAlign:
         if (eType == FDE_CSSPrimitiveType::Enum) {
           pComputedStyle->m_InheritedData.m_eTextAlign =
-              ToTextAlign(ToValue<CFDE_CSSEnumValue>(pValue)->Value());
+              ToTextAlign(pValue.As<CFDE_CSSEnumValue>()->Value());
         }
         break;
       case FDE_CSSProperty::TextIndent:
@@ -428,10 +220,10 @@
       case FDE_CSSProperty::FontWeight:
         if (eType == FDE_CSSPrimitiveType::Enum) {
           pComputedStyle->m_InheritedData.m_wFontWeight =
-              ToFontWeight(ToValue<CFDE_CSSEnumValue>(pValue)->Value());
+              ToFontWeight(pValue.As<CFDE_CSSEnumValue>()->Value());
         } else if (eType == FDE_CSSPrimitiveType::Number) {
           int32_t iValue =
-              (int32_t)ToValue<CFDE_CSSNumberValue>(pValue)->Value() / 100;
+              (int32_t)pValue.As<CFDE_CSSNumberValue>()->Value() / 100;
           if (iValue >= 1 && iValue <= 9) {
             pComputedStyle->m_InheritedData.m_wFontWeight = iValue * 100;
           }
@@ -440,13 +232,13 @@
       case FDE_CSSProperty::FontStyle:
         if (eType == FDE_CSSPrimitiveType::Enum) {
           pComputedStyle->m_InheritedData.m_eFontStyle =
-              ToFontStyle(ToValue<CFDE_CSSEnumValue>(pValue)->Value());
+              ToFontStyle(pValue.As<CFDE_CSSEnumValue>()->Value());
         }
         break;
       case FDE_CSSProperty::Color:
         if (eType == FDE_CSSPrimitiveType::RGB) {
           pComputedStyle->m_InheritedData.m_dwFontColor =
-              ToValue<CFDE_CSSColorValue>(pValue)->Value();
+              pValue.As<CFDE_CSSColorValue>()->Value();
         }
         break;
       case FDE_CSSProperty::MarginLeft:
@@ -536,19 +328,19 @@
       case FDE_CSSProperty::VerticalAlign:
         if (eType == FDE_CSSPrimitiveType::Enum) {
           pComputedStyle->m_NonInheritedData.m_eVerticalAlign =
-              ToVerticalAlign(ToValue<CFDE_CSSEnumValue>(pValue)->Value());
+              ToVerticalAlign(pValue.As<CFDE_CSSEnumValue>()->Value());
         } else if (eType == FDE_CSSPrimitiveType::Number) {
           pComputedStyle->m_NonInheritedData.m_eVerticalAlign =
               FDE_CSSVerticalAlign::Number;
           pComputedStyle->m_NonInheritedData.m_fVerticalAlign =
-              ToValue<CFDE_CSSNumberValue>(pValue)->Apply(
+              pValue.As<CFDE_CSSNumberValue>()->Apply(
                   pComputedStyle->m_InheritedData.m_fFontSize);
         }
         break;
       case FDE_CSSProperty::FontVariant:
         if (eType == FDE_CSSPrimitiveType::Enum) {
           pComputedStyle->m_InheritedData.m_eFontVariant =
-              ToFontVariant(ToValue<CFDE_CSSEnumValue>(pValue)->Value());
+              ToFontVariant(pValue.As<CFDE_CSSEnumValue>()->Value());
         }
         break;
       case FDE_CSSProperty::LetterSpacing:
@@ -556,7 +348,7 @@
           pComputedStyle->m_InheritedData.m_LetterSpacing.Set(
               FDE_CSSLengthUnit::Normal);
         } else if (eType == FDE_CSSPrimitiveType::Number) {
-          if (ToValue<CFDE_CSSNumberValue>(pValue)->Kind() ==
+          if (pValue.As<CFDE_CSSNumberValue>()->Kind() ==
               FDE_CSSNumberType::Percent) {
             break;
           }
@@ -571,7 +363,7 @@
           pComputedStyle->m_InheritedData.m_WordSpacing.Set(
               FDE_CSSLengthUnit::Normal);
         } else if (eType == FDE_CSSPrimitiveType::Number) {
-          if (ToValue<CFDE_CSSNumberValue>(pValue)->Kind() ==
+          if (pValue.As<CFDE_CSSNumberValue>()->Kind() ==
               FDE_CSSNumberType::Percent) {
             break;
           }
@@ -604,7 +396,7 @@
         break;
     }
   } else if (pValue->GetType() == FDE_CSSPrimitiveType::List) {
-    CFDE_CSSValueList* pList = ToValue<CFDE_CSSValueList>(pValue);
+    CFX_RetainPtr<CFDE_CSSValueList> pList = pValue.As<CFDE_CSSValueList>();
     int32_t iCount = pList->CountValues();
     if (iCount > 0) {
       switch (eProperty) {
@@ -682,15 +474,16 @@
   }
 }
 
-bool CFDE_CSSStyleSelector::SetLengthWithPercent(FDE_CSSLength& width,
-                                                 FDE_CSSPrimitiveType eType,
-                                                 CFDE_CSSValue* pValue,
-                                                 FX_FLOAT fFontSize) {
+bool CFDE_CSSStyleSelector::SetLengthWithPercent(
+    FDE_CSSLength& width,
+    FDE_CSSPrimitiveType eType,
+    const CFX_RetainPtr<CFDE_CSSValue>& pValue,
+    FX_FLOAT fFontSize) {
   if (eType == FDE_CSSPrimitiveType::Number) {
-    const CFDE_CSSNumberValue* v = ToValue<CFDE_CSSNumberValue>(pValue);
+    CFX_RetainPtr<CFDE_CSSNumberValue> v = pValue.As<CFDE_CSSNumberValue>();
     if (v->Kind() == FDE_CSSNumberType::Percent) {
       width.Set(FDE_CSSLengthUnit::Percent,
-                ToValue<CFDE_CSSNumberValue>(pValue)->Value() / 100.0f);
+                pValue.As<CFDE_CSSNumberValue>()->Value() / 100.0f);
       return width.NonZero();
     }
 
@@ -698,7 +491,7 @@
     width.Set(FDE_CSSLengthUnit::Point, fValue);
     return width.NonZero();
   } else if (eType == FDE_CSSPrimitiveType::Enum) {
-    switch (ToValue<CFDE_CSSEnumValue>(pValue)->Value()) {
+    switch (pValue.As<CFDE_CSSEnumValue>()->Value()) {
       case FDE_CSSPropertyValue::Auto:
         width.Set(FDE_CSSLengthUnit::Auto);
         return true;
@@ -770,14 +563,15 @@
   }
 }
 
-uint32_t CFDE_CSSStyleSelector::ToTextDecoration(CFDE_CSSValueList* pValue) {
+uint32_t CFDE_CSSStyleSelector::ToTextDecoration(
+    const CFX_RetainPtr<CFDE_CSSValueList>& pValue) {
   uint32_t dwDecoration = 0;
   for (int32_t i = pValue->CountValues() - 1; i >= 0; --i) {
-    CFDE_CSSValue* pVal = pValue->GetValue(i);
+    const CFX_RetainPtr<CFDE_CSSValue> pVal = pValue->GetValue(i);
     if (pVal->GetType() != FDE_CSSPrimitiveType::Enum)
       continue;
 
-    switch (ToValue<CFDE_CSSEnumValue>(pVal)->Value()) {
+    switch (pVal.As<CFDE_CSSEnumValue>()->Value()) {
       case FDE_CSSPropertyValue::Underline:
         dwDecoration |= FDE_CSSTEXTDECORATION_Underline;
         break;
diff --git a/xfa/fde/css/cfde_cssstyleselector.h b/xfa/fde/css/cfde_cssstyleselector.h
index 6a7ae99..c7b6b41 100644
--- a/xfa/fde/css/cfde_cssstyleselector.h
+++ b/xfa/fde/css/cfde_cssstyleselector.h
@@ -15,16 +15,15 @@
 #include "xfa/fde/css/cfde_cssrulecollection.h"
 #include "xfa/fde/css/fde_css.h"
 
-class CFDE_CSSAccelerator;
 class CFDE_CSSComputedStyle;
+class CFDE_CSSCustomProperty;
 class CFDE_CSSDeclaration;
+class CFDE_CSSPropertyHolder;
 class CFDE_CSSSelector;
 class CFDE_CSSStyleSheet;
-class CFDE_CSSTagCache;
 class CFDE_CSSValue;
 class CFDE_CSSValueList;
 class CFGAS_FontMgr;
-class CXFA_CSSTagProvider;
 
 class CFDE_CSSStyleSelector {
  public:
@@ -32,47 +31,43 @@
   ~CFDE_CSSStyleSelector();
 
   void SetDefFontSize(FX_FLOAT fFontSize);
+  void SetUAStyleSheet(std::unique_ptr<CFDE_CSSStyleSheet> pSheet);
+  void UpdateStyleIndex();
 
-  bool SetStyleSheet(FDE_CSSStyleSheetGroup eType, CFDE_CSSStyleSheet* pSheet);
-  bool SetStyleSheets(FDE_CSSStyleSheetGroup eType,
-                      const CFX_ArrayTemplate<CFDE_CSSStyleSheet*>* pArray);
-  void SetStylePriority(FDE_CSSStyleSheetGroup eType,
-                        FDE_CSSStyleSheetPriority ePriority);
-  void UpdateStyleIndex(uint32_t dwMediaList);
-  CFDE_CSSAccelerator* InitAccelerator();
-  CFDE_CSSComputedStyle* CreateComputedStyle(
+  CFX_RetainPtr<CFDE_CSSComputedStyle> CreateComputedStyle(
       CFDE_CSSComputedStyle* pParentStyle);
-  int32_t MatchDeclarations(
-      CXFA_CSSTagProvider* pTag,
-      CFX_ArrayTemplate<CFDE_CSSDeclaration*>& matchedDecls,
-      FDE_CSSPseudo ePseudoType = FDE_CSSPseudo::NONE);
-  void ComputeStyle(CXFA_CSSTagProvider* pTag,
-                    const CFDE_CSSDeclaration** ppDeclArray,
-                    int32_t iDeclCount,
+
+  // Note, the dest style has to be an out param because the CXFA_TextParser
+  // adds non-inherited data from the parent style. Attempting to copy
+  // internally will fail as you'll lose the non-inherited data.
+  void ComputeStyle(const std::vector<const CFDE_CSSDeclaration*>& declArray,
+                    const CFX_WideString& styleString,
+                    const CFX_WideString& alignString,
                     CFDE_CSSComputedStyle* pDestStyle);
 
- protected:
-  void Reset();
-  void MatchRules(CFDE_CSSTagCache* pCache,
-                  CFDE_CSSRuleCollection::Data* pList,
-                  FDE_CSSPseudo ePseudoType);
-  bool MatchSelector(CFDE_CSSTagCache* pCache,
-                     CFDE_CSSSelector* pSel,
-                     FDE_CSSPseudo ePseudoType);
+  std::vector<const CFDE_CSSDeclaration*> MatchDeclarations(
+      const CFX_WideString& tagname);
+
+ private:
+  bool MatchSelector(const CFX_WideString& tagname, CFDE_CSSSelector* pSel);
+
   void AppendInlineStyle(CFDE_CSSDeclaration* pDecl,
-                         const FX_WCHAR* psz,
-                         int32_t iLen);
-  void ApplyDeclarations(bool bPriority,
-                         const CFDE_CSSDeclaration** ppDeclArray,
-                         int32_t iDeclCount,
-                         CFDE_CSSComputedStyle* pDestStyle);
+                         const CFX_WideString& style);
+  void ApplyDeclarations(
+      const std::vector<const CFDE_CSSDeclaration*>& declArray,
+      const CFDE_CSSDeclaration* extraDecl,
+      CFDE_CSSComputedStyle* pDestStyle);
   void ApplyProperty(FDE_CSSProperty eProperty,
-                     CFDE_CSSValue* pValue,
+                     const CFX_RetainPtr<CFDE_CSSValue>& pValue,
                      CFDE_CSSComputedStyle* pComputedStyle);
+  void ExtractValues(const CFDE_CSSDeclaration* decl,
+                     std::vector<const CFDE_CSSPropertyHolder*>* importants,
+                     std::vector<const CFDE_CSSPropertyHolder*>* normals,
+                     std::vector<const CFDE_CSSCustomProperty*>* custom);
 
   bool SetLengthWithPercent(FDE_CSSLength& width,
                             FDE_CSSPrimitiveType eType,
-                            CFDE_CSSValue* pValue,
+                            const CFX_RetainPtr<CFDE_CSSValue>& pValue,
                             FX_FLOAT fFontSize);
   FX_FLOAT ToFontSize(FDE_CSSPropertyValue eValue, FX_FLOAT fCurFontSize);
   FDE_CSSDisplay ToDisplay(FDE_CSSPropertyValue eValue);
@@ -80,16 +75,13 @@
   uint16_t ToFontWeight(FDE_CSSPropertyValue eValue);
   FDE_CSSFontStyle ToFontStyle(FDE_CSSPropertyValue eValue);
   FDE_CSSVerticalAlign ToVerticalAlign(FDE_CSSPropertyValue eValue);
-  uint32_t ToTextDecoration(CFDE_CSSValueList* pList);
+  uint32_t ToTextDecoration(const CFX_RetainPtr<CFDE_CSSValueList>& pList);
   FDE_CSSFontVariant ToFontVariant(FDE_CSSPropertyValue eValue);
 
   CFGAS_FontMgr* const m_pFontMgr;
   FX_FLOAT m_fDefFontSize;
-  CFX_ArrayTemplate<CFDE_CSSStyleSheet*> m_SheetGroups[3];
-  CFDE_CSSRuleCollection m_RuleCollection[3];
-  FDE_CSSStyleSheetGroup m_ePriorities[3];
-  std::unique_ptr<CFDE_CSSAccelerator> m_pAccelerator;
-  std::vector<CFDE_CSSRuleCollection::Data*> m_MatchedRules;
+  std::unique_ptr<CFDE_CSSStyleSheet> m_UAStyles;
+  CFDE_CSSRuleCollection m_UARules;
 };
 
 #endif  // XFA_FDE_CSS_CFDE_CSSSTYLESELECTOR_H_
diff --git a/xfa/fde/css/cfde_cssstylesheet.cpp b/xfa/fde/css/cfde_cssstylesheet.cpp
index 4ff1b97..c8bf70e 100644
--- a/xfa/fde/css/cfde_cssstylesheet.cpp
+++ b/xfa/fde/css/cfde_cssstylesheet.cpp
@@ -11,17 +11,11 @@
 #include "third_party/base/ptr_util.h"
 #include "third_party/base/stl_util.h"
 #include "xfa/fde/css/cfde_cssdeclaration.h"
-#include "xfa/fde/css/cfde_cssfontfacerule.h"
-#include "xfa/fde/css/cfde_cssmediarule.h"
-#include "xfa/fde/css/cfde_cssrule.h"
 #include "xfa/fde/css/cfde_cssstylerule.h"
 #include "xfa/fde/css/fde_cssdatatable.h"
 #include "xfa/fgas/crt/fgas_codepage.h"
 
-CFDE_CSSStyleSheet::CFDE_CSSStyleSheet()
-    : m_wRefCount(1), m_dwMediaList(FDE_CSSMEDIATYPE_ALL) {
-  ASSERT(m_dwMediaList > 0);
-}
+CFDE_CSSStyleSheet::CFDE_CSSStyleSheet() {}
 
 CFDE_CSSStyleSheet::~CFDE_CSSStyleSheet() {
   Reset();
@@ -32,56 +26,27 @@
   m_StringCache.clear();
 }
 
-uint32_t CFDE_CSSStyleSheet::Retain() {
-  return ++m_wRefCount;
-}
-
-uint32_t CFDE_CSSStyleSheet::Release() {
-  uint32_t dwRefCount = --m_wRefCount;
-  if (dwRefCount == 0)
-    delete this;
-  return dwRefCount;
-}
-
-uint32_t CFDE_CSSStyleSheet::GetMediaList() const {
-  return m_dwMediaList;
-}
-
 int32_t CFDE_CSSStyleSheet::CountRules() const {
   return pdfium::CollectionSize<int32_t>(m_RuleArray);
 }
 
-CFDE_CSSRule* CFDE_CSSStyleSheet::GetRule(int32_t index) {
+CFDE_CSSStyleRule* CFDE_CSSStyleSheet::GetRule(int32_t index) const {
   return m_RuleArray[index].get();
 }
 
-bool CFDE_CSSStyleSheet::LoadFromBuffer(const FX_WCHAR* pBuffer,
-                                        int32_t iBufSize) {
+bool CFDE_CSSStyleSheet::LoadBuffer(const FX_WCHAR* pBuffer, int32_t iBufSize) {
   ASSERT(pBuffer && iBufSize > 0);
 
   auto pSyntax = pdfium::MakeUnique<CFDE_CSSSyntaxParser>();
-  return pSyntax->Init(pBuffer, iBufSize) && LoadFromSyntax(pSyntax.get());
-}
+  if (!pSyntax->Init(pBuffer, iBufSize))
+    return false;
 
-bool CFDE_CSSStyleSheet::LoadFromSyntax(CFDE_CSSSyntaxParser* pSyntax) {
   Reset();
   FDE_CSSSyntaxStatus eStatus;
   do {
     switch (eStatus = pSyntax->DoSyntaxParse()) {
       case FDE_CSSSyntaxStatus::StyleRule:
-        eStatus = LoadStyleRule(pSyntax, &m_RuleArray);
-        break;
-      case FDE_CSSSyntaxStatus::MediaRule:
-        eStatus = LoadMediaRule(pSyntax);
-        break;
-      case FDE_CSSSyntaxStatus::FontFaceRule:
-        eStatus = LoadFontFaceRule(pSyntax, &m_RuleArray);
-        break;
-      case FDE_CSSSyntaxStatus::ImportRule:
-        eStatus = LoadImportRule(pSyntax);
-        break;
-      case FDE_CSSSyntaxStatus::PageRule:
-        eStatus = LoadPageRule(pSyntax);
+        eStatus = LoadStyleRule(pSyntax.get(), &m_RuleArray);
         break;
       default:
         break;
@@ -92,95 +57,46 @@
   return eStatus != FDE_CSSSyntaxStatus::Error;
 }
 
-FDE_CSSSyntaxStatus CFDE_CSSStyleSheet::LoadMediaRule(
-    CFDE_CSSSyntaxParser* pSyntax) {
-  uint32_t dwMediaList = 0;
-  CFDE_CSSMediaRule* pMediaRule = nullptr;
-  for (;;) {
-    switch (pSyntax->DoSyntaxParse()) {
-      case FDE_CSSSyntaxStatus::MediaType: {
-        int32_t iLen;
-        const FX_WCHAR* psz = pSyntax->GetCurrentString(iLen);
-        const FDE_CSSMEDIATYPETABLE* pMediaType =
-            FDE_GetCSSMediaTypeByName(CFX_WideStringC(psz, iLen));
-        if (pMediaType)
-          dwMediaList |= pMediaType->wValue;
-      } break;
-      case FDE_CSSSyntaxStatus::StyleRule:
-        if (pMediaRule) {
-          FDE_CSSSyntaxStatus eStatus =
-              LoadStyleRule(pSyntax, &pMediaRule->GetArray());
-          if (eStatus < FDE_CSSSyntaxStatus::None) {
-            return eStatus;
-          }
-        } else {
-          SkipRuleSet(pSyntax);
-        }
-        break;
-      case FDE_CSSSyntaxStatus::DeclOpen:
-        if ((dwMediaList & m_dwMediaList) > 0 && !pMediaRule) {
-          m_RuleArray.push_back(
-              pdfium::MakeUnique<CFDE_CSSMediaRule>(dwMediaList));
-          pMediaRule =
-              static_cast<CFDE_CSSMediaRule*>(m_RuleArray.back().get());
-        }
-        break;
-      case FDE_CSSSyntaxStatus::DeclClose:
-        return FDE_CSSSyntaxStatus::None;
-      case FDE_CSSSyntaxStatus::EOS:
-        return FDE_CSSSyntaxStatus::EOS;
-      case FDE_CSSSyntaxStatus::Error:
-      default:
-        return FDE_CSSSyntaxStatus::Error;
-    }
-  }
-}
-
 FDE_CSSSyntaxStatus CFDE_CSSStyleSheet::LoadStyleRule(
     CFDE_CSSSyntaxParser* pSyntax,
-    std::vector<std::unique_ptr<CFDE_CSSRule>>* ruleArray) {
+    std::vector<std::unique_ptr<CFDE_CSSStyleRule>>* ruleArray) {
   std::vector<std::unique_ptr<CFDE_CSSSelector>> selectors;
 
   CFDE_CSSStyleRule* pStyleRule = nullptr;
-  const FX_WCHAR* pszValue = nullptr;
   int32_t iValueLen = 0;
-  FDE_CSSPropertyArgs propertyArgs;
-  propertyArgs.pStringCache = &m_StringCache;
-  propertyArgs.pProperty = nullptr;
+  const FDE_CSSPropertyTable* propertyTable = nullptr;
   CFX_WideString wsName;
-  for (;;) {
+  while (1) {
     switch (pSyntax->DoSyntaxParse()) {
       case FDE_CSSSyntaxStatus::Selector: {
-        pszValue = pSyntax->GetCurrentString(iValueLen);
-        auto pSelector = CFDE_CSSSelector::FromString(pszValue, iValueLen);
+        CFX_WideStringC strValue = pSyntax->GetCurrentString();
+        auto pSelector = CFDE_CSSSelector::FromString(strValue);
         if (pSelector)
           selectors.push_back(std::move(pSelector));
         break;
       }
-      case FDE_CSSSyntaxStatus::PropertyName:
-        pszValue = pSyntax->GetCurrentString(iValueLen);
-        propertyArgs.pProperty =
-            FDE_GetCSSPropertyByName(CFX_WideStringC(pszValue, iValueLen));
-        if (!propertyArgs.pProperty)
-          wsName = CFX_WideStringC(pszValue, iValueLen);
+      case FDE_CSSSyntaxStatus::PropertyName: {
+        CFX_WideStringC strValue = pSyntax->GetCurrentString();
+        propertyTable = FDE_GetCSSPropertyByName(strValue);
+        if (!propertyTable)
+          wsName = CFX_WideString(strValue);
         break;
-      case FDE_CSSSyntaxStatus::PropertyValue:
-        if (propertyArgs.pProperty) {
-          pszValue = pSyntax->GetCurrentString(iValueLen);
-          if (iValueLen > 0) {
-            pStyleRule->GetDeclaration()->AddProperty(&propertyArgs, pszValue,
-                                                      iValueLen);
-          }
-        } else if (iValueLen > 0) {
-          pszValue = pSyntax->GetCurrentString(iValueLen);
-          if (iValueLen > 0) {
-            pStyleRule->GetDeclaration()->AddProperty(
-                &propertyArgs, wsName.c_str(), wsName.GetLength(), pszValue,
-                iValueLen);
+      }
+      case FDE_CSSSyntaxStatus::PropertyValue: {
+        if (propertyTable || iValueLen > 0) {
+          CFX_WideStringC strValue = pSyntax->GetCurrentString();
+          auto decl = pStyleRule->GetDeclaration();
+          if (!strValue.IsEmpty()) {
+            if (propertyTable) {
+              decl->AddProperty(propertyTable, strValue);
+            } else {
+              decl->AddProperty(wsName, CFX_WideString(strValue));
+            }
           }
         }
         break;
-      case FDE_CSSSyntaxStatus::DeclOpen:
+      }
+      case FDE_CSSSyntaxStatus::DeclOpen: {
         if (!pStyleRule && !selectors.empty()) {
           auto rule = pdfium::MakeUnique<CFDE_CSSStyleRule>();
           pStyleRule = rule.get();
@@ -191,12 +107,14 @@
           return FDE_CSSSyntaxStatus::None;
         }
         break;
-      case FDE_CSSSyntaxStatus::DeclClose:
+      }
+      case FDE_CSSSyntaxStatus::DeclClose: {
         if (pStyleRule && pStyleRule->GetDeclaration()->empty()) {
           ruleArray->pop_back();
           pStyleRule = nullptr;
         }
         return FDE_CSSSyntaxStatus::None;
+      }
       case FDE_CSSSyntaxStatus::EOS:
         return FDE_CSSSyntaxStatus::EOS;
       case FDE_CSSSyntaxStatus::Error:
@@ -206,74 +124,8 @@
   }
 }
 
-FDE_CSSSyntaxStatus CFDE_CSSStyleSheet::LoadFontFaceRule(
-    CFDE_CSSSyntaxParser* pSyntax,
-    std::vector<std::unique_ptr<CFDE_CSSRule>>* ruleArray) {
-  CFDE_CSSFontFaceRule* pFontFaceRule = nullptr;
-  const FX_WCHAR* pszValue = nullptr;
-  int32_t iValueLen = 0;
-  FDE_CSSPropertyArgs propertyArgs;
-  propertyArgs.pStringCache = &m_StringCache;
-  propertyArgs.pProperty = nullptr;
-  for (;;) {
-    switch (pSyntax->DoSyntaxParse()) {
-      case FDE_CSSSyntaxStatus::PropertyName:
-        pszValue = pSyntax->GetCurrentString(iValueLen);
-        propertyArgs.pProperty =
-            FDE_GetCSSPropertyByName(CFX_WideStringC(pszValue, iValueLen));
-        break;
-      case FDE_CSSSyntaxStatus::PropertyValue:
-        if (propertyArgs.pProperty) {
-          pszValue = pSyntax->GetCurrentString(iValueLen);
-          if (iValueLen > 0) {
-            pFontFaceRule->GetDeclaration()->AddProperty(&propertyArgs,
-                                                         pszValue, iValueLen);
-          }
-        }
-        break;
-      case FDE_CSSSyntaxStatus::DeclOpen:
-        if (!pFontFaceRule) {
-          auto rule = pdfium::MakeUnique<CFDE_CSSFontFaceRule>();
-          pFontFaceRule = rule.get();
-          ruleArray->push_back(std::move(rule));
-        }
-        break;
-      case FDE_CSSSyntaxStatus::DeclClose:
-        return FDE_CSSSyntaxStatus::None;
-      case FDE_CSSSyntaxStatus::EOS:
-        return FDE_CSSSyntaxStatus::EOS;
-      case FDE_CSSSyntaxStatus::Error:
-      default:
-        return FDE_CSSSyntaxStatus::Error;
-    }
-  }
-}
-
-FDE_CSSSyntaxStatus CFDE_CSSStyleSheet::LoadImportRule(
-    CFDE_CSSSyntaxParser* pSyntax) {
-  for (;;) {
-    switch (pSyntax->DoSyntaxParse()) {
-      case FDE_CSSSyntaxStatus::ImportClose:
-        return FDE_CSSSyntaxStatus::None;
-      case FDE_CSSSyntaxStatus::URI:
-        break;
-      case FDE_CSSSyntaxStatus::EOS:
-        return FDE_CSSSyntaxStatus::EOS;
-      case FDE_CSSSyntaxStatus::Error:
-      default:
-        return FDE_CSSSyntaxStatus::Error;
-    }
-  }
-}
-
-FDE_CSSSyntaxStatus CFDE_CSSStyleSheet::LoadPageRule(
-    CFDE_CSSSyntaxParser* pSyntax) {
-  return SkipRuleSet(pSyntax);
-}
-
-FDE_CSSSyntaxStatus CFDE_CSSStyleSheet::SkipRuleSet(
-    CFDE_CSSSyntaxParser* pSyntax) {
-  for (;;) {
+void CFDE_CSSStyleSheet::SkipRuleSet(CFDE_CSSSyntaxParser* pSyntax) {
+  while (1) {
     switch (pSyntax->DoSyntaxParse()) {
       case FDE_CSSSyntaxStatus::Selector:
       case FDE_CSSSyntaxStatus::DeclOpen:
@@ -281,12 +133,10 @@
       case FDE_CSSSyntaxStatus::PropertyValue:
         break;
       case FDE_CSSSyntaxStatus::DeclClose:
-        return FDE_CSSSyntaxStatus::None;
       case FDE_CSSSyntaxStatus::EOS:
-        return FDE_CSSSyntaxStatus::EOS;
       case FDE_CSSSyntaxStatus::Error:
       default:
-        return FDE_CSSSyntaxStatus::Error;
+        return;
     }
   }
 }
diff --git a/xfa/fde/css/cfde_cssstylesheet.h b/xfa/fde/css/cfde_cssstylesheet.h
index 2268efa..4de3772 100644
--- a/xfa/fde/css/cfde_cssstylesheet.h
+++ b/xfa/fde/css/cfde_cssstylesheet.h
@@ -11,44 +11,29 @@
 #include <unordered_map>
 #include <vector>
 
-#include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_string.h"
 #include "xfa/fde/css/cfde_csssyntaxparser.h"
 
-class CFDE_CSSRule;
+class CFDE_CSSStyleRule;
 
-class CFDE_CSSStyleSheet : public IFX_Retainable {
+class CFDE_CSSStyleSheet {
  public:
   CFDE_CSSStyleSheet();
-  ~CFDE_CSSStyleSheet() override;
+  ~CFDE_CSSStyleSheet();
 
-  // IFX_Retainable:
-  uint32_t Retain() override;
-  uint32_t Release() override;
+  bool LoadBuffer(const FX_WCHAR* pBuffer, int32_t iBufSize);
 
-  bool LoadFromBuffer(const FX_WCHAR* pBuffer, int32_t iBufSize);
-
-  uint32_t GetMediaList() const;
   int32_t CountRules() const;
-  CFDE_CSSRule* GetRule(int32_t index);
+  CFDE_CSSStyleRule* GetRule(int32_t index) const;
 
  private:
   void Reset();
-  bool LoadFromSyntax(CFDE_CSSSyntaxParser* pSyntax);
   FDE_CSSSyntaxStatus LoadStyleRule(
       CFDE_CSSSyntaxParser* pSyntax,
-      std::vector<std::unique_ptr<CFDE_CSSRule>>* ruleArray);
-  FDE_CSSSyntaxStatus LoadImportRule(CFDE_CSSSyntaxParser* pSyntax);
-  FDE_CSSSyntaxStatus LoadPageRule(CFDE_CSSSyntaxParser* pSyntax);
-  FDE_CSSSyntaxStatus LoadMediaRule(CFDE_CSSSyntaxParser* pSyntax);
-  FDE_CSSSyntaxStatus LoadFontFaceRule(
-      CFDE_CSSSyntaxParser* pSyntax,
-      std::vector<std::unique_ptr<CFDE_CSSRule>>* ruleArray);
-  FDE_CSSSyntaxStatus SkipRuleSet(CFDE_CSSSyntaxParser* pSyntax);
+      std::vector<std::unique_ptr<CFDE_CSSStyleRule>>* ruleArray);
+  void SkipRuleSet(CFDE_CSSSyntaxParser* pSyntax);
 
-  uint16_t m_wRefCount;
-  uint32_t m_dwMediaList;
-  std::vector<std::unique_ptr<CFDE_CSSRule>> m_RuleArray;
+  std::vector<std::unique_ptr<CFDE_CSSStyleRule>> m_RuleArray;
   std::unordered_map<uint32_t, FX_WCHAR*> m_StringCache;
 };
 
diff --git a/xfa/fde/css/cfde_cssstylesheet_unittest.cpp b/xfa/fde/css/cfde_cssstylesheet_unittest.cpp
index 080b45a..fa73a7a 100644
--- a/xfa/fde/css/cfde_cssstylesheet_unittest.cpp
+++ b/xfa/fde/css/cfde_cssstylesheet_unittest.cpp
@@ -15,7 +15,6 @@
 #include "xfa/fde/css/cfde_cssdeclaration.h"
 #include "xfa/fde/css/cfde_cssenumvalue.h"
 #include "xfa/fde/css/cfde_cssnumbervalue.h"
-#include "xfa/fde/css/cfde_cssrule.h"
 #include "xfa/fde/css/cfde_cssstylerule.h"
 #include "xfa/fde/css/cfde_cssvaluelist.h"
 
@@ -33,13 +32,10 @@
                          size_t decl_count) {
     ASSERT(sheet_);
 
-    EXPECT_TRUE(sheet_->LoadFromBuffer(buf, FXSYS_wcslen(buf)));
+    EXPECT_TRUE(sheet_->LoadBuffer(buf, FXSYS_wcslen(buf)));
     EXPECT_EQ(sheet_->CountRules(), 1);
 
-    CFDE_CSSRule* rule = sheet_->GetRule(0);
-    EXPECT_EQ(rule->GetType(), FDE_CSSRuleType::Style);
-
-    CFDE_CSSStyleRule* style = static_cast<CFDE_CSSStyleRule*>(rule);
+    CFDE_CSSStyleRule* style = sheet_->GetRule(0);
     EXPECT_EQ(selectors.size(), style->CountSelectorLists());
 
     for (size_t i = 0; i < selectors.size(); i++) {
@@ -55,19 +51,19 @@
     ASSERT(decl_);
 
     bool important;
-    CFDE_CSSValue* v = decl_->GetProperty(prop, important);
+    CFX_RetainPtr<CFDE_CSSValue> v = decl_->GetProperty(prop, &important);
     EXPECT_EQ(v->GetType(), FDE_CSSPrimitiveType::Number);
-    EXPECT_EQ(static_cast<CFDE_CSSNumberValue*>(v)->Kind(), type);
-    EXPECT_EQ(static_cast<CFDE_CSSNumberValue*>(v)->Value(), val);
+    EXPECT_EQ(v.As<CFDE_CSSNumberValue>()->Kind(), type);
+    EXPECT_EQ(v.As<CFDE_CSSNumberValue>()->Value(), val);
   }
 
   void VerifyEnum(FDE_CSSProperty prop, FDE_CSSPropertyValue val) {
     ASSERT(decl_);
 
     bool important;
-    CFDE_CSSValue* v = decl_->GetProperty(prop, important);
+    CFX_RetainPtr<CFDE_CSSValue> v = decl_->GetProperty(prop, &important);
     EXPECT_EQ(v->GetType(), FDE_CSSPrimitiveType::Enum);
-    EXPECT_EQ(static_cast<CFDE_CSSEnumValue*>(v)->Value(), val);
+    EXPECT_EQ(v.As<CFDE_CSSEnumValue>()->Value(), val);
   }
 
   void VerifyList(FDE_CSSProperty prop,
@@ -75,14 +71,14 @@
     ASSERT(decl_);
 
     bool important;
-    CFDE_CSSValue* v = decl_->GetProperty(prop, important);
-    CFDE_CSSValueList* list = static_cast<CFDE_CSSValueList*>(v);
+    CFX_RetainPtr<CFDE_CSSValueList> list =
+        decl_->GetProperty(prop, &important).As<CFDE_CSSValueList>();
     EXPECT_EQ(list->CountValues(), pdfium::CollectionSize<int32_t>(values));
 
     for (size_t i = 0; i < values.size(); i++) {
-      CFDE_CSSValue* val = list->GetValue(i);
+      CFX_RetainPtr<CFDE_CSSValue> val = list->GetValue(i);
       EXPECT_EQ(val->GetType(), FDE_CSSPrimitiveType::Enum);
-      EXPECT_EQ(static_cast<CFDE_CSSEnumValue*>(val)->Value(), values[i]);
+      EXPECT_EQ(val.As<CFDE_CSSEnumValue>()->Value(), values[i]);
     }
   }
 
@@ -93,13 +89,10 @@
 TEST_F(CFDE_CSSStyleSheetTest, ParseMultipleSelectors) {
   const FX_WCHAR* buf =
       L"a { border: 10px; }\nb { text-decoration: underline; }";
-  EXPECT_TRUE(sheet_->LoadFromBuffer(buf, FXSYS_wcslen(buf)));
+  EXPECT_TRUE(sheet_->LoadBuffer(buf, FXSYS_wcslen(buf)));
   EXPECT_EQ(2, sheet_->CountRules());
 
-  CFDE_CSSRule* rule = sheet_->GetRule(0);
-  EXPECT_EQ(FDE_CSSRuleType::Style, rule->GetType());
-
-  CFDE_CSSStyleRule* style = static_cast<CFDE_CSSStyleRule*>(rule);
+  CFDE_CSSStyleRule* style = sheet_->GetRule(0);
   EXPECT_EQ(1UL, style->CountSelectorLists());
 
   bool found_selector = false;
@@ -123,10 +116,7 @@
   VerifyFloat(FDE_CSSProperty::BorderBottomWidth, 10.0,
               FDE_CSSNumberType::Pixels);
 
-  rule = sheet_->GetRule(1);
-  EXPECT_EQ(FDE_CSSRuleType::Style, rule->GetType());
-
-  style = static_cast<CFDE_CSSStyleRule*>(rule);
+  style = sheet_->GetRule(1);
   EXPECT_EQ(1UL, style->CountSelectorLists());
 
   found_selector = false;
@@ -145,22 +135,63 @@
              {FDE_CSSPropertyValue::Underline});
 }
 
+TEST_F(CFDE_CSSStyleSheetTest, ParseChildSelectors) {
+  const FX_WCHAR* buf = L"a b c { border: 10px; }";
+  EXPECT_TRUE(sheet_->LoadBuffer(buf, FXSYS_wcslen(buf)));
+  EXPECT_EQ(1, sheet_->CountRules());
+
+  CFDE_CSSStyleRule* style = sheet_->GetRule(0);
+  EXPECT_EQ(1UL, style->CountSelectorLists());
+
+  auto sel = style->GetSelectorList(0);
+  EXPECT_TRUE(sel != nullptr);
+  EXPECT_EQ(FX_HashCode_GetW(L"c", true), sel->GetNameHash());
+
+  sel = sel->GetNextSelector();
+  EXPECT_TRUE(sel != nullptr);
+  EXPECT_EQ(FX_HashCode_GetW(L"b", true), sel->GetNameHash());
+
+  sel = sel->GetNextSelector();
+  EXPECT_TRUE(sel != nullptr);
+  EXPECT_EQ(FX_HashCode_GetW(L"a", true), sel->GetNameHash());
+
+  sel = sel->GetNextSelector();
+  EXPECT_TRUE(sel == nullptr);
+
+  decl_ = style->GetDeclaration();
+  EXPECT_EQ(4UL, decl_->PropertyCountForTesting());
+
+  VerifyFloat(FDE_CSSProperty::BorderLeftWidth, 10.0,
+              FDE_CSSNumberType::Pixels);
+  VerifyFloat(FDE_CSSProperty::BorderRightWidth, 10.0,
+              FDE_CSSNumberType::Pixels);
+  VerifyFloat(FDE_CSSProperty::BorderTopWidth, 10.0, FDE_CSSNumberType::Pixels);
+  VerifyFloat(FDE_CSSProperty::BorderBottomWidth, 10.0,
+              FDE_CSSNumberType::Pixels);
+}
+
+TEST_F(CFDE_CSSStyleSheetTest, ParseUnhandledSelectors) {
+  const FX_WCHAR* buf = L"a > b { padding: 0; }";
+  EXPECT_TRUE(sheet_->LoadBuffer(buf, FXSYS_wcslen(buf)));
+  EXPECT_EQ(0, sheet_->CountRules());
+
+  buf = L"a[first] { padding: 0; }";
+  EXPECT_TRUE(sheet_->LoadBuffer(buf, FXSYS_wcslen(buf)));
+  EXPECT_EQ(0, sheet_->CountRules());
+
+  buf = L"a+b { padding: 0; }";
+  EXPECT_TRUE(sheet_->LoadBuffer(buf, FXSYS_wcslen(buf)));
+  EXPECT_EQ(0, sheet_->CountRules());
+
+  buf = L"a ^ b { padding: 0; }";
+  EXPECT_TRUE(sheet_->LoadBuffer(buf, FXSYS_wcslen(buf)));
+  EXPECT_EQ(0, sheet_->CountRules());
+}
+
 TEST_F(CFDE_CSSStyleSheetTest, ParseMultipleSelectorsCombined) {
   LoadAndVerifyDecl(L"a, b, c { border: 5px; }", {L"a", L"b", L"c"}, 4);
 }
 
-TEST_F(CFDE_CSSStyleSheetTest, ParseWithPseudo) {
-  // TODO(dsinclair): I think this is wrong, as the selector just becomes
-  // :before and we lose the a?
-  LoadAndVerifyDecl(L"a:before { border: 10px; }", {L":before"}, 4);
-}
-
-TEST_F(CFDE_CSSStyleSheetTest, ParseWithSelectorsAndPseudo) {
-  // TODO(dsinclair): I think this is wrong as we lose the b on the b:before
-  LoadAndVerifyDecl(L"a, b:before, c { border: 1px; }",
-                    {L"a", L":before", L"c"}, 4);
-}
-
 TEST_F(CFDE_CSSStyleSheetTest, ParseBorder) {
   LoadAndVerifyDecl(L"a { border: 5px; }", {L"a"}, 4);
   VerifyFloat(FDE_CSSProperty::BorderLeftWidth, 5.0, FDE_CSSNumberType::Pixels);
diff --git a/xfa/fde/css/cfde_csssyntaxparser.cpp b/xfa/fde/css/cfde_csssyntaxparser.cpp
index a24b4ee..2f7bcce 100644
--- a/xfa/fde/css/cfde_csssyntaxparser.cpp
+++ b/xfa/fde/css/cfde_csssyntaxparser.cpp
@@ -19,24 +19,10 @@
          (wch >= 'A' && wch <= 'Z');
 }
 
-bool ParseCSSURI(const FX_WCHAR* pszValue, int32_t* iOffset, int32_t* iLength) {
-  ASSERT(pszValue && *iLength > 0);
-  if (*iLength < 6 || pszValue[*iLength - 1] != ')' ||
-      FXSYS_wcsnicmp(L"url(", pszValue, 4)) {
-    return false;
-  }
-  if (CFDE_CSSDeclaration::ParseCSSString(pszValue + 4, *iLength - 5, iOffset,
-                                          iLength)) {
-    *iOffset += 4;
-    return true;
-  }
-  return false;
-}
-
 }  // namespace
 
 CFDE_CSSSyntaxParser::CFDE_CSSSyntaxParser()
-    : m_iTextDatLen(0),
+    : m_iTextDataLen(0),
       m_dwCheck((uint32_t)-1),
       m_eMode(FDE_CSSSyntaxMode::RuleSet),
       m_eStatus(FDE_CSSSyntaxStatus::None) {}
@@ -60,7 +46,7 @@
 void CFDE_CSSSyntaxParser::Reset(bool bOnlyDeclaration) {
   m_TextPlane.Reset();
   m_TextData.Reset();
-  m_iTextDatLen = 0;
+  m_iTextDataLen = 0;
   m_dwCheck = (uint32_t)-1;
   m_eStatus = FDE_CSSSyntaxStatus::None;
   m_eMode = bOnlyDeclaration ? FDE_CSSSyntaxMode::PropertyName
@@ -85,10 +71,6 @@
       switch (m_eMode) {
         case FDE_CSSSyntaxMode::RuleSet:
           switch (wch) {
-            case '@':
-              m_TextPlane.MoveNext();
-              SwitchMode(FDE_CSSSyntaxMode::AtRule);
-              break;
             case '}':
               m_TextPlane.MoveNext();
               if (RestoreMode())
@@ -120,7 +102,7 @@
             case ',':
               m_TextPlane.MoveNext();
               SwitchMode(FDE_CSSSyntaxMode::Selector);
-              if (m_iTextDatLen > 0)
+              if (m_iTextDataLen > 0)
                 return FDE_CSSSyntaxStatus::Selector;
               break;
             case '{':
@@ -194,128 +176,6 @@
           }
           m_TextPlane.MoveNext();
           break;
-        case FDE_CSSSyntaxMode::MediaType:
-          switch (wch) {
-            case ',':
-              m_TextPlane.MoveNext();
-              SwitchMode(FDE_CSSSyntaxMode::MediaType);
-              if (m_iTextDatLen > 0)
-                return FDE_CSSSyntaxStatus::MediaType;
-              break;
-            case '{': {
-              if (m_ModeStack.empty() ||
-                  m_ModeStack.top() != FDE_CSSSyntaxMode::MediaRule) {
-                m_eStatus = FDE_CSSSyntaxStatus::Error;
-                return m_eStatus;
-              }
-
-              if (m_TextData.GetLength() > 0) {
-                SaveTextData();
-                return FDE_CSSSyntaxStatus::MediaType;
-              }
-              m_TextPlane.MoveNext();
-
-              // Replace the MediaRule with a RuleSet rule.
-              m_ModeStack.top() = FDE_CSSSyntaxMode::RuleSet;
-
-              SwitchMode(FDE_CSSSyntaxMode::RuleSet);
-              return FDE_CSSSyntaxStatus::DeclOpen;
-            }
-            case ';': {
-              if (m_ModeStack.empty() ||
-                  m_ModeStack.top() != FDE_CSSSyntaxMode::Import) {
-                m_eStatus = FDE_CSSSyntaxStatus::Error;
-                return m_eStatus;
-              }
-
-              if (m_TextData.GetLength() > 0) {
-                SaveTextData();
-                if (IsImportEnabled())
-                  return FDE_CSSSyntaxStatus::MediaType;
-              } else {
-                bool bEnabled = IsImportEnabled();
-                m_TextPlane.MoveNext();
-                m_ModeStack.pop();
-                SwitchMode(FDE_CSSSyntaxMode::RuleSet);
-                if (bEnabled) {
-                  DisableImport();
-                  return FDE_CSSSyntaxStatus::ImportClose;
-                }
-              }
-            } break;
-            case '/':
-              if (m_TextPlane.GetNextChar() == '*') {
-                if (SwitchToComment() > 0)
-                  return FDE_CSSSyntaxStatus::MediaType;
-                break;
-              }
-            default:
-              AppendChar(wch);
-              break;
-          }
-          break;
-        case FDE_CSSSyntaxMode::URI: {
-          if (m_ModeStack.empty() ||
-              m_ModeStack.top() != FDE_CSSSyntaxMode::Import) {
-            m_eStatus = FDE_CSSSyntaxStatus::Error;
-            return m_eStatus;
-          }
-
-          if (wch <= ' ' || wch == ';') {
-            int32_t iURIStart, iURILength = m_TextData.GetLength();
-            if (iURILength > 0 &&
-                ParseCSSURI(m_TextData.GetBuffer(), &iURIStart, &iURILength)) {
-              m_TextData.Subtract(iURIStart, iURILength);
-              SwitchMode(FDE_CSSSyntaxMode::MediaType);
-              if (IsImportEnabled())
-                return FDE_CSSSyntaxStatus::URI;
-              break;
-            }
-          }
-          AppendChar(wch);
-        } break;
-        case FDE_CSSSyntaxMode::AtRule:
-          if (wch > ' ') {
-            AppendChar(wch);
-          } else {
-            int32_t iLen = m_TextData.GetLength();
-            const FX_WCHAR* psz = m_TextData.GetBuffer();
-            if (FXSYS_wcsncmp(L"charset", psz, iLen) == 0) {
-              SwitchMode(FDE_CSSSyntaxMode::Charset);
-            } else if (FXSYS_wcsncmp(L"import", psz, iLen) == 0) {
-              m_ModeStack.push(FDE_CSSSyntaxMode::Import);
-              SwitchMode(FDE_CSSSyntaxMode::URI);
-              if (IsImportEnabled())
-                return FDE_CSSSyntaxStatus::ImportRule;
-              break;
-            } else if (FXSYS_wcsncmp(L"media", psz, iLen) == 0) {
-              m_ModeStack.push(FDE_CSSSyntaxMode::MediaRule);
-              SwitchMode(FDE_CSSSyntaxMode::MediaType);
-              return FDE_CSSSyntaxStatus::MediaRule;
-            } else if (FXSYS_wcsncmp(L"font-face", psz, iLen) == 0) {
-              SwitchMode(FDE_CSSSyntaxMode::Selector);
-              return FDE_CSSSyntaxStatus::FontFaceRule;
-            } else if (FXSYS_wcsncmp(L"page", psz, iLen) == 0) {
-              SwitchMode(FDE_CSSSyntaxMode::Selector);
-              return FDE_CSSSyntaxStatus::PageRule;
-            } else {
-              SwitchMode(FDE_CSSSyntaxMode::UnknownRule);
-            }
-          }
-          break;
-        case FDE_CSSSyntaxMode::Charset:
-          if (wch == ';') {
-            m_TextPlane.MoveNext();
-            SwitchMode(FDE_CSSSyntaxMode::RuleSet);
-            if (IsCharsetEnabled()) {
-              DisableCharset();
-              if (m_iTextDatLen > 0)
-                return FDE_CSSSyntaxStatus::Charset;
-            }
-          } else {
-            AppendChar(wch);
-          }
-          break;
         case FDE_CSSSyntaxMode::UnknownRule:
           if (wch == ';')
             SwitchMode(FDE_CSSSyntaxMode::RuleSet);
@@ -348,9 +208,9 @@
 }
 
 int32_t CFDE_CSSSyntaxParser::SaveTextData() {
-  m_iTextDatLen = m_TextData.TrimEnd();
+  m_iTextDataLen = m_TextData.TrimEnd();
   m_TextData.Clear();
-  return m_iTextDatLen;
+  return m_iTextDataLen;
 }
 
 void CFDE_CSSSyntaxParser::SwitchMode(FDE_CSSSyntaxMode eMode) {
@@ -374,7 +234,6 @@
   return true;
 }
 
-const FX_WCHAR* CFDE_CSSSyntaxParser::GetCurrentString(int32_t& iLength) const {
-  iLength = m_iTextDatLen;
-  return m_TextData.GetBuffer();
+CFX_WideStringC CFDE_CSSSyntaxParser::GetCurrentString() const {
+  return CFX_WideStringC(m_TextData.GetBuffer(), m_iTextDataLen);
 }
diff --git a/xfa/fde/css/cfde_csssyntaxparser.h b/xfa/fde/css/cfde_csssyntaxparser.h
index 131fe4b..b583b98 100644
--- a/xfa/fde/css/cfde_csssyntaxparser.h
+++ b/xfa/fde/css/cfde_csssyntaxparser.h
@@ -17,13 +17,7 @@
 enum class FDE_CSSSyntaxMode {
   RuleSet,
   Comment,
-  AtRule,
   UnknownRule,
-  Charset,
-  Import,
-  MediaRule,
-  URI,
-  MediaType,
   Selector,
   PropertyName,
   PropertyValue,
@@ -33,15 +27,7 @@
   Error,
   EOS,
   None,
-  Charset,
-  ImportRule,
-  ImportClose,
-  PageRule,
   StyleRule,
-  FontFaceRule,
-  MediaRule,
-  MediaType,
-  URI,
   Selector,
   DeclOpen,
   DeclClose,
@@ -59,7 +45,7 @@
             int32_t iTextDatSize = 32,
             bool bOnlyDeclaration = false);
   FDE_CSSSyntaxStatus DoSyntaxParse();
-  const FX_WCHAR* GetCurrentString(int32_t& iLength) const;
+  CFX_WideStringC GetCurrentString() const;
 
  protected:
   void Reset(bool bOnlyDeclaration);
@@ -78,7 +64,7 @@
 
   CFDE_CSSTextBuf m_TextData;
   CFDE_CSSTextBuf m_TextPlane;
-  int32_t m_iTextDatLen;
+  int32_t m_iTextDataLen;
   uint32_t m_dwCheck;
   FDE_CSSSyntaxMode m_eMode;
   FDE_CSSSyntaxStatus m_eStatus;
diff --git a/xfa/fde/css/cfde_csstagcache.cpp b/xfa/fde/css/cfde_csstagcache.cpp
deleted file mode 100644
index 13e3798..0000000
--- a/xfa/fde/css/cfde_csstagcache.cpp
+++ /dev/null
@@ -1,44 +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/fde/css/cfde_csstagcache.h"
-
-#include <algorithm>
-
-#include "core/fxcrt/fx_ext.h"
-#include "xfa/fxfa/app/cxfa_csstagprovider.h"
-
-CFDE_CSSTagCache::CFDE_CSSTagCache(CFDE_CSSTagCache* parent,
-                                   CXFA_CSSTagProvider* tag)
-    : pTag(tag), pParent(parent), dwIDHash(0), dwTagHash(0), iClassIndex(0) {
-  static const uint32_t s_dwIDHash = FX_HashCode_GetW(L"id", true);
-  static const uint32_t s_dwClassHash = FX_HashCode_GetW(L"class", true);
-  dwTagHash = FX_HashCode_GetW(pTag->GetTagName().AsStringC(), true);
-
-  for (auto it : *pTag) {
-    CFX_WideString wsValue = it.first;
-    CFX_WideString wsName = it.second;
-    uint32_t dwNameHash = FX_HashCode_GetW(wsName.AsStringC(), true);
-    if (dwNameHash == s_dwClassHash) {
-      uint32_t dwHash = FX_HashCode_GetW(wsValue.AsStringC(), false);
-      dwClassHashes.push_back(dwHash);
-    } else if (dwNameHash == s_dwIDHash) {
-      dwIDHash = FX_HashCode_GetW(wsValue.AsStringC(), false);
-    }
-  }
-}
-
-CFDE_CSSTagCache::CFDE_CSSTagCache(const CFDE_CSSTagCache& it)
-    : pTag(it.pTag),
-      pParent(it.pParent),
-      dwIDHash(it.dwIDHash),
-      dwTagHash(it.dwTagHash),
-      iClassIndex(0) {
-  std::copy(it.dwClassHashes.begin(), it.dwClassHashes.end(),
-            dwClassHashes.begin());
-}
-
-CFDE_CSSTagCache::~CFDE_CSSTagCache() {}
diff --git a/xfa/fde/css/cfde_csstagcache.h b/xfa/fde/css/cfde_csstagcache.h
deleted file mode 100644
index 6d9b4e7..0000000
--- a/xfa/fde/css/cfde_csstagcache.h
+++ /dev/null
@@ -1,46 +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_FDE_CSS_CFDE_CSSTAGCACHE_H_
-#define XFA_FDE_CSS_CFDE_CSSTAGCACHE_H_
-
-#include <vector>
-
-#include "core/fxcrt/fx_system.h"
-#include "third_party/base/stl_util.h"
-
-class CXFA_CSSTagProvider;
-
-class CFDE_CSSTagCache {
- public:
-  CFDE_CSSTagCache(CFDE_CSSTagCache* parent, CXFA_CSSTagProvider* tag);
-  CFDE_CSSTagCache(const CFDE_CSSTagCache& it);
-  ~CFDE_CSSTagCache();
-
-  CFDE_CSSTagCache* GetParent() const { return pParent; }
-  CXFA_CSSTagProvider* GetTag() const { return pTag; }
-  uint32_t HashID() const { return dwIDHash; }
-  uint32_t HashTag() const { return dwTagHash; }
-  int32_t CountHashClass() const {
-    return pdfium::CollectionSize<int32_t>(dwClassHashes);
-  }
-  void SetClassIndex(int32_t index) { iClassIndex = index; }
-  uint32_t HashClass() const {
-    return iClassIndex < pdfium::CollectionSize<int32_t>(dwClassHashes)
-               ? dwClassHashes[iClassIndex]
-               : 0;
-  }
-
- private:
-  CXFA_CSSTagProvider* pTag;
-  CFDE_CSSTagCache* pParent;
-  uint32_t dwIDHash;
-  uint32_t dwTagHash;
-  int32_t iClassIndex;
-  std::vector<uint32_t> dwClassHashes;
-};
-
-#endif  // XFA_FDE_CSS_CFDE_CSSTAGCACHE_H_
diff --git a/xfa/fde/css/cfde_cssvaluelist.cpp b/xfa/fde/css/cfde_cssvaluelist.cpp
index 64ffb9a..737ffcb 100644
--- a/xfa/fde/css/cfde_cssvaluelist.cpp
+++ b/xfa/fde/css/cfde_cssvaluelist.cpp
@@ -20,6 +20,6 @@
   return m_ppList.size();
 }
 
-CFDE_CSSValue* CFDE_CSSValueList::GetValue(int32_t index) const {
-  return m_ppList[index].Get();
+CFX_RetainPtr<CFDE_CSSValue> CFDE_CSSValueList::GetValue(int32_t index) const {
+  return m_ppList[index];
 }
diff --git a/xfa/fde/css/cfde_cssvaluelist.h b/xfa/fde/css/cfde_cssvaluelist.h
index 117b925..a47f8a3 100644
--- a/xfa/fde/css/cfde_cssvaluelist.h
+++ b/xfa/fde/css/cfde_cssvaluelist.h
@@ -17,7 +17,7 @@
   ~CFDE_CSSValueList() override;
 
   int32_t CountValues() const;
-  CFDE_CSSValue* GetValue(int32_t index) const;
+  CFX_RetainPtr<CFDE_CSSValue> GetValue(int32_t index) const;
 
  protected:
   std::vector<CFX_RetainPtr<CFDE_CSSValue>> m_ppList;
diff --git a/xfa/fde/css/cfde_cssvaluelistparser.cpp b/xfa/fde/css/cfde_cssvaluelistparser.cpp
index 3c204b0..42c3296 100644
--- a/xfa/fde/css/cfde_cssvaluelistparser.cpp
+++ b/xfa/fde/css/cfde_cssvaluelistparser.cpp
@@ -16,50 +16,36 @@
 bool CFDE_CSSValueListParser::NextValue(FDE_CSSPrimitiveType& eType,
                                         const FX_WCHAR*& pStart,
                                         int32_t& iLength) {
-  while (m_pCur < m_pEnd && (*m_pCur <= ' ' || *m_pCur == m_Separator)) {
+  while (m_pCur < m_pEnd && (*m_pCur <= ' ' || *m_pCur == m_Separator))
     ++m_pCur;
-  }
-  if (m_pCur >= m_pEnd) {
+
+  if (m_pCur >= m_pEnd)
     return false;
-  }
+
   eType = FDE_CSSPrimitiveType::Unknown;
   pStart = m_pCur;
   iLength = 0;
   FX_WCHAR wch = *m_pCur;
   if (wch == '#') {
-    iLength = SkipTo(' ');
-    if (iLength == 4 || iLength == 7) {
+    iLength = SkipTo(' ', false, false);
+    if (iLength == 4 || iLength == 7)
       eType = FDE_CSSPrimitiveType::RGB;
-    }
   } else if ((wch >= '0' && wch <= '9') || wch == '.' || wch == '-' ||
              wch == '+') {
-    while (m_pCur < m_pEnd && (*m_pCur > ' ' && *m_pCur != m_Separator)) {
+    while (m_pCur < m_pEnd && (*m_pCur > ' ' && *m_pCur != m_Separator))
       ++m_pCur;
-    }
+
     iLength = m_pCur - pStart;
-    if (iLength > 0) {
-      eType = FDE_CSSPrimitiveType::Number;
-    }
+    eType = FDE_CSSPrimitiveType::Number;
   } else if (wch == '\"' || wch == '\'') {
     pStart++;
-    iLength = SkipTo(wch) - 1;
+    m_pCur++;
+    iLength = SkipTo(wch, false, false);
     m_pCur++;
     eType = FDE_CSSPrimitiveType::String;
   } else if (m_pEnd - m_pCur > 5 && m_pCur[3] == '(') {
-    if (FXSYS_wcsnicmp(L"url", m_pCur, 3) == 0) {
-      wch = m_pCur[4];
-      if (wch == '\"' || wch == '\'') {
-        pStart += 5;
-        iLength = SkipTo(wch) - 6;
-        m_pCur += 2;
-      } else {
-        pStart += 4;
-        iLength = SkipTo(')') - 4;
-        m_pCur++;
-      }
-      eType = FDE_CSSPrimitiveType::String;
-    } else if (FXSYS_wcsnicmp(L"rgb", m_pCur, 3) == 0) {
-      iLength = SkipTo(')') + 1;
+    if (FXSYS_wcsnicmp(L"rgb", m_pCur, 3) == 0) {
+      iLength = SkipTo(')', false, false) + 1;
       m_pCur++;
       eType = FDE_CSSPrimitiveType::RGB;
     }
@@ -69,48 +55,32 @@
   }
   return m_pCur <= m_pEnd && iLength > 0;
 }
+
 int32_t CFDE_CSSValueListParser::SkipTo(FX_WCHAR wch,
-                                        bool bWSSeparator,
-                                        bool bBrContinue) {
+                                        bool breakOnSpace,
+                                        bool matchBrackets) {
   const FX_WCHAR* pStart = m_pCur;
-  if (!bBrContinue) {
-    if (bWSSeparator) {
-      while ((++m_pCur < m_pEnd) && (*m_pCur != wch) && (*m_pCur > ' ')) {
-        continue;
-      }
-    } else {
-      while (++m_pCur < m_pEnd && *m_pCur != wch) {
-        continue;
-      }
+  int32_t bracketCount = 0;
+  while (m_pCur < m_pEnd && *m_pCur != wch) {
+    if (breakOnSpace && *m_pCur <= ' ')
+      break;
+    if (!matchBrackets) {
+      m_pCur++;
+      continue;
     }
 
-  } else {
-    int32_t iBracketCount = 0;
-    if (bWSSeparator) {
-      while ((m_pCur < m_pEnd) && (*m_pCur != wch) && (*m_pCur > ' ')) {
-        if (*m_pCur == '(') {
-          iBracketCount++;
-        } else if (*m_pCur == ')') {
-          iBracketCount--;
-        }
-        m_pCur++;
-      }
-    } else {
-      while (m_pCur < m_pEnd && *m_pCur != wch) {
-        if (*m_pCur == '(') {
-          iBracketCount++;
-        } else if (*m_pCur == ')') {
-          iBracketCount--;
-        }
-        m_pCur++;
-      }
-    }
-    while (iBracketCount > 0 && m_pCur < m_pEnd) {
-      if (*m_pCur == ')') {
-        iBracketCount--;
-      }
-      m_pCur++;
-    }
+    if (*m_pCur == '(')
+      bracketCount++;
+    else if (*m_pCur == ')')
+      bracketCount--;
+
+    m_pCur++;
+  }
+
+  while (bracketCount > 0 && m_pCur < m_pEnd) {
+    if (*m_pCur == ')')
+      bracketCount--;
+    m_pCur++;
   }
   return m_pCur - pStart;
 }
diff --git a/xfa/fde/css/cfde_cssvaluelistparser.h b/xfa/fde/css/cfde_cssvaluelistparser.h
index 731ac3c..734aed8 100644
--- a/xfa/fde/css/cfde_cssvaluelistparser.h
+++ b/xfa/fde/css/cfde_cssvaluelistparser.h
@@ -19,12 +19,11 @@
   bool NextValue(FDE_CSSPrimitiveType& eType,
                  const FX_WCHAR*& pStart,
                  int32_t& iLength);
+
   FX_WCHAR m_Separator;
 
- protected:
-  int32_t SkipTo(FX_WCHAR wch,
-                 bool bWSSeparator = false,
-                 bool bBrContinue = false);
+ private:
+  int32_t SkipTo(FX_WCHAR wch, bool breakOnSpace, bool matchBrackets);
 
   const FX_WCHAR* m_pCur;
   const FX_WCHAR* m_pEnd;
diff --git a/xfa/fde/css/cfde_cssvaluelistparser_unittest.cpp b/xfa/fde/css/cfde_cssvaluelistparser_unittest.cpp
new file mode 100644
index 0000000..71bb807
--- /dev/null
+++ b/xfa/fde/css/cfde_cssvaluelistparser_unittest.cpp
@@ -0,0 +1,142 @@
+// 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/fde/css/cfde_cssvaluelistparser.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/base/ptr_util.h"
+
+TEST(CFDE_CSSValueListParser, rgb_short) {
+  FDE_CSSPrimitiveType type;
+  const FX_WCHAR* start;
+  int32_t len;
+
+  auto parser = pdfium::MakeUnique<CFDE_CSSValueListParser>(L"#abc", 4, L' ');
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::RGB, type);
+  EXPECT_EQ(L"#abc", CFX_WideString(start, len));
+  EXPECT_FALSE(parser->NextValue(type, start, len));
+
+  parser = pdfium::MakeUnique<CFDE_CSSValueListParser>(L"#abcdef", 7, L' ');
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::RGB, type);
+  EXPECT_EQ(L"#abcdef", CFX_WideString(start, len));
+  EXPECT_FALSE(parser->NextValue(type, start, len));
+
+  parser =
+      pdfium::MakeUnique<CFDE_CSSValueListParser>(L"rgb(1, 255, 4)", 14, L' ');
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::RGB, type);
+  EXPECT_EQ(L"rgb(1, 255, 4)", CFX_WideString(start, len));
+
+  parser =
+      pdfium::MakeUnique<CFDE_CSSValueListParser>(L"#abcdefghij", 11, L' ');
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::Unknown, type);
+  EXPECT_EQ(L"#abcdefghij", CFX_WideString(start, len));
+  EXPECT_FALSE(parser->NextValue(type, start, len));
+}
+
+TEST(CFDE_CSSValueListParser, number_parsing) {
+  FDE_CSSPrimitiveType type;
+  const FX_WCHAR* start;
+  int32_t len;
+
+  auto parser = pdfium::MakeUnique<CFDE_CSSValueListParser>(L"1234", 4, L' ');
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::Number, type);
+  EXPECT_EQ(L"1234", CFX_WideString(start, len));
+
+  parser = pdfium::MakeUnique<CFDE_CSSValueListParser>(L"-1234", 5, L' ');
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::Number, type);
+  EXPECT_EQ(L"-1234", CFX_WideString(start, len));
+
+  parser = pdfium::MakeUnique<CFDE_CSSValueListParser>(L"+1234", 5, L' ');
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::Number, type);
+  EXPECT_EQ(L"+1234", CFX_WideString(start, len));
+
+  parser = pdfium::MakeUnique<CFDE_CSSValueListParser>(L".1234", 5, L' ');
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::Number, type);
+  EXPECT_EQ(L".1234", CFX_WideString(start, len));
+
+  parser = pdfium::MakeUnique<CFDE_CSSValueListParser>(L"4321.1234", 9, L' ');
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::Number, type);
+  EXPECT_EQ(L"4321.1234", CFX_WideString(start, len));
+
+  // TODO(dsinclair): These should probably fail but currently don't.
+  parser = pdfium::MakeUnique<CFDE_CSSValueListParser>(L"4321.12.34", 10, L' ');
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::Number, type);
+  EXPECT_EQ(L"4321.12.34", CFX_WideString(start, len));
+
+  parser = pdfium::MakeUnique<CFDE_CSSValueListParser>(L"43a1.12.34", 10, L' ');
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::Number, type);
+  EXPECT_EQ(L"43a1.12.34", CFX_WideString(start, len));
+}
+
+TEST(CFDE_CSSValueListParser, string_parsing) {
+  FDE_CSSPrimitiveType type;
+  const FX_WCHAR* start;
+  int32_t len;
+
+  auto parser =
+      pdfium::MakeUnique<CFDE_CSSValueListParser>(L"'string'", 8, L' ');
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::String, type);
+  EXPECT_EQ(L"string", CFX_WideString(start, len));
+
+  parser = pdfium::MakeUnique<CFDE_CSSValueListParser>(L"\"another string\"",
+                                                       16, L' ');
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::String, type);
+  EXPECT_EQ(L"another string", CFX_WideString(start, len));
+
+  parser = pdfium::MakeUnique<CFDE_CSSValueListParser>(L"standalone", 10, L' ');
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::String, type);
+  EXPECT_EQ(L"standalone", CFX_WideString(start, len));
+}
+
+TEST(CFDE_CSSValueListParser, multiparsing) {
+  FDE_CSSPrimitiveType type;
+  const FX_WCHAR* start;
+  int32_t len;
+
+  auto parser =
+      pdfium::MakeUnique<CFDE_CSSValueListParser>(L"1, 2, 3", 7, L',');
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::Number, type);
+  EXPECT_EQ(L"1", CFX_WideString(start, len));
+
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::Number, type);
+  EXPECT_EQ(L"2", CFX_WideString(start, len));
+
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::Number, type);
+  EXPECT_EQ(L"3", CFX_WideString(start, len));
+
+  EXPECT_FALSE(parser->NextValue(type, start, len));
+
+  parser = pdfium::MakeUnique<CFDE_CSSValueListParser>(
+      L"'str', rgb(1, 2, 3), 4", 22, L',');
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::String, type);
+  EXPECT_EQ(L"str", CFX_WideString(start, len));
+
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::RGB, type);
+  EXPECT_EQ(L"rgb(1, 2, 3)", CFX_WideString(start, len));
+
+  EXPECT_TRUE(parser->NextValue(type, start, len));
+  EXPECT_EQ(FDE_CSSPrimitiveType::Number, type);
+  EXPECT_EQ(L"4", CFX_WideString(start, len));
+}
diff --git a/xfa/fde/css/fde_css.h b/xfa/fde/css/fde_css.h
index 2194657..6c2629f 100644
--- a/xfa/fde/css/fde_css.h
+++ b/xfa/fde/css/fde_css.h
@@ -12,18 +12,6 @@
 #include "xfa/fgas/crt/fgas_utils.h"
 #include "xfa/fgas/font/cfgas_fontmgr.h"
 
-enum FDE_CSSMEDIATYPE {
-  FDE_CSSMEDIATYPE_Braille = 0x01,
-  FDE_CSSMEDIATYPE_Emboss = 0x02,
-  FDE_CSSMEDIATYPE_Handheld = 0x04,
-  FDE_CSSMEDIATYPE_Print = 0x08,
-  FDE_CSSMEDIATYPE_Projection = 0x10,
-  FDE_CSSMEDIATYPE_Screen = 0x20,
-  FDE_CSSMEDIATYPE_TTY = 0x40,
-  FDE_CSSMEDIATYPE_TV = 0x80,
-  FDE_CSSMEDIATYPE_ALL = 0xFF,
-};
-
 enum FDE_CSSVALUETYPE {
   FDE_CSSVALUETYPE_Primitive = 1 << 0,
   FDE_CSSVALUETYPE_List = 1 << 1,
@@ -137,17 +125,7 @@
   LAST_MARKER
 };
 
-enum class FDE_CSSPseudo : uint8_t { After, Before, NONE };
-
-enum class FDE_CSSSelectorType : uint8_t {
-  Element = 0,
-  Descendant,
-  Class,
-  Pseudo,
-  ID,
-};
-
-enum class FDE_CSSRuleType : uint8_t { Style, Media, FontFace };
+enum class FDE_CSSSelectorType : uint8_t { Element = 0, Descendant };
 
 enum class FDE_CSSLengthUnit : uint8_t {
   Auto,
@@ -205,18 +183,6 @@
   FDE_CSSTEXTDECORATION_Double = 1 << 4,
 };
 
-enum class FDE_CSSStyleSheetGroup : uint8_t {
-  UserAgent = 0,
-  User,
-  Author,
-};
-
-enum class FDE_CSSStyleSheetPriority : uint8_t {
-  High = 0,
-  Mid,
-  Low,
-};
-
 class FDE_CSSLength {
  public:
   FDE_CSSLength() {}
diff --git a/xfa/fde/css/fde_cssdatatable.cpp b/xfa/fde/css/fde_cssdatatable.cpp
index fd4ef6b..d61c610 100644
--- a/xfa/fde/css/fde_cssdatatable.cpp
+++ b/xfa/fde/css/fde_cssdatatable.cpp
@@ -173,14 +173,6 @@
                   static_cast<int32_t>(FDE_CSSPropertyValue::LAST_MARKER),
               "Property value table differs in size from property value enum");
 
-static const FDE_CSSMEDIATYPETABLE g_FDE_CSSMediaTypes[] = {
-    {0xF09, FDE_CSSMEDIATYPE_Emboss},    {FDE_CSSMEDIATYPE_Screen},
-    {0x536A, FDE_CSSMEDIATYPE_TV},       {0x741D, FDE_CSSMEDIATYPE_Projection},
-    {0x76ED, FDE_CSSMEDIATYPE_Print},    {0x7CFB, FDE_CSSMEDIATYPE_Braille},
-    {0x9578, FDE_CSSMEDIATYPE_Handheld}, {0xC8E1, FDE_CSSMEDIATYPE_TTY},
-    {0xD0F9, FDE_CSSMEDIATYPE_ALL},
-};
-
 static const FDE_CSSLengthUnitTable g_FDE_CSSLengthUnits[] = {
     {0x0672, FDE_CSSNumberType::EMS},
     {0x067D, FDE_CSSNumberType::EXS},
@@ -204,15 +196,6 @@
     {0xF6EFFF31, 0xff008000},
 };
 
-static const FDE_CSSPseudoTable g_FDE_CSSPseudoType[] = {
-    {FDE_CSSPseudo::After, L":after", 0x16EE1FEC},
-    {FDE_CSSPseudo::Before, L":before", 0x7DCDDE2D},
-};
-
-const FDE_CSSPseudoTable* FDE_GetCSSPseudoByEnum(FDE_CSSPseudo ePseudo) {
-  return g_FDE_CSSPseudoType + static_cast<int>(ePseudo);
-}
-
 const FDE_CSSPropertyTable* FDE_GetCSSPropertyByName(
     const CFX_WideStringC& wsName) {
   ASSERT(!wsName.IsEmpty());
@@ -259,28 +242,6 @@
   return nullptr;
 }
 
-const FDE_CSSMEDIATYPETABLE* FDE_GetCSSMediaTypeByName(
-    const CFX_WideStringC& wsName) {
-  ASSERT(!wsName.IsEmpty());
-  uint16_t wHash = FX_HashCode_GetW(wsName, true);
-  int32_t iEnd =
-      sizeof(g_FDE_CSSMediaTypes) / sizeof(FDE_CSSMEDIATYPETABLE) - 1;
-  int32_t iMid, iStart = 0;
-  uint16_t uMid;
-  do {
-    iMid = (iStart + iEnd) / 2;
-    uMid = g_FDE_CSSMediaTypes[iMid].wHash;
-    if (wHash == uMid) {
-      return g_FDE_CSSMediaTypes + iMid;
-    } else if (wHash > uMid) {
-      iStart = iMid + 1;
-    } else {
-      iEnd = iMid - 1;
-    }
-  } while (iStart <= iEnd);
-  return nullptr;
-}
-
 const FDE_CSSLengthUnitTable* FDE_GetCSSLengthUnitByName(
     const CFX_WideStringC& wsName) {
   ASSERT(!wsName.IsEmpty());
diff --git a/xfa/fde/css/fde_cssdatatable.h b/xfa/fde/css/fde_cssdatatable.h
index 4769f16..afb0b85 100644
--- a/xfa/fde/css/fde_cssdatatable.h
+++ b/xfa/fde/css/fde_cssdatatable.h
@@ -31,11 +31,6 @@
   uint32_t dwHash;
 };
 
-struct FDE_CSSMEDIATYPETABLE {
-  uint16_t wHash;
-  uint16_t wValue;
-};
-
 struct FDE_CSSLengthUnitTable {
   uint16_t wHash;
   FDE_CSSNumberType wValue;
@@ -46,12 +41,6 @@
   FX_ARGB dwValue;
 };
 
-struct FDE_CSSPseudoTable {
-  FDE_CSSPseudo eName;
-  const FX_WCHAR* pszName;
-  uint32_t dwHash;
-};
-
 const FDE_CSSPropertyTable* FDE_GetCSSPropertyByName(
     const CFX_WideStringC& wsName);
 const FDE_CSSPropertyTable* FDE_GetCSSPropertyByEnum(FDE_CSSProperty eName);
@@ -59,14 +48,9 @@
 const FDE_CSSPropertyValueTable* FDE_GetCSSPropertyValueByName(
     const CFX_WideStringC& wsName);
 
-const FDE_CSSMEDIATYPETABLE* FDE_GetCSSMediaTypeByName(
-    const CFX_WideStringC& wsName);
-
 const FDE_CSSLengthUnitTable* FDE_GetCSSLengthUnitByName(
     const CFX_WideStringC& wsName);
 
 const FDE_CSSCOLORTABLE* FDE_GetCSSColorByName(const CFX_WideStringC& wsName);
 
-const FDE_CSSPseudoTable* FDE_GetCSSPseudoByEnum(FDE_CSSPseudo ePseudo);
-
 #endif  // XFA_FDE_CSS_FDE_CSSDATATABLE_H_
diff --git a/xfa/fde/fde_gedevice.cpp b/xfa/fde/fde_gedevice.cpp
index 081f00a..db05f76 100644
--- a/xfa/fde/fde_gedevice.cpp
+++ b/xfa/fde/fde_gedevice.cpp
@@ -24,29 +24,36 @@
   ASSERT(pDevice);
 
   FX_RECT rt = m_pDevice->GetClipBox();
-  m_rtClip.Set((FX_FLOAT)rt.left, (FX_FLOAT)rt.top, (FX_FLOAT)rt.Width(),
-               (FX_FLOAT)rt.Height());
+  m_rtClip = CFX_RectF(
+      static_cast<FX_FLOAT>(rt.left), static_cast<FX_FLOAT>(rt.top),
+      static_cast<FX_FLOAT>(rt.Width()), static_cast<FX_FLOAT>(rt.Height()));
 }
 
 CFDE_RenderDevice::~CFDE_RenderDevice() {
   if (m_bOwnerDevice)
     delete m_pDevice;
 }
+
 int32_t CFDE_RenderDevice::GetWidth() const {
   return m_pDevice->GetWidth();
 }
+
 int32_t CFDE_RenderDevice::GetHeight() const {
   return m_pDevice->GetHeight();
 }
+
 void CFDE_RenderDevice::SaveState() {
   m_pDevice->SaveState();
 }
+
 void CFDE_RenderDevice::RestoreState() {
   m_pDevice->RestoreState(false);
   const FX_RECT& rt = m_pDevice->GetClipBox();
-  m_rtClip.Set((FX_FLOAT)rt.left, (FX_FLOAT)rt.top, (FX_FLOAT)rt.Width(),
-               (FX_FLOAT)rt.Height());
+  m_rtClip = CFX_RectF(
+      static_cast<FX_FLOAT>(rt.left), static_cast<FX_FLOAT>(rt.top),
+      static_cast<FX_FLOAT>(rt.Width()), static_cast<FX_FLOAT>(rt.Height()));
 }
+
 bool CFDE_RenderDevice::SetClipRect(const CFX_RectF& rtClip) {
   m_rtClip = rtClip;
   return m_pDevice->SetClip_Rect(FX_RECT((int32_t)FXSYS_floor(rtClip.left),
@@ -54,21 +61,27 @@
                                          (int32_t)FXSYS_ceil(rtClip.right()),
                                          (int32_t)FXSYS_ceil(rtClip.bottom())));
 }
+
 const CFX_RectF& CFDE_RenderDevice::GetClipRect() {
   return m_rtClip;
 }
+
 bool CFDE_RenderDevice::SetClipPath(const CFDE_Path* pClip) {
   return false;
 }
+
 CFDE_Path* CFDE_RenderDevice::GetClipPath() const {
   return nullptr;
 }
+
 FX_FLOAT CFDE_RenderDevice::GetDpiX() const {
   return 96;
 }
+
 FX_FLOAT CFDE_RenderDevice::GetDpiY() const {
   return 96;
 }
+
 bool CFDE_RenderDevice::DrawImage(CFX_DIBSource* pDib,
                                   const CFX_RectF* pSrcRect,
                                   const CFX_RectF& dstRect,
@@ -78,11 +91,13 @@
   if (pSrcRect) {
     srcRect = *pSrcRect;
   } else {
-    srcRect.Set(0, 0, (FX_FLOAT)pDib->GetWidth(), (FX_FLOAT)pDib->GetHeight());
+    srcRect = CFX_RectF(0, 0, static_cast<FX_FLOAT>(pDib->GetWidth()),
+                        static_cast<FX_FLOAT>(pDib->GetHeight()));
   }
-  if (srcRect.IsEmpty()) {
+
+  if (srcRect.IsEmpty())
     return false;
-  }
+
   CFX_Matrix dib2fxdev;
   if (pImgMatrix) {
     dib2fxdev = *pImgMatrix;
@@ -104,6 +119,7 @@
   m_pDevice->CancelDIBits(handle);
   return !!handle;
 }
+
 bool CFDE_RenderDevice::DrawString(CFDE_Brush* pBrush,
                                    const CFX_RetainPtr<CFGAS_GEFont>& pFont,
                                    const FXTEXT_CHARPOS* pCharPos,
@@ -152,12 +168,10 @@
 #if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
         FxFont.SetFace(pFxFont->GetFace());
         m_pDevice->DrawNormalText(iCurCount, pCurCP, &FxFont, -fFontSize,
-                                  (const CFX_Matrix*)pMatrix, argb,
-                                  FXTEXT_CLEARTYPE);
+                                  pMatrix, argb, FXTEXT_CLEARTYPE);
 #else
         m_pDevice->DrawNormalText(iCurCount, pCurCP, pFxFont, -fFontSize,
-                                  (const CFX_Matrix*)pMatrix, argb,
-                                  FXTEXT_CLEARTYPE);
+                                  pMatrix, argb, FXTEXT_CLEARTYPE);
 #endif  // _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
       }
       pCurFont = pSTFont;
@@ -172,15 +186,14 @@
     pFxFont = pCurFont->GetDevFont();
 #if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
     FxFont.SetFace(pFxFont->GetFace());
-    bool bRet = m_pDevice->DrawNormalText(
-        iCurCount, pCurCP, &FxFont, -fFontSize, (const CFX_Matrix*)pMatrix,
-        argb, FXTEXT_CLEARTYPE);
+    bool bRet =
+        m_pDevice->DrawNormalText(iCurCount, pCurCP, &FxFont, -fFontSize,
+                                  pMatrix, argb, FXTEXT_CLEARTYPE);
     FxFont.SetFace(nullptr);
     return bRet;
 #else
     return m_pDevice->DrawNormalText(iCurCount, pCurCP, pFxFont, -fFontSize,
-                                     (const CFX_Matrix*)pMatrix, argb,
-                                     FXTEXT_CLEARTYPE);
+                                     pMatrix, argb, FXTEXT_CLEARTYPE);
 #endif  // _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
   }
 
@@ -198,18 +211,19 @@
                                    const CFX_PointF& pt3,
                                    const CFX_PointF& pt4,
                                    const CFX_Matrix* pMatrix) {
-  CFX_PointsF points;
-  points.Add(pt1);
-  points.Add(pt2);
-  points.Add(pt3);
-  points.Add(pt4);
+  std::vector<CFX_PointF> points;
+  points.push_back(pt1);
+  points.push_back(pt2);
+  points.push_back(pt3);
+  points.push_back(pt4);
   CFDE_Path path;
   path.AddBezier(points);
   return DrawPath(pPen, fPenWidth, &path, pMatrix);
 }
+
 bool CFDE_RenderDevice::DrawCurve(CFDE_Pen* pPen,
                                   FX_FLOAT fPenWidth,
-                                  const CFX_PointsF& points,
+                                  const std::vector<CFX_PointF>& points,
                                   bool bClosed,
                                   FX_FLOAT fTension,
                                   const CFX_Matrix* pMatrix) {
@@ -217,6 +231,7 @@
   path.AddCurve(points, bClosed, fTension);
   return DrawPath(pPen, fPenWidth, &path, pMatrix);
 }
+
 bool CFDE_RenderDevice::DrawEllipse(CFDE_Pen* pPen,
                                     FX_FLOAT fPenWidth,
                                     const CFX_RectF& rect,
@@ -225,14 +240,16 @@
   path.AddEllipse(rect);
   return DrawPath(pPen, fPenWidth, &path, pMatrix);
 }
+
 bool CFDE_RenderDevice::DrawLines(CFDE_Pen* pPen,
                                   FX_FLOAT fPenWidth,
-                                  const CFX_PointsF& points,
+                                  const std::vector<CFX_PointF>& points,
                                   const CFX_Matrix* pMatrix) {
   CFDE_Path path;
   path.AddLines(points);
   return DrawPath(pPen, fPenWidth, &path, pMatrix);
 }
+
 bool CFDE_RenderDevice::DrawLine(CFDE_Pen* pPen,
                                  FX_FLOAT fPenWidth,
                                  const CFX_PointF& pt1,
@@ -242,6 +259,7 @@
   path.AddLine(pt1, pt2);
   return DrawPath(pPen, fPenWidth, &path, pMatrix);
 }
+
 bool CFDE_RenderDevice::DrawPath(CFDE_Pen* pPen,
                                  FX_FLOAT fPenWidth,
                                  const CFDE_Path* pPath,
@@ -257,14 +275,16 @@
   return m_pDevice->DrawPath(&pGePath->m_Path, (const CFX_Matrix*)pMatrix,
                              &graphState, 0, pPen->GetColor(), 0);
 }
+
 bool CFDE_RenderDevice::DrawPolygon(CFDE_Pen* pPen,
                                     FX_FLOAT fPenWidth,
-                                    const CFX_PointsF& points,
+                                    const std::vector<CFX_PointF>& points,
                                     const CFX_Matrix* pMatrix) {
   CFDE_Path path;
   path.AddPolygon(points);
   return DrawPath(pPen, fPenWidth, &path, pMatrix);
 }
+
 bool CFDE_RenderDevice::DrawRectangle(CFDE_Pen* pPen,
                                       FX_FLOAT fPenWidth,
                                       const CFX_RectF& rect,
@@ -273,14 +293,16 @@
   path.AddRectangle(rect);
   return DrawPath(pPen, fPenWidth, &path, pMatrix);
 }
+
 bool CFDE_RenderDevice::FillClosedCurve(CFDE_Brush* pBrush,
-                                        const CFX_PointsF& points,
+                                        const std::vector<CFX_PointF>& points,
                                         FX_FLOAT fTension,
                                         const CFX_Matrix* pMatrix) {
   CFDE_Path path;
   path.AddCurve(points, true, fTension);
   return FillPath(pBrush, &path, pMatrix);
 }
+
 bool CFDE_RenderDevice::FillEllipse(CFDE_Brush* pBrush,
                                     const CFX_RectF& rect,
                                     const CFX_Matrix* pMatrix) {
@@ -288,13 +310,15 @@
   path.AddEllipse(rect);
   return FillPath(pBrush, &path, pMatrix);
 }
+
 bool CFDE_RenderDevice::FillPolygon(CFDE_Brush* pBrush,
-                                    const CFX_PointsF& points,
+                                    const std::vector<CFX_PointF>& points,
                                     const CFX_Matrix* pMatrix) {
   CFDE_Path path;
   path.AddPolygon(points);
   return FillPath(pBrush, &path, pMatrix);
 }
+
 bool CFDE_RenderDevice::FillRectangle(CFDE_Brush* pBrush,
                                       const CFX_RectF& rect,
                                       const CFX_Matrix* pMatrix) {
@@ -302,6 +326,7 @@
   path.AddRectangle(rect);
   return FillPath(pBrush, &path, pMatrix);
 }
+
 bool CFDE_RenderDevice::CreatePen(CFDE_Pen* pPen,
                                   FX_FLOAT fPenWidth,
                                   CFX_GraphStateData& graphState) {
diff --git a/xfa/fde/fde_gedevice.h b/xfa/fde/fde_gedevice.h
index 170bef5..7c772cf 100644
--- a/xfa/fde/fde_gedevice.h
+++ b/xfa/fde/fde_gedevice.h
@@ -7,6 +7,8 @@
 #ifndef XFA_FDE_FDE_GEDEVICE_H_
 #define XFA_FDE_FDE_GEDEVICE_H_
 
+#include <vector>
+
 #include "core/fxge/cfx_renderdevice.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
 
@@ -52,7 +54,7 @@
                   const CFX_Matrix* pMatrix = nullptr);
   bool DrawCurve(CFDE_Pen* pPen,
                  FX_FLOAT fPenWidth,
-                 const CFX_PointsF& points,
+                 const std::vector<CFX_PointF>& points,
                  bool bClosed,
                  FX_FLOAT fTension = 0.5f,
                  const CFX_Matrix* pMatrix = nullptr);
@@ -62,7 +64,7 @@
                    const CFX_Matrix* pMatrix = nullptr);
   bool DrawLines(CFDE_Pen* pPen,
                  FX_FLOAT fPenWidth,
-                 const CFX_PointsF& points,
+                 const std::vector<CFX_PointF>& points,
                  const CFX_Matrix* pMatrix = nullptr);
   bool DrawLine(CFDE_Pen* pPen,
                 FX_FLOAT fPenWidth,
@@ -75,14 +77,14 @@
                 const CFX_Matrix* pMatrix = nullptr);
   bool DrawPolygon(CFDE_Pen* pPen,
                    FX_FLOAT fPenWidth,
-                   const CFX_PointsF& points,
+                   const std::vector<CFX_PointF>& points,
                    const CFX_Matrix* pMatrix = nullptr);
   bool DrawRectangle(CFDE_Pen* pPen,
                      FX_FLOAT fPenWidth,
                      const CFX_RectF& rect,
                      const CFX_Matrix* pMatrix = nullptr);
   bool FillClosedCurve(CFDE_Brush* pBrush,
-                       const CFX_PointsF& points,
+                       const std::vector<CFX_PointF>& points,
                        FX_FLOAT fTension = 0.5f,
                        const CFX_Matrix* pMatrix = nullptr);
   bool FillEllipse(CFDE_Brush* pBrush,
@@ -92,7 +94,7 @@
                 const CFDE_Path* pPath,
                 const CFX_Matrix* pMatrix = nullptr);
   bool FillPolygon(CFDE_Brush* pBrush,
-                   const CFX_PointsF& points,
+                   const std::vector<CFX_PointF>& points,
                    const CFX_Matrix* pMatrix = nullptr);
   bool FillRectangle(CFDE_Brush* pBrush,
                      const CFX_RectF& rect,
diff --git a/xfa/fde/fde_render.cpp b/xfa/fde/fde_render.cpp
index c0fb926..b6a8f7e 100644
--- a/xfa/fde/fde_render.cpp
+++ b/xfa/fde/fde_render.cpp
@@ -61,7 +61,6 @@
   rm.TransformRect(rtDocClip);
   IFDE_VisualSet* pVisualSet;
   FDE_TEXTEDITPIECE* pPiece;
-  CFX_RectF rtObj;
   int32_t iCount = 0;
   while (true) {
     pPiece = m_pIterator->GetNext(pVisualSet);
@@ -69,9 +68,7 @@
       eStatus = FDE_RENDERSTATUS_Done;
       break;
     }
-    rtObj.Empty();
-    pVisualSet->GetRect(pPiece, rtObj);
-    if (!rtDocClip.IntersectWith(rtObj))
+    if (!rtDocClip.IntersectWith(pVisualSet->GetRect(*pPiece)))
       continue;
 
     switch (pVisualSet->GetType()) {
@@ -111,7 +108,7 @@
   if (!pFont)
     return;
 
-  int32_t iCount = pTextSet->GetDisplayPos(pText, nullptr, false);
+  int32_t iCount = pTextSet->GetDisplayPos(*pText, nullptr, false);
   if (iCount < 1)
     return;
 
@@ -121,7 +118,7 @@
   if (m_CharPos.size() < static_cast<size_t>(iCount))
     m_CharPos.resize(iCount, FXTEXT_CHARPOS());
 
-  iCount = pTextSet->GetDisplayPos(pText, m_CharPos.data(), false);
+  iCount = pTextSet->GetDisplayPos(*pText, m_CharPos.data(), false);
   FX_FLOAT fFontSize = pTextSet->GetFontSize();
   FX_ARGB dwColor = pTextSet->GetFontColor();
   m_pBrush->SetColor(dwColor);
diff --git a/xfa/fde/fde_visualset.h b/xfa/fde/fde_visualset.h
index 8aef237..5cf02cd 100644
--- a/xfa/fde/fde_visualset.h
+++ b/xfa/fde/fde_visualset.h
@@ -7,6 +7,8 @@
 #ifndef XFA_FDE_FDE_VISUALSET_H_
 #define XFA_FDE_FDE_VISUALSET_H_
 
+#include <vector>
+
 #include "core/fxcrt/cfx_retain_ptr.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_system.h"
@@ -15,7 +17,7 @@
 #include "xfa/fde/fde_object.h"
 #include "xfa/fgas/font/cfgas_fontmgr.h"
 
-struct FXTEXT_CHARPOS;
+class FXTEXT_CHARPOS;
 
 enum FDE_VISUALOBJTYPE {
   FDE_VISUALOBJ_Canvas = 0x00,
@@ -23,18 +25,26 @@
 };
 
 struct FDE_TEXTEDITPIECE {
+  FDE_TEXTEDITPIECE();
+  FDE_TEXTEDITPIECE(const FDE_TEXTEDITPIECE& that);
+  ~FDE_TEXTEDITPIECE();
+
   int32_t nStart;
   int32_t nCount;
   int32_t nBidiLevel;
   CFX_RectF rtPiece;
   uint32_t dwCharStyles;
 };
+inline FDE_TEXTEDITPIECE::FDE_TEXTEDITPIECE() = default;
+inline FDE_TEXTEDITPIECE::FDE_TEXTEDITPIECE(const FDE_TEXTEDITPIECE& that) =
+    default;
+inline FDE_TEXTEDITPIECE::~FDE_TEXTEDITPIECE() = default;
 
 class IFDE_VisualSet {
  public:
   virtual ~IFDE_VisualSet() {}
   virtual FDE_VISUALOBJTYPE GetType() = 0;
-  virtual void GetRect(FDE_TEXTEDITPIECE* hVisualObj, CFX_RectF& rt) = 0;
+  virtual CFX_RectF GetRect(const FDE_TEXTEDITPIECE& hVisualObj) = 0;
 };
 
 class IFDE_CanvasSet : public IFDE_VisualSet {
@@ -51,13 +61,12 @@
   virtual CFX_RetainPtr<CFGAS_GEFont> GetFont() = 0;
   virtual FX_FLOAT GetFontSize() = 0;
   virtual FX_ARGB GetFontColor() = 0;
-  virtual int32_t GetDisplayPos(FDE_TEXTEDITPIECE* hText,
+  virtual int32_t GetDisplayPos(const FDE_TEXTEDITPIECE& hText,
                                 FXTEXT_CHARPOS* pCharPos,
                                 bool bCharCode = false,
                                 CFX_WideString* pWSForms = nullptr) = 0;
-  virtual int32_t GetCharRects(const FDE_TEXTEDITPIECE* hText,
-                               CFX_RectFArray& rtArray,
-                               bool bbox) = 0;
+  virtual std::vector<CFX_RectF> GetCharRects(const FDE_TEXTEDITPIECE* hText,
+                                              bool bbox) = 0;
 };
 
 #endif  // XFA_FDE_FDE_VISUALSET_H_
diff --git a/xfa/fde/ifde_txtedtpage.h b/xfa/fde/ifde_txtedtpage.h
index ecc7d16..0ab3897 100644
--- a/xfa/fde/ifde_txtedtpage.h
+++ b/xfa/fde/ifde_txtedtpage.h
@@ -7,6 +7,8 @@
 #ifndef XFA_FDE_IFDE_TXTEDTPAGE_H_
 #define XFA_FDE_IFDE_TXTEDTPAGE_H_
 
+#include <vector>
+
 #include "xfa/fde/fde_visualset.h"
 #include "xfa/fgas/layout/fgas_textbreak.h"
 
@@ -24,7 +26,7 @@
   virtual int32_t GetCharIndex(const CFX_PointF& fPoint, bool& bBefore) = 0;
   virtual void CalcRangeRectArray(int32_t nStart,
                                   int32_t nCount,
-                                  CFX_RectFArray& RectFArr) const = 0;
+                                  std::vector<CFX_RectF>* RectFArr) const = 0;
   virtual int32_t SelectWord(const CFX_PointF& fPoint, int32_t& nCount) = 0;
   virtual int32_t GetCharStart() const = 0;
   virtual int32_t GetCharCount() const = 0;
diff --git a/xfa/fde/tto/fde_textout.cpp b/xfa/fde/tto/fde_textout.cpp
index 4d207fb..421876b 100644
--- a/xfa/fde/tto/fde_textout.cpp
+++ b/xfa/fde/tto/fde_textout.cpp
@@ -11,12 +11,17 @@
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_system.h"
 #include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
 #include "xfa/fde/cfde_path.h"
 #include "xfa/fde/fde_gedevice.h"
 #include "xfa/fde/fde_object.h"
 #include "xfa/fgas/crt/fgas_utils.h"
 #include "xfa/fgas/layout/fgas_textbreak.h"
 
+FDE_TTOPIECE::FDE_TTOPIECE() = default;
+FDE_TTOPIECE::FDE_TTOPIECE(const FDE_TTOPIECE& that) = default;
+FDE_TTOPIECE::~FDE_TTOPIECE() = default;
+
 CFDE_TextOut::CFDE_TextOut()
     : m_pTxtBreak(new CFX_TxtBreak(FX_TXTBREAKPOLICY_None)),
       m_pFont(nullptr),
@@ -41,9 +46,7 @@
   m_rtLogicClip.Reset();
 }
 
-CFDE_TextOut::~CFDE_TextOut() {
-  m_ttoLines.RemoveAll(false);
-}
+CFDE_TextOut::~CFDE_TextOut() {}
 
 void CFDE_TextOut::SetFont(const CFX_RetainPtr<CFGAS_GEFont>& pFont) {
   ASSERT(pFont);
@@ -138,8 +141,7 @@
 }
 
 void CFDE_TextOut::SetClipRect(const CFX_Rect& rtClip) {
-  m_rtClip.Set((FX_FLOAT)rtClip.left, (FX_FLOAT)rtClip.top,
-               (FX_FLOAT)rtClip.Width(), (FX_FLOAT)rtClip.Height());
+  m_rtClip = rtClip.As<FX_FLOAT>();
 }
 
 void CFDE_TextOut::SetClipRect(const CFX_RectF& rtClip) {
@@ -163,60 +165,12 @@
   return m_iTotalLines;
 }
 
-void CFDE_TextOut::CalcSize(const FX_WCHAR* pwsStr,
-                            int32_t iLength,
-                            CFX_Size& size) {
-  CFX_RectF rtText;
-  rtText.Set(0.0f, 0.0f, (FX_FLOAT)size.x, (FX_FLOAT)size.y);
-  CalcSize(pwsStr, iLength, rtText);
-  size.x = (int32_t)rtText.Width();
-  size.y = (int32_t)rtText.Height();
-}
-
-void CFDE_TextOut::CalcSize(const FX_WCHAR* pwsStr,
-                            int32_t iLength,
-                            CFX_SizeF& size) {
-  CFX_RectF rtText;
-  rtText.Set(0.0f, 0.0f, size.x, size.y);
-  CalcSize(pwsStr, iLength, rtText);
-  size.x = rtText.Width();
-  size.y = rtText.Height();
-}
-
-void CFDE_TextOut::CalcSize(const FX_WCHAR* pwsStr,
-                            int32_t iLength,
-                            CFX_Rect& rect) {
-  CFX_RectF rtText;
-  rtText.Set((FX_FLOAT)rect.left, (FX_FLOAT)rect.top, (FX_FLOAT)rect.Width(),
-             (FX_FLOAT)rect.Height());
-  CalcSize(pwsStr, iLength, rtText);
-  rect.Set((int32_t)rtText.left, (int32_t)rtText.top, (int32_t)rtText.Width(),
-           (int32_t)rtText.Height());
-}
-
-void CFDE_TextOut::CalcSize(const FX_WCHAR* pwsStr,
-                            int32_t iLength,
-                            CFX_RectF& rect) {
-  if (!pwsStr || iLength < 1) {
-    rect.width = 0.0f;
-    rect.height = 0.0f;
-  } else {
-    CFX_Matrix rm;
-    rm.SetReverse(m_Matrix);
-    rm.TransformRect(rect);
-    CalcTextSize(pwsStr, iLength, rect);
-    m_Matrix.TransformRect(rect);
-  }
-}
-
 void CFDE_TextOut::CalcLogicSize(const FX_WCHAR* pwsStr,
                                  int32_t iLength,
                                  CFX_SizeF& size) {
-  CFX_RectF rtText;
-  rtText.Set(0.0f, 0.0f, size.x, size.y);
+  CFX_RectF rtText(0.0f, 0.0f, size.width, size.height);
   CalcLogicSize(pwsStr, iLength, rtText);
-  size.x = rtText.Width();
-  size.y = rtText.Height();
+  size = rtText.Size();
 }
 
 void CFDE_TextOut::CalcLogicSize(const FX_WCHAR* pwsStr,
@@ -346,9 +300,8 @@
                             int32_t iLength,
                             int32_t x,
                             int32_t y) {
-  CFX_RectF rtText;
-  rtText.Set((FX_FLOAT)x, (FX_FLOAT)y, m_fFontSize * 1000.0f,
-             m_fFontSize * 1000.0f);
+  CFX_RectF rtText(static_cast<FX_FLOAT>(x), static_cast<FX_FLOAT>(y),
+                   m_fFontSize * 1000.0f, m_fFontSize * 1000.0f);
   DrawText(pwsStr, iLength, rtText);
 }
 
@@ -356,25 +309,20 @@
                             int32_t iLength,
                             FX_FLOAT x,
                             FX_FLOAT y) {
-  CFX_RectF rtText;
-  rtText.Set(x, y, m_fFontSize * 1000.0f, m_fFontSize * 1000.0f);
-  DrawText(pwsStr, iLength, rtText);
+  DrawText(pwsStr, iLength,
+           CFX_RectF(x, y, m_fFontSize * 1000.0f, m_fFontSize * 1000.0f));
 }
 
 void CFDE_TextOut::DrawText(const FX_WCHAR* pwsStr,
                             int32_t iLength,
                             const CFX_Rect& rect) {
-  CFX_RectF rtText;
-  rtText.Set((FX_FLOAT)rect.left, (FX_FLOAT)rect.top, (FX_FLOAT)rect.width,
-             (FX_FLOAT)rect.height);
-  DrawText(pwsStr, iLength, rtText);
+  DrawText(pwsStr, iLength, rect.As<FX_FLOAT>());
 }
 
 void CFDE_TextOut::DrawText(const FX_WCHAR* pwsStr,
                             int32_t iLength,
                             const CFX_RectF& rect) {
-  CFX_RectF rtText;
-  rtText.Set(rect.left, rect.top, rect.width, rect.height);
+  CFX_RectF rtText(rect.left, rect.top, rect.width, rect.height);
   CFX_Matrix rm;
   rm.SetReverse(m_Matrix);
   rm.TransformRect(rtText);
@@ -385,17 +333,15 @@
                                  int32_t iLength,
                                  FX_FLOAT x,
                                  FX_FLOAT y) {
-  CFX_RectF rtText;
-  rtText.Set(x, y, m_fFontSize * 1000.0f, m_fFontSize * 1000.0f);
+  CFX_RectF rtText(x, y, m_fFontSize * 1000.0f, m_fFontSize * 1000.0f);
   DrawLogicText(pwsStr, iLength, rtText);
 }
 
 void CFDE_TextOut::DrawLogicText(const FX_WCHAR* pwsStr,
                                  int32_t iLength,
                                  const CFX_RectF& rect) {
-  CFX_RectF rtClip;
-  rtClip.Set(m_rtLogicClip.left, m_rtLogicClip.top, m_rtLogicClip.width,
-             m_rtLogicClip.height);
+  CFX_RectF rtClip(m_rtLogicClip.left, m_rtLogicClip.top, m_rtLogicClip.width,
+                   m_rtLogicClip.height);
   m_Matrix.TransformRect(rtClip);
   DrawText(pwsStr, iLength, rect, rtClip);
 }
@@ -416,7 +362,7 @@
     fLineWidth = rect.height;
   }
   m_pTxtBreak->SetLineWidth(fLineWidth);
-  m_ttoLines.RemoveAll(true);
+  m_ttoLines.clear();
   m_wsText.clear();
   LoadText(pwsStr, iLength, rect);
   if (m_dwStyles & FDE_TTOSTYLE_Ellipsis) {
@@ -532,12 +478,8 @@
       }
       if ((bVertical && m_fLinePos + fLineStep < fLineStop) ||
           (!bVertical && m_fLinePos + fLineStep > fLineStop)) {
-        int32_t iCurLine = m_iCurLine;
-        if (bEndofLine) {
-          iCurLine--;
-        }
-        CFDE_TTOLine* pLine = m_ttoLines.GetPtrAt(iCurLine);
-        pLine->m_bNewReload = true;
+        int32_t iCurLine = bEndofLine ? m_iCurLine - 1 : m_iCurLine;
+        m_ttoLines[iCurLine].SetNewReload(true);
         bRet = true;
         break;
       }
@@ -589,8 +531,7 @@
       m_CharWidths[iChar++] = iCurCharWidth;
     }
     if (j == 0 && !bReload) {
-      CFDE_TTOLine* pLine = m_ttoLines.GetPtrAt(m_iCurLine);
-      pLine->m_bNewReload = true;
+      m_ttoLines[m_iCurLine].SetNewReload(true);
     } else if (j > 0) {
       CFX_RectF rtPiece;
       if (bVertical) {
@@ -626,14 +567,15 @@
 void CFDE_TextOut::AppendPiece(const FDE_TTOPIECE& ttoPiece,
                                bool bNeedReload,
                                bool bEnd) {
-  if (m_iCurLine >= m_ttoLines.GetSize()) {
+  if (m_iCurLine >= pdfium::CollectionSize<int32_t>(m_ttoLines)) {
     CFDE_TTOLine ttoLine;
-    ttoLine.m_bNewReload = bNeedReload;
+    ttoLine.SetNewReload(bNeedReload);
     m_iCurPiece = ttoLine.AddPiece(m_iCurPiece, ttoPiece);
-    m_iCurLine = m_ttoLines.Add(ttoLine);
+    m_ttoLines.push_back(ttoLine);
+    m_iCurLine = pdfium::CollectionSize<int32_t>(m_ttoLines) - 1;
   } else {
-    CFDE_TTOLine* pLine = m_ttoLines.GetPtrAt(m_iCurLine);
-    pLine->m_bNewReload = bNeedReload;
+    CFDE_TTOLine* pLine = &m_ttoLines[m_iCurLine];
+    pLine->SetNewReload(bNeedReload);
     m_iCurPiece = pLine->AddPiece(m_iCurPiece, ttoPiece);
     if (bEnd) {
       int32_t iPieces = pLine->GetSize();
@@ -642,36 +584,33 @@
       }
     }
   }
-  if (!bEnd && bNeedReload) {
+  if (!bEnd && bNeedReload)
     m_iCurPiece = 0;
-  }
 }
 
 void CFDE_TextOut::ReplaceWidthEllipsis() {
   LoadEllipsis();
   int32_t iLength = m_wsEllipsis.GetLength();
-  if (iLength < 1) {
+  if (iLength < 1)
     return;
-  }
-  int32_t iLines = m_ttoLines.GetSize();
-  for (int32_t i = 0; i < iLines; i++) {
-    CFDE_TTOLine* pLine = m_ttoLines.GetPtrAt(i);
-    if (!pLine->m_bNewReload) {
+
+  for (auto& line : m_ttoLines) {
+    if (!line.GetNewReload())
       continue;
-    }
+
     int32_t iEllipsisCharIndex = iLength - 1;
     int32_t iCharWidth = 0;
     int32_t iCharCount = 0;
-    int32_t iPiece = pLine->GetSize();
+    int32_t iPiece = line.GetSize();
     while (iPiece-- > 0) {
-      FDE_TTOPIECE* pPiece = pLine->GetPtrAt(iPiece);
+      FDE_TTOPIECE* pPiece = line.GetPtrAt(iPiece);
       if (!pPiece)
         break;
 
       for (int32_t j = pPiece->iChars - 1; j >= 0; j--) {
-        if (iEllipsisCharIndex < 0) {
+        if (iEllipsisCharIndex < 0)
           break;
-        }
+
         int32_t index = pPiece->iStartChar + j;
         iCharWidth += m_CharWidths[index];
         iCharCount++;
@@ -684,23 +623,21 @@
         }
         iEllipsisCharIndex--;
       }
-      if (iEllipsisCharIndex < 0) {
+      if (iEllipsisCharIndex < 0)
         break;
-      }
     }
   }
 }
 
 void CFDE_TextOut::Reload(const CFX_RectF& rect) {
-  int32_t iCount = m_ttoLines.GetSize();
-  for (int32_t i = 0; i < iCount; i++) {
-    CFDE_TTOLine* pLine = m_ttoLines.GetPtrAt(i);
-    if (!pLine || !pLine->m_bNewReload)
-      continue;
-
-    m_iCurLine = i;
-    m_iCurPiece = 0;
-    ReloadLinePiece(pLine, rect);
+  int i = 0;
+  for (auto& line : m_ttoLines) {
+    if (line.GetNewReload()) {
+      m_iCurLine = i;
+      m_iCurPiece = 0;
+      ReloadLinePiece(&line, rect);
+    }
+    ++i;
   }
 }
 
@@ -737,12 +674,12 @@
 }
 
 void CFDE_TextOut::DoAlignment(const CFX_RectF& rect) {
+  if (m_ttoLines.empty())
+    return;
+
   bool bVertical = !!(m_dwStyles & FDE_TTOSTYLE_VerticalLayout);
   FX_FLOAT fLineStopS = bVertical ? rect.right() : rect.bottom();
-  int32_t iLines = m_ttoLines.GetSize();
-  if (iLines < 1)
-    return;
-  FDE_TTOPIECE* pFirstPiece = m_ttoLines.GetPtrAt(iLines - 1)->GetPtrAt(0);
+  FDE_TTOPIECE* pFirstPiece = m_ttoLines.back().GetPtrAt(0);
   if (!pFirstPiece)
     return;
 
@@ -757,11 +694,10 @@
   }
   if (fInc < 1.0f)
     return;
-  for (int32_t i = 0; i < iLines; i++) {
-    CFDE_TTOLine* pLine = m_ttoLines.GetPtrAt(i);
-    int32_t iPieces = pLine->GetSize();
+  for (auto& line : m_ttoLines) {
+    int32_t iPieces = line.GetSize();
     for (int32_t j = 0; j < iPieces; j++) {
-      FDE_TTOPIECE* pPiece = pLine->GetPtrAt(j);
+      FDE_TTOPIECE* pPiece = line.GetPtrAt(j);
       if (bVertical)
         pPiece->rtPiece.left += fInc;
       else
@@ -771,39 +707,34 @@
 }
 
 void CFDE_TextOut::OnDraw(const CFX_RectF& rtClip) {
-  if (!m_pRenderDevice)
+  if (!m_pRenderDevice || m_ttoLines.empty())
     return;
 
-  int32_t iLines = m_ttoLines.GetSize();
-  if (iLines < 1)
-    return;
-
-  CFDE_Brush* pBrush = new CFDE_Brush;
+  auto pBrush = pdfium::MakeUnique<CFDE_Brush>();
   pBrush->SetColor(m_TxtColor);
-  CFDE_Pen* pPen = nullptr;
   m_pRenderDevice->SaveState();
-  if (rtClip.Width() > 0.0f && rtClip.Height() > 0.0f) {
+  if (rtClip.Width() > 0.0f && rtClip.Height() > 0.0f)
     m_pRenderDevice->SetClipRect(rtClip);
-  }
-  for (int32_t i = 0; i < iLines; i++) {
-    CFDE_TTOLine* pLine = m_ttoLines.GetPtrAt(i);
-    int32_t iPieces = pLine->GetSize();
+
+  auto pPen = pdfium::MakeUnique<CFDE_Pen>();
+  pPen->SetColor(m_TxtColor);
+
+  for (auto& line : m_ttoLines) {
+    int32_t iPieces = line.GetSize();
     for (int32_t j = 0; j < iPieces; j++) {
-      FDE_TTOPIECE* pPiece = pLine->GetPtrAt(j);
+      FDE_TTOPIECE* pPiece = line.GetPtrAt(j);
       if (!pPiece)
         continue;
 
       int32_t iCount = GetDisplayPos(pPiece);
       if (iCount > 0) {
-        m_pRenderDevice->DrawString(pBrush, m_pFont, m_CharPos.data(), iCount,
-                                    m_fFontSize, &m_Matrix);
+        m_pRenderDevice->DrawString(pBrush.get(), m_pFont, m_CharPos.data(),
+                                    iCount, m_fFontSize, &m_Matrix);
       }
-      DrawLine(pPiece, pPen);
+      DrawLine(pPiece, pPen.get());
     }
   }
   m_pRenderDevice->RestoreState();
-  delete pBrush;
-  delete pPen;
 }
 
 int32_t CFDE_TextOut::GetDisplayPos(FDE_TTOPIECE* pPiece) {
@@ -814,8 +745,8 @@
 
 int32_t CFDE_TextOut::GetCharRects(const FDE_TTOPIECE* pPiece) {
   FX_TXTRUN tr = ToTextRun(pPiece);
-  m_rectArray.RemoveAll();
-  return m_pTxtBreak->GetCharRects(&tr, m_rectArray);
+  m_rectArray = m_pTxtBreak->GetCharRects(&tr);
+  return pdfium::CollectionSize<int32_t>(m_rectArray);
 }
 
 FX_TXTRUN CFDE_TextOut::ToTextRun(const FDE_TTOPIECE* pPiece) {
@@ -832,7 +763,7 @@
   return tr;
 }
 
-void CFDE_TextOut::DrawLine(const FDE_TTOPIECE* pPiece, CFDE_Pen*& pPen) {
+void CFDE_TextOut::DrawLine(const FDE_TTOPIECE* pPiece, CFDE_Pen* pPen) {
   bool bUnderLine = !!(m_dwStyles & FDE_TTOSTYLE_Underline);
   bool bStrikeOut = !!(m_dwStyles & FDE_TTOSTYLE_Strikeout);
   bool bHotKey = !!(m_dwStyles & FDE_TTOSTYLE_HotKey);
@@ -840,10 +771,6 @@
   if (!bUnderLine && !bStrikeOut && !bHotKey)
     return;
 
-  if (!pPen) {
-    pPen = new CFDE_Pen;
-    pPen->SetColor(m_TxtColor);
-  }
   std::unique_ptr<CFDE_Path> pPath(new CFDE_Path);
   int32_t iLineCount = 0;
   CFX_RectF rtText = pPiece->rtPiece;
@@ -886,7 +813,7 @@
         int32_t iCharIndex = m_hotKeys.GetAt(i);
         if (iCharIndex >= pPiece->iStartChar &&
             iCharIndex < pPiece->iStartChar + pPiece->iChars) {
-          CFX_RectF rect = m_rectArray.GetAt(iCharIndex - pPiece->iStartChar);
+          CFX_RectF rect = m_rectArray[iCharIndex - pPiece->iStartChar];
           if (bVertical) {
             pt1.x = rect.left;
             pt1.y = rect.top;
@@ -908,43 +835,42 @@
     m_pRenderDevice->DrawPath(pPen, 1, pPath.get(), &m_Matrix);
 }
 
-CFDE_TTOLine::CFDE_TTOLine()
-    : m_bNewReload(false), m_pieces(5), m_iPieceCount(0) {}
+CFDE_TTOLine::CFDE_TTOLine() : m_bNewReload(false) {}
 
 CFDE_TTOLine::CFDE_TTOLine(const CFDE_TTOLine& ttoLine) : m_pieces(5) {
   m_bNewReload = ttoLine.m_bNewReload;
-  m_iPieceCount = ttoLine.m_iPieceCount;
-  m_pieces.Copy(ttoLine.m_pieces, 0, -1);
+  m_pieces = ttoLine.m_pieces;
 }
 
 CFDE_TTOLine::~CFDE_TTOLine() {}
 
 int32_t CFDE_TTOLine::AddPiece(int32_t index, const FDE_TTOPIECE& ttoPiece) {
-  if (index >= m_iPieceCount) {
-    index = m_pieces.Add(ttoPiece) + 1;
-    m_iPieceCount++;
-  } else {
-    FDE_TTOPIECE& piece = m_pieces.GetAt(index);
-    piece = ttoPiece;
+  if (index >= pdfium::CollectionSize<int32_t>(m_pieces)) {
+    m_pieces.push_back(ttoPiece);
+    return pdfium::CollectionSize<int32_t>(m_pieces);
   }
+  m_pieces[index] = ttoPiece;
   return index;
 }
 
 int32_t CFDE_TTOLine::GetSize() const {
-  return m_iPieceCount;
+  return pdfium::CollectionSize<int32_t>(m_pieces);
 }
 
 FDE_TTOPIECE* CFDE_TTOLine::GetPtrAt(int32_t index) {
-  if (index >= m_iPieceCount) {
+  if (index < 0 || index >= pdfium::CollectionSize<int32_t>(m_pieces))
     return nullptr;
-  }
-  return m_pieces.GetPtrAt(index);
+
+  return &m_pieces[index];
 }
 
-void CFDE_TTOLine::RemoveLast(int32_t iCount) {
-  m_pieces.RemoveLast(iCount);
+void CFDE_TTOLine::RemoveLast(int32_t icount) {
+  if (icount < 0)
+    return;
+  icount = std::min(icount, pdfium::CollectionSize<int32_t>(m_pieces));
+  m_pieces.erase(m_pieces.end() - icount, m_pieces.end());
 }
 
-void CFDE_TTOLine::RemoveAll(bool bLeaveMemory) {
-  m_pieces.RemoveAll(bLeaveMemory);
+void CFDE_TTOLine::RemoveAll() {
+  m_pieces.clear();
 }
diff --git a/xfa/fde/tto/fde_textout.h b/xfa/fde/tto/fde_textout.h
index 94b72f8..04d6567 100644
--- a/xfa/fde/tto/fde_textout.h
+++ b/xfa/fde/tto/fde_textout.h
@@ -7,6 +7,7 @@
 #ifndef XFA_FDE_TTO_FDE_TEXTOUT_H_
 #define XFA_FDE_TTO_FDE_TEXTOUT_H_
 
+#include <deque>
 #include <memory>
 #include <vector>
 
@@ -47,12 +48,15 @@
 struct FX_TXTRUN;
 
 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;
 };
-typedef CFX_MassArrayTemplate<FDE_TTOPIECE> CFDE_TTOPieceArray;
 
 class CFDE_TTOLine {
  public:
@@ -60,19 +64,18 @@
   CFDE_TTOLine(const CFDE_TTOLine& ttoLine);
   ~CFDE_TTOLine();
 
+  bool GetNewReload() const { return m_bNewReload; }
+  void SetNewReload(bool reload) { m_bNewReload = reload; }
   int32_t AddPiece(int32_t index, const FDE_TTOPIECE& ttoPiece);
   int32_t GetSize() const;
   FDE_TTOPIECE* GetPtrAt(int32_t index);
   void RemoveLast(int32_t iCount);
-  void RemoveAll(bool bLeaveMemory);
+  void RemoveAll();
 
+ private:
   bool m_bNewReload;
-  CFDE_TTOPieceArray m_pieces;
-
- protected:
-  int32_t m_iPieceCount;
+  std::deque<FDE_TTOPIECE> m_pieces;
 };
-typedef CFX_ObjectMassArrayTemplate<CFDE_TTOLine> CFDE_TTOLineArray;
 
 class CFDE_TextOut {
  public:
@@ -94,10 +97,6 @@
   void SetClipRect(const CFX_RectF& rtClip);
   void SetMatrix(const CFX_Matrix& matrix);
   void SetLineBreakTolerance(FX_FLOAT fTolerance);
-  void CalcSize(const FX_WCHAR* pwsStr, int32_t iLength, CFX_Size& size);
-  void CalcSize(const FX_WCHAR* pwsStr, int32_t iLength, CFX_SizeF& size);
-  void CalcSize(const FX_WCHAR* pwsStr, int32_t iLength, CFX_Rect& rect);
-  void CalcSize(const FX_WCHAR* pwsStr, int32_t iLength, CFX_RectF& rect);
 
   void DrawText(const FX_WCHAR* pwsStr, int32_t iLength, int32_t x, int32_t y);
   void DrawText(const FX_WCHAR* pwsStr,
@@ -150,7 +149,7 @@
   int32_t GetCharRects(const FDE_TTOPIECE* pPiece);
 
   FX_TXTRUN ToTextRun(const FDE_TTOPIECE* pPiece);
-  void DrawLine(const FDE_TTOPIECE* pPiece, CFDE_Pen*& pPen);
+  void DrawLine(const FDE_TTOPIECE* pPiece, CFDE_Pen* pPen);
 
   std::unique_ptr<CFX_TxtBreak> m_pTxtBreak;
   CFX_RetainPtr<CFGAS_GEFont> m_pFont;
@@ -173,14 +172,14 @@
   CFX_RectF m_rtClip;
   CFX_RectF m_rtLogicClip;
   CFX_Matrix m_Matrix;
-  CFDE_TTOLineArray m_ttoLines;
+  std::deque<CFDE_TTOLine> m_ttoLines;
   int32_t m_iCurLine;
   int32_t m_iCurPiece;
   int32_t m_iTotalLines;
   std::vector<FXTEXT_CHARPOS> m_CharPos;
   std::unique_ptr<CFDE_RenderDevice> m_pRenderDevice;
-  CFX_Int32Array m_hotKeys;
-  CFX_RectFArray m_rectArray;
+  CFX_ArrayTemplate<int32_t> m_hotKeys;
+  std::vector<CFX_RectF> m_rectArray;
 };
 
 #endif  // XFA_FDE_TTO_FDE_TEXTOUT_H_
diff --git a/xfa/fde/xml/cfx_saxreader.h b/xfa/fde/xml/cfx_saxreader.h
index 8e06d9b..129399d 100644
--- a/xfa/fde/xml/cfx_saxreader.h
+++ b/xfa/fde/xml/cfx_saxreader.h
@@ -128,7 +128,7 @@
   bool m_bCharData;
   uint8_t m_CurByte;
   uint32_t m_dwDataOffset;
-  CFX_ByteArray m_SkipStack;
+  CFX_ArrayTemplate<uint8_t> m_SkipStack;
   uint8_t m_SkipChar;
   uint32_t m_dwNodePos;
   uint8_t* m_pszData;
diff --git a/xfa/fde/xml/fde_xml_imp.cpp b/xfa/fde/xml/fde_xml_imp.cpp
index 2bdaf51..5ce274b 100644
--- a/xfa/fde/xml/fde_xml_imp.cpp
+++ b/xfa/fde/xml/fde_xml_imp.cpp
@@ -84,10 +84,6 @@
       m_pPrior(nullptr),
       m_pNext(nullptr) {}
 
-void CFDE_XMLNode::Release() {
-  delete this;
-}
-
 FDE_XMLNODETYPE CFDE_XMLNode::GetType() const {
   return FDE_XMLNODE_Unknown;
 }
@@ -99,9 +95,9 @@
 void CFDE_XMLNode::DeleteChildren() {
   CFDE_XMLNode* pChild = m_pChild;
   while (pChild) {
-    CFDE_XMLNode* pTemp = pChild->m_pNext;
-    pChild->Release();
-    pChild = pTemp;
+    CFDE_XMLNode* pNext = pChild->m_pNext;
+    delete pChild;
+    pChild = pNext;
   }
   m_pChild = nullptr;
 }
@@ -529,10 +525,6 @@
   ASSERT(m_wsTarget.GetLength() > 0);
 }
 
-void CFDE_XMLInstruction::Release() {
-  delete this;
-}
-
 FDE_XMLNODETYPE CFDE_XMLInstruction::GetType() const {
   return FDE_XMLNODE_Instruction;
 }
@@ -687,10 +679,6 @@
 
 CFDE_XMLElement::~CFDE_XMLElement() {}
 
-void CFDE_XMLElement::Release() {
-  delete this;
-}
-
 FDE_XMLNODETYPE CFDE_XMLElement::GetType() const {
   return FDE_XMLNODE_Element;
 }
@@ -899,10 +887,6 @@
 CFDE_XMLText::CFDE_XMLText(const CFX_WideString& wsText)
     : CFDE_XMLNode(), m_wsText(wsText) {}
 
-void CFDE_XMLText::Release() {
-  delete this;
-}
-
 FDE_XMLNODETYPE CFDE_XMLText::GetType() const {
   return FDE_XMLNODE_Text;
 }
@@ -917,10 +901,6 @@
 CFDE_XMLCharData::CFDE_XMLCharData(const CFX_WideString& wsCData)
     : CFDE_XMLDeclaration(), m_wsCharData(wsCData) {}
 
-void CFDE_XMLCharData::Release() {
-  delete this;
-}
-
 FDE_XMLNODETYPE CFDE_XMLCharData::GetType() const {
   return FDE_XMLNODE_CharData;
 }
@@ -932,8 +912,7 @@
 
 CFDE_XMLCharData::~CFDE_XMLCharData() {}
 
-CFDE_XMLDoc::CFDE_XMLDoc()
-    : m_pRoot(nullptr), m_pSyntaxParser(nullptr), m_pXMLParser(nullptr) {
+CFDE_XMLDoc::CFDE_XMLDoc() : m_pRoot(nullptr) {
   Reset(true);
   CFDE_XMLInstruction* pXML = new CFDE_XMLInstruction(L"xml");
   m_pRoot->InsertChildNode(pXML);
@@ -952,20 +931,14 @@
     else
       m_pRoot = new CFDE_XMLNode;
   } else {
-    if (m_pRoot) {
-      m_pRoot->Release();
-      m_pRoot = nullptr;
-    }
+    delete m_pRoot;
+    m_pRoot = nullptr;
   }
   ReleaseParser();
 }
 
 void CFDE_XMLDoc::ReleaseParser() {
   m_pXMLParser.reset();
-  if (m_pSyntaxParser) {
-    m_pSyntaxParser->Release();
-    m_pSyntaxParser = nullptr;
-  }
 }
 
 bool CFDE_XMLDoc::LoadXML(std::unique_ptr<IFDE_XMLParser> pXMLParser) {
@@ -1314,7 +1287,8 @@
     return;
   }
 
-  m_pBuffer = FX_Alloc(FX_WCHAR, alloc_size_safe.ValueOrDie());
+  m_pBuffer = FX_Alloc(
+      FX_WCHAR, pdfium::base::ValueOrDieForType<size_t>(alloc_size_safe));
   m_pStart = m_pEnd = m_pBuffer;
   ASSERT(!m_BlockBuffer.IsInitialized());
   m_BlockBuffer.InitBuffer();
diff --git a/xfa/fde/xml/fde_xml_imp.h b/xfa/fde/xml/fde_xml_imp.h
index 49c5c51..41e84ba 100644
--- a/xfa/fde/xml/fde_xml_imp.h
+++ b/xfa/fde/xml/fde_xml_imp.h
@@ -44,7 +44,6 @@
   CFDE_XMLNode();
   virtual ~CFDE_XMLNode();
 
-  virtual void Release();
   virtual FDE_XMLNODETYPE GetType() const;
   virtual CFDE_XMLNode* Clone(bool bRecursive);
 
@@ -79,7 +78,6 @@
   ~CFDE_XMLInstruction() override;
 
   // CFDE_XMLNode
-  void Release() override;
   FDE_XMLNODETYPE GetType() const override;
   CFDE_XMLNode* Clone(bool bRecursive) override;
 
@@ -115,7 +113,6 @@
   ~CFDE_XMLElement() override;
 
   // CFDE_XMLNode
-  void Release() override;
   FDE_XMLNODETYPE GetType() const override;
   CFDE_XMLNode* Clone(bool bRecursive) override;
 
@@ -157,7 +154,6 @@
   ~CFDE_XMLText() override;
 
   // CFDE_XMLNode
-  void Release() override;
   FDE_XMLNODETYPE GetType() const override;
   CFDE_XMLNode* Clone(bool bRecursive) override;
 
@@ -178,7 +174,6 @@
   explicit CFDE_XMLCharData(const CFX_WideString& wsCData);
   ~CFDE_XMLCharData() override;
 
-  void Release() override;
   FDE_XMLNODETYPE GetType() const override;
   CFDE_XMLNode* Clone(bool bRecursive) override;
 
@@ -210,7 +205,6 @@
   CFX_RetainPtr<IFGAS_Stream> m_pStream;
   int32_t m_iStatus;
   CFDE_XMLNode* m_pRoot;
-  CFDE_XMLSyntaxParser* m_pSyntaxParser;
   std::unique_ptr<IFDE_XMLParser> m_pXMLParser;
 };
 
@@ -227,7 +221,6 @@
 
   bool InitBuffer(int32_t iBufferSize = 1024 * 1024);
   bool IsInitialized() { return m_iBufferSize / m_iAllocStep >= 1; }
-  void ReleaseBuffer() { delete this; }
   FX_WCHAR* GetAvailableBlock(int32_t& iIndexInBlock);
   inline int32_t GetAllocStep() const { return m_iAllocStep; }
   inline int32_t& GetDataLengthRef() { return m_iDataLength; }
@@ -261,7 +254,6 @@
   CFDE_XMLSyntaxParser();
   ~CFDE_XMLSyntaxParser();
 
-  void Release() { delete this; }
   void Init(const CFX_RetainPtr<IFGAS_Stream>& pStream,
             int32_t iXMLPlaneSize,
             int32_t iTextDataSize = 256);
diff --git a/xfa/fgas/crt/fgas_utils.cpp b/xfa/fgas/crt/fgas_utils.cpp
index 1e86c6c..c09198f 100644
--- a/xfa/fgas/crt/fgas_utils.cpp
+++ b/xfa/fgas/crt/fgas_utils.cpp
@@ -301,37 +301,6 @@
   m_iChunkCount = 0;
   m_iBlockCount = 0;
 }
-CFX_BaseMassArray::CFX_BaseMassArray(int32_t iChunkSize, int32_t iBlockSize) {
-  m_pData = new CFX_BaseMassArrayImp(iChunkSize, iBlockSize);
-}
-CFX_BaseMassArray::~CFX_BaseMassArray() {
-  delete m_pData;
-}
-int32_t CFX_BaseMassArray::GetSize() const {
-  return m_pData->m_iBlockCount;
-}
-uint8_t* CFX_BaseMassArray::AddSpaceTo(int32_t index) {
-  return m_pData->AddSpaceTo(index);
-}
-uint8_t* CFX_BaseMassArray::GetAt(int32_t index) const {
-  return m_pData->GetAt(index);
-}
-int32_t CFX_BaseMassArray::Append(const CFX_BaseMassArray& src,
-                                  int32_t iStart,
-                                  int32_t iCount) {
-  return m_pData->Append(*(CFX_BaseMassArrayImp*)src.m_pData, iStart, iCount);
-}
-int32_t CFX_BaseMassArray::Copy(const CFX_BaseMassArray& src,
-                                int32_t iStart,
-                                int32_t iCount) {
-  return m_pData->Copy(*(CFX_BaseMassArrayImp*)src.m_pData, iStart, iCount);
-}
-int32_t CFX_BaseMassArray::RemoveLast(int32_t iCount) {
-  return m_pData->RemoveLast(iCount);
-}
-void CFX_BaseMassArray::RemoveAll(bool bLeaveMemory) {
-  m_pData->RemoveAll(bLeaveMemory);
-}
 
 struct FX_BASEDISCRETEARRAYDATA {
   int32_t iBlockSize;
diff --git a/xfa/fgas/crt/fgas_utils.h b/xfa/fgas/crt/fgas_utils.h
index 4656011..105920d 100644
--- a/xfa/fgas/crt/fgas_utils.h
+++ b/xfa/fgas/crt/fgas_utils.h
@@ -104,152 +104,6 @@
               int32_t iSrcCount);
 };
 
-class CFX_BaseMassArray {
- protected:
-  CFX_BaseMassArray(int32_t iChunkSize, int32_t iBlockSize);
-  ~CFX_BaseMassArray();
-
-  int32_t GetSize() const;
-  uint8_t* AddSpaceTo(int32_t index);
-  uint8_t* GetAt(int32_t index) const;
-  int32_t Append(const CFX_BaseMassArray& src, int32_t iStart, int32_t iCount);
-  int32_t Copy(const CFX_BaseMassArray& src, int32_t iStart, int32_t iCount);
-  int32_t RemoveLast(int32_t iCount);
-  void RemoveAll(bool bLeaveMemory);
-  CFX_BaseMassArrayImp* m_pData;
-};
-
-template <class baseType>
-class CFX_MassArrayTemplate : public CFX_BaseMassArray {
- public:
-  explicit CFX_MassArrayTemplate(int32_t iChunkSize)
-      : CFX_BaseMassArray(iChunkSize, sizeof(baseType)) {}
-  CFX_MassArrayTemplate(int32_t iChunkSize, int32_t iBlockSize)
-      : CFX_BaseMassArray(iChunkSize, iBlockSize) {}
-
-  int32_t GetSize() const { return CFX_BaseMassArray::GetSize(); }
-  baseType* AddSpace() {
-    return (baseType*)CFX_BaseMassArray::AddSpaceTo(
-        CFX_BaseMassArray::GetSize());
-  }
-  int32_t Add(const baseType& element) {
-    int32_t index = CFX_BaseMassArray::GetSize();
-    *(baseType*)CFX_BaseMassArray::AddSpaceTo(index) = element;
-    return index;
-  }
-  baseType& GetAt(int32_t index) const {
-    return *(baseType*)CFX_BaseMassArray::GetAt(index);
-  }
-  baseType* GetPtrAt(int32_t index) const {
-    return (baseType*)CFX_BaseMassArray::GetAt(index);
-  }
-  void SetAt(int32_t index, const baseType& element) {
-    *(baseType*)CFX_BaseMassArray::GetAt(index) = element;
-  }
-  void SetAtGrow(int32_t index, const baseType& element) {
-    *(baseType*)CFX_BaseMassArray::AddSpaceTo(index) = element;
-  }
-  int32_t Append(const CFX_MassArrayTemplate& src,
-                 int32_t iStart,
-                 int32_t iCount) {
-    return CFX_BaseMassArray::Append(src, iStart, iCount);
-  }
-  int32_t Copy(const CFX_MassArrayTemplate& src,
-               int32_t iStart,
-               int32_t iCount) {
-    return CFX_BaseMassArray::Copy(src, iStart, iCount);
-  }
-  int32_t RemoveLast(int32_t iCount) {
-    return CFX_BaseMassArray::RemoveLast(iCount);
-  }
-  void RemoveAll(bool bLeaveMemory) {
-    CFX_BaseMassArray::RemoveAll(bLeaveMemory);
-  }
-};
-
-template <class baseType>
-class CFX_ObjectMassArrayTemplate : public CFX_BaseMassArray {
- public:
-  explicit CFX_ObjectMassArrayTemplate(int32_t iChunkSize)
-      : CFX_BaseMassArray(iChunkSize, sizeof(baseType)) {}
-  ~CFX_ObjectMassArrayTemplate() { RemoveAll(false); }
-
-  int32_t GetSize() const { return CFX_BaseMassArray::GetSize(); }
-  int32_t Add(const baseType& element) {
-    int32_t index = CFX_BaseMassArray::GetSize();
-    baseType* p = (baseType*)CFX_BaseMassArray::AddSpaceTo(index);
-    new ((void*)p) baseType(element);
-    return index;
-  }
-  baseType& GetAt(int32_t index) const {
-    return *(baseType*)CFX_BaseMassArray::GetAt(index);
-  }
-  baseType* GetPtrAt(int32_t index) const {
-    return (baseType*)CFX_BaseMassArray::GetAt(index);
-  }
-  int32_t Append(const CFX_ObjectMassArrayTemplate& src,
-                 int32_t iStart,
-                 int32_t iCount) {
-    if (iCount == 0) {
-      return CFX_BaseMassArray::GetSize();
-    }
-    int32_t iSize = src.GetSize();
-    ASSERT(iStart > -1 && iStart < iSize);
-    if (iCount < 0) {
-      iCount = iSize;
-    }
-    int32_t iEnd = iStart + iCount;
-    if (iEnd > iSize) {
-      iEnd = iSize;
-    }
-    for (int32_t i = iStart; i < iEnd; i++) {
-      Add(src.GetAt(i));
-    }
-    return CFX_BaseMassArray::GetSize();
-  }
-  int32_t Copy(const CFX_ObjectMassArrayTemplate& src,
-               int32_t iStart,
-               int32_t iCount) {
-    if (iCount == 0) {
-      return CFX_BaseMassArray::GetSize();
-    }
-    int32_t iSize = src.GetSize();
-    ASSERT(iStart > -1 && iStart < iSize);
-    if (iCount < 0) {
-      iCount = iSize;
-    }
-    int32_t iEnd = iStart + iCount;
-    if (iEnd > iSize) {
-      iEnd = iSize;
-    }
-    RemoveAll(true);
-    for (int32_t i = iStart; i < iEnd; i++) {
-      Add(src.GetAt(i));
-    }
-    return CFX_BaseMassArray::GetSize();
-  }
-  int32_t RemoveLast(int32_t iCount) {
-    int32_t iSize = CFX_BaseMassArray::GetSize();
-    if (iCount < 0 || iCount > iSize) {
-      iCount = iSize;
-    }
-    if (iCount == 0) {
-      return iSize;
-    }
-    for (int32_t i = iSize - iCount; i < iSize; i++) {
-      ((baseType*)GetPtrAt(i))->~baseType();
-    }
-    return CFX_BaseMassArray::RemoveLast(iCount);
-  }
-  void RemoveAll(bool bLeaveMemory) {
-    int32_t iSize = CFX_BaseMassArray::GetSize();
-    for (int32_t i = 0; i < iSize; i++) {
-      ((baseType*)GetPtrAt(i))->~baseType();
-    }
-    CFX_BaseMassArray::RemoveAll(bLeaveMemory);
-  }
-};
-
 class CFX_BaseDiscreteArray {
  protected:
   CFX_BaseDiscreteArray(int32_t iChunkSize, int32_t iBlockSize);
@@ -316,61 +170,4 @@
   void RemoveAll(bool bLeaveMemory) { CFX_BaseStack::RemoveAll(bLeaveMemory); }
 };
 
-template <class baseType>
-class CFX_ObjectStackTemplate : public CFX_BaseStack {
- public:
-  explicit CFX_ObjectStackTemplate(int32_t iChunkSize)
-      : CFX_BaseStack(iChunkSize, sizeof(baseType)) {}
-  ~CFX_ObjectStackTemplate() { RemoveAll(false); }
-
-  int32_t Push(const baseType& element) {
-    int32_t index = CFX_BaseStack::GetSize();
-    baseType* p = (baseType*)CFX_BaseStack::Push();
-    new ((void*)p) baseType(element);
-    return index;
-  }
-  void Pop() {
-    baseType* p = (baseType*)CFX_BaseStack::GetTopElement();
-    if (p) {
-      p->~baseType();
-    }
-    CFX_BaseStack::Pop();
-  }
-  baseType* GetTopElement() const {
-    return (baseType*)CFX_BaseStack::GetTopElement();
-  }
-  int32_t GetSize() const { return CFX_BaseStack::GetSize(); }
-  baseType* GetAt(int32_t index) const {
-    return (baseType*)CFX_BaseStack::GetAt(index);
-  }
-  void RemoveAll(bool bLeaveMemory) {
-    int32_t iSize = CFX_BaseStack::GetSize();
-    for (int32_t i = 0; i < iSize; i++) {
-      ((baseType*)CFX_BaseStack::GetAt(i))->~baseType();
-    }
-    CFX_BaseStack::RemoveAll(bLeaveMemory);
-  }
-  int32_t Copy(const CFX_ObjectStackTemplate& src,
-               int32_t iStart,
-               int32_t iCount) {
-    if (iCount == 0) {
-      return CFX_BaseStack::GetSize();
-    }
-    int32_t iSize = src.GetSize();
-    ASSERT(iStart > -1 && iStart < iSize);
-    if (iCount < 0) {
-      iCount = iSize;
-    }
-    int32_t iEnd = iStart + iCount;
-    if (iEnd > iSize) {
-      iEnd = iSize;
-    }
-    RemoveAll(true);
-    for (int32_t i = iStart; i < iEnd; i++) {
-      Push(*src.GetAt(i));
-    }
-    return CFX_BaseStack::GetSize();
-  }
-};
-
 #endif  // XFA_FGAS_CRT_FGAS_UTILS_H_
diff --git a/xfa/fgas/font/cfgas_fontmgr.cpp b/xfa/fgas/font/cfgas_fontmgr.cpp
index add6689..aa41318 100644
--- a/xfa/fgas/font/cfgas_fontmgr.cpp
+++ b/xfa/fgas/font/cfgas_fontmgr.cpp
@@ -47,49 +47,49 @@
   return iValue;
 }
 
-FX_FONTDESCRIPTOR const* MatchDefaultFont(FX_FONTMATCHPARAMS* pParams,
-                                          const CFX_FontDescriptors& fonts) {
-  FX_FONTDESCRIPTOR const* pBestFont = nullptr;
+const FX_FONTDESCRIPTOR* MatchDefaultFont(
+    FX_FONTMATCHPARAMS* pParams,
+    const std::deque<FX_FONTDESCRIPTOR>& fonts) {
+  const FX_FONTDESCRIPTOR* pBestFont = nullptr;
   int32_t iBestSimilar = 0;
   bool bMatchStyle = (pParams->dwMatchFlags & FX_FONTMATCHPARA_MatchStyle) > 0;
-  for (int32_t i = 0; i < fonts.GetSize(); ++i) {
-    FX_FONTDESCRIPTOR const* pFont = fonts.GetPtrAt(i);
-    if ((pFont->dwFontStyles & FX_FONTSTYLE_BoldItalic) ==
+  for (const auto& font : fonts) {
+    if ((font.dwFontStyles & FX_FONTSTYLE_BoldItalic) ==
         FX_FONTSTYLE_BoldItalic) {
       continue;
     }
     if (pParams->pwsFamily) {
-      if (FXSYS_wcsicmp(pParams->pwsFamily, pFont->wsFontFace))
+      if (FXSYS_wcsicmp(pParams->pwsFamily, font.wsFontFace))
         continue;
-      if (pFont->uCharSet == FX_CHARSET_Symbol)
-        return pFont;
+      if (font.uCharSet == FX_CHARSET_Symbol)
+        return &font;
     }
-    if (pFont->uCharSet == FX_CHARSET_Symbol)
+    if (font.uCharSet == FX_CHARSET_Symbol)
       continue;
     if (pParams->wCodePage != 0xFFFF) {
-      if (FX_GetCodePageFromCharset(pFont->uCharSet) != pParams->wCodePage)
+      if (FX_GetCodePageFromCharset(font.uCharSet) != pParams->wCodePage)
         continue;
     } else {
       if (pParams->dwUSB < 128) {
         uint32_t dwByte = pParams->dwUSB / 32;
         uint32_t dwUSB = 1 << (pParams->dwUSB % 32);
-        if ((pFont->FontSignature.fsUsb[dwByte] & dwUSB) == 0)
+        if ((font.FontSignature.fsUsb[dwByte] & dwUSB) == 0)
           continue;
       }
     }
     if (bMatchStyle) {
-      if ((pFont->dwFontStyles & 0x0F) == (pParams->dwFontStyles & 0x0F))
-        return pFont;
+      if ((font.dwFontStyles & 0x0F) == (pParams->dwFontStyles & 0x0F))
+        return &font;
       continue;
     }
     if (pParams->pwsFamily) {
-      if (FXSYS_wcsicmp(pParams->pwsFamily, pFont->wsFontFace) == 0)
-        return pFont;
+      if (FXSYS_wcsicmp(pParams->pwsFamily, font.wsFontFace) == 0)
+        return &font;
     }
-    int32_t iSimilarValue = GetSimilarityScore(pFont, pParams->dwFontStyles);
+    int32_t iSimilarValue = GetSimilarityScore(&font, pParams->dwFontStyles);
     if (iBestSimilar < iSimilarValue) {
       iBestSimilar = iSimilarValue;
-      pBestFont = pFont;
+      pBestFont = &font;
     }
   }
   return iBestSimilar < 1 ? nullptr : pBestFont;
@@ -105,12 +105,10 @@
 CFGAS_FontMgr::CFGAS_FontMgr(FX_LPEnumAllFonts pEnumerator)
     : m_pEnumerator(pEnumerator), m_FontFaces(100) {
   if (m_pEnumerator)
-    m_pEnumerator(m_FontFaces, nullptr, 0xFEFF);
+    m_pEnumerator(&m_FontFaces, nullptr, 0xFEFF);
 }
 
-CFGAS_FontMgr::~CFGAS_FontMgr() {
-  m_FontFaces.RemoveAll(false);
-}
+CFGAS_FontMgr::~CFGAS_FontMgr() {}
 
 CFX_RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByCodePage(
     uint16_t wCodePage,
@@ -264,7 +262,7 @@
     m_Fonts.erase(it);
 }
 
-FX_FONTDESCRIPTOR const* CFGAS_FontMgr::FindFont(const FX_WCHAR* pszFontFamily,
+const FX_FONTDESCRIPTOR* CFGAS_FontMgr::FindFont(const FX_WCHAR* pszFontFamily,
                                                  uint32_t dwFontStyles,
                                                  uint32_t dwMatchFlags,
                                                  uint16_t wCodePage,
@@ -278,25 +276,26 @@
   params.pwsFamily = pszFontFamily;
   params.dwFontStyles = dwFontStyles;
   params.dwMatchFlags = dwMatchFlags;
-  FX_FONTDESCRIPTOR const* pDesc = MatchDefaultFont(&params, m_FontFaces);
+  const FX_FONTDESCRIPTOR* pDesc = MatchDefaultFont(&params, m_FontFaces);
   if (pDesc)
     return pDesc;
+
   if (!pszFontFamily || !m_pEnumerator)
     return nullptr;
 
-  CFX_FontDescriptors namedFonts(100);
-  m_pEnumerator(namedFonts, pszFontFamily, wUnicode);
+  std::deque<FX_FONTDESCRIPTOR> namedFonts;
+  m_pEnumerator(&namedFonts, pszFontFamily, wUnicode);
   params.pwsFamily = nullptr;
   pDesc = MatchDefaultFont(&params, namedFonts);
   if (!pDesc)
     return nullptr;
-  for (int32_t i = m_FontFaces.GetSize() - 1; i >= 0; i--) {
-    FX_FONTDESCRIPTOR const* pMatch = m_FontFaces.GetPtrAt(i);
-    if (*pMatch == *pDesc)
-      return pMatch;
-  }
-  int index = m_FontFaces.Add(*pDesc);
-  return m_FontFaces.GetPtrAt(index);
+
+  auto it = std::find(m_FontFaces.rbegin(), m_FontFaces.rend(), *pDesc);
+  if (it != m_FontFaces.rend())
+    return &*it;
+
+  m_FontFaces.push_back(*pDesc);
+  return &m_FontFaces.back();
 }
 
 uint32_t FX_GetGdiFontStyles(const LOGFONTW& lf) {
@@ -330,12 +329,12 @@
   pFont->wsFontFace[31] = 0;
   FXSYS_memcpy(&pFont->FontSignature, &lpntme->ntmFontSig,
                sizeof(lpntme->ntmFontSig));
-  ((CFX_FontDescriptors*)lParam)->Add(*pFont);
+  reinterpret_cast<std::deque<FX_FONTDESCRIPTOR>*>(lParam)->push_back(*pFont);
   FX_Free(pFont);
   return 1;
 }
 
-static void FX_EnumGdiFonts(CFX_FontDescriptors& fonts,
+static void FX_EnumGdiFonts(std::deque<FX_FONTDESCRIPTOR>* fonts,
                             const FX_WCHAR* pwsFaceName,
                             FX_WCHAR wUnicode) {
   HDC hDC = ::GetDC(nullptr);
@@ -347,7 +346,7 @@
     lfFind.lfFaceName[31] = 0;
   }
   EnumFontFamiliesExW(hDC, (LPLOGFONTW)&lfFind,
-                      (FONTENUMPROCW)FX_GdiFontEnumProc, (LPARAM)&fonts, 0);
+                      (FONTENUMPROCW)FX_GdiFontEnumProc, (LPARAM)fonts, 0);
   ::ReleaseDC(nullptr, hDC);
 }
 
@@ -516,7 +515,7 @@
       FX_CloseFolder(pCurHandle);
       if (!m_FolderQueue.empty())
         m_FolderQueue.pop_back();
-      if (!m_FolderQueue.empty()) {
+      if (m_FolderQueue.empty()) {
         if (!m_FolderPaths.empty())
           m_FolderPaths.pop_back();
         return !m_FolderPaths.empty() ? GetNextFile() : "";
@@ -629,7 +628,7 @@
     const FX_WCHAR* pszFontFamily) {
   CFX_ByteString bsHash;
   bsHash.Format("%d, %d", wCodePage, dwFontStyles);
-  bsHash += CFX_WideString(pszFontFamily).UTF8Encode();
+  bsHash += FX_UTF8Encode(CFX_WideStringC(pszFontFamily));
   uint32_t dwHash = FX_HashCode_GetA(bsHash.AsStringC(), false);
   std::vector<CFX_RetainPtr<CFGAS_GEFont>>* pFontArray = &m_Hash2Fonts[dwHash];
   if (!pFontArray->empty())
@@ -673,7 +672,7 @@
     bsHash.Format("%d, %d, %d", wCodePage, wBitField, dwFontStyles);
   else
     bsHash.Format("%d, %d", wCodePage, dwFontStyles);
-  bsHash += CFX_WideString(pszFontFamily).UTF8Encode();
+  bsHash += FX_UTF8Encode(CFX_WideStringC(pszFontFamily));
   uint32_t dwHash = FX_HashCode_GetA(bsHash.AsStringC(), false);
   std::vector<CFX_RetainPtr<CFGAS_GEFont>>* pFonts = &m_Hash2Fonts[dwHash];
   for (size_t i = 0; i < pFonts->size(); ++i) {
diff --git a/xfa/fgas/font/cfgas_fontmgr.h b/xfa/fgas/font/cfgas_fontmgr.h
index 1dadfd3..dffdb8a 100644
--- a/xfa/fgas/font/cfgas_fontmgr.h
+++ b/xfa/fgas/font/cfgas_fontmgr.h
@@ -7,6 +7,7 @@
 #ifndef XFA_FGAS_FONT_CFGAS_FONTMGR_H_
 #define XFA_FGAS_FONT_CFGAS_FONTMGR_H_
 
+#include <deque>
 #include <map>
 #include <memory>
 #include <set>
@@ -70,8 +71,6 @@
   FX_FONTSIGNATURE FontSignature;
 };
 
-typedef CFX_MassArrayTemplate<FX_FONTDESCRIPTOR> CFX_FontDescriptors;
-
 inline bool operator==(const FX_FONTDESCRIPTOR& left,
                        const FX_FONTDESCRIPTOR& right) {
   return left.uCharSet == right.uCharSet &&
@@ -80,7 +79,7 @@
          FXSYS_wcscmp(left.wsFontFace, right.wsFontFace) == 0;
 }
 
-typedef void (*FX_LPEnumAllFonts)(CFX_FontDescriptors& fonts,
+typedef void (*FX_LPEnumAllFonts)(std::deque<FX_FONTDESCRIPTOR>* fonts,
                                   const FX_WCHAR* pwsFaceName,
                                   FX_WCHAR wUnicode);
 
@@ -119,7 +118,7 @@
                                     FX_WCHAR wUnicode = 0);
 
   FX_LPEnumAllFonts m_pEnumerator;
-  CFX_FontDescriptors m_FontFaces;
+  std::deque<FX_FONTDESCRIPTOR> m_FontFaces;
   std::vector<CFX_RetainPtr<CFGAS_GEFont>> m_Fonts;
   std::map<uint32_t, CFX_RetainPtr<CFGAS_GEFont>> m_CPFonts;
   std::map<uint32_t, CFX_RetainPtr<CFGAS_GEFont>> m_FamilyFonts;
diff --git a/xfa/fgas/font/cfgas_gefont.cpp b/xfa/fgas/font/cfgas_gefont.cpp
index d0e7f13..a57962d 100644
--- a/xfa/fgas/font/cfgas_gefont.cpp
+++ b/xfa/fgas/font/cfgas_gefont.cpp
@@ -220,8 +220,6 @@
     m_pCharWidthMap =
         pdfium::MakeUnique<CFX_DiscreteArrayTemplate<uint16_t>>(1024);
   }
-  if (!m_pRectArray)
-    m_pRectArray = pdfium::MakeUnique<CFX_MassArrayTemplate<CFX_Rect>>(16);
   return true;
 }
 
@@ -315,33 +313,27 @@
                                        CFX_Rect* bbox,
                                        bool bRecursive,
                                        bool bCharCode) {
-  ASSERT(m_pRectArray);
-  CFX_Rect* pRect = nullptr;
   auto it = m_BBoxMap.find(wUnicode);
-  if (it == m_BBoxMap.end()) {
-    CFX_RetainPtr<CFGAS_GEFont> pFont;
-    int32_t iGlyph = GetGlyphIndex(wUnicode, true, &pFont, bCharCode);
-    if (iGlyph != 0xFFFF && pFont) {
-      if (pFont.Get() == this) {
-        FX_RECT rtBBox;
-        if (m_pFont->GetGlyphBBox(iGlyph, rtBBox)) {
-          CFX_Rect rt;
-          rt.Set(rtBBox.left, rtBBox.top, rtBBox.Width(), rtBBox.Height());
-          int32_t index = m_pRectArray->Add(rt);
-          pRect = m_pRectArray->GetPtrAt(index);
-          m_BBoxMap[wUnicode] = pRect;
-        }
-      } else if (pFont->GetCharBBoxInternal(wUnicode, bbox, false, bCharCode)) {
-        return true;
-      }
-    }
-  } else {
-    pRect = it->second;
+  if (it != m_BBoxMap.end()) {
+    *bbox = it->second;
+    return true;
   }
-  if (!pRect)
+
+  CFX_RetainPtr<CFGAS_GEFont> pFont;
+  int32_t iGlyph = GetGlyphIndex(wUnicode, true, &pFont, bCharCode);
+  if (!pFont || iGlyph == 0xFFFF)
     return false;
 
-  *bbox = *pRect;
+  if (pFont.Get() != this)
+    return pFont->GetCharBBoxInternal(wUnicode, bbox, false, bCharCode);
+
+  FX_RECT 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;
   return true;
 }
 
diff --git a/xfa/fgas/font/cfgas_gefont.h b/xfa/fgas/font/cfgas_gefont.h
index 6c9d890..2201721 100644
--- a/xfa/fgas/font/cfgas_gefont.h
+++ b/xfa/fgas/font/cfgas_gefont.h
@@ -109,8 +109,7 @@
   CFX_RetainPtr<IFX_SeekableReadStream> m_pFileRead;
   std::unique_ptr<CFX_UnicodeEncoding> m_pFontEncoding;
   std::unique_ptr<CFX_DiscreteArrayTemplate<uint16_t>> m_pCharWidthMap;
-  std::unique_ptr<CFX_MassArrayTemplate<CFX_Rect>> m_pRectArray;
-  std::map<FX_WCHAR, CFX_Rect*> m_BBoxMap;  // Rect owned by m_pRectArray.
+  std::map<FX_WCHAR, CFX_Rect> m_BBoxMap;
   CXFA_PDFFontMgr* m_pProvider;  // not owned.
   std::vector<CFX_RetainPtr<CFGAS_GEFont>> m_SubstFonts;
   std::map<FX_WCHAR, CFX_RetainPtr<CFGAS_GEFont>> m_FontMapper;
diff --git a/xfa/fgas/layout/fgas_rtfbreak.cpp b/xfa/fgas/layout/fgas_rtfbreak.cpp
index f7ba0e7..9a83be6 100644
--- a/xfa/fgas/layout/fgas_rtfbreak.cpp
+++ b/xfa/fgas/layout/fgas_rtfbreak.cpp
@@ -13,36 +13,40 @@
 #include "third_party/base/stl_util.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
 #include "xfa/fgas/layout/fgas_linebreak.h"
-#include "xfa/fgas/layout/fgas_unicode.h"
 
-CFX_RTFBreak::CFX_RTFBreak(uint32_t dwPolicies)
-    : m_dwPolicies(dwPolicies),
-      m_iBoundaryStart(0),
+namespace {
+
+typedef CFX_RTFBreakType (CFX_RTFBreak::*FX_RTFBreak_LPFAppendChar)(
+    CFX_RTFChar* pCurChar);
+const FX_RTFBreak_LPFAppendChar g_FX_RTFBreak_lpfAppendChar[16] = {
+    &CFX_RTFBreak::AppendChar_Others,      &CFX_RTFBreak::AppendChar_Tab,
+    &CFX_RTFBreak::AppendChar_Others,      &CFX_RTFBreak::AppendChar_Control,
+    &CFX_RTFBreak::AppendChar_Combination, &CFX_RTFBreak::AppendChar_Others,
+    &CFX_RTFBreak::AppendChar_Others,      &CFX_RTFBreak::AppendChar_Arabic,
+    &CFX_RTFBreak::AppendChar_Arabic,      &CFX_RTFBreak::AppendChar_Arabic,
+    &CFX_RTFBreak::AppendChar_Arabic,      &CFX_RTFBreak::AppendChar_Arabic,
+    &CFX_RTFBreak::AppendChar_Arabic,      &CFX_RTFBreak::AppendChar_Others,
+    &CFX_RTFBreak::AppendChar_Others,      &CFX_RTFBreak::AppendChar_Others,
+};
+
+}  // namespace
+
+CFX_RTFBreak::CFX_RTFBreak(uint32_t dwLayoutStyles)
+    : m_iBoundaryStart(0),
       m_iBoundaryEnd(2000000),
-      m_dwLayoutStyles(0),
+      m_dwLayoutStyles(dwLayoutStyles),
       m_bPagination(false),
-      m_bVertical(false),
-      m_bSingleLine(false),
-      m_bCharCode(false),
       m_pFont(nullptr),
       m_iFontHeight(240),
       m_iFontSize(240),
       m_iTabWidth(720000),
-      m_PositionedTabs(),
-      m_bOrphanLine(false),
       m_wDefChar(0xFEFF),
       m_iDefChar(0),
       m_wLineBreakChar(L'\n'),
       m_iHorizontalScale(100),
       m_iVerticalScale(100),
-      m_iLineRotation(0),
-      m_iCharRotation(0),
-      m_iRotation(0),
       m_iCharSpace(0),
-      m_bWordSpace(false),
-      m_iWordSpace(0),
-      m_bRTL(false),
-      m_iAlignment(FX_RTFLINEALIGNMENT_Left),
+      m_iAlignment(CFX_RTFLineAlignment::Left),
       m_pUserData(nullptr),
       m_eCharType(FX_CHARTYPE_Unknown),
       m_dwIdentity(0),
@@ -52,13 +56,13 @@
       m_iReady(0),
       m_iTolerance(0) {
   m_pCurLine = &m_RTFLine1;
+
+  SetBreakStatus();
+  m_bPagination = (m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_Pagination) != 0;
 }
 
 CFX_RTFBreak::~CFX_RTFBreak() {
   Reset();
-  m_PositionedTabs.RemoveAll();
-  if (m_pUserData)
-    m_pUserData->Release();
 }
 
 void CFX_RTFBreak::SetLineBoundary(FX_FLOAT fLineStart, FX_FLOAT fLineEnd) {
@@ -78,443 +82,249 @@
   m_pCurLine->m_iStart = iLinePos;
 }
 
-void CFX_RTFBreak::SetLayoutStyles(uint32_t dwLayoutStyles) {
-  if (m_dwLayoutStyles == dwLayoutStyles)
-    return;
-
-  SetBreakStatus();
-  m_dwLayoutStyles = dwLayoutStyles;
-  m_bPagination = (m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_Pagination) != 0;
-  m_bVertical = (m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_VerticalChars) != 0;
-  m_bSingleLine = (m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_SingleLine) != 0;
-  m_bCharCode = (m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_MBCSCode) != 0;
-  m_iLineRotation = GetLineRotation(m_dwLayoutStyles);
-  m_iRotation = m_iLineRotation + m_iCharRotation;
-  m_iRotation %= 4;
-}
-
 void CFX_RTFBreak::SetFont(const CFX_RetainPtr<CFGAS_GEFont>& pFont) {
   if (!pFont || pFont == m_pFont)
     return;
 
   SetBreakStatus();
   m_pFont = pFont;
-  m_iDefChar = 0;
-  if (m_pFont) {
-    m_iFontHeight = m_iFontSize;
-    if (m_wDefChar != 0xFEFF) {
-      m_pFont->GetCharWidth(m_wDefChar, m_iDefChar, false);
-      m_iDefChar *= m_iFontSize;
-    }
-  }
+  FontChanged();
 }
 
 void CFX_RTFBreak::SetFontSize(FX_FLOAT fFontSize) {
   int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
-  if (m_iFontSize == iFontSize) {
+  if (m_iFontSize == iFontSize)
     return;
-  }
+
   SetBreakStatus();
   m_iFontSize = iFontSize;
-  m_iDefChar = 0;
-  if (m_pFont) {
-    m_iFontHeight = m_iFontSize;
-    if (m_wDefChar != 0xFEFF) {
-      m_pFont->GetCharWidth(m_wDefChar, m_iDefChar, false);
-      m_iDefChar *= m_iFontSize;
-    }
-  }
+  FontChanged();
 }
+
+void CFX_RTFBreak::FontChanged() {
+  m_iDefChar = 0;
+  if (!m_pFont)
+    return;
+
+  m_iFontHeight = m_iFontSize;
+  if (m_wDefChar == 0xFEFF)
+    return;
+
+  m_pFont->GetCharWidth(m_wDefChar, m_iDefChar, false);
+  m_iDefChar *= m_iFontSize;
+}
+
 void CFX_RTFBreak::SetTabWidth(FX_FLOAT fTabWidth) {
   m_iTabWidth = FXSYS_round(fTabWidth * 20000.0f);
 }
+
 void CFX_RTFBreak::AddPositionedTab(FX_FLOAT fTabPos) {
-  int32_t iLineEnd = m_iBoundaryEnd;
-  int32_t iTabPos = FXSYS_round(fTabPos * 20000.0f) + m_iBoundaryStart;
-  if (iTabPos > iLineEnd) {
-    iTabPos = iLineEnd;
-  }
-  if (m_PositionedTabs.Find(iTabPos, 0) > -1) {
+  int32_t iTabPos = std::min(FXSYS_round(fTabPos * 20000.0f) + m_iBoundaryStart,
+                             m_iBoundaryEnd);
+  auto it = std::lower_bound(m_PositionedTabs.begin(), m_PositionedTabs.end(),
+                             iTabPos);
+  if (it != m_PositionedTabs.end() && *it == iTabPos)
     return;
-  }
-  int32_t iCount = m_PositionedTabs.GetSize();
-  int32_t iFind = 0;
-  for (; iFind < iCount; iFind++) {
-    if (m_PositionedTabs[iFind] > iTabPos) {
-      break;
-    }
-  }
-  m_PositionedTabs.InsertAt(iFind, iTabPos);
-  if (m_dwPolicies & FX_RTFBREAKPOLICY_OrphanPositionedTab) {
-    m_bOrphanLine = GetLastPositionedTab() >= iLineEnd;
-  } else {
-    m_bOrphanLine = false;
-  }
+  m_PositionedTabs.insert(it, iTabPos);
 }
-void CFX_RTFBreak::SetPositionedTabs(const std::vector<FX_FLOAT>& tabs) {
-  m_PositionedTabs.RemoveAll();
-  int32_t iCount = pdfium::CollectionSize<int32_t>(tabs);
-  m_PositionedTabs.SetSize(iCount);
-  int32_t iLineEnd = m_iBoundaryEnd;
-  int32_t iTabPos;
-  for (int32_t i = 0; i < iCount; i++) {
-    iTabPos = FXSYS_round(tabs[i] * 20000.0f) + m_iBoundaryStart;
-    if (iTabPos > iLineEnd) {
-      iTabPos = iLineEnd;
-    }
-    m_PositionedTabs[i] = iTabPos;
-  }
-  if (m_dwPolicies & FX_RTFBREAKPOLICY_OrphanPositionedTab) {
-    m_bOrphanLine = GetLastPositionedTab() >= iLineEnd;
-  } else {
-    m_bOrphanLine = false;
-  }
-}
-void CFX_RTFBreak::ClearPositionedTabs() {
-  m_PositionedTabs.RemoveAll();
-  m_bOrphanLine = false;
-}
-void CFX_RTFBreak::SetDefaultChar(FX_WCHAR wch) {
-  m_wDefChar = wch;
-  m_iDefChar = 0;
-  if (m_wDefChar != 0xFEFF && m_pFont) {
-    m_pFont->GetCharWidth(m_wDefChar, m_iDefChar, false);
-    if (m_iDefChar < 0) {
-      m_iDefChar = 0;
-    } else {
-      m_iDefChar *= m_iFontSize;
-    }
-  }
-}
-void CFX_RTFBreak::SetLineBreakChar(FX_WCHAR wch) {
-  if (wch != L'\r' && wch != L'\n') {
-    return;
-  }
-  m_wLineBreakChar = wch;
-}
+
 void CFX_RTFBreak::SetLineBreakTolerance(FX_FLOAT fTolerance) {
   m_iTolerance = FXSYS_round(fTolerance * 20000.0f);
 }
+
 void CFX_RTFBreak::SetHorizontalScale(int32_t iScale) {
-  if (iScale < 0) {
+  if (iScale < 0)
     iScale = 0;
-  }
-  if (m_iHorizontalScale == iScale) {
+  if (m_iHorizontalScale == iScale)
     return;
-  }
+
   SetBreakStatus();
   m_iHorizontalScale = iScale;
 }
+
 void CFX_RTFBreak::SetVerticalScale(int32_t iScale) {
-  if (iScale < 0) {
+  if (iScale < 0)
     iScale = 0;
-  }
-  if (m_iVerticalScale == iScale) {
+  if (m_iVerticalScale == iScale)
     return;
-  }
+
   SetBreakStatus();
   m_iVerticalScale = iScale;
 }
-void CFX_RTFBreak::SetCharRotation(int32_t iCharRotation) {
-  if (iCharRotation < 0) {
-    iCharRotation += (-iCharRotation / 4 + 1) * 4;
-  } else if (iCharRotation > 3) {
-    iCharRotation -= (iCharRotation / 4) * 4;
-  }
-  if (m_iCharRotation == iCharRotation) {
-    return;
-  }
-  SetBreakStatus();
-  m_iCharRotation = iCharRotation;
-  m_iRotation = m_iLineRotation + m_iCharRotation;
-  m_iRotation %= 4;
-}
+
 void CFX_RTFBreak::SetCharSpace(FX_FLOAT fCharSpace) {
   m_iCharSpace = FXSYS_round(fCharSpace * 20000.0f);
 }
-void CFX_RTFBreak::SetWordSpace(bool bDefault, FX_FLOAT fWordSpace) {
-  m_bWordSpace = !bDefault;
-  m_iWordSpace = FXSYS_round(fWordSpace * 20000.0f);
-}
-void CFX_RTFBreak::SetReadingOrder(bool bRTL) {
-  m_bRTL = bRTL;
-}
-void CFX_RTFBreak::SetAlignment(int32_t iAlignment) {
-  ASSERT(iAlignment >= FX_RTFLINEALIGNMENT_Left &&
-         iAlignment <= FX_RTFLINEALIGNMENT_Distributed);
-  m_iAlignment = iAlignment;
-}
-void CFX_RTFBreak::SetUserData(IFX_Retainable* pUserData) {
-  if (m_pUserData == pUserData) {
+
+void CFX_RTFBreak::SetUserData(const CFX_RetainPtr<CFX_Retainable>& pUserData) {
+  if (m_pUserData == pUserData)
     return;
-  }
+
   SetBreakStatus();
-  if (m_pUserData) {
-    m_pUserData->Release();
-  }
   m_pUserData = pUserData;
-  if (m_pUserData) {
-    m_pUserData->Retain();
-  }
 }
-static const int32_t gs_FX_RTFLineRotations[8] = {0, 3, 1, 0, 2, 1, 3, 2};
-int32_t CFX_RTFBreak::GetLineRotation(uint32_t dwStyles) const {
-  return gs_FX_RTFLineRotations[(dwStyles & 0x0E) >> 1];
-}
+
 void CFX_RTFBreak::SetBreakStatus() {
   m_dwIdentity++;
   int32_t iCount = m_pCurLine->CountChars();
-  if (iCount < 1) {
+  if (iCount < 1)
     return;
-  }
+
   CFX_RTFChar& tc = m_pCurLine->GetChar(iCount - 1);
-  if (tc.m_dwStatus == 0) {
-    tc.m_dwStatus = FX_RTFBREAK_PieceBreak;
-  }
+  if (tc.m_dwStatus == CFX_RTFBreakType::None)
+    tc.m_dwStatus = CFX_RTFBreakType::Piece;
 }
+
 CFX_RTFChar* CFX_RTFBreak::GetLastChar(int32_t index) const {
-  CFX_RTFCharArray& tca = m_pCurLine->m_LineChars;
-  int32_t iCount = tca.GetSize();
-  if (index < 0 || index >= iCount) {
+  std::vector<CFX_RTFChar>& tca = m_pCurLine->m_LineChars;
+  int32_t iCount = pdfium::CollectionSize<int32_t>(tca);
+  if (index < 0 || index >= iCount)
     return nullptr;
-  }
-  CFX_RTFChar* pTC;
+
   int32_t iStart = iCount - 1;
   while (iStart > -1) {
-    pTC = tca.GetDataPtr(iStart--);
+    CFX_RTFChar* pTC = &tca[iStart--];
     if (pTC->m_iCharWidth >= 0 ||
         pTC->GetCharType() != FX_CHARTYPE_Combination) {
-      if (--index < 0) {
+      if (--index < 0)
         return pTC;
-      }
     }
   }
   return nullptr;
 }
-CFX_RTFLine* CFX_RTFBreak::GetRTFLine(bool bReady) const {
-  if (bReady) {
-    if (m_iReady == 1) {
-      return (CFX_RTFLine*)&m_RTFLine1;
-    } else if (m_iReady == 2) {
-      return (CFX_RTFLine*)&m_RTFLine2;
-    } else {
-      return nullptr;
-    }
-  }
-  ASSERT(m_pCurLine);
-  return m_pCurLine;
+
+const CFX_RTFLine* CFX_RTFBreak::GetRTFLine() const {
+  if (m_iReady == 1)
+    return &m_RTFLine1;
+  if (m_iReady == 2)
+    return &m_RTFLine2;
+  return nullptr;
 }
-CFX_RTFPieceArray* CFX_RTFBreak::GetRTFPieces(bool bReady) const {
-  CFX_RTFLine* pRTFLine = GetRTFLine(bReady);
+
+const CFX_RTFPieceArray* CFX_RTFBreak::GetRTFPieces() const {
+  const CFX_RTFLine* pRTFLine = GetRTFLine();
   return pRTFLine ? &pRTFLine->m_LinePieces : nullptr;
 }
+
 inline FX_CHARTYPE CFX_RTFBreak::GetUnifiedCharType(
     FX_CHARTYPE chartype) const {
   return chartype >= FX_CHARTYPE_ArabicAlef ? FX_CHARTYPE_Arabic : chartype;
 }
-int32_t CFX_RTFBreak::GetLastPositionedTab() const {
-  int32_t iCount = m_PositionedTabs.GetSize();
-  if (iCount < 1) {
-    return m_iBoundaryStart;
-  }
-  return m_PositionedTabs[iCount - 1];
-}
-bool CFX_RTFBreak::GetPositionedTab(int32_t& iTabPos) const {
-  int32_t iCount = m_PositionedTabs.GetSize();
-  for (int32_t i = 0; i < iCount; i++) {
-    if (m_PositionedTabs[i] > iTabPos) {
-      iTabPos = m_PositionedTabs[i];
-      return true;
-    }
-  }
-  return false;
-}
-typedef uint32_t (CFX_RTFBreak::*FX_RTFBreak_LPFAppendChar)(
-    CFX_RTFChar* pCurChar,
-    int32_t iRotation);
-static const FX_RTFBreak_LPFAppendChar g_FX_RTFBreak_lpfAppendChar[16] = {
-    &CFX_RTFBreak::AppendChar_Others,      &CFX_RTFBreak::AppendChar_Tab,
-    &CFX_RTFBreak::AppendChar_Others,      &CFX_RTFBreak::AppendChar_Control,
-    &CFX_RTFBreak::AppendChar_Combination, &CFX_RTFBreak::AppendChar_Others,
-    &CFX_RTFBreak::AppendChar_Others,      &CFX_RTFBreak::AppendChar_Arabic,
-    &CFX_RTFBreak::AppendChar_Arabic,      &CFX_RTFBreak::AppendChar_Arabic,
-    &CFX_RTFBreak::AppendChar_Arabic,      &CFX_RTFBreak::AppendChar_Arabic,
-    &CFX_RTFBreak::AppendChar_Arabic,      &CFX_RTFBreak::AppendChar_Others,
-    &CFX_RTFBreak::AppendChar_Others,      &CFX_RTFBreak::AppendChar_Others,
-};
-uint32_t CFX_RTFBreak::AppendChar(FX_WCHAR wch) {
-  ASSERT(m_pFont && m_pCurLine);
-  if (m_bCharCode)
-    return AppendChar_CharCode(wch);
 
-  uint32_t dwProps = kTextLayoutCodeProperties[(uint16_t)wch];
+int32_t CFX_RTFBreak::GetLastPositionedTab() const {
+  return m_PositionedTabs.empty() ? m_iBoundaryStart : m_PositionedTabs.back();
+}
+
+bool CFX_RTFBreak::GetPositionedTab(int32_t* iTabPos) const {
+  auto it = std::upper_bound(m_PositionedTabs.begin(), m_PositionedTabs.end(),
+                             *iTabPos);
+  if (it == m_PositionedTabs.end())
+    return false;
+
+  *iTabPos = *it;
+  return true;
+}
+
+CFX_RTFBreakType CFX_RTFBreak::AppendChar(FX_WCHAR wch) {
+  ASSERT(m_pFont && m_pCurLine);
+
+  uint32_t dwProps = kTextLayoutCodeProperties[static_cast<uint16_t>(wch)];
   FX_CHARTYPE chartype = GetCharTypeFromProp(dwProps);
-  CFX_RTFCharArray& tca = m_pCurLine->m_LineChars;
-  CFX_RTFChar* pCurChar = tca.AddSpace();
-  pCurChar->m_dwStatus = 0;
+  m_pCurLine->m_LineChars.emplace_back();
+
+  CFX_RTFChar* pCurChar = &m_pCurLine->m_LineChars.back();
+  pCurChar->m_dwStatus = CFX_RTFBreakType::None;
   pCurChar->m_wCharCode = wch;
   pCurChar->m_dwCharProps = dwProps;
-  pCurChar->m_dwCharStyles = 0;
-  pCurChar->m_dwLayoutStyles = 0;
   pCurChar->m_iFontSize = m_iFontSize;
   pCurChar->m_iFontHeight = m_iFontHeight;
   pCurChar->m_iHorizontalScale = m_iHorizontalScale;
-  pCurChar->m_iVertialScale = m_iVerticalScale;
-  pCurChar->m_nRotation = m_iCharRotation;
+  pCurChar->m_iVerticalScale = m_iVerticalScale;
   pCurChar->m_iCharWidth = 0;
   pCurChar->m_dwIdentity = m_dwIdentity;
-  if (m_pUserData) {
-    m_pUserData->Retain();
-  }
   pCurChar->m_pUserData = m_pUserData;
-  uint32_t dwRet1 = FX_RTFBREAK_None;
+
+  CFX_RTFBreakType dwRet1 = CFX_RTFBreakType::None;
   if (chartype != FX_CHARTYPE_Combination &&
-      GetUnifiedCharType(m_eCharType) != GetUnifiedCharType(chartype)) {
-    if (!m_bSingleLine && !m_bOrphanLine &&
-        m_eCharType != FX_CHARTYPE_Unknown &&
-        m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance) {
-      if (m_eCharType != FX_CHARTYPE_Space || chartype != FX_CHARTYPE_Control) {
-        dwRet1 = EndBreak(FX_RTFBREAK_LineBreak);
-        int32_t iCount = m_pCurLine->CountChars();
-        if (iCount > 0) {
-          pCurChar = m_pCurLine->m_LineChars.GetDataPtr(iCount - 1);
-        }
-      }
-    }
+      GetUnifiedCharType(m_eCharType) != GetUnifiedCharType(chartype) &&
+      m_eCharType != FX_CHARTYPE_Unknown &&
+      m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance &&
+      (m_eCharType != FX_CHARTYPE_Space || chartype != FX_CHARTYPE_Control)) {
+    dwRet1 = EndBreak(CFX_RTFBreakType::Line);
+    int32_t iCount = m_pCurLine->CountChars();
+    if (iCount > 0)
+      pCurChar = &m_pCurLine->m_LineChars[iCount - 1];
   }
-  int32_t iRotation = m_iRotation;
-  if (m_bVertical && (dwProps & 0x8000) != 0) {
-    iRotation = (iRotation + 1) % 4;
-  }
-  uint32_t dwRet2 =
+
+  CFX_RTFBreakType dwRet2 =
       (this->*g_FX_RTFBreak_lpfAppendChar[chartype >> FX_CHARTYPEBITS])(
-          pCurChar, iRotation);
+          pCurChar);
   m_eCharType = chartype;
   return std::max(dwRet1, dwRet2);
 }
 
-uint32_t CFX_RTFBreak::AppendChar_CharCode(FX_WCHAR wch) {
-  ASSERT(m_pFont && m_pCurLine);
-  ASSERT(m_bCharCode);
-  m_pCurLine->m_iMBCSChars++;
-  CFX_RTFCharArray& tca = m_pCurLine->m_LineChars;
-  CFX_RTFChar* pCurChar = tca.AddSpace();
-  pCurChar->m_dwStatus = 0;
-  pCurChar->m_wCharCode = wch;
-  pCurChar->m_dwCharProps = 0;
-  pCurChar->m_dwCharStyles = 0;
-  pCurChar->m_dwLayoutStyles = m_dwLayoutStyles;
-  pCurChar->m_iFontSize = m_iFontSize;
-  pCurChar->m_iFontHeight = m_iFontHeight;
-  pCurChar->m_iHorizontalScale = m_iHorizontalScale;
-  pCurChar->m_iVertialScale = m_iVerticalScale;
-  pCurChar->m_nRotation = m_iCharRotation;
-  pCurChar->m_iCharWidth = 0;
-  pCurChar->m_dwIdentity = m_dwIdentity;
-  if (m_pUserData)
-    m_pUserData->Retain();
-
-  pCurChar->m_pUserData = m_pUserData;
+CFX_RTFBreakType CFX_RTFBreak::AppendChar_Combination(CFX_RTFChar* pCurChar) {
   int32_t iCharWidth = 0;
-  if (m_bVertical != FX_IsOdd(m_iRotation)) {
-    iCharWidth = 1000;
-  } else {
-    if (!m_pFont->GetCharWidth(wch, iCharWidth, true)) {
-      iCharWidth = m_iDefChar;
-    }
-  }
-  iCharWidth *= m_iFontSize;
-  iCharWidth = iCharWidth * m_iHorizontalScale / 100;
-  iCharWidth += m_iCharSpace;
-  pCurChar->m_iCharWidth = iCharWidth;
-  m_pCurLine->m_iWidth += iCharWidth;
-  m_eCharType = FX_CHARTYPE_Unknown;
-  if (!m_bSingleLine &&
-      m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance) {
-    return EndBreak(FX_RTFBREAK_LineBreak);
-  }
-  return FX_RTFBREAK_None;
-}
+  if (!m_pFont->GetCharWidth(pCurChar->m_wCharCode, iCharWidth, false))
+    iCharWidth = 0;
 
-uint32_t CFX_RTFBreak::AppendChar_Combination(CFX_RTFChar* pCurChar,
-                                              int32_t iRotation) {
-  int32_t iCharWidth = 0;
-  if (m_bVertical != FX_IsOdd(iRotation)) {
-    iCharWidth = 1000;
-  } else {
-    if (!m_pFont->GetCharWidth(pCurChar->m_wCharCode, iCharWidth,
-                               m_bCharCode)) {
-      iCharWidth = 0;
-    }
-  }
   iCharWidth *= m_iFontSize;
   iCharWidth = iCharWidth * m_iHorizontalScale / 100;
   CFX_RTFChar* pLastChar = GetLastChar(0);
-  if (pLastChar && pLastChar->GetCharType() > FX_CHARTYPE_Combination) {
+  if (pLastChar && pLastChar->GetCharType() > FX_CHARTYPE_Combination)
     iCharWidth = -iCharWidth;
-  } else {
+  else
     m_eCharType = FX_CHARTYPE_Combination;
-  }
+
   pCurChar->m_iCharWidth = iCharWidth;
-  if (iCharWidth > 0) {
+  if (iCharWidth > 0)
     m_pCurLine->m_iWidth += iCharWidth;
-  }
-  return FX_RTFBREAK_None;
+
+  return CFX_RTFBreakType::None;
 }
-uint32_t CFX_RTFBreak::AppendChar_Tab(CFX_RTFChar* pCurChar,
-                                      int32_t iRotation) {
-  if (m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_ExpandTab) {
-    bool bBreak = false;
-    if ((m_dwPolicies & FX_RTFBREAKPOLICY_TabBreak) != 0) {
-      bBreak = (m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance);
-    }
-    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;
-    }
-    pCurChar->m_iCharWidth = iCharWidth;
-    iLineWidth += iCharWidth;
-    if (!m_bSingleLine && !m_bOrphanLine && bBreak) {
-      return EndBreak(FX_RTFBREAK_LineBreak);
-    }
-  }
-  return FX_RTFBREAK_None;
+
+CFX_RTFBreakType CFX_RTFBreak::AppendChar_Tab(CFX_RTFChar* pCurChar) {
+  if (!(m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_ExpandTab))
+    return CFX_RTFBreakType::None;
+
+  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;
+
+  pCurChar->m_iCharWidth = iCharWidth;
+  iLineWidth += iCharWidth;
+  return CFX_RTFBreakType::None;
 }
-uint32_t CFX_RTFBreak::AppendChar_Control(CFX_RTFChar* pCurChar,
-                                          int32_t iRotation) {
-  uint32_t dwRet2 = FX_RTFBREAK_None;
-  if (!m_bSingleLine) {
-    switch (pCurChar->m_wCharCode) {
-      case L'\v':
-      case 0x2028:
-        dwRet2 = FX_RTFBREAK_LineBreak;
-        break;
-      case L'\f':
-        dwRet2 = FX_RTFBREAK_PageBreak;
-        break;
-      case 0x2029:
-        dwRet2 = FX_RTFBREAK_ParagraphBreak;
-        break;
-      default:
-        if (pCurChar->m_wCharCode == m_wLineBreakChar) {
-          dwRet2 = FX_RTFBREAK_ParagraphBreak;
-        }
-        break;
-    }
-    if (dwRet2 != FX_RTFBREAK_None) {
-      dwRet2 = EndBreak(dwRet2);
-    }
+
+CFX_RTFBreakType CFX_RTFBreak::AppendChar_Control(CFX_RTFChar* pCurChar) {
+  CFX_RTFBreakType dwRet2 = CFX_RTFBreakType::None;
+  switch (pCurChar->m_wCharCode) {
+    case L'\v':
+    case 0x2028:
+      dwRet2 = CFX_RTFBreakType::Line;
+      break;
+    case L'\f':
+      dwRet2 = CFX_RTFBreakType::Page;
+      break;
+    case 0x2029:
+      dwRet2 = CFX_RTFBreakType::Paragraph;
+      break;
+    default:
+      if (pCurChar->m_wCharCode == m_wLineBreakChar)
+        dwRet2 = CFX_RTFBreakType::Paragraph;
+      break;
   }
+  if (dwRet2 != CFX_RTFBreakType::None)
+    dwRet2 = EndBreak(dwRet2);
+
   return dwRet2;
 }
 
-uint32_t CFX_RTFBreak::AppendChar_Arabic(CFX_RTFChar* pCurChar,
-                                         int32_t iRotation) {
+CFX_RTFBreakType CFX_RTFBreak::AppendChar_Arabic(CFX_RTFChar* pCurChar) {
   CFX_RTFChar* pLastChar = nullptr;
-  int32_t& iLineWidth = m_pCurLine->m_iWidth;
   int32_t iCharWidth = 0;
   FX_WCHAR wForm;
   bool bAlef = false;
@@ -522,146 +332,116 @@
       m_eCharType <= FX_CHARTYPE_ArabicDistortion) {
     pLastChar = GetLastChar(1);
     if (pLastChar) {
-      iLineWidth -= pLastChar->m_iCharWidth;
+      m_pCurLine->m_iWidth -= pLastChar->m_iCharWidth;
       CFX_RTFChar* pPrevChar = GetLastChar(2);
       wForm = pdfium::arabic::GetFormChar(pLastChar, pPrevChar, pCurChar);
       bAlef = (wForm == 0xFEFF &&
                pLastChar->GetCharType() == FX_CHARTYPE_ArabicAlef);
-      int32_t iLastRotation = pLastChar->m_nRotation + m_iLineRotation;
-      if (m_bVertical && (pLastChar->m_dwCharProps & 0x8000) != 0) {
-        iLastRotation++;
+      if (!m_pFont->GetCharWidth(wForm, iCharWidth, false) &&
+          !m_pFont->GetCharWidth(pLastChar->m_wCharCode, iCharWidth, false)) {
+        iCharWidth = m_iDefChar;
       }
-      if (m_bVertical != FX_IsOdd(iLastRotation)) {
-        iCharWidth = 1000;
-      } else {
-        if (!m_pFont->GetCharWidth(wForm, iCharWidth, m_bCharCode)) {
-          if (!m_pFont->GetCharWidth(pLastChar->m_wCharCode, iCharWidth,
-                                     m_bCharCode)) {
-            iCharWidth = m_iDefChar;
-          }
-        }
-      }
+
       iCharWidth *= m_iFontSize;
       iCharWidth = iCharWidth * m_iHorizontalScale / 100;
       pLastChar->m_iCharWidth = iCharWidth;
-      iLineWidth += iCharWidth;
+      m_pCurLine->m_iWidth += iCharWidth;
       iCharWidth = 0;
     }
   }
+
   wForm = pdfium::arabic::GetFormChar(pCurChar, bAlef ? nullptr : pLastChar,
                                       nullptr);
-  if (m_bVertical != FX_IsOdd(iRotation)) {
-    iCharWidth = 1000;
-  } else if (!m_pFont->GetCharWidth(wForm, iCharWidth, m_bCharCode) &&
-             !m_pFont->GetCharWidth(pCurChar->m_wCharCode, iCharWidth,
-                                    m_bCharCode)) {
+  if (!m_pFont->GetCharWidth(wForm, iCharWidth, false) &&
+      !m_pFont->GetCharWidth(pCurChar->m_wCharCode, iCharWidth, false)) {
     iCharWidth = m_iDefChar;
   }
 
   iCharWidth *= m_iFontSize;
   iCharWidth = iCharWidth * m_iHorizontalScale / 100;
   pCurChar->m_iCharWidth = iCharWidth;
-  iLineWidth += iCharWidth;
+  m_pCurLine->m_iWidth += iCharWidth;
   m_pCurLine->m_iArabicChars++;
-  if (!m_bSingleLine && !m_bOrphanLine &&
-      m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance) {
-    return EndBreak(FX_RTFBREAK_LineBreak);
-  }
-  return FX_RTFBREAK_None;
+
+  if (m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance)
+    return EndBreak(CFX_RTFBreakType::Line);
+  return CFX_RTFBreakType::None;
 }
 
-uint32_t CFX_RTFBreak::AppendChar_Others(CFX_RTFChar* pCurChar,
-                                         int32_t iRotation) {
+CFX_RTFBreakType CFX_RTFBreak::AppendChar_Others(CFX_RTFChar* pCurChar) {
   FX_CHARTYPE chartype = pCurChar->GetCharType();
-  FX_WCHAR wForm;
-  if (chartype == FX_CHARTYPE_Numeric) {
-    if (m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_ArabicNumber)
-      wForm = pCurChar->m_wCharCode + 0x0630;
-    else
-      wForm = pCurChar->m_wCharCode;
-  } else if (m_bRTL || m_bVertical) {
-    wForm = FX_GetMirrorChar(pCurChar->m_wCharCode, pCurChar->m_dwCharProps,
-                             m_bRTL, m_bVertical);
-  } else {
-    wForm = pCurChar->m_wCharCode;
-  }
+  FX_WCHAR wForm = pCurChar->m_wCharCode;
   int32_t iCharWidth = 0;
-  if (m_bVertical == FX_IsOdd(iRotation)) {
-    if (!m_pFont->GetCharWidth(wForm, iCharWidth, m_bCharCode))
-      iCharWidth = m_iDefChar;
-  } else {
-    iCharWidth = 1000;
-  }
+  if (!m_pFont->GetCharWidth(wForm, iCharWidth, false))
+    iCharWidth = m_iDefChar;
+
   iCharWidth *= m_iFontSize;
   iCharWidth *= m_iHorizontalScale / 100;
   iCharWidth += m_iCharSpace;
-  if (chartype == FX_CHARTYPE_Space && m_bWordSpace)
-    iCharWidth += m_iWordSpace;
 
   pCurChar->m_iCharWidth = iCharWidth;
   m_pCurLine->m_iWidth += iCharWidth;
-  bool bBreak = (chartype != FX_CHARTYPE_Space ||
-                 (m_dwPolicies & FX_RTFBREAKPOLICY_SpaceBreak) != 0);
-  if (!m_bSingleLine && !m_bOrphanLine && bBreak &&
+  if (chartype != FX_CHARTYPE_Space &&
       m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance) {
-    return EndBreak(FX_RTFBREAK_LineBreak);
+    return EndBreak(CFX_RTFBreakType::Line);
   }
-  return FX_RTFBREAK_None;
+  return CFX_RTFBreakType::None;
 }
 
-uint32_t CFX_RTFBreak::EndBreak(uint32_t dwStatus) {
-  ASSERT(dwStatus >= FX_RTFBREAK_PieceBreak &&
-         dwStatus <= FX_RTFBREAK_PageBreak);
+CFX_RTFBreakType CFX_RTFBreak::EndBreak(CFX_RTFBreakType dwStatus) {
+  ASSERT(dwStatus != CFX_RTFBreakType::None);
+
   m_dwIdentity++;
-  CFX_RTFPieceArray* pCurPieces = &m_pCurLine->m_LinePieces;
+  const CFX_RTFPieceArray* pCurPieces = &m_pCurLine->m_LinePieces;
   int32_t iCount = pCurPieces->GetSize();
   if (iCount > 0) {
     CFX_RTFPiece* pLastPiece = pCurPieces->GetPtrAt(--iCount);
-    if (dwStatus > FX_RTFBREAK_PieceBreak)
+    if (dwStatus != CFX_RTFBreakType::Piece)
       pLastPiece->m_dwStatus = dwStatus;
     else
       dwStatus = pLastPiece->m_dwStatus;
     return dwStatus;
   }
 
-  CFX_RTFLine* pLastLine = GetRTFLine(true);
+  const CFX_RTFLine* pLastLine = GetRTFLine();
   if (pLastLine) {
     pCurPieces = &pLastLine->m_LinePieces;
     iCount = pCurPieces->GetSize();
     if (iCount-- > 0) {
       CFX_RTFPiece* pLastPiece = pCurPieces->GetPtrAt(iCount);
-      if (dwStatus > FX_RTFBREAK_PieceBreak)
+      if (dwStatus != CFX_RTFBreakType::Piece)
         pLastPiece->m_dwStatus = dwStatus;
       else
         dwStatus = pLastPiece->m_dwStatus;
       return dwStatus;
     }
-    return FX_RTFBREAK_None;
+    return CFX_RTFBreakType::None;
   }
+
   iCount = m_pCurLine->CountChars();
   if (iCount < 1)
-    return FX_RTFBREAK_None;
+    return CFX_RTFBreakType::None;
 
   CFX_RTFChar& tc = m_pCurLine->GetChar(iCount - 1);
   tc.m_dwStatus = dwStatus;
-  if (dwStatus <= FX_RTFBREAK_PieceBreak)
+  if (dwStatus == CFX_RTFBreakType::Piece)
     return dwStatus;
 
-  m_iReady = (m_pCurLine == &m_RTFLine1) ? 1 : 2;
+  m_iReady = m_pCurLine == &m_RTFLine1 ? 1 : 2;
   CFX_RTFLine* pNextLine =
-      (m_pCurLine == &m_RTFLine1) ? &m_RTFLine2 : &m_RTFLine1;
-  bool bAllChars = (m_iAlignment > FX_RTFLINEALIGNMENT_Right);
-  CFX_TPOArray tpos(100);
-  if (!EndBreak_SplitLine(pNextLine, bAllChars, dwStatus)) {
-    if (!m_bCharCode)
-      EndBreak_BidiLine(tpos, dwStatus);
+      m_pCurLine == &m_RTFLine1 ? &m_RTFLine2 : &m_RTFLine1;
+  bool bAllChars = m_iAlignment == CFX_RTFLineAlignment::Justified ||
+                   m_iAlignment == CFX_RTFLineAlignment::Distributed;
 
-    if (!m_bPagination && m_iAlignment > FX_RTFLINEALIGNMENT_Left)
+  if (!EndBreak_SplitLine(pNextLine, bAllChars, dwStatus)) {
+    std::deque<FX_TPO> tpos;
+    EndBreak_BidiLine(&tpos, dwStatus);
+    if (!m_bPagination && m_iAlignment != CFX_RTFLineAlignment::Left)
       EndBreak_Alignment(tpos, bAllChars, dwStatus);
   }
-
   m_pCurLine = pNextLine;
   m_pCurLine->m_iStart = m_iBoundaryStart;
+
   CFX_RTFChar* pTC = GetLastChar(0);
   m_eCharType = pTC ? pTC->GetCharType() : FX_CHARTYPE_Unknown;
   return dwStatus;
@@ -669,25 +449,14 @@
 
 bool CFX_RTFBreak::EndBreak_SplitLine(CFX_RTFLine* pNextLine,
                                       bool bAllChars,
-                                      uint32_t dwStatus) {
+                                      CFX_RTFBreakType dwStatus) {
   bool bDone = false;
-  if (!m_bSingleLine && !m_bOrphanLine &&
-      m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance) {
-    CFX_RTFChar& tc = m_pCurLine->GetChar(m_pCurLine->CountChars() - 1);
+  if (m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance) {
+    const CFX_RTFChar& tc = m_pCurLine->GetChar(m_pCurLine->CountChars() - 1);
     switch (tc.GetCharType()) {
       case FX_CHARTYPE_Tab:
-        if ((m_dwPolicies & FX_RTFBREAKPOLICY_TabBreak) != 0) {
-          SplitTextLine(m_pCurLine, pNextLine, !m_bPagination && bAllChars);
-          bDone = true;
-        }
-        break;
       case FX_CHARTYPE_Control:
-        break;
       case FX_CHARTYPE_Space:
-        if ((m_dwPolicies & FX_RTFBREAKPOLICY_SpaceBreak) != 0) {
-          SplitTextLine(m_pCurLine, pNextLine, !m_bPagination && bAllChars);
-          bDone = true;
-        }
         break;
       default:
         SplitTextLine(m_pCurLine, pNextLine, !m_bPagination && bAllChars);
@@ -695,114 +464,115 @@
         break;
     }
   }
-  if (m_bPagination || m_pCurLine->m_iMBCSChars > 0) {
-    const CFX_RTFChar* pCurChars = m_pCurLine->m_LineChars.GetData();
-    const CFX_RTFChar* pTC;
-    CFX_RTFPieceArray* pCurPieces = &m_pCurLine->m_LinePieces;
-    CFX_RTFPiece tp;
-    tp.m_pChars = &m_pCurLine->m_LineChars;
-    bool bNew = true;
-    uint32_t dwIdentity = (uint32_t)-1;
-    int32_t iLast = m_pCurLine->CountChars() - 1, j = 0;
-    for (int32_t i = 0; i <= iLast;) {
-      pTC = pCurChars + i;
-      if (bNew) {
-        tp.m_iStartChar = i;
-        tp.m_iStartPos += tp.m_iWidth;
-        tp.m_iWidth = 0;
+
+  if (!m_bPagination && m_pCurLine->m_iMBCSChars <= 0) {
+    if (bAllChars && !bDone) {
+      int32_t endPos = m_pCurLine->GetLineEnd();
+      GetBreakPos(m_pCurLine->m_LineChars, endPos, bAllChars, true);
+    }
+    return false;
+  }
+
+  const CFX_RTFChar* pCurChars = m_pCurLine->m_LineChars.data();
+  const CFX_RTFChar* pTC;
+  CFX_RTFPieceArray* pCurPieces = &m_pCurLine->m_LinePieces;
+  CFX_RTFPiece tp;
+  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 j = 0;
+  for (int32_t i = 0; i <= iLast;) {
+    pTC = pCurChars + i;
+    if (bNew) {
+      tp.m_iStartChar = i;
+      tp.m_iStartPos += tp.m_iWidth;
+      tp.m_iWidth = 0;
+      tp.m_dwStatus = pTC->m_dwStatus;
+      tp.m_iFontSize = pTC->m_iFontSize;
+      tp.m_iFontHeight = pTC->m_iFontHeight;
+      tp.m_iHorizontalScale = pTC->m_iHorizontalScale;
+      tp.m_iVerticalScale = pTC->m_iVerticalScale;
+      dwIdentity = pTC->m_dwIdentity;
+      tp.m_dwIdentity = dwIdentity;
+      tp.m_pUserData = pTC->m_pUserData;
+      j = i;
+      bNew = false;
+    }
+
+    if (i == iLast || pTC->m_dwStatus != CFX_RTFBreakType::None ||
+        pTC->m_dwIdentity != dwIdentity) {
+      tp.m_iChars = i - j;
+      if (pTC->m_dwIdentity == dwIdentity) {
         tp.m_dwStatus = pTC->m_dwStatus;
-        tp.m_iFontSize = pTC->m_iFontSize;
-        tp.m_iFontHeight = pTC->m_iFontHeight;
-        tp.m_iHorizontalScale = pTC->m_iHorizontalScale;
-        tp.m_iVerticalScale = pTC->m_iVertialScale;
-        tp.m_dwLayoutStyles = pTC->m_dwLayoutStyles;
-        dwIdentity = pTC->m_dwIdentity;
-        tp.m_dwIdentity = dwIdentity;
-        tp.m_pUserData = pTC->m_pUserData;
-        j = i;
-        bNew = false;
-      }
-      if (i == iLast || pTC->m_dwStatus != FX_RTFBREAK_None ||
-          pTC->m_dwIdentity != dwIdentity) {
-        tp.m_iChars = i - j;
-        if (pTC->m_dwIdentity == dwIdentity) {
-          tp.m_dwStatus = pTC->m_dwStatus;
-          tp.m_iWidth += pTC->m_iCharWidth;
-          tp.m_iChars += 1;
-          i++;
-        }
-        pCurPieces->Add(tp);
-        bNew = true;
-      } else {
         tp.m_iWidth += pTC->m_iCharWidth;
+        tp.m_iChars += 1;
         i++;
       }
+      pCurPieces->Add(tp);
+      bNew = true;
+    } else {
+      tp.m_iWidth += pTC->m_iCharWidth;
+      i++;
     }
-    return true;
   }
-  if (bAllChars && !bDone) {
-    int32_t iEndPos = m_pCurLine->GetLineEnd();
-    GetBreakPos(m_pCurLine->m_LineChars, iEndPos, bAllChars, true);
-  }
-  return false;
+  return true;
 }
-void CFX_RTFBreak::EndBreak_BidiLine(CFX_TPOArray& tpos, uint32_t dwStatus) {
+
+void CFX_RTFBreak::EndBreak_BidiLine(std::deque<FX_TPO>* tpos,
+                                     CFX_RTFBreakType dwStatus) {
   FX_TPO tpo;
   CFX_RTFPiece tp;
   CFX_RTFChar* pTC;
-  int32_t i, j;
-  CFX_RTFCharArray& chars = m_pCurLine->m_LineChars;
+  int32_t i;
+  int32_t j;
+  std::vector<CFX_RTFChar>& chars = m_pCurLine->m_LineChars;
   int32_t iCount = m_pCurLine->CountChars();
-  bool bDone = (!m_bPagination && !m_bCharCode &&
-                (m_pCurLine->m_iArabicChars > 0 || m_bRTL));
-  if (bDone) {
+  if (!m_bPagination && m_pCurLine->m_iArabicChars > 0) {
     int32_t iBidiNum = 0;
     for (i = 0; i < iCount; i++) {
-      pTC = chars.GetDataPtr(i);
+      pTC = &chars[i];
       pTC->m_iBidiPos = i;
-      if (pTC->GetCharType() != FX_CHARTYPE_Control) {
+      if (pTC->GetCharType() != FX_CHARTYPE_Control)
         iBidiNum = i;
-      }
-      if (i == 0) {
+      if (i == 0)
         pTC->m_iBidiLevel = 1;
-      }
     }
-    FX_BidiLine(chars, iBidiNum + 1, m_bRTL ? 1 : 0);
+    FX_BidiLine(chars, iBidiNum + 1, 0);
   } else {
     for (i = 0; i < iCount; i++) {
-      pTC = chars.GetDataPtr(i);
+      pTC = &chars[i];
       pTC->m_iBidiLevel = 0;
       pTC->m_iBidiPos = 0;
       pTC->m_iBidiOrder = 0;
     }
   }
-  tp.m_dwStatus = FX_RTFBREAK_PieceBreak;
+
+  tp.m_dwStatus = CFX_RTFBreakType::Piece;
   tp.m_iStartPos = m_pCurLine->m_iStart;
   tp.m_pChars = &chars;
   CFX_RTFPieceArray* pCurPieces = &m_pCurLine->m_LinePieces;
-  int32_t iBidiLevel = -1, iCharWidth;
-  uint32_t dwIdentity = (uint32_t)-1;
-  i = j = 0;
+  int32_t iBidiLevel = -1;
+  int32_t iCharWidth;
+  uint32_t dwIdentity = static_cast<uint32_t>(-1);
+  i = 0;
+  j = 0;
   while (i < iCount) {
-    pTC = chars.GetDataPtr(i);
+    pTC = &chars[i];
     if (iBidiLevel < 0) {
       iBidiLevel = pTC->m_iBidiLevel;
       iCharWidth = pTC->m_iCharWidth;
-      if (iCharWidth < 1) {
-        tp.m_iWidth = 0;
-      } else {
-        tp.m_iWidth = iCharWidth;
-      }
+      tp.m_iWidth = iCharWidth < 1 ? 0 : iCharWidth;
       tp.m_iBidiLevel = iBidiLevel;
       tp.m_iBidiPos = pTC->m_iBidiOrder;
       tp.m_iFontSize = pTC->m_iFontSize;
       tp.m_iFontHeight = pTC->m_iFontHeight;
       tp.m_iHorizontalScale = pTC->m_iHorizontalScale;
-      tp.m_iVerticalScale = pTC->m_iVertialScale;
+      tp.m_iVerticalScale = pTC->m_iVerticalScale;
       dwIdentity = pTC->m_dwIdentity;
       tp.m_dwIdentity = dwIdentity;
       tp.m_pUserData = pTC->m_pUserData;
-      tp.m_dwStatus = FX_RTFBREAK_PieceBreak;
+      tp.m_dwStatus = CFX_RTFBreakType::Piece;
       i++;
     } else if (iBidiLevel != pTC->m_iBidiLevel ||
                pTC->m_dwIdentity != dwIdentity) {
@@ -812,118 +582,113 @@
       tp.m_iStartChar = i;
       tpo.index = j++;
       tpo.pos = tp.m_iBidiPos;
-      tpos.Add(tpo);
+      tpos->push_back(tpo);
       iBidiLevel = -1;
     } else {
       iCharWidth = pTC->m_iCharWidth;
-      if (iCharWidth > 0) {
+      if (iCharWidth > 0)
         tp.m_iWidth += iCharWidth;
-      }
       i++;
     }
   }
+
   if (i > tp.m_iStartChar) {
     tp.m_dwStatus = dwStatus;
     tp.m_iChars = i - tp.m_iStartChar;
     pCurPieces->Add(tp);
     tpo.index = j;
     tpo.pos = tp.m_iBidiPos;
-    tpos.Add(tpo);
+    tpos->push_back(tpo);
   }
-  if (!m_bCharCode) {
-    j = tpos.GetSize() - 1;
-    FX_TEXTLAYOUT_PieceSort(tpos, 0, j);
-    int32_t iStartPos = m_pCurLine->m_iStart;
-    for (i = 0; i <= j; i++) {
-      tpo = tpos.GetAt(i);
-      CFX_RTFPiece& ttp = pCurPieces->GetAt(tpo.index);
-      ttp.m_iStartPos = iStartPos;
-      iStartPos += ttp.m_iWidth;
-    }
+
+  std::sort(tpos->begin(), tpos->end());
+  int32_t iStartPos = m_pCurLine->m_iStart;
+  for (const auto& it : *tpos) {
+    CFX_RTFPiece& ttp = pCurPieces->GetAt(it.index);
+    ttp.m_iStartPos = iStartPos;
+    iStartPos += ttp.m_iWidth;
   }
 }
-void CFX_RTFBreak::EndBreak_Alignment(CFX_TPOArray& tpos,
+
+void CFX_RTFBreak::EndBreak_Alignment(const std::deque<FX_TPO>& tpos,
                                       bool bAllChars,
-                                      uint32_t dwStatus) {
+                                      CFX_RTFBreakType dwStatus) {
   CFX_RTFPieceArray* pCurPieces = &m_pCurLine->m_LinePieces;
-  int32_t iNetWidth = m_pCurLine->m_iWidth, iGapChars = 0, iCharWidth;
+  int32_t iNetWidth = m_pCurLine->m_iWidth;
+  int32_t iGapChars = 0;
+  int32_t iCharWidth;
   int32_t iCount = pCurPieces->GetSize();
   bool bFind = false;
   uint32_t dwCharType;
-  int32_t i, j;
+  int32_t i;
+  int32_t j;
   FX_TPO tpo;
   for (i = iCount - 1; i > -1; i--) {
-    tpo = tpos.GetAt(i);
+    tpo = tpos[i];
     CFX_RTFPiece& ttp = pCurPieces->GetAt(tpo.index);
-    if (!bFind) {
+    if (!bFind)
       iNetWidth = ttp.GetEndPos();
-    }
+
     bool bArabic = FX_IsOdd(ttp.m_iBidiLevel);
     j = bArabic ? 0 : ttp.m_iChars - 1;
     while (j > -1 && j < ttp.m_iChars) {
       const CFX_RTFChar& tc = ttp.GetChar(j);
-      if (tc.m_nBreakType == FX_LBT_DIRECT_BRK) {
+      if (tc.m_nBreakType == FX_LBT_DIRECT_BRK)
         iGapChars++;
-      }
+
       if (!bFind || !bAllChars) {
         dwCharType = tc.GetCharType();
         if (dwCharType == FX_CHARTYPE_Space ||
             dwCharType == FX_CHARTYPE_Control) {
           if (!bFind) {
             iCharWidth = tc.m_iCharWidth;
-            if (bAllChars && iCharWidth > 0) {
+            if (bAllChars && iCharWidth > 0)
               iNetWidth -= iCharWidth;
-            }
           }
         } else {
           bFind = true;
-          if (!bAllChars) {
+          if (!bAllChars)
             break;
-          }
         }
       }
       j += bArabic ? 1 : -1;
     }
-    if (!bAllChars && bFind) {
+    if (!bAllChars && bFind)
       break;
-    }
   }
+
   int32_t iOffset = m_iBoundaryEnd - iNetWidth;
-  int32_t iLowerAlignment = (m_iAlignment & FX_RTFLINEALIGNMENT_LowerMask);
-  int32_t iHigherAlignment = (m_iAlignment & FX_RTFLINEALIGNMENT_HigherMask);
-  if (iGapChars > 0 && (iHigherAlignment == FX_RTFLINEALIGNMENT_Distributed ||
-                        (iHigherAlignment == FX_RTFLINEALIGNMENT_Justified &&
-                         dwStatus != FX_RTFBREAK_ParagraphBreak))) {
+  if (iGapChars > 0 && (m_iAlignment == CFX_RTFLineAlignment::Distributed ||
+                        (m_iAlignment == CFX_RTFLineAlignment::Justified &&
+                         dwStatus != CFX_RTFBreakType::Paragraph))) {
     int32_t iStart = -1;
     for (i = 0; i < iCount; i++) {
-      tpo = tpos.GetAt(i);
+      tpo = tpos[i];
       CFX_RTFPiece& ttp = pCurPieces->GetAt(tpo.index);
-      if (iStart < 0) {
+      if (iStart < 0)
         iStart = ttp.m_iStartPos;
-      } else {
+      else
         ttp.m_iStartPos = iStart;
-      }
-      int32_t k;
+
       for (j = 0; j < ttp.m_iChars; j++) {
         CFX_RTFChar& tc = ttp.GetChar(j);
-        if (tc.m_nBreakType != FX_LBT_DIRECT_BRK || tc.m_iCharWidth < 0) {
+        if (tc.m_nBreakType != FX_LBT_DIRECT_BRK || tc.m_iCharWidth < 0)
           continue;
-        }
-        k = iOffset / iGapChars;
+
+        int32_t k = iOffset / iGapChars;
         tc.m_iCharWidth += k;
         ttp.m_iWidth += k;
         iOffset -= k;
         iGapChars--;
-        if (iGapChars < 1) {
+        if (iGapChars < 1)
           break;
-        }
       }
       iStart += ttp.m_iWidth;
     }
-  } else if (iLowerAlignment > FX_RTFLINEALIGNMENT_Left) {
-    if (iLowerAlignment == FX_RTFLINEALIGNMENT_Center) {
+  } else if (m_iAlignment == CFX_RTFLineAlignment::Right ||
+             m_iAlignment == CFX_RTFLineAlignment::Center) {
+    if (m_iAlignment == CFX_RTFLineAlignment::Center)
       iOffset /= 2;
-    }
     if (iOffset > 0) {
       for (i = 0; i < iCount; i++) {
         CFX_RTFPiece& ttp = pCurPieces->GetAt(i);
@@ -933,101 +698,68 @@
   }
 }
 
-int32_t CFX_RTFBreak::GetBreakPos(CFX_RTFCharArray& tca,
+int32_t CFX_RTFBreak::GetBreakPos(std::vector<CFX_RTFChar>& tca,
                                   int32_t& iEndPos,
                                   bool bAllChars,
                                   bool bOnlyBrk) {
-  int32_t iLength = tca.GetSize() - 1;
+  int32_t iLength = pdfium::CollectionSize<int32_t>(tca) - 1;
   if (iLength < 1)
     return iLength;
 
-  int32_t iBreak = -1, iBreakPos = -1, iIndirect = -1, iIndirectPos = -1,
-          iLast = -1, iLastPos = -1;
-  if (m_bSingleLine || m_bOrphanLine || iEndPos <= m_iBoundaryEnd) {
-    if (!bAllChars || m_bCharCode)
+  int32_t iBreak = -1;
+  int32_t iBreakPos = -1;
+  int32_t iIndirect = -1;
+  int32_t iIndirectPos = -1;
+  int32_t iLast = -1;
+  int32_t iLastPos = -1;
+  if (iEndPos <= m_iBoundaryEnd) {
+    if (!bAllChars)
       return iLength;
 
     iBreak = iLength;
     iBreakPos = iEndPos;
   }
-  CFX_RTFChar* pCharArray = tca.GetData();
-  if (m_bCharCode) {
-    const CFX_RTFChar* pChar;
-    int32_t iCharWidth;
-    while (iLength > 0) {
-      if (iEndPos <= m_iBoundaryEnd)
-        break;
 
-      pChar = pCharArray + iLength--;
-      iCharWidth = pChar->m_iCharWidth;
-      if (iCharWidth > 0)
-        iEndPos -= iCharWidth;
-    }
-    return iLength;
-  }
-  bool bSpaceBreak = (m_dwPolicies & FX_RTFBREAKPOLICY_SpaceBreak) != 0;
-  bool bTabBreak = (m_dwPolicies & FX_RTFBREAKPOLICY_TabBreak) != 0;
-  bool bNumberBreak = (m_dwPolicies & FX_RTFBREAKPOLICY_NumberBreak) != 0;
-  bool bInfixBreak = (m_dwPolicies & FX_RTFBREAKPOLICY_InfixBreak) != 0;
-  FX_LINEBREAKTYPE eType;
-  uint32_t nCodeProp, nCur, nNext;
-  CFX_RTFChar* pCur = pCharArray + iLength--;
-  if (bAllChars) {
+  CFX_RTFChar* pCharArray = tca.data();
+  CFX_RTFChar* pCur = pCharArray + iLength;
+  --iLength;
+  if (bAllChars)
     pCur->m_nBreakType = FX_LBT_UNKNOWN;
-  }
-  nCodeProp = pCur->m_dwCharProps;
-  nNext = nCodeProp & 0x003F;
+
+  uint32_t nCodeProp = pCur->m_dwCharProps;
+  uint32_t nNext = nCodeProp & 0x003F;
   int32_t iCharWidth = pCur->m_iCharWidth;
-  if (iCharWidth > 0) {
+  if (iCharWidth > 0)
     iEndPos -= iCharWidth;
-  }
+
   while (iLength >= 0) {
     pCur = pCharArray + iLength;
     nCodeProp = pCur->m_dwCharProps;
-    nCur = nCodeProp & 0x003F;
+    uint32_t nCur = nCodeProp & 0x003F;
     bool bNeedBreak = false;
-    if (nCur == FX_CBP_SP) {
-      bNeedBreak = !bSpaceBreak;
-      if (nNext == FX_CBP_SP) {
-        eType = bSpaceBreak ? FX_LBT_DIRECT_BRK : FX_LBT_PROHIBITED_BRK;
-      } else {
-        eType = gs_FX_LineBreak_PairTable[nCur][nNext];
-      }
-    } else if (nCur == FX_CBP_TB) {
-      bNeedBreak = !bTabBreak;
-      if (nNext == FX_CBP_TB) {
-        eType = bTabBreak ? FX_LBT_DIRECT_BRK : FX_LBT_PROHIBITED_BRK;
-      } else {
-        eType = gs_FX_LineBreak_PairTable[nCur][nNext];
-      }
-    } else if ((bNumberBreak && nCur == FX_CBP_NU && nNext == FX_CBP_NU) ||
-               (bInfixBreak && nCur == FX_CBP_IS && nNext == FX_CBP_IS)) {
-      eType = FX_LBT_DIRECT_BRK;
+    FX_LINEBREAKTYPE eType;
+    if (nCur == FX_CBP_TB) {
+      bNeedBreak = true;
+      eType = nNext == FX_CBP_TB ? FX_LBT_PROHIBITED_BRK
+                                 : gs_FX_LineBreak_PairTable[nCur][nNext];
     } else {
-      if (nNext == FX_CBP_SP) {
-        eType = FX_LBT_PROHIBITED_BRK;
-      } else {
-        eType = gs_FX_LineBreak_PairTable[nCur][nNext];
-      }
+      if (nCur == FX_CBP_SP)
+        bNeedBreak = true;
+
+      eType = nNext == FX_CBP_SP ? FX_LBT_PROHIBITED_BRK
+                                 : gs_FX_LineBreak_PairTable[nCur][nNext];
     }
-    if (bAllChars) {
+    if (bAllChars)
       pCur->m_nBreakType = eType;
-    }
+
     if (!bOnlyBrk) {
       iCharWidth = pCur->m_iCharWidth;
-      bool bBreak = false;
-      if (nCur == FX_CBP_TB && bTabBreak) {
-        bBreak = iCharWidth > 0 && iEndPos - iCharWidth <= m_iBoundaryEnd;
-      } else {
-        bBreak = iEndPos <= m_iBoundaryEnd;
-      }
-      if (m_bSingleLine || m_bOrphanLine || bBreak || bNeedBreak) {
+      if (iEndPos <= m_iBoundaryEnd || bNeedBreak) {
         if (eType == FX_LBT_DIRECT_BRK && iBreak < 0) {
           iBreak = iLength;
           iBreakPos = iEndPos;
-          if (!bAllChars) {
+          if (!bAllChars)
             return iLength;
-          }
         } else if (eType == FX_LBT_INDIRECT_BRK && iIndirect < 0) {
           iIndirect = iLength;
           iIndirectPos = iEndPos;
@@ -1037,9 +769,8 @@
           iLastPos = iEndPos;
         }
       }
-      if (iCharWidth > 0) {
+      if (iCharWidth > 0)
         iEndPos -= iCharWidth;
-      }
     }
     nNext = nCodeProp & 0x003F;
     iLength--;
@@ -1067,123 +798,76 @@
                                  bool bAllChars) {
   ASSERT(pCurLine && pNextLine);
   int32_t iCount = pCurLine->CountChars();
-  if (iCount < 2) {
+  if (iCount < 2)
     return;
-  }
+
   int32_t iEndPos = pCurLine->GetLineEnd();
-  CFX_RTFCharArray& curChars = pCurLine->m_LineChars;
+  std::vector<CFX_RTFChar>& curChars = pCurLine->m_LineChars;
   int32_t iCharPos = GetBreakPos(curChars, iEndPos, bAllChars, false);
-  if (iCharPos < 0) {
+  if (iCharPos < 0)
     iCharPos = 0;
-  }
+
   iCharPos++;
   if (iCharPos >= iCount) {
     pNextLine->RemoveAll(true);
-    CFX_Char* pTC = curChars.GetDataPtr(iCharPos - 1);
+    CFX_Char* pTC = &curChars[iCharPos - 1];
     pTC->m_nBreakType = FX_LBT_UNKNOWN;
     return;
   }
-  CFX_RTFCharArray& nextChars = pNextLine->m_LineChars;
-  int cur_size = curChars.GetSize();
-  nextChars.SetSize(cur_size - iCharPos);
-  FXSYS_memcpy(nextChars.GetData(), curChars.GetDataPtr(iCharPos),
-               (cur_size - iCharPos) * sizeof(CFX_RTFChar));
-  iCount -= iCharPos;
-  cur_size = curChars.GetSize();
-  curChars.RemoveAt(cur_size - iCount, iCount);
+
+  pNextLine->m_LineChars =
+      std::vector<CFX_RTFChar>(curChars.begin() + iCharPos, curChars.end());
+  curChars.erase(curChars.begin() + iCharPos, curChars.end());
   pNextLine->m_iStart = pCurLine->m_iStart;
   pNextLine->m_iWidth = pCurLine->GetLineEnd() - iEndPos;
   pCurLine->m_iWidth = iEndPos;
-  curChars.GetDataPtr(iCharPos - 1)->m_nBreakType = FX_LBT_UNKNOWN;
-  iCount = nextChars.GetSize();
-  CFX_RTFChar* pNextChars = nextChars.GetData();
-  for (int32_t i = 0; i < iCount; i++) {
-    CFX_RTFChar* tc = pNextChars + i;
-    if (tc->GetCharType() >= FX_CHARTYPE_ArabicAlef) {
+  curChars[iCharPos - 1].m_nBreakType = FX_LBT_UNKNOWN;
+
+  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 (tc->m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_MBCSCode) {
-      pCurLine->m_iMBCSChars--;
-      pNextLine->m_iMBCSChars++;
-    }
-    tc->m_dwStatus = 0;
+    pNextLine->m_LineChars[i].m_dwStatus = CFX_RTFBreakType::None;
   }
 }
 
 int32_t CFX_RTFBreak::CountBreakPieces() const {
-  CFX_RTFPieceArray* pRTFPieces = GetRTFPieces(true);
+  const CFX_RTFPieceArray* pRTFPieces = GetRTFPieces();
   return pRTFPieces ? pRTFPieces->GetSize() : 0;
 }
 
 const CFX_RTFPiece* CFX_RTFBreak::GetBreakPiece(int32_t index) const {
-  CFX_RTFPieceArray* pRTFPieces = GetRTFPieces(true);
+  const CFX_RTFPieceArray* pRTFPieces = GetRTFPieces();
   if (!pRTFPieces)
     return nullptr;
-
   if (index < 0 || index >= pRTFPieces->GetSize())
     return nullptr;
-
   return pRTFPieces->GetPtrAt(index);
 }
 
-void CFX_RTFBreak::GetLineRect(CFX_RectF& rect) const {
-  rect.top = 0;
-  CFX_RTFLine* pRTFLine = GetRTFLine(true);
-  if (!pRTFLine) {
-    rect.left = ((FX_FLOAT)m_iBoundaryStart) / 20000.0f;
-    rect.width = rect.height = 0;
-    return;
-  }
-  rect.left = ((FX_FLOAT)pRTFLine->m_iStart) / 20000.0f;
-  rect.width = ((FX_FLOAT)pRTFLine->m_iWidth) / 20000.0f;
-  CFX_RTFPieceArray& rtfPieces = pRTFLine->m_LinePieces;
-  int32_t iCount = rtfPieces.GetSize();
-  if (iCount < 1) {
-    rect.width = 0;
-    return;
-  }
-  CFX_RTFPiece* pBreakPiece;
-  int32_t iLineHeight = 0, iMax;
-  for (int32_t i = 0; i < iCount; i++) {
-    pBreakPiece = rtfPieces.GetPtrAt(i);
-    int32_t iFontHeight = FXSYS_round(pBreakPiece->m_iFontHeight *
-                                      pBreakPiece->m_iVerticalScale / 100.0f);
-    iMax = std::max(pBreakPiece->m_iFontSize, iFontHeight);
-    if (i == 0) {
-      iLineHeight = iMax;
-    } else if (iLineHeight < iMax) {
-      iLineHeight = iMax;
-    }
-  }
-  rect.height = ((FX_FLOAT)iLineHeight) / 20.0f;
-}
 void CFX_RTFBreak::ClearBreakPieces() {
-  CFX_RTFLine* pRTFLine = GetRTFLine(true);
-  if (pRTFLine) {
-    pRTFLine->RemoveAll(true);
-  }
+  const CFX_RTFLine* pRTFLine = GetRTFLine();
+  if (pRTFLine)
+    const_cast<CFX_RTFLine*>(pRTFLine)->RemoveAll(true);
   m_iReady = 0;
 }
+
 void CFX_RTFBreak::Reset() {
   m_eCharType = FX_CHARTYPE_Unknown;
   m_RTFLine1.RemoveAll(true);
   m_RTFLine2.RemoveAll(true);
 }
+
 int32_t CFX_RTFBreak::GetDisplayPos(const FX_RTFTEXTOBJ* pText,
                                     FXTEXT_CHARPOS* pCharPos,
-                                    bool bCharCode,
-                                    CFX_WideString* pWSForms,
-                                    FX_AdjustCharDisplayPos pAdjustPos) const {
-  if (!pText || pText->iLength < 1) {
+                                    bool bCharCode) const {
+  if (!pText || pText->iLength < 1)
     return 0;
-  }
-  ASSERT(pText->pStr && pText->pWidths && pText->pFont && pText->pRect);
-  const FX_WCHAR* pStr = pText->pStr;
-  int32_t* pWidths = pText->pWidths;
-  int32_t iLength = pText->iLength - 1;
+
+  ASSERT(pText->pFont && pText->pRect);
+
   CFX_RetainPtr<CFGAS_GEFont> pFont = pText->pFont;
-  uint32_t dwStyles = pText->dwLayoutStyles;
   CFX_RectF rtText(*pText->pRect);
   bool bRTLPiece = FX_IsOdd(pText->iBidiLevel);
   FX_FLOAT fFontSize = pText->fFontSize;
@@ -1192,335 +876,119 @@
   int32_t iDescent = pFont->GetDescent();
   int32_t iMaxHeight = iAscent - iDescent;
   FX_FLOAT fFontHeight = fFontSize;
-  FX_FLOAT fAscent = fFontHeight * (FX_FLOAT)iAscent / (FX_FLOAT)iMaxHeight;
-  FX_FLOAT fDescent = fFontHeight * (FX_FLOAT)iDescent / (FX_FLOAT)iMaxHeight;
-  bool bVerticalDoc = (dwStyles & FX_RTFLAYOUTSTYLE_VerticalLayout) != 0;
-  bool bVerticalChar = (dwStyles & FX_RTFLAYOUTSTYLE_VerticalChars) != 0;
-  bool bArabicNumber = (dwStyles & FX_RTFLAYOUTSTYLE_ArabicNumber) != 0;
-  bool bMBCSCode = (dwStyles & FX_RTFLAYOUTSTYLE_MBCSCode) != 0;
-  int32_t iRotation = GetLineRotation(dwStyles) + pText->iCharRotation;
-  int32_t iCharRotation;
-  FX_WCHAR wch, wPrev = 0xFEFF, wNext, wForm;
-  int32_t iWidth, iCharWidth, iCharHeight;
-  FX_FLOAT fX, fY, fCharWidth, fCharHeight;
+  FX_FLOAT fAscent = fFontHeight * static_cast<FX_FLOAT>(iAscent) /
+                     static_cast<FX_FLOAT>(iMaxHeight);
+  FX_WCHAR wch;
+  FX_WCHAR wPrev = 0xFEFF;
+  FX_WCHAR wNext;
+  FX_WCHAR wForm;
+  int32_t iWidth;
+  int32_t iCharWidth;
+  int32_t iCharHeight;
+  FX_FLOAT fX = rtText.left;
+  FX_FLOAT fY = rtText.top;
+  FX_FLOAT fCharWidth;
+  FX_FLOAT fCharHeight;
   int32_t iHorScale = pText->iHorizontalScale;
   int32_t iVerScale = pText->iVerticalScale;
   bool bEmptyChar;
-  uint32_t dwProps, dwCharType;
-  fX = rtText.left;
-  fY = rtText.top;
-  if (bVerticalDoc) {
-    fX += (rtText.width - fFontSize) / 2.0f;
-    if (bRTLPiece) {
-      fY = rtText.bottom();
-    }
-  } else {
-    if (bRTLPiece) {
-      fX = rtText.right();
-    }
-    fY += fAscent;
-  }
+  uint32_t dwProps;
+  uint32_t dwCharType;
+
+  if (bRTLPiece)
+    fX = rtText.right();
+
+  fY += fAscent;
   int32_t iCount = 0;
-  for (int32_t i = 0; i <= iLength; i++) {
-    wch = *pStr++;
-    iWidth = *pWidths++;
-    if (!bMBCSCode) {
-      dwProps = FX_GetUnicodeProperties(wch);
-      dwCharType = (dwProps & FX_CHARTYPEBITSMASK);
-      if (dwCharType == FX_CHARTYPE_ArabicAlef && iWidth == 0) {
+  for (int32_t i = 0; i < pText->iLength; i++) {
+    wch = pText->pStr[i];
+    iWidth = pText->pWidths[i];
+    dwProps = FX_GetUnicodeProperties(wch);
+    dwCharType = (dwProps & FX_CHARTYPEBITSMASK);
+    if (iWidth == 0) {
+      if (dwCharType == FX_CHARTYPE_ArabicAlef)
         wPrev = 0xFEFF;
-        continue;
-      }
-    } else {
-      dwProps = 0;
-      dwCharType = 0;
+      continue;
     }
-    if (iWidth != 0) {
-      iCharWidth = iWidth;
-      if (iCharWidth < 0) {
-        iCharWidth = -iCharWidth;
-      }
-      if (!bMBCSCode) {
-        bEmptyChar = (dwCharType >= FX_CHARTYPE_Tab &&
-                      dwCharType <= FX_CHARTYPE_Control);
-      } else {
-        bEmptyChar = false;
-      }
-      if (!bEmptyChar) {
-        iCount++;
-      }
-      if (pCharPos) {
-        iCharWidth /= iFontSize;
-        wForm = wch;
-        if (!bMBCSCode) {
-          if (dwCharType >= FX_CHARTYPE_ArabicAlef) {
-            if (i < iLength) {
-              wNext = *pStr;
-              if (*pWidths < 0) {
-                if (i + 1 < iLength) {
-                  wNext = pStr[1];
-                }
-              }
-            } else {
-              wNext = 0xFEFF;
-            }
-            wForm = pdfium::arabic::GetFormChar(wch, wPrev, wNext);
-          } else if (bRTLPiece || bVerticalChar) {
-            wForm = FX_GetMirrorChar(wch, dwProps, bRTLPiece, bVerticalChar);
-          } else if (dwCharType == FX_CHARTYPE_Numeric && bArabicNumber) {
-            wForm = wch + 0x0630;
-          }
-          dwProps = FX_GetUnicodeProperties(wForm);
-        }
-        iCharRotation = iRotation;
-        if (!bMBCSCode && bVerticalChar && (dwProps & 0x8000) != 0) {
-          iCharRotation++;
-          iCharRotation %= 4;
-        }
-        if (!bEmptyChar) {
-          if (bCharCode) {
-            pCharPos->m_GlyphIndex = wch;
-          } else {
-            pCharPos->m_GlyphIndex = pFont->GetGlyphIndex(wForm, bMBCSCode);
-            if (pCharPos->m_GlyphIndex == 0xFFFF) {
-              pCharPos->m_GlyphIndex = pFont->GetGlyphIndex(wch, bMBCSCode);
-            }
-          }
-#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
-          pCharPos->m_ExtGID = pCharPos->m_GlyphIndex;
-#endif
-          pCharPos->m_FontCharWidth = iCharWidth;
-          if (pWSForms) {
-            *pWSForms += wForm;
-          }
-        }
-        if (bVerticalDoc) {
-          iCharHeight = iCharWidth;
-          iCharWidth = 1000;
+
+    iCharWidth = FXSYS_abs(iWidth);
+    bEmptyChar =
+        (dwCharType >= FX_CHARTYPE_Tab && dwCharType <= FX_CHARTYPE_Control);
+    if (!bEmptyChar)
+      iCount++;
+
+    if (pCharPos) {
+      iCharWidth /= iFontSize;
+      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 {
-          iCharHeight = 1000;
+          wNext = 0xFEFF;
         }
-        fCharWidth = fFontSize * iCharWidth / 1000.0f;
-        fCharHeight = fFontSize * iCharHeight / 1000.0f;
-        if (!bMBCSCode && bRTLPiece && dwCharType != FX_CHARTYPE_Combination) {
-          if (bVerticalDoc) {
-            fY -= fCharHeight;
-          } else {
-            fX -= fCharWidth;
-          }
+        wForm = pdfium::arabic::GetFormChar(wch, wPrev, wNext);
+      } else if (bRTLPiece) {
+        wForm = FX_GetMirrorChar(wch, dwProps, bRTLPiece, false);
+      }
+      dwProps = FX_GetUnicodeProperties(wForm);
+
+      if (!bEmptyChar) {
+        if (bCharCode) {
+          pCharPos->m_GlyphIndex = wch;
+        } else {
+          pCharPos->m_GlyphIndex = pFont->GetGlyphIndex(wForm, false);
+          if (pCharPos->m_GlyphIndex == 0xFFFF)
+            pCharPos->m_GlyphIndex = pFont->GetGlyphIndex(wch, false);
         }
-        if (!bEmptyChar) {
-          CFX_PointF ptOffset;
-          bool bAdjusted = false;
-          if (pAdjustPos) {
-            bAdjusted = pAdjustPos(wForm, bMBCSCode, pFont, fFontSize,
-                                   bVerticalChar, ptOffset);
-          }
-          if (!bAdjusted && bVerticalChar && (dwProps & 0x00010000) != 0) {
-            CFX_Rect rtBBox;
-            rtBBox.Reset();
-            if (pFont->GetCharBBox(wForm, &rtBBox, bMBCSCode)) {
-              ptOffset.x = fFontSize * (850 - rtBBox.right()) / 1000.0f;
-              ptOffset.y = fFontSize * (1000 - rtBBox.height) / 2000.0f;
-            }
-          }
-          pCharPos->m_OriginX = fX + ptOffset.x;
-          pCharPos->m_OriginY = fY - ptOffset.y;
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
+        pCharPos->m_ExtGID = pCharPos->m_GlyphIndex;
+#endif
+        pCharPos->m_FontCharWidth = iCharWidth;
+      }
+      iCharHeight = 1000;
+
+      fCharWidth = fFontSize * iCharWidth / 1000.0f;
+      fCharHeight = fFontSize * iCharHeight / 1000.0f;
+      if (bRTLPiece && dwCharType != FX_CHARTYPE_Combination)
+        fX -= fCharWidth;
+
+      if (!bEmptyChar)
+        pCharPos->m_Origin = CFX_PointF(fX, fY);
+      if (!bRTLPiece && dwCharType != FX_CHARTYPE_Combination)
+        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 (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;
         }
-        if (!bRTLPiece && dwCharType != FX_CHARTYPE_Combination) {
-          if (bVerticalDoc) {
-            fY += fCharHeight;
-          } else {
-            fX += fCharWidth;
-          }
-        }
-        if (!bEmptyChar) {
-          pCharPos->m_bGlyphAdjust = true;
-          if (bVerticalDoc) {
-            if (iCharRotation == 0) {
-              pCharPos->m_AdjustMatrix[0] = -1;
-              pCharPos->m_AdjustMatrix[1] = 0;
-              pCharPos->m_AdjustMatrix[2] = 0;
-              pCharPos->m_AdjustMatrix[3] = 1;
-              pCharPos->m_OriginY += fAscent * iVerScale / 100.0f;
-            } else if (iCharRotation == 1) {
-              pCharPos->m_AdjustMatrix[0] = 0;
-              pCharPos->m_AdjustMatrix[1] = -1;
-              pCharPos->m_AdjustMatrix[2] = -1;
-              pCharPos->m_AdjustMatrix[3] = 0;
-              pCharPos->m_OriginX -=
-                  fDescent + fAscent * iVerScale / 100.0f - fAscent;
-            } else if (iCharRotation == 2) {
-              pCharPos->m_AdjustMatrix[0] = 1;
-              pCharPos->m_AdjustMatrix[1] = 0;
-              pCharPos->m_AdjustMatrix[2] = 0;
-              pCharPos->m_AdjustMatrix[3] = -1;
-              pCharPos->m_OriginX += fCharWidth;
-              pCharPos->m_OriginY += fAscent;
-            } else {
-              pCharPos->m_AdjustMatrix[0] = 0;
-              pCharPos->m_AdjustMatrix[1] = 1;
-              pCharPos->m_AdjustMatrix[2] = 1;
-              pCharPos->m_AdjustMatrix[3] = 0;
-              pCharPos->m_OriginX += fAscent;
-              pCharPos->m_OriginY += fCharWidth;
-            }
-          } else {
-            if (iCharRotation == 0) {
-              pCharPos->m_AdjustMatrix[0] = -1;
-              pCharPos->m_AdjustMatrix[1] = 0;
-              pCharPos->m_AdjustMatrix[2] = 0;
-              pCharPos->m_AdjustMatrix[3] = 1;
-              pCharPos->m_OriginY += fAscent * iVerScale / 100.0f - fAscent;
-            } else if (iCharRotation == 1) {
-              pCharPos->m_AdjustMatrix[0] = 0;
-              pCharPos->m_AdjustMatrix[1] = -1;
-              pCharPos->m_AdjustMatrix[2] = -1;
-              pCharPos->m_AdjustMatrix[3] = 0;
-              pCharPos->m_OriginX -= fDescent;
-              pCharPos->m_OriginY -= fAscent + fDescent;
-            } else if (iCharRotation == 2) {
-              pCharPos->m_AdjustMatrix[0] = 1;
-              pCharPos->m_AdjustMatrix[1] = 0;
-              pCharPos->m_AdjustMatrix[2] = 0;
-              pCharPos->m_AdjustMatrix[3] = -1;
-              pCharPos->m_OriginX += fCharWidth;
-              pCharPos->m_OriginY -= fAscent;
-            } else {
-              pCharPos->m_AdjustMatrix[0] = 0;
-              pCharPos->m_AdjustMatrix[1] = 1;
-              pCharPos->m_AdjustMatrix[2] = 1;
-              pCharPos->m_AdjustMatrix[3] = 0;
-              pCharPos->m_OriginX += fAscent * iVerScale / 100.0f;
-            }
-          }
-          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++;
-        }
+        pCharPos++;
       }
     }
-    if (iWidth > 0) {
+    if (iWidth > 0)
       wPrev = wch;
-    }
   }
   return iCount;
 }
-int32_t CFX_RTFBreak::GetCharRects(const FX_RTFTEXTOBJ* pText,
-                                   CFX_RectFArray& rtArray,
-                                   bool bCharBBox) const {
-  if (!pText || pText->iLength < 1)
-    return 0;
-
-  ASSERT(pText->pStr && pText->pWidths && pText->pFont && pText->pRect);
-  const FX_WCHAR* pStr = pText->pStr;
-  int32_t* pWidths = pText->pWidths;
-  int32_t iLength = pText->iLength;
-  CFX_RectF rect(*pText->pRect);
-  bool bRTLPiece = FX_IsOdd(pText->iBidiLevel);
-  FX_FLOAT fFontSize = pText->fFontSize;
-  int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
-  FX_FLOAT fScale = fFontSize / 1000.0f;
-  CFX_RetainPtr<CFGAS_GEFont> pFont = pText->pFont;
-  if (!pFont)
-    bCharBBox = false;
-
-  CFX_Rect bbox;
-  bbox.Set(0, 0, 0, 0);
-  if (bCharBBox)
-    bCharBBox = pFont->GetBBox(&bbox);
-
-  FX_FLOAT fLeft = std::max(0.0f, bbox.left * fScale);
-  FX_FLOAT fHeight = FXSYS_fabs(bbox.height * fScale);
-  rtArray.RemoveAll();
-  rtArray.SetSize(iLength);
-  uint32_t dwStyles = pText->dwLayoutStyles;
-  bool bVertical = (dwStyles & FX_RTFLAYOUTSTYLE_VerticalLayout) != 0;
-  bool bSingleLine = (dwStyles & FX_RTFLAYOUTSTYLE_SingleLine) != 0;
-  bool bCombText = (dwStyles & FX_TXTLAYOUTSTYLE_CombText) != 0;
-  FX_WCHAR wch, wLineBreakChar = pText->wLineBreakChar;
-  int32_t iCharSize;
-  FX_FLOAT fCharSize, fStart;
-  if (bVertical) {
-    fStart = bRTLPiece ? rect.bottom() : rect.top;
-  } else {
-    fStart = bRTLPiece ? rect.right() : rect.left;
-  }
-  for (int32_t i = 0; i < iLength; i++) {
-    wch = *pStr++;
-    iCharSize = *pWidths++;
-    fCharSize = (FX_FLOAT)iCharSize / 20000.0f;
-    bool bRet = (!bSingleLine && FX_IsCtrlCode(wch));
-    if (!(wch == L'\v' || wch == L'\f' || wch == 0x2028 || wch == 0x2029 ||
-          (wLineBreakChar != 0xFEFF && wch == wLineBreakChar))) {
-      bRet = false;
-    }
-    if (bRet) {
-      iCharSize = iFontSize * 500;
-      fCharSize = fFontSize / 2.0f;
-    }
-    if (bVertical) {
-      rect.top = fStart;
-      if (bRTLPiece) {
-        rect.top -= fCharSize;
-        fStart -= fCharSize;
-      } else {
-        fStart += fCharSize;
-      }
-      rect.height = fCharSize;
-    } else {
-      rect.left = fStart;
-      if (bRTLPiece) {
-        rect.left -= fCharSize;
-        fStart -= fCharSize;
-      } else {
-        fStart += fCharSize;
-      }
-      rect.width = fCharSize;
-    }
-    if (bCharBBox && !bRet) {
-      int32_t iCharWidth = 1000;
-      pFont->GetCharWidth(wch, iCharWidth, false);
-      FX_FLOAT fRTLeft = 0, fCharWidth = 0;
-      if (iCharWidth > 0) {
-        fCharWidth = iCharWidth * fScale;
-        fRTLeft = fLeft;
-        if (bCombText) {
-          fRTLeft = (rect.width - fCharWidth) / 2.0f;
-        }
-      }
-      CFX_RectF rtBBoxF;
-      if (bVertical) {
-        rtBBoxF.top = rect.left + fRTLeft;
-        rtBBoxF.left = rect.top + (rect.height - fHeight) / 2.0f;
-        rtBBoxF.height = fCharWidth;
-        rtBBoxF.width = fHeight;
-        rtBBoxF.left = std::max(rtBBoxF.left, 0.0f);
-      } else {
-        rtBBoxF.left = rect.left + fRTLeft;
-        rtBBoxF.top = rect.top + (rect.height - fHeight) / 2.0f;
-        rtBBoxF.width = fCharWidth;
-        rtBBoxF.height = fHeight;
-        rtBBoxF.top = std::max(rtBBoxF.top, 0.0f);
-      }
-      rtArray.SetAt(i, rtBBoxF);
-      continue;
-    }
-    rtArray.SetAt(i, rect);
-  }
-  return iLength;
-}
 
 CFX_RTFPiece::CFX_RTFPiece()
-    : m_dwStatus(FX_RTFBREAK_PieceBreak),
+    : m_dwStatus(CFX_RTFBreakType::Piece),
       m_iStartPos(0),
       m_iWidth(-1),
       m_iStartChar(0),
@@ -1531,7 +999,6 @@
       m_iFontHeight(0),
       m_iHorizontalScale(100),
       m_iVerticalScale(100),
-      m_dwLayoutStyles(0),
       m_dwIdentity(0),
       m_pChars(nullptr),
       m_pUserData(nullptr) {}
@@ -1548,20 +1015,16 @@
       m_iMBCSChars(0) {}
 
 CFX_RTFLine::~CFX_RTFLine() {
-  RemoveAll();
+  RemoveAll(false);
 }
 
 FX_RTFTEXTOBJ::FX_RTFTEXTOBJ()
-    : pStr(nullptr),
-      pWidths(nullptr),
-      iLength(0),
-      pFont(nullptr),
-      fFontSize(12.0f),
-      dwLayoutStyles(0),
-      iCharRotation(0),
-      iBidiLevel(0),
+    : pFont(nullptr),
       pRect(nullptr),
       wLineBreakChar(L'\n'),
+      fFontSize(12.0f),
+      iLength(0),
+      iBidiLevel(0),
       iHorizontalScale(100),
       iVerticalScale(100) {}
 
diff --git a/xfa/fgas/layout/fgas_rtfbreak.h b/xfa/fgas/layout/fgas_rtfbreak.h
index 6edd860..4d999ec 100644
--- a/xfa/fgas/layout/fgas_rtfbreak.h
+++ b/xfa/fgas/layout/fgas_rtfbreak.h
@@ -7,77 +7,40 @@
 #ifndef XFA_FGAS_LAYOUT_FGAS_RTFBREAK_H_
 #define XFA_FGAS_LAYOUT_FGAS_RTFBREAK_H_
 
+#include <deque>
 #include <vector>
 
+#include "core/fxcrt/cfx_retain_ptr.h"
 #include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_ucd.h"
 #include "xfa/fgas/crt/fgas_utils.h"
 #include "xfa/fgas/layout/fgas_textbreak.h"
-#include "xfa/fgas/layout/fgas_unicode.h"
 
 class CFGAS_GEFont;
 
-#define FX_RTFBREAKPOLICY_None 0x00
-#define FX_RTFBREAKPOLICY_SpaceBreak 0x01
-#define FX_RTFBREAKPOLICY_NumberBreak 0x02
-#define FX_RTFBREAKPOLICY_InfixBreak 0x04
-#define FX_RTFBREAKPOLICY_TabBreak 0x08
-#define FX_RTFBREAKPOLICY_OrphanPositionedTab 0x10
-#define FX_RTFBREAK_None 0x00
-#define FX_RTFBREAK_PieceBreak 0x01
-#define FX_RTFBREAK_LineBreak 0x02
-#define FX_RTFBREAK_ParagraphBreak 0x03
-#define FX_RTFBREAK_PageBreak 0x04
 #define FX_RTFLAYOUTSTYLE_Pagination 0x01
-#define FX_RTFLAYOUTSTYLE_VerticalLayout 0x02
-#define FX_RTFLAYOUTSTYLE_VerticalChars 0x04
-#define FX_RTFLAYOUTSTYLE_LineDirection 0x08
 #define FX_RTFLAYOUTSTYLE_ExpandTab 0x10
-#define FX_RTFLAYOUTSTYLE_ArabicNumber 0x20
-#define FX_RTFLAYOUTSTYLE_SingleLine 0x40
-#define FX_RTFLAYOUTSTYLE_MBCSCode 0x80
-#define FX_RTFCHARSTYLE_Alignment 0x000F
-#define FX_RTFCHARSTYLE_ArabicNumber 0x0010
-#define FX_RTFCHARSTYLE_ArabicShadda 0x0020
-#define FX_RTFCHARSTYLE_OddBidiLevel 0x0040
-#define FX_RTFCHARSTYLE_RTLReadingOrder 0x0080
-#define FX_RTFCHARSTYLE_ArabicContext 0x0300
-#define FX_RTFCHARSTYLE_ArabicIndic 0x0400
-#define FX_RTFCHARSTYLE_ArabicComma 0x0800
-#define FX_RTFLINEALIGNMENT_Left 0
-#define FX_RTFLINEALIGNMENT_Center 1
-#define FX_RTFLINEALIGNMENT_Right 2
-#define FX_RTFLINEALIGNMENT_Justified (1 << 2)
-#define FX_RTFLINEALIGNMENT_Distributed (2 << 2)
-#define FX_RTFLINEALIGNMENT_JustifiedLeft \
-  (FX_RTFLINEALIGNMENT_Left | FX_RTFLINEALIGNMENT_Justified)
-#define FX_RTFLINEALIGNMENT_JustifiedCenter \
-  (FX_RTFLINEALIGNMENT_Center | FX_RTFLINEALIGNMENT_Justified)
-#define FX_RTFLINEALIGNMENT_JustifiedRight \
-  (FX_RTFLINEALIGNMENT_Right | FX_RTFLINEALIGNMENT_Justified)
-#define FX_RTFLINEALIGNMENT_DistributedLeft \
-  (FX_RTFLINEALIGNMENT_Left | FX_RTFLINEALIGNMENT_Distributed)
-#define FX_RTFLINEALIGNMENT_DistributedCenter \
-  (FX_RTFLINEALIGNMENT_Center | FX_RTFLINEALIGNMENT_Distributed)
-#define FX_RTFLINEALIGNMENT_DistributedRight \
-  (FX_RTFLINEALIGNMENT_Right | FX_RTFLINEALIGNMENT_Distributed)
-#define FX_RTFLINEALIGNMENT_LowerMask 0x03
-#define FX_RTFLINEALIGNMENT_HigherMask 0x0C
+
+enum class CFX_RTFLineAlignment {
+  Left = 0,
+  Center,
+  Right,
+  Justified,
+  Distributed
+};
 
 struct FX_RTFTEXTOBJ {
   FX_RTFTEXTOBJ();
   ~FX_RTFTEXTOBJ();
 
-  const FX_WCHAR* pStr;
-  int32_t* pWidths;
-  int32_t iLength;
+  CFX_WideString pStr;
+  std::vector<int32_t> pWidths;
   CFX_RetainPtr<CFGAS_GEFont> pFont;
-  FX_FLOAT fFontSize;
-  uint32_t dwLayoutStyles;
-  int32_t iCharRotation;
-  int32_t iBidiLevel;
   const CFX_RectF* pRect;
   FX_WCHAR wLineBreakChar;
+  FX_FLOAT fFontSize;
+  int32_t iLength;
+  int32_t iBidiLevel;
   int32_t iHorizontalScale;
   int32_t iVerticalScale;
 };
@@ -87,57 +50,36 @@
   CFX_RTFPiece();
   ~CFX_RTFPiece();
 
-  void AppendChar(const CFX_RTFChar& tc) {
-    ASSERT(m_pChars);
-    m_pChars->Add(tc);
-    if (m_iWidth < 0) {
-      m_iWidth = tc.m_iCharWidth;
-    } else {
-      m_iWidth += tc.m_iCharWidth;
-    }
-    m_iChars++;
-  }
   int32_t GetEndPos() const {
     return m_iWidth < 0 ? m_iStartPos : m_iStartPos + m_iWidth;
   }
-  int32_t GetLength() const { return m_iChars; }
-  int32_t GetEndChar() const { return m_iStartChar + m_iChars; }
+
   CFX_RTFChar& GetChar(int32_t index) {
     ASSERT(index > -1 && index < m_iChars && m_pChars);
-    return *m_pChars->GetDataPtr(m_iStartChar + index);
+    return (*m_pChars)[m_iStartChar + index];
   }
-  CFX_RTFChar* GetCharPtr(int32_t index) const {
-    ASSERT(index > -1 && index < m_iChars && m_pChars);
-    return m_pChars->GetDataPtr(m_iStartChar + index);
+
+  CFX_WideString GetString() const {
+    CFX_WideString ret;
+    ret.Reserve(m_iChars);
+    for (int32_t i = m_iStartChar; i < m_iStartChar + m_iChars; i++)
+      ret += static_cast<FX_WCHAR>((*m_pChars)[i].m_wCharCode);
+    return ret;
   }
-  void GetString(FX_WCHAR* pText) const {
-    ASSERT(pText);
-    int32_t iEndChar = m_iStartChar + m_iChars;
-    CFX_RTFChar* pChar;
-    for (int32_t i = m_iStartChar; i < iEndChar; i++) {
-      pChar = m_pChars->GetDataPtr(i);
-      *pText++ = (FX_WCHAR)pChar->m_wCharCode;
-    }
+
+  std::vector<int32_t> GetWidths() const {
+    std::vector<int32_t> ret;
+    ret.reserve(m_iChars);
+    for (int32_t i = m_iStartChar; i < m_iStartChar + m_iChars; i++)
+      ret.push_back((*m_pChars)[i].m_iCharWidth);
+    return ret;
   }
-  void GetString(CFX_WideString& wsText) const {
-    FX_WCHAR* pText = wsText.GetBuffer(m_iChars);
-    GetString(pText);
-    wsText.ReleaseBuffer(m_iChars);
-  }
-  void GetWidths(int32_t* pWidths) const {
-    ASSERT(pWidths);
-    int32_t iEndChar = m_iStartChar + m_iChars;
-    CFX_RTFChar* pChar;
-    for (int32_t i = m_iStartChar; i < iEndChar; i++) {
-      pChar = m_pChars->GetDataPtr(i);
-      *pWidths++ = pChar->m_iCharWidth;
-    }
-  }
+
   void Reset() {
-    m_dwStatus = FX_RTFBREAK_PieceBreak;
-    if (m_iWidth > -1) {
+    m_dwStatus = CFX_RTFBreakType::Piece;
+    if (m_iWidth > -1)
       m_iStartPos += m_iWidth;
-    }
+
     m_iWidth = -1;
     m_iStartChar += m_iChars;
     m_iChars = 0;
@@ -147,7 +89,7 @@
     m_iVerticalScale = 100;
   }
 
-  uint32_t m_dwStatus;
+  CFX_RTFBreakType m_dwStatus;
   int32_t m_iStartPos;
   int32_t m_iWidth;
   int32_t m_iStartChar;
@@ -158,10 +100,9 @@
   int32_t m_iFontHeight;
   int32_t m_iHorizontalScale;
   int32_t m_iVerticalScale;
-  uint32_t m_dwLayoutStyles;
   uint32_t m_dwIdentity;
-  CFX_RTFCharArray* m_pChars;
-  IFX_Retainable* m_pUserData;
+  std::vector<CFX_RTFChar>* m_pChars;  // not owned.
+  CFX_RetainPtr<CFX_Retainable> m_pUserData;
 };
 
 typedef CFX_BaseArrayTemplate<CFX_RTFPiece> CFX_RTFPieceArray;
@@ -171,41 +112,25 @@
   CFX_RTFLine();
   ~CFX_RTFLine();
 
-  int32_t CountChars() const { return m_LineChars.GetSize(); }
+  int32_t CountChars() const {
+    return pdfium::CollectionSize<int32_t>(m_LineChars);
+  }
+
   CFX_RTFChar& GetChar(int32_t index) {
-    ASSERT(index > -1 && index < m_LineChars.GetSize());
-    return *m_LineChars.GetDataPtr(index);
+    ASSERT(index >= 0 && index < pdfium::CollectionSize<int32_t>(m_LineChars));
+    return m_LineChars[index];
   }
-  CFX_RTFChar* GetCharPtr(int32_t index) {
-    ASSERT(index > -1 && index < m_LineChars.GetSize());
-    return m_LineChars.GetDataPtr(index);
-  }
-  int32_t CountPieces() const { return m_LinePieces.GetSize(); }
-  CFX_RTFPiece& GetPiece(int32_t index) const {
-    ASSERT(index > -1 && index < m_LinePieces.GetSize());
-    return m_LinePieces.GetAt(index);
-  }
-  CFX_RTFPiece* GetPiecePtr(int32_t index) const {
-    ASSERT(index > -1 && index < m_LinePieces.GetSize());
-    return m_LinePieces.GetPtrAt(index);
-  }
+
   int32_t GetLineEnd() const { return m_iStart + m_iWidth; }
-  void RemoveAll(bool bLeaveMemory = false) {
-    CFX_RTFChar* pChar;
-    int32_t iCount = m_LineChars.GetSize();
-    for (int32_t i = 0; i < iCount; i++) {
-      pChar = m_LineChars.GetDataPtr(i);
-      if (pChar->m_pUserData)
-        pChar->m_pUserData->Release();
-    }
-    m_LineChars.RemoveAll();
+  void RemoveAll(bool bLeaveMemory) {
+    m_LineChars.clear();
     m_LinePieces.RemoveAll(bLeaveMemory);
     m_iWidth = 0;
     m_iArabicChars = 0;
     m_iMBCSChars = 0;
   }
 
-  CFX_RTFCharArray m_LineChars;
+  std::vector<CFX_RTFChar> m_LineChars;
   CFX_RTFPieceArray m_LinePieces;
   int32_t m_iStart;
   int32_t m_iWidth;
@@ -215,105 +140,83 @@
 
 class CFX_RTFBreak {
  public:
-  explicit CFX_RTFBreak(uint32_t dwPolicies);
+  explicit CFX_RTFBreak(uint32_t dwLayoutStyles);
   ~CFX_RTFBreak();
 
   void SetLineBoundary(FX_FLOAT fLineStart, FX_FLOAT fLineEnd);
   void SetLineStartPos(FX_FLOAT fLinePos);
-  uint32_t GetLayoutStyles() const { return m_dwLayoutStyles; }
-  void SetLayoutStyles(uint32_t dwLayoutStyles);
   void SetFont(const CFX_RetainPtr<CFGAS_GEFont>& pFont);
   void SetFontSize(FX_FLOAT fFontSize);
   void SetTabWidth(FX_FLOAT fTabWidth);
-  void AddPositionedTab(FX_FLOAT fTabPos);
-  void SetPositionedTabs(const std::vector<FX_FLOAT>& tabs);
-  void ClearPositionedTabs();
-  void SetDefaultChar(FX_WCHAR wch);
-  void SetLineBreakChar(FX_WCHAR wch);
   void SetLineBreakTolerance(FX_FLOAT fTolerance);
   void SetHorizontalScale(int32_t iScale);
   void SetVerticalScale(int32_t iScale);
-  void SetCharRotation(int32_t iCharRotation);
   void SetCharSpace(FX_FLOAT fCharSpace);
-  void SetWordSpace(bool bDefault, FX_FLOAT fWordSpace);
-  void SetReadingOrder(bool bRTL = false);
-  void SetAlignment(int32_t iAlignment = FX_RTFLINEALIGNMENT_Left);
-  void SetUserData(IFX_Retainable* pUserData);
-  uint32_t AppendChar(FX_WCHAR wch);
-  uint32_t EndBreak(uint32_t dwStatus = FX_RTFBREAK_PieceBreak);
+  void SetAlignment(CFX_RTFLineAlignment align) { m_iAlignment = align; }
+  void SetUserData(const CFX_RetainPtr<CFX_Retainable>& pUserData);
+
+  void AddPositionedTab(FX_FLOAT fTabPos);
+
+  CFX_RTFBreakType EndBreak(CFX_RTFBreakType dwStatus);
   int32_t CountBreakPieces() const;
   const CFX_RTFPiece* GetBreakPiece(int32_t index) const;
-  void GetLineRect(CFX_RectF& rect) const;
   void ClearBreakPieces();
+
   void Reset();
+
   int32_t GetDisplayPos(const FX_RTFTEXTOBJ* pText,
                         FXTEXT_CHARPOS* pCharPos,
-                        bool bCharCode = false,
-                        CFX_WideString* pWSForms = nullptr,
-                        FX_AdjustCharDisplayPos pAdjustPos = nullptr) const;
-  int32_t GetCharRects(const FX_RTFTEXTOBJ* pText,
-                       CFX_RectFArray& rtArray,
-                       bool bCharBBox = false) const;
-  uint32_t AppendChar_CharCode(FX_WCHAR wch);
-  uint32_t AppendChar_Combination(CFX_RTFChar* pCurChar, int32_t iRotation);
-  uint32_t AppendChar_Tab(CFX_RTFChar* pCurChar, int32_t iRotation);
-  uint32_t AppendChar_Control(CFX_RTFChar* pCurChar, int32_t iRotation);
-  uint32_t AppendChar_Arabic(CFX_RTFChar* pCurChar, int32_t iRotation);
-  uint32_t AppendChar_Others(CFX_RTFChar* pCurChar, int32_t iRotation);
+                        bool bCharCode) const;
 
- protected:
-  int32_t GetLineRotation(uint32_t dwStyles) const;
+  CFX_RTFBreakType AppendChar(FX_WCHAR wch);
+  CFX_RTFBreakType AppendChar_Combination(CFX_RTFChar* pCurChar);
+  CFX_RTFBreakType AppendChar_Tab(CFX_RTFChar* pCurChar);
+  CFX_RTFBreakType AppendChar_Control(CFX_RTFChar* pCurChar);
+  CFX_RTFBreakType AppendChar_Arabic(CFX_RTFChar* pCurChar);
+  CFX_RTFBreakType AppendChar_Others(CFX_RTFChar* pCurChar);
+
+ private:
+  void FontChanged();
   void SetBreakStatus();
   CFX_RTFChar* GetLastChar(int32_t index) const;
-  CFX_RTFLine* GetRTFLine(bool bReady) const;
-  CFX_RTFPieceArray* GetRTFPieces(bool bReady) const;
+  const CFX_RTFLine* GetRTFLine() const;
+  const CFX_RTFPieceArray* GetRTFPieces() const;
   FX_CHARTYPE GetUnifiedCharType(FX_CHARTYPE chartype) const;
   int32_t GetLastPositionedTab() const;
-  bool GetPositionedTab(int32_t& iTabPos) const;
+  bool GetPositionedTab(int32_t* iTabPos) const;
 
-  int32_t GetBreakPos(CFX_RTFCharArray& tca,
+  int32_t GetBreakPos(std::vector<CFX_RTFChar>& tca,
                       int32_t& iEndPos,
-                      bool bAllChars = false,
-                      bool bOnlyBrk = false);
+                      bool bAllChars,
+                      bool bOnlyBrk);
   void SplitTextLine(CFX_RTFLine* pCurLine,
                      CFX_RTFLine* pNextLine,
-                     bool bAllChars = false);
+                     bool bAllChars);
   bool EndBreak_SplitLine(CFX_RTFLine* pNextLine,
                           bool bAllChars,
-                          uint32_t dwStatus);
-  void EndBreak_BidiLine(CFX_TPOArray& tpos, uint32_t dwStatus);
-  void EndBreak_Alignment(CFX_TPOArray& tpos,
+                          CFX_RTFBreakType dwStatus);
+  void EndBreak_BidiLine(std::deque<FX_TPO>* tpos, CFX_RTFBreakType dwStatus);
+  void EndBreak_Alignment(const std::deque<FX_TPO>& tpos,
                           bool bAllChars,
-                          uint32_t dwStatus);
+                          CFX_RTFBreakType dwStatus);
 
-  uint32_t m_dwPolicies;
   int32_t m_iBoundaryStart;
   int32_t m_iBoundaryEnd;
   uint32_t m_dwLayoutStyles;
   bool m_bPagination;
-  bool m_bVertical;
-  bool m_bSingleLine;
-  bool m_bCharCode;
   CFX_RetainPtr<CFGAS_GEFont> m_pFont;
   int32_t m_iFontHeight;
   int32_t m_iFontSize;
   int32_t m_iTabWidth;
-  CFX_Int32Array m_PositionedTabs;
-  bool m_bOrphanLine;
+  std::vector<int32_t> m_PositionedTabs;
   FX_WCHAR m_wDefChar;
   int32_t m_iDefChar;
   FX_WCHAR m_wLineBreakChar;
   int32_t m_iHorizontalScale;
   int32_t m_iVerticalScale;
-  int32_t m_iLineRotation;
-  int32_t m_iCharRotation;
-  int32_t m_iRotation;
   int32_t m_iCharSpace;
-  bool m_bWordSpace;
-  int32_t m_iWordSpace;
-  bool m_bRTL;
-  int32_t m_iAlignment;
-  IFX_Retainable* m_pUserData;
+  CFX_RTFLineAlignment m_iAlignment;
+  CFX_RetainPtr<CFX_Retainable> m_pUserData;
   FX_CHARTYPE m_eCharType;
   uint32_t m_dwIdentity;
   CFX_RTFLine m_RTFLine1;
diff --git a/xfa/fgas/layout/fgas_textbreak.cpp b/xfa/fgas/layout/fgas_textbreak.cpp
index 35984f5..8be72f2 100644
--- a/xfa/fgas/layout/fgas_textbreak.cpp
+++ b/xfa/fgas/layout/fgas_textbreak.cpp
@@ -14,7 +14,6 @@
 #include "third_party/base/ptr_util.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
 #include "xfa/fgas/layout/fgas_linebreak.h"
-#include "xfa/fgas/layout/fgas_unicode.h"
 
 namespace {
 
@@ -67,7 +66,6 @@
       m_iReady(0),
       m_iTolerance(0),
       m_iHorScale(100),
-      m_iVerScale(100),
       m_iCharSpace(0) {
   m_bPagination = (m_dwPolicies & FX_TXTBREAKPOLICY_Pagination) != 0;
   int32_t iSize = m_bPagination ? sizeof(CFX_Char) : sizeof(CFX_TxtChar);
@@ -87,13 +85,8 @@
 }
 
 void CFX_TxtBreak::SetLinePos(FX_FLOAT fLinePos) {
-  int32_t iLinePos = FXSYS_round(fLinePos * 20000.0f);
-  if (iLinePos < 0) {
-    iLinePos = 0;
-  }
-  if (iLinePos > m_iLineWidth) {
-    iLinePos = m_iLineWidth;
-  }
+  int32_t iLinePos =
+      std::min(std::max(FXSYS_round(fLinePos * 20000.0f), 0), m_iLineWidth);
   m_pCurLine->m_iStart = iLinePos;
   m_pCurLine->m_iWidth += iLinePos;
 }
@@ -118,52 +111,52 @@
 
   SetBreakStatus();
   m_pFont = pFont;
-  m_iDefChar = 0;
-  if (m_wDefChar != 0xFEFF && m_pFont) {
-    m_pFont->GetCharWidth(m_wDefChar, m_iDefChar, false);
-    m_iDefChar *= m_iFontSize;
-  }
+  FontChanged();
 }
 
 void CFX_TxtBreak::SetFontSize(FX_FLOAT fFontSize) {
   int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
-  if (m_iFontSize == iFontSize) {
+  if (m_iFontSize == iFontSize)
     return;
-  }
+
   SetBreakStatus();
   m_iFontSize = iFontSize;
+  FontChanged();
+}
+
+void CFX_TxtBreak::FontChanged() {
   m_iDefChar = 0;
-  if (m_wDefChar != 0xFEFF && m_pFont) {
-    m_pFont->GetCharWidth(m_wDefChar, m_iDefChar, false);
-    m_iDefChar *= m_iFontSize;
-  }
+  if (m_wDefChar == 0xFEFF || !m_pFont)
+    return;
+
+  m_pFont->GetCharWidth(m_wDefChar, m_iDefChar, false);
+  m_iDefChar *= m_iFontSize;
 }
 
 void CFX_TxtBreak::SetTabWidth(FX_FLOAT fTabWidth, bool bEquidistant) {
   m_iTabWidth = FXSYS_round(fTabWidth * 20000.0f);
-  if (m_iTabWidth < FX_TXTBREAK_MinimumTabWidth) {
+  if (m_iTabWidth < FX_TXTBREAK_MinimumTabWidth)
     m_iTabWidth = FX_TXTBREAK_MinimumTabWidth;
-  }
+
   m_bEquidistant = bEquidistant;
 }
 
 void CFX_TxtBreak::SetDefaultChar(FX_WCHAR wch) {
   m_wDefChar = wch;
   m_iDefChar = 0;
-  if (m_wDefChar != 0xFEFF && m_pFont) {
-    m_pFont->GetCharWidth(m_wDefChar, m_iDefChar, false);
-    if (m_iDefChar < 0) {
-      m_iDefChar = 0;
-    } else {
-      m_iDefChar *= m_iFontSize;
-    }
-  }
+  if (m_wDefChar == 0xFEFF || !m_pFont)
+    return;
+
+  m_pFont->GetCharWidth(m_wDefChar, m_iDefChar, false);
+  if (m_iDefChar < 0)
+    m_iDefChar = 0;
+  else
+    m_iDefChar *= m_iFontSize;
 }
 
 void CFX_TxtBreak::SetParagraphBreakChar(FX_WCHAR wch) {
-  if (wch != L'\r' && wch != L'\n') {
+  if (wch != L'\r' && wch != L'\n')
     return;
-  }
   m_wParagBreakChar = wch;
 }
 
@@ -172,14 +165,14 @@
 }
 
 void CFX_TxtBreak::SetCharRotation(int32_t iCharRotation) {
-  if (iCharRotation < 0) {
+  if (iCharRotation < 0)
     iCharRotation += (-iCharRotation / 4 + 1) * 4;
-  } else if (iCharRotation > 3) {
+  else if (iCharRotation > 3)
     iCharRotation -= (iCharRotation / 4) * 4;
-  }
-  if (m_iCharRotation == iCharRotation) {
+
+  if (m_iCharRotation == iCharRotation)
     return;
-  }
+
   SetBreakStatus();
   m_iCharRotation = iCharRotation;
   m_iRotation = m_iLineRotation + m_iCharRotation;
@@ -195,111 +188,78 @@
 
 void CFX_TxtBreak::ResetContextCharStyles() {
   m_dwContextCharStyles = m_bArabicContext ? m_iCurAlignment : m_iAlignment;
-  if (m_bArabicNumber) {
+  if (m_bArabicNumber)
     m_dwContextCharStyles |= FX_TXTCHARSTYLE_ArabicNumber;
-  }
-  if (m_bArabicComma) {
+  if (m_bArabicComma)
     m_dwContextCharStyles |= FX_TXTCHARSTYLE_ArabicComma;
-  }
-  if ((m_bArabicContext && m_bCurRTL) || (!m_bArabicContext && m_bRTL)) {
+  if ((m_bArabicContext && m_bCurRTL) || (!m_bArabicContext && m_bRTL))
     m_dwContextCharStyles |= FX_TXTCHARSTYLE_RTLReadingOrder;
-  }
   m_dwContextCharStyles |= (m_iArabicContext << 8);
 }
 
-uint32_t CFX_TxtBreak::GetContextCharStyles() const {
-  return m_dwContextCharStyles;
-}
-
-void CFX_TxtBreak::SetContextCharStyles(uint32_t dwCharStyles) {
-  m_iCurAlignment = dwCharStyles & 0x0F;
-  m_bArabicNumber = (dwCharStyles & FX_TXTCHARSTYLE_ArabicNumber) != 0;
-  m_bArabicComma = (dwCharStyles & FX_TXTCHARSTYLE_ArabicComma) != 0;
-  m_bCurRTL = (dwCharStyles & FX_TXTCHARSTYLE_RTLReadingOrder) != 0;
-  m_iCurArabicContext = m_iArabicContext = ((dwCharStyles & 0x0300) >> 8);
-  ResetContextCharStyles();
-}
-
 void CFX_TxtBreak::SetCombWidth(FX_FLOAT fCombWidth) {
   m_iCombWidth = FXSYS_round(fCombWidth * 20000.0f);
 }
 
 void CFX_TxtBreak::SetUserData(void* pUserData) {
-  if (m_pUserData == pUserData) {
+  if (m_pUserData == pUserData)
     return;
-  }
+
   SetBreakStatus();
   m_pUserData = pUserData;
 }
 
 void CFX_TxtBreak::SetBreakStatus() {
-  if (m_bPagination) {
+  if (m_bPagination)
     return;
-  }
+
   int32_t iCount = m_pCurLine->CountChars();
-  if (iCount < 1) {
+  if (iCount < 1)
     return;
-  }
+
   CFX_TxtChar* pTC = m_pCurLine->GetCharPtr(iCount - 1);
-  if (pTC->m_dwStatus == 0) {
+  if (pTC->m_dwStatus == 0)
     pTC->m_dwStatus = FX_TXTBREAK_PieceBreak;
-  }
 }
 
 void CFX_TxtBreak::SetHorizontalScale(int32_t iScale) {
-  if (iScale < 0) {
+  if (iScale < 0)
     iScale = 0;
-  }
-  if (iScale == m_iHorScale) {
+  if (iScale == m_iHorScale)
     return;
-  }
+
   SetBreakStatus();
   m_iHorScale = iScale;
 }
 
-void CFX_TxtBreak::SetVerticalScale(int32_t iScale) {
-  if (iScale < 0) {
-    iScale = 0;
-  }
-  if (iScale == m_iHorScale) {
-    return;
-  }
-  SetBreakStatus();
-  m_iVerScale = iScale;
-}
-
 void CFX_TxtBreak::SetCharSpace(FX_FLOAT fCharSpace) {
   m_iCharSpace = FXSYS_round(fCharSpace * 20000.0f);
 }
 
 static const int32_t gs_FX_TxtLineRotations[8] = {0, 3, 1, 0, 2, 1, 3, 2};
+
 int32_t CFX_TxtBreak::GetLineRotation(uint32_t dwStyles) const {
   return gs_FX_TxtLineRotations[(dwStyles & 0x0E) >> 1];
 }
 
 CFX_TxtChar* CFX_TxtBreak::GetLastChar(int32_t index, bool bOmitChar) const {
-  CFX_TxtCharArray& ca = *m_pCurLine->m_pLineChars.get();
-  int32_t iCount = ca.GetSize();
-  if (index < 0 || index >= iCount) {
+  std::vector<CFX_TxtChar>& ca = *m_pCurLine->m_pLineChars.get();
+  int32_t iCount = pdfium::CollectionSize<int32_t>(ca);
+  if (index < 0 || index >= iCount)
     return nullptr;
-  }
-  CFX_TxtChar* pTC;
+
   int32_t iStart = iCount - 1;
   while (iStart > -1) {
-    pTC = ca.GetDataPtr(iStart--);
-    if (bOmitChar && pTC->GetCharType() == FX_CHARTYPE_Combination) {
+    CFX_TxtChar* pTC = &ca[iStart--];
+    if (bOmitChar && pTC->GetCharType() == FX_CHARTYPE_Combination)
       continue;
-    }
-    if (--index < 0) {
+    if (--index < 0)
       return pTC;
-    }
   }
   return nullptr;
 }
 
-CFX_TxtLine* CFX_TxtBreak::GetTxtLine(bool bReady) const {
-  if (!bReady)
-    return m_pCurLine;
+CFX_TxtLine* CFX_TxtBreak::GetTxtLine() const {
   if (m_iReady == 1)
     return m_pTxtLine1.get();
   if (m_iReady == 2)
@@ -307,12 +267,9 @@
   return nullptr;
 }
 
-CFX_TxtPieceArray* CFX_TxtBreak::GetTxtPieces(bool bReady) const {
-  CFX_TxtLine* pTxtLine = GetTxtLine(bReady);
-  if (!pTxtLine) {
-    return nullptr;
-  }
-  return pTxtLine->m_pLinePieces.get();
+CFX_TxtPieceArray* CFX_TxtBreak::GetTxtPieces() const {
+  CFX_TxtLine* pTxtLine = GetTxtLine();
+  return pTxtLine ? pTxtLine->m_pLinePieces.get() : nullptr;
 }
 
 inline FX_CHARTYPE CFX_TxtBreak::GetUnifiedCharType(
@@ -335,11 +292,10 @@
       m_bCurRTL = m_bRTL;
       m_iCurAlignment = m_iAlignment;
     }
-    if (m_bRTL) {
+    if (m_bRTL)
       m_bArabicNumber = m_iArabicContext >= 1;
-    } else {
+    else
       m_bArabicNumber = m_iArabicContext > 1;
-    }
     m_bArabicNumber = m_bArabicNumber && m_bArabicShapes;
   }
   m_bArabicComma = m_bArabicNumber;
@@ -361,15 +317,14 @@
                                                                           : 1);
     if (iArabicContext != m_iArabicContext && iArabicContext != 1) {
       m_iArabicContext = iArabicContext;
-      if (m_iCurArabicContext == 1) {
+      if (m_iCurArabicContext == 1)
         m_iCurArabicContext = iArabicContext;
-      }
+
       ResetArabicContext();
       if (!m_bPagination) {
         CFX_TxtChar* pLastChar = GetLastChar(1, false);
-        if (pLastChar && pLastChar->m_dwStatus < 1) {
+        if (pLastChar && pLastChar->m_dwStatus < 1)
           pLastChar->m_dwStatus = FX_TXTBREAK_PieceBreak;
-        }
       }
     }
   }
@@ -413,9 +368,8 @@
           }
         }
       }
-      if (!m_pFont->GetCharWidth(wForm, iCharWidth, false)) {
+      if (!m_pFont->GetCharWidth(wForm, iCharWidth, false))
         iCharWidth = 0;
-      }
     }
     iCharWidth *= m_iFontSize;
     iCharWidth = iCharWidth * m_iHorScale / 100;
@@ -427,9 +381,9 @@
 uint32_t CFX_TxtBreak::AppendChar_Tab(CFX_TxtChar* pCurChar,
                                       int32_t iRotation) {
   m_eCharType = FX_CHARTYPE_Tab;
-  if ((m_dwLayoutStyles & FX_TXTLAYOUTSTYLE_ExpandTab) == 0) {
+  if ((m_dwLayoutStyles & FX_TXTLAYOUTSTYLE_ExpandTab) == 0)
     return FX_TXTBREAK_None;
-  }
+
   int32_t& iLineWidth = m_pCurLine->m_iWidth;
   int32_t iCharWidth;
   if (m_bCombText) {
@@ -438,18 +392,18 @@
     if (m_bEquidistant) {
       iCharWidth = iLineWidth;
       iCharWidth = m_iTabWidth * (iCharWidth / m_iTabWidth + 1) - iCharWidth;
-      if (iCharWidth < FX_TXTBREAK_MinimumTabWidth) {
+      if (iCharWidth < FX_TXTBREAK_MinimumTabWidth)
         iCharWidth += m_iTabWidth;
-      }
     } else {
       iCharWidth = m_iTabWidth;
     }
   }
+
   pCurChar->m_iCharWidth = iCharWidth;
   iLineWidth += iCharWidth;
-  if (!m_bSingleLine && iLineWidth >= m_iLineWidth + m_iTolerance) {
+  if (!m_bSingleLine && iLineWidth >= m_iLineWidth + m_iTolerance)
     return EndBreak(FX_TXTBREAK_LineBreak);
-  }
+
   return FX_TXTBREAK_None;
 }
 
@@ -471,14 +425,12 @@
         dwRet = FX_TXTBREAK_ParagraphBreak;
         break;
       default:
-        if (wch == m_wParagBreakChar) {
+        if (wch == m_wParagBreakChar)
           dwRet = FX_TXTBREAK_ParagraphBreak;
-        }
         break;
     }
-    if (dwRet != FX_TXTBREAK_None) {
+    if (dwRet != FX_TXTBREAK_None)
       dwRet = EndBreak(dwRet);
-    }
   }
   return dwRet;
 }
@@ -489,32 +441,31 @@
   int32_t& iLineWidth = m_pCurLine->m_iWidth;
   FX_WCHAR wForm;
   int32_t iCharWidth = 0;
-  CFX_Char* pLastChar = nullptr;
+  CFX_TxtChar* pLastChar = nullptr;
   bool bAlef = false;
   if (!m_bCombText && m_eCharType >= FX_CHARTYPE_ArabicAlef &&
       m_eCharType <= FX_CHARTYPE_ArabicDistortion) {
     pLastChar = GetLastChar(1);
     if (pLastChar) {
       iCharWidth = pLastChar->m_iCharWidth;
-      if (iCharWidth > 0) {
+      if (iCharWidth > 0)
         iLineWidth -= iCharWidth;
-      }
+
       CFX_Char* pPrevChar = GetLastChar(2);
       wForm = pdfium::arabic::GetFormChar(pLastChar, pPrevChar, pCurChar);
       bAlef = (wForm == 0xFEFF &&
                pLastChar->GetCharType() == FX_CHARTYPE_ArabicAlef);
       int32_t iLastRotation = pLastChar->m_nRotation + m_iLineRotation;
-      if (m_bVertical && (pLastChar->m_dwCharProps & 0x8000) != 0) {
+      if (m_bVertical && (pLastChar->m_dwCharProps & 0x8000) != 0)
         iLastRotation++;
-      }
-      if (m_bVertical != FX_IsOdd(iLastRotation)) {
+      if (m_bVertical != FX_IsOdd(iLastRotation))
         iCharWidth = 1000;
-      } else {
+      else
         m_pFont->GetCharWidth(wForm, iCharWidth, false);
-      }
-      if (wForm == 0xFEFF) {
+
+      if (wForm == 0xFEFF)
         iCharWidth = m_iDefChar;
-      }
+
       iCharWidth *= m_iFontSize;
       iCharWidth = iCharWidth * m_iHorScale / 100;
       pLastChar->m_iCharWidth = iCharWidth;
@@ -522,29 +473,29 @@
       iCharWidth = 0;
     }
   }
+
   m_eCharType = chartype;
   wForm = pdfium::arabic::GetFormChar(pCurChar, bAlef ? nullptr : pLastChar,
                                       nullptr);
   if (m_bCombText) {
     iCharWidth = m_iCombWidth;
   } else {
-    if (m_bVertical != FX_IsOdd(iRotation)) {
+    if (m_bVertical != FX_IsOdd(iRotation))
       iCharWidth = 1000;
-    } else {
+    else
       m_pFont->GetCharWidth(wForm, iCharWidth, false);
-    }
-    if (wForm == 0xFEFF) {
+
+    if (wForm == 0xFEFF)
       iCharWidth = m_iDefChar;
-    }
+
     iCharWidth *= m_iFontSize;
     iCharWidth = iCharWidth * m_iHorScale / 100;
   }
   pCurChar->m_iCharWidth = iCharWidth;
   iLineWidth += iCharWidth;
   m_pCurLine->m_iArabicChars++;
-  if (!m_bSingleLine && iLineWidth > m_iLineWidth + m_iTolerance) {
+  if (!m_bSingleLine && iLineWidth > m_iLineWidth + m_iTolerance)
     return EndBreak(FX_TXTBREAK_LineBreak);
-  }
   return FX_TXTBREAK_None;
 }
 
@@ -570,39 +521,43 @@
   } else if (m_bCurRTL || m_bVertical) {
     wForm = FX_GetMirrorChar(wch, dwProps, m_bCurRTL, m_bVertical);
   }
+
   if (m_bCombText) {
     iCharWidth = m_iCombWidth;
   } else {
-    if (m_bVertical != FX_IsOdd(iRotation)) {
+    if (m_bVertical != FX_IsOdd(iRotation))
       iCharWidth = 1000;
-    } else if (!m_pFont->GetCharWidth(wForm, iCharWidth, false)) {
+    else if (!m_pFont->GetCharWidth(wForm, iCharWidth, false))
       iCharWidth = m_iDefChar;
-    }
+
     iCharWidth *= m_iFontSize;
     iCharWidth = iCharWidth * m_iHorScale / 100;
   }
+
   iCharWidth += m_iCharSpace;
   pCurChar->m_iCharWidth = iCharWidth;
   iLineWidth += iCharWidth;
   bool bBreak = (chartype != FX_CHARTYPE_Space ||
                  (m_dwPolicies & FX_TXTBREAKPOLICY_SpaceBreak) != 0);
-  if (!m_bSingleLine && bBreak && iLineWidth > m_iLineWidth + m_iTolerance) {
+  if (!m_bSingleLine && bBreak && iLineWidth > m_iLineWidth + m_iTolerance)
     return EndBreak(FX_TXTBREAK_LineBreak);
-  }
+
   return FX_TXTBREAK_None;
 }
 
 uint32_t CFX_TxtBreak::AppendChar(FX_WCHAR wch) {
-  uint32_t dwProps = kTextLayoutCodeProperties[(uint16_t)wch];
+  uint32_t dwProps = kTextLayoutCodeProperties[static_cast<uint16_t>(wch)];
   FX_CHARTYPE chartype = GetCharTypeFromProp(dwProps);
-  CFX_TxtChar* pCurChar = m_pCurLine->m_pLineChars->AddSpace();
-  pCurChar->m_wCharCode = (uint16_t)wch;
+  m_pCurLine->m_pLineChars->emplace_back();
+
+  CFX_TxtChar* pCurChar = &m_pCurLine->m_pLineChars->back();
+  pCurChar->m_wCharCode = static_cast<uint16_t>(wch);
   pCurChar->m_nRotation = m_iCharRotation;
   pCurChar->m_dwCharProps = dwProps;
   pCurChar->m_dwCharStyles = 0;
   pCurChar->m_iCharWidth = 0;
   pCurChar->m_iHorizontalScale = m_iHorScale;
-  pCurChar->m_iVertialScale = m_iVerScale;
+  pCurChar->m_iVerticalScale = 100;
   pCurChar->m_dwStatus = 0;
   pCurChar->m_iBidiClass = 0;
   pCurChar->m_iBidiLevel = 0;
@@ -612,22 +567,20 @@
   AppendChar_PageLoad(pCurChar, dwProps);
   uint32_t dwRet1 = FX_TXTBREAK_None;
   if (chartype != FX_CHARTYPE_Combination &&
-      GetUnifiedCharType(m_eCharType) != GetUnifiedCharType(chartype)) {
-    if (m_eCharType != FX_CHARTYPE_Unknown &&
-        m_pCurLine->m_iWidth > m_iLineWidth + m_iTolerance && !m_bSingleLine) {
-      if (m_eCharType != FX_CHARTYPE_Space || chartype != FX_CHARTYPE_Control) {
-        dwRet1 = EndBreak(FX_TXTBREAK_LineBreak);
-        int32_t iCount = m_pCurLine->CountChars();
-        if (iCount > 0) {
-          pCurChar = m_pCurLine->m_pLineChars->GetDataPtr(iCount - 1);
-        }
-      }
-    }
+      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)) {
+    dwRet1 = EndBreak(FX_TXTBREAK_LineBreak);
+    int32_t iCount = m_pCurLine->CountChars();
+    if (iCount > 0)
+      pCurChar = &(*m_pCurLine->m_pLineChars)[iCount - 1];
   }
+
   int32_t iRotation = m_iRotation;
-  if (m_bVertical && (dwProps & 0x8000) != 0) {
+  if (m_bVertical && (dwProps & 0x8000) != 0)
     iRotation = (iRotation + 1) % 4;
-  }
+
   uint32_t dwRet2 =
       (this->*g_FX_TxtBreak_lpfAppendChar[chartype >> FX_CHARTYPEBITS])(
           pCurChar, iRotation);
@@ -637,11 +590,11 @@
 void CFX_TxtBreak::EndBreak_UpdateArabicShapes() {
   ASSERT(m_bArabicShapes);
   int32_t iCount = m_pCurLine->CountChars();
-  if (iCount < 2) {
+  if (iCount < 2)
     return;
-  }
+
   int32_t& iLineWidth = m_pCurLine->m_iWidth;
-  CFX_Char* pCur = m_pCurLine->GetCharPtr(0);
+  CFX_TxtChar* pCur = m_pCurLine->GetCharPtr(0);
   bool bPrevNum = (pCur->m_dwCharStyles & FX_TXTCHARSTYLE_ArabicIndic) != 0;
   pCur = m_pCurLine->GetCharPtr(1);
   FX_WCHAR wch, wForm;
@@ -649,7 +602,7 @@
   int32_t i = 1;
   int32_t iCharWidth;
   int32_t iRotation;
-  CFX_Char* pNext;
+  CFX_TxtChar* pNext;
   do {
     i++;
     if (i < iCount) {
@@ -659,23 +612,24 @@
       pNext = nullptr;
       bNextNum = false;
     }
+
     wch = pCur->m_wCharCode;
     if (wch == L'.') {
       if (bPrevNum && bNextNum) {
         iRotation = m_iRotation;
-        if (m_bVertical && (pCur->m_dwCharProps & 0x8000) != 0) {
+        if (m_bVertical && (pCur->m_dwCharProps & 0x8000) != 0)
           iRotation = ((iRotation + 1) & 0x03);
-        }
+
         wForm = wch == L'.' ? 0x066B : 0x066C;
         iLineWidth -= pCur->m_iCharWidth;
         if (m_bCombText) {
           iCharWidth = m_iCombWidth;
         } else {
-          if (m_bVertical != FX_IsOdd(iRotation)) {
+          if (m_bVertical != FX_IsOdd(iRotation))
             iCharWidth = 1000;
-          } else if (!m_pFont->GetCharWidth(wForm, iCharWidth, false)) {
+          else if (!m_pFont->GetCharWidth(wForm, iCharWidth, false))
             iCharWidth = m_iDefChar;
-          }
+
           iCharWidth *= m_iFontSize;
           iCharWidth = iCharWidth * m_iHorScale / 100;
         }
@@ -693,7 +647,7 @@
                                       uint32_t dwStatus) {
   int32_t iCount = m_pCurLine->CountChars();
   bool bDone = false;
-  CFX_Char* pTC;
+  CFX_TxtChar* pTC;
   if (!m_bSingleLine && m_pCurLine->m_iWidth > m_iLineWidth + m_iTolerance) {
     pTC = m_pCurLine->GetCharPtr(iCount - 1);
     switch (pTC->GetCharType()) {
@@ -712,6 +666,7 @@
         break;
     }
   }
+
   iCount = m_pCurLine->CountChars();
   CFX_TxtPieceArray* pCurPieces = m_pCurLine->m_pLinePieces.get();
   CFX_TxtPiece tp;
@@ -726,7 +681,7 @@
     pTC = m_pCurLine->GetCharPtr(0);
     tp.m_dwCharStyles = pTC->m_dwCharStyles;
     tp.m_iHorizontalScale = pTC->m_iHorizontalScale;
-    tp.m_iVerticalScale = pTC->m_iVertialScale;
+    tp.m_iVerticalScale = pTC->m_iVerticalScale;
     pCurPieces->Add(tp);
     m_pCurLine = pNextLine;
     m_eCharType = FX_CHARTYPE_Unknown;
@@ -739,38 +694,41 @@
   return false;
 }
 
-void CFX_TxtBreak::EndBreak_BidiLine(CFX_TPOArray& tpos, uint32_t dwStatus) {
+void CFX_TxtBreak::EndBreak_BidiLine(std::deque<FX_TPO>* tpos,
+                                     uint32_t dwStatus) {
   CFX_TxtPiece tp;
   FX_TPO tpo;
   CFX_TxtChar* pTC;
-  int32_t i, j;
-  CFX_TxtCharArray& chars = *m_pCurLine->m_pLineChars.get();
+  int32_t i;
+  int32_t j;
+  std::vector<CFX_TxtChar>& chars = *m_pCurLine->m_pLineChars.get();
   int32_t iCount = m_pCurLine->CountChars();
   bool bDone = (m_pCurLine->m_iArabicChars > 0 || m_bCurRTL);
   if (!m_bPagination && bDone) {
     int32_t iBidiNum = 0;
     for (i = 0; i < iCount; i++) {
-      pTC = chars.GetDataPtr(i);
+      pTC = &chars[i];
       pTC->m_iBidiPos = i;
-      if (pTC->GetCharType() != FX_CHARTYPE_Control) {
+      if (pTC->GetCharType() != FX_CHARTYPE_Control)
         iBidiNum = i;
-      }
-      if (i == 0) {
+      if (i == 0)
         pTC->m_iBidiLevel = 1;
-      }
     }
     FX_BidiLine(chars, iBidiNum + 1, m_bCurRTL ? 1 : 0);
   }
+
   CFX_TxtPieceArray* pCurPieces = m_pCurLine->m_pLinePieces.get();
   if (!m_bPagination &&
       (bDone || (m_dwLayoutStyles & FX_TXTLAYOUTSTYLE_MutipleFormat) != 0)) {
     tp.m_dwStatus = FX_TXTBREAK_PieceBreak;
     tp.m_iStartPos = m_pCurLine->m_iStart;
     tp.m_pChars = m_pCurLine->m_pLineChars.get();
-    int32_t iBidiLevel = -1, iCharWidth;
-    i = 0, j = -1;
+    int32_t iBidiLevel = -1;
+    int32_t iCharWidth;
+    i = 0;
+    j = -1;
     while (i < iCount) {
-      pTC = chars.GetDataPtr(i);
+      pTC = &chars[i];
       if (iBidiLevel < 0) {
         iBidiLevel = pTC->m_iBidiLevel;
         tp.m_iWidth = 0;
@@ -779,16 +737,16 @@
         tp.m_dwCharStyles = pTC->m_dwCharStyles;
         tp.m_pUserData = pTC->m_pUserData;
         tp.m_iHorizontalScale = pTC->m_iHorizontalScale;
-        tp.m_iVerticalScale = pTC->m_iVertialScale;
+        tp.m_iVerticalScale = pTC->m_iVerticalScale;
         tp.m_dwStatus = FX_TXTBREAK_PieceBreak;
       }
       if (iBidiLevel != pTC->m_iBidiLevel || pTC->m_dwStatus != 0) {
         if (iBidiLevel == pTC->m_iBidiLevel) {
           tp.m_dwStatus = pTC->m_dwStatus;
           iCharWidth = pTC->m_iCharWidth;
-          if (iCharWidth > 0) {
+          if (iCharWidth > 0)
             tp.m_iWidth += iCharWidth;
-          }
+
           i++;
         }
         tp.m_iChars = i - tp.m_iStartChar;
@@ -797,13 +755,13 @@
         tp.m_iStartChar = i;
         tpo.index = ++j;
         tpo.pos = tp.m_iBidiPos;
-        tpos.Add(tpo);
+        tpos->push_back(tpo);
         iBidiLevel = -1;
       } else {
         iCharWidth = pTC->m_iCharWidth;
-        if (iCharWidth > 0) {
+        if (iCharWidth > 0)
           tp.m_iWidth += iCharWidth;
-        }
+
         i++;
       }
     }
@@ -813,14 +771,14 @@
       pCurPieces->Add(tp);
       tpo.index = ++j;
       tpo.pos = tp.m_iBidiPos;
-      tpos.Add(tpo);
+      tpos->push_back(tpo);
     }
     if (j > -1) {
       if (j > 0) {
-        FX_TEXTLAYOUT_PieceSort(tpos, 0, j);
+        std::sort(tpos->begin(), tpos->end());
         int32_t iStartPos = 0;
         for (i = 0; i <= j; i++) {
-          tpo = tpos.GetAt(i);
+          tpo = (*tpos)[i];
           CFX_TxtPiece& ttp = pCurPieces->GetAt(tpo.index);
           ttp.m_iStartPos = iStartPos;
           iStartPos += ttp.m_iWidth;
@@ -837,62 +795,61 @@
     tp.m_iChars = iCount;
     tp.m_pChars = m_pCurLine->m_pLineChars.get();
     tp.m_pUserData = m_pUserData;
-    pTC = chars.GetDataPtr(0);
+    pTC = &chars[0];
     tp.m_dwCharStyles = pTC->m_dwCharStyles;
     tp.m_iHorizontalScale = pTC->m_iHorizontalScale;
-    tp.m_iVerticalScale = pTC->m_iVertialScale;
+    tp.m_iVerticalScale = pTC->m_iVerticalScale;
     pCurPieces->Add(tp);
-    tpo.index = 0;
-    tpo.pos = 0;
-    tpos.Add(tpo);
+    tpos->push_back({0, 0});
   }
 }
 
-void CFX_TxtBreak::EndBreak_Alignment(CFX_TPOArray& tpos,
+void CFX_TxtBreak::EndBreak_Alignment(const std::deque<FX_TPO>& tpos,
                                       bool bAllChars,
                                       uint32_t dwStatus) {
-  int32_t iNetWidth = m_pCurLine->m_iWidth, iGapChars = 0, iCharWidth;
+  int32_t iNetWidth = m_pCurLine->m_iWidth;
+  int32_t iGapChars = 0;
+  int32_t iCharWidth;
   CFX_TxtPieceArray* pCurPieces = m_pCurLine->m_pLinePieces.get();
-  int32_t i, j, iCount = pCurPieces->GetSize();
+  int32_t i;
+  int32_t j;
+  int32_t iCount = pCurPieces->GetSize();
   bool bFind = false;
   FX_TPO tpo;
   CFX_TxtChar* pTC;
   FX_CHARTYPE chartype;
   for (i = iCount - 1; i > -1; i--) {
-    tpo = tpos.GetAt(i);
+    tpo = tpos[i];
     CFX_TxtPiece& ttp = pCurPieces->GetAt(tpo.index);
-    if (!bFind) {
+    if (!bFind)
       iNetWidth = ttp.GetEndPos();
-    }
+
     bool bArabic = FX_IsOdd(ttp.m_iBidiLevel);
     j = bArabic ? 0 : ttp.m_iChars - 1;
     while (j > -1 && j < ttp.m_iChars) {
       pTC = ttp.GetCharPtr(j);
-      if (pTC->m_nBreakType == FX_LBT_DIRECT_BRK) {
+      if (pTC->m_nBreakType == FX_LBT_DIRECT_BRK)
         iGapChars++;
-      }
       if (!bFind || !bAllChars) {
         chartype = pTC->GetCharType();
         if (chartype == FX_CHARTYPE_Space || chartype == FX_CHARTYPE_Control) {
           if (!bFind) {
             iCharWidth = pTC->m_iCharWidth;
-            if (bAllChars && iCharWidth > 0) {
+            if (bAllChars && iCharWidth > 0)
               iNetWidth -= iCharWidth;
-            }
           }
         } else {
           bFind = true;
-          if (!bAllChars) {
+          if (!bAllChars)
             break;
-          }
         }
       }
       j += bArabic ? 1 : -1;
     }
-    if (!bAllChars && bFind) {
+    if (!bAllChars && bFind)
       break;
-    }
   }
+
   int32_t iOffset = m_iLineWidth - iNetWidth;
   int32_t iLowerAlignment = (m_iCurAlignment & FX_TXTLINEALIGNMENT_LowerMask);
   int32_t iHigherAlignment = (m_iCurAlignment & FX_TXTLINEALIGNMENT_HigherMask);
@@ -901,34 +858,31 @@
                          dwStatus != FX_TXTBREAK_ParagraphBreak))) {
     int32_t iStart = -1;
     for (i = 0; i < iCount; i++) {
-      tpo = tpos.GetAt(i);
+      tpo = tpos[i];
       CFX_TxtPiece& ttp = pCurPieces->GetAt(tpo.index);
-      if (iStart < -1) {
+      if (iStart < -1)
         iStart = ttp.m_iStartPos;
-      } else {
+      else
         ttp.m_iStartPos = iStart;
-      }
-      int32_t k;
+
       for (j = 0; j < ttp.m_iChars; j++) {
         pTC = ttp.GetCharPtr(j);
-        if (pTC->m_nBreakType != FX_LBT_DIRECT_BRK || pTC->m_iCharWidth < 0) {
+        if (pTC->m_nBreakType != FX_LBT_DIRECT_BRK || pTC->m_iCharWidth < 0)
           continue;
-        }
-        k = iOffset / iGapChars;
+
+        int32_t k = iOffset / iGapChars;
         pTC->m_iCharWidth += k;
         ttp.m_iWidth += k;
         iOffset -= k;
         iGapChars--;
-        if (iGapChars < 1) {
+        if (iGapChars < 1)
           break;
-        }
       }
       iStart += ttp.m_iWidth;
     }
   } else if (iLowerAlignment > FX_TXTLINEALIGNMENT_Left) {
-    if (iLowerAlignment == FX_TXTLINEALIGNMENT_Center) {
+    if (iLowerAlignment == FX_TXTLINEALIGNMENT_Center)
       iOffset /= 2;
-    }
     if (iOffset > 0) {
       for (i = 0; i < iCount; i++) {
         CFX_TxtPiece& ttp = pCurPieces->GetAt(i);
@@ -945,59 +899,54 @@
   int32_t iCount = pCurPieces->GetSize();
   if (iCount > 0) {
     CFX_TxtPiece* pLastPiece = pCurPieces->GetPtrAt(--iCount);
-    if (dwStatus > FX_TXTBREAK_PieceBreak) {
+    if (dwStatus > FX_TXTBREAK_PieceBreak)
       pLastPiece->m_dwStatus = dwStatus;
-    } else {
+    else
       dwStatus = pLastPiece->m_dwStatus;
-    }
     return dwStatus;
   } else {
-    CFX_TxtLine* pLastLine = GetTxtLine(true);
+    CFX_TxtLine* pLastLine = GetTxtLine();
     if (pLastLine) {
       pCurPieces = pLastLine->m_pLinePieces.get();
       iCount = pCurPieces->GetSize();
       if (iCount-- > 0) {
         CFX_TxtPiece* pLastPiece = pCurPieces->GetPtrAt(iCount);
-        if (dwStatus > FX_TXTBREAK_PieceBreak) {
+        if (dwStatus > FX_TXTBREAK_PieceBreak)
           pLastPiece->m_dwStatus = dwStatus;
-        } else {
+        else
           dwStatus = pLastPiece->m_dwStatus;
-        }
         return dwStatus;
       }
       return FX_TXTBREAK_None;
     }
+
     iCount = m_pCurLine->CountChars();
-    if (iCount < 1) {
+    if (iCount < 1)
       return FX_TXTBREAK_None;
-    }
     if (!m_bPagination) {
       CFX_TxtChar* pTC = m_pCurLine->GetCharPtr(iCount - 1);
       pTC->m_dwStatus = dwStatus;
     }
-    if (dwStatus <= FX_TXTBREAK_PieceBreak) {
+    if (dwStatus <= FX_TXTBREAK_PieceBreak)
       return dwStatus;
-    }
   }
+
   m_iReady = (m_pCurLine == m_pTxtLine1.get()) ? 1 : 2;
   CFX_TxtLine* pNextLine =
       (m_pCurLine == m_pTxtLine1.get()) ? m_pTxtLine2.get() : m_pTxtLine1.get();
   bool bAllChars = (m_iCurAlignment > FX_TXTLINEALIGNMENT_Right);
-  CFX_TPOArray tpos(100);
-  CFX_Char* pTC;
-  if (m_bArabicShapes) {
+  if (m_bArabicShapes)
     EndBreak_UpdateArabicShapes();
+
+  if (!EndBreak_SplitLine(pNextLine, bAllChars, dwStatus)) {
+    std::deque<FX_TPO> tpos;
+    EndBreak_BidiLine(&tpos, dwStatus);
+    if (!m_bPagination && m_iCurAlignment > FX_TXTLINEALIGNMENT_Left)
+      EndBreak_Alignment(tpos, bAllChars, dwStatus);
   }
-  if (EndBreak_SplitLine(pNextLine, bAllChars, dwStatus)) {
-    goto EndBreak_Ret;
-  }
-  EndBreak_BidiLine(tpos, dwStatus);
-  if (!m_bPagination && m_iCurAlignment > FX_TXTLINEALIGNMENT_Left) {
-    EndBreak_Alignment(tpos, bAllChars, dwStatus);
-  }
-EndBreak_Ret:
+
   m_pCurLine = pNextLine;
-  pTC = GetLastChar(0, false);
+  CFX_Char* pTC = GetLastChar(0, false);
   m_eCharType = pTC ? pTC->GetCharType() : FX_CHARTYPE_Unknown;
   if (dwStatus == FX_TXTBREAK_ParagraphBreak) {
     m_iArabicContext = m_iCurArabicContext = 1;
@@ -1006,68 +955,71 @@
   return dwStatus;
 }
 
-int32_t CFX_TxtBreak::GetBreakPos(CFX_TxtCharArray& ca,
+int32_t CFX_TxtBreak::GetBreakPos(std::vector<CFX_TxtChar>& ca,
                                   int32_t& iEndPos,
                                   bool bAllChars,
                                   bool bOnlyBrk) {
-  int32_t iLength = ca.GetSize() - 1;
-  if (iLength < 1) {
+  int32_t iLength = pdfium::CollectionSize<int32_t>(ca) - 1;
+  if (iLength < 1)
     return iLength;
-  }
-  int32_t iBreak = -1, iBreakPos = -1, iIndirect = -1, iIndirectPos = -1,
-          iLast = -1, iLastPos = -1;
+
+  int32_t iBreak = -1;
+  int32_t iBreakPos = -1;
+  int32_t iIndirect = -1;
+  int32_t iIndirectPos = -1;
+  int32_t iLast = -1;
+  int32_t iLastPos = -1;
   if (m_bSingleLine || iEndPos <= m_iLineWidth) {
-    if (!bAllChars) {
+    if (!bAllChars)
       return iLength;
-    }
+
     iBreak = iLength;
     iBreakPos = iEndPos;
   }
+
   bool bSpaceBreak = (m_dwPolicies & FX_TXTBREAKPOLICY_SpaceBreak) != 0;
   bool bNumberBreak = (m_dwPolicies & FX_TXTBREAKPOLICY_NumberBreak) != 0;
   FX_LINEBREAKTYPE eType;
-  uint32_t nCodeProp, nCur, nNext;
-  CFX_Char* pCur = ca.GetDataPtr(iLength--);
-  if (bAllChars) {
+  uint32_t nCodeProp;
+  uint32_t nCur;
+  uint32_t nNext;
+  CFX_Char* pCur = &ca[iLength--];
+  if (bAllChars)
     pCur->m_nBreakType = FX_LBT_UNKNOWN;
-  }
+
   nCodeProp = pCur->m_dwCharProps;
   nNext = nCodeProp & 0x003F;
   int32_t iCharWidth = pCur->m_iCharWidth;
-  if (iCharWidth > 0) {
+  if (iCharWidth > 0)
     iEndPos -= iCharWidth;
-  }
+
   while (iLength >= 0) {
-    pCur = ca.GetDataPtr(iLength);
+    pCur = &ca[iLength];
     nCodeProp = pCur->m_dwCharProps;
     nCur = nCodeProp & 0x003F;
     if (nCur == FX_CBP_SP) {
-      if (nNext == FX_CBP_SP) {
+      if (nNext == FX_CBP_SP)
         eType = bSpaceBreak ? FX_LBT_DIRECT_BRK : FX_LBT_PROHIBITED_BRK;
-      } else {
+      else
         eType = gs_FX_LineBreak_PairTable[nCur][nNext];
-      }
     } else if (bNumberBreak && nCur == FX_CBP_NU && nNext == FX_CBP_NU) {
       eType = FX_LBT_DIRECT_BRK;
     } else {
-      if (nNext == FX_CBP_SP) {
+      if (nNext == FX_CBP_SP)
         eType = FX_LBT_PROHIBITED_BRK;
-      } else {
+      else
         eType = gs_FX_LineBreak_PairTable[nCur][nNext];
-      }
     }
-    if (bAllChars) {
-      pCur->m_nBreakType = (uint8_t)eType;
-    }
+    if (bAllChars)
+      pCur->m_nBreakType = static_cast<uint8_t>(eType);
     if (!bOnlyBrk) {
       if (m_bSingleLine || iEndPos <= m_iLineWidth ||
           (nCur == FX_CBP_SP && !bSpaceBreak)) {
         if (eType == FX_LBT_DIRECT_BRK && iBreak < 0) {
           iBreak = iLength;
           iBreakPos = iEndPos;
-          if (!bAllChars) {
+          if (!bAllChars)
             return iLength;
-          }
         } else if (eType == FX_LBT_INDIRECT_BRK && iIndirect < 0) {
           iIndirect = iLength;
           iIndirectPos = iEndPos;
@@ -1078,16 +1030,14 @@
         }
       }
       iCharWidth = pCur->m_iCharWidth;
-      if (iCharWidth > 0) {
+      if (iCharWidth > 0)
         iEndPos -= iCharWidth;
-      }
     }
     nNext = nCodeProp & 0x003F;
     iLength--;
   }
-  if (bOnlyBrk) {
+  if (bOnlyBrk)
     return 0;
-  }
   if (iBreak > -1) {
     iEndPos = iBreakPos;
     return iBreak;
@@ -1108,85 +1058,75 @@
                                  bool bAllChars) {
   ASSERT(pCurLine && pNextLine);
   int32_t iCount = pCurLine->CountChars();
-  if (iCount < 2) {
+  if (iCount < 2)
     return;
-  }
+
   int32_t iEndPos = pCurLine->m_iWidth;
-  CFX_TxtCharArray& curChars = *pCurLine->m_pLineChars.get();
+  std::vector<CFX_TxtChar>& curChars = *pCurLine->m_pLineChars;
   int32_t iCharPos = GetBreakPos(curChars, iEndPos, bAllChars, false);
-  if (iCharPos < 0) {
+  if (iCharPos < 0)
     iCharPos = 0;
-  }
+
   iCharPos++;
   if (iCharPos >= iCount) {
     pNextLine->RemoveAll(true);
-    CFX_Char* pTC = curChars.GetDataPtr(iCharPos - 1);
+    CFX_Char* pTC = &curChars[iCharPos - 1];
     pTC->m_nBreakType = FX_LBT_UNKNOWN;
     return;
   }
-  CFX_TxtCharArray& nextChars = *pNextLine->m_pLineChars.get();
-  int cur_size = curChars.GetSize();
-  nextChars.SetSize(cur_size - iCharPos);
-  FXSYS_memcpy(nextChars.GetData(), curChars.GetDataPtr(iCharPos),
-               (cur_size - iCharPos) * sizeof(CFX_TxtChar));
-  iCount -= iCharPos;
-  cur_size = curChars.GetSize();
-  curChars.RemoveAt(cur_size - iCount, iCount);
+
+  // m_pLineChars is a unique_ptr<vector>. Assign the ref into nextChars
+  // so we can change the m_pLineChars vector ...
+  std::vector<CFX_TxtChar>& nextChars = *pNextLine->m_pLineChars;
+  nextChars =
+      std::vector<CFX_TxtChar>(curChars.begin() + iCharPos, curChars.end());
+  curChars.erase(curChars.begin() + iCharPos, curChars.end());
   pCurLine->m_iWidth = iEndPos;
-  CFX_TxtChar* pTC = curChars.GetDataPtr(iCharPos - 1);
+  CFX_TxtChar* pTC = &curChars[iCharPos - 1];
   pTC->m_nBreakType = FX_LBT_UNKNOWN;
-  iCount = nextChars.GetSize();
-  int32_t iCharWidth, iWidth = 0;
+  iCount = pdfium::CollectionSize<int>(nextChars);
+  int32_t iWidth = 0;
   for (int32_t i = 0; i < iCount; i++) {
-    pTC = nextChars.GetDataPtr(i);
-    if (pTC->GetCharType() >= FX_CHARTYPE_ArabicAlef) {
+    if (nextChars[i].GetCharType() >= FX_CHARTYPE_ArabicAlef) {
       pCurLine->m_iArabicChars--;
       pNextLine->m_iArabicChars++;
     }
-    iCharWidth = pTC->m_iCharWidth;
-    if (iCharWidth > 0) {
+    int32_t iCharWidth = nextChars[i].m_iCharWidth;
+    if (iCharWidth > 0)
       iWidth += iCharWidth;
-    }
-    if (m_bPagination) {
+    if (m_bPagination)
       continue;
-    }
-    pTC->m_dwStatus = 0;
+
+    nextChars[i].m_dwStatus = 0;
   }
   pNextLine->m_iWidth = iWidth;
 }
 
-int32_t CFX_TxtBreak::CountBreakChars() const {
-  CFX_TxtLine* pTxtLine = GetTxtLine(true);
-  return pTxtLine ? pTxtLine->CountChars() : 0;
-}
-
 int32_t CFX_TxtBreak::CountBreakPieces() const {
-  CFX_TxtPieceArray* pTxtPieces = GetTxtPieces(true);
+  CFX_TxtPieceArray* pTxtPieces = GetTxtPieces();
   return pTxtPieces ? pTxtPieces->GetSize() : 0;
 }
 
 const CFX_TxtPiece* CFX_TxtBreak::GetBreakPiece(int32_t index) const {
-  CFX_TxtPieceArray* pTxtPieces = GetTxtPieces(true);
-  if (!pTxtPieces) {
+  CFX_TxtPieceArray* pTxtPieces = GetTxtPieces();
+  if (!pTxtPieces)
     return nullptr;
-  }
-  if (index < 0 || index >= pTxtPieces->GetSize()) {
+  if (index < 0 || index >= pTxtPieces->GetSize())
     return nullptr;
-  }
   return pTxtPieces->GetPtrAt(index);
 }
 
 void CFX_TxtBreak::ClearBreakPieces() {
-  CFX_TxtLine* pTxtLine = GetTxtLine(true);
-  if (pTxtLine) {
+  CFX_TxtLine* pTxtLine = GetTxtLine();
+  if (pTxtLine)
     pTxtLine->RemoveAll(true);
-  }
   m_iReady = 0;
 }
 
 void CFX_TxtBreak::Reset() {
   m_eCharType = FX_CHARTYPE_Unknown;
-  m_iArabicContext = m_iCurArabicContext = 1;
+  m_iArabicContext = 1;
+  m_iCurArabicContext = 1;
   ResetArabicContext();
   m_pTxtLine1->RemoveAll(true);
   m_pTxtLine2->RemoveAll(true);
@@ -1201,11 +1141,10 @@
 int32_t CFX_TxtBreak::GetDisplayPos(const FX_TXTRUN* pTxtRun,
                                     FXTEXT_CHARPOS* pCharPos,
                                     bool bCharCode,
-                                    CFX_WideString* pWSForms,
-                                    FX_AdjustCharDisplayPos pAdjustPos) const {
-  if (!pTxtRun || pTxtRun->iLength < 1) {
+                                    CFX_WideString* pWSForms) const {
+  if (!pTxtRun || pTxtRun->iLength < 1)
     return 0;
-  }
+
   IFX_TxtAccess* pAccess = pTxtRun->pAccess;
   const FDE_TEXTEDITPIECE* pIdentity = pTxtRun->pIdentity;
   const FX_WCHAR* pStr = pTxtRun->wsStr.c_str();
@@ -1230,24 +1169,28 @@
   bool bVerticalDoc = (dwStyles & FX_TXTLAYOUTSTYLE_VerticalLayout) != 0;
   bool bVerticalChar = (dwStyles & FX_TXTLAYOUTSTYLE_VerticalChars) != 0;
   int32_t iRotation = GetLineRotation(dwStyles) + pTxtRun->iCharRotation;
-  FX_FLOAT fX, fY, fCharWidth, fCharHeight;
+  FX_FLOAT fX = rtText.left;
+  FX_FLOAT fY;
+  FX_FLOAT fCharWidth;
+  FX_FLOAT fCharHeight;
   int32_t iHorScale = pTxtRun->iHorizontalScale;
   int32_t iVerScale = pTxtRun->iVerticalScale;
   bool bSkipSpace = pTxtRun->bSkipSpace;
   FX_FORMCHAR formChars[3];
   FX_FLOAT fYBase;
-  fX = rtText.left;
+
   if (bVerticalDoc) {
     fX += (rtText.width - fFontSize) / 2.0f;
     fYBase = bRTLPiece ? rtText.bottom() : rtText.top;
     fY = fYBase;
   } else {
-    if (bRTLPiece) {
+    if (bRTLPiece)
       fX = rtText.right();
-    }
+
     fYBase = rtText.top + (rtText.height - fFontSize) / 2.0f;
     fY = fYBase + fAscent;
   }
+
   int32_t iCount = 0;
   int32_t iNext = 0;
   FX_WCHAR wPrev = 0xFEFF;
@@ -1266,6 +1209,7 @@
       wch = *pStr++;
       iWidth = *pWidths++;
     }
+
     uint32_t dwProps = FX_GetUnicodeProperties(wch);
     FX_CHARTYPE chartype = GetCharTypeFromProp(dwProps);
     if (chartype == FX_CHARTYPE_ArabicAlef && iWidth == 0) {
@@ -1273,6 +1217,7 @@
       wLast = wch;
       continue;
     }
+
     if (chartype >= FX_CHARTYPE_ArabicAlef) {
       if (i < iLength) {
         if (pAccess) {
@@ -1280,31 +1225,30 @@
           while (iNext <= iLength) {
             wNext = pAccess->GetChar(pIdentity, iNext);
             dwProps = FX_GetUnicodeProperties(wNext);
-            if ((dwProps & FX_CHARTYPEBITSMASK) != FX_CHARTYPE_Combination) {
+            if ((dwProps & FX_CHARTYPEBITSMASK) != FX_CHARTYPE_Combination)
               break;
-            }
+
             iNext++;
           }
-          if (iNext > iLength) {
+          if (iNext > iLength)
             wNext = 0xFEFF;
-          }
         } else {
           int32_t j = -1;
           do {
             j++;
-            if (i + j >= iLength) {
+            if (i + j >= iLength)
               break;
-            }
+
             wNext = pStr[j];
             dwProps = FX_GetUnicodeProperties(wNext);
           } while ((dwProps & FX_CHARTYPEBITSMASK) == FX_CHARTYPE_Combination);
-          if (i + j >= iLength) {
+          if (i + j >= iLength)
             wNext = 0xFEFF;
-          }
         }
       } else {
         wNext = 0xFEFF;
       }
+
       wForm = pdfium::arabic::GetFormChar(wch, wPrev, wNext);
       bLam = (wPrev == 0x0644 && wch == 0x0644 && wNext == 0x0647);
     } else if (chartype == FX_CHARTYPE_Combination) {
@@ -1317,13 +1261,11 @@
           wNext = 0xFEFF;
           if (pAccess) {
             iNext = i + 1;
-            if (iNext <= iLength) {
+            if (iNext <= iLength)
               wNext = pAccess->GetChar(pIdentity, iNext);
-            }
           } else {
-            if (i < iLength) {
+            if (i < iLength)
               wNext = *pStr;
-            }
           }
           if (wch == 0x0651) {
             if (wNext >= 0x064C && wNext <= 0x0650) {
@@ -1342,67 +1284,61 @@
       }
     } else if (chartype == FX_CHARTYPE_Numeric) {
       wForm = wch;
-      if (bArabicNumber) {
+      if (bArabicNumber)
         wForm += 0x0630;
-      }
     } else if (wch == L'.') {
       wForm = wch;
       if (bArabicNumber) {
         wNext = 0xFEFF;
         if (pAccess) {
           iNext = i + 1;
-          if (iNext <= iLength) {
+          if (iNext <= iLength)
             wNext = pAccess->GetChar(pIdentity, iNext);
-          }
         } else {
-          if (i < iLength) {
+          if (i < iLength)
             wNext = *pStr;
-          }
         }
-        if (wNext >= L'0' && wNext <= L'9') {
+        if (wNext >= L'0' && wNext <= L'9')
           wForm = 0x066B;
-        }
       }
     } else if (wch == L',') {
       wForm = wch;
-      if (bArabicComma) {
+      if (bArabicComma)
         wForm = 0x060C;
-      }
     } else if (bRTLPiece || bVerticalChar) {
       wForm = FX_GetMirrorChar(wch, dwProps, bRTLPiece, bVerticalChar);
     } else {
       wForm = wch;
     }
-    if (chartype != FX_CHARTYPE_Combination) {
+    if (chartype != FX_CHARTYPE_Combination)
       bShadda = false;
-    }
-    if (chartype < FX_CHARTYPE_ArabicAlef) {
+    if (chartype < FX_CHARTYPE_ArabicAlef)
       bLam = false;
-    }
+
     dwProps = FX_GetUnicodeProperties(wForm);
     int32_t iCharRotation = iRotation;
-    if (bVerticalChar && (dwProps & 0x8000) != 0) {
+    if (bVerticalChar && (dwProps & 0x8000) != 0)
       iCharRotation++;
-    }
+
     iCharRotation %= 4;
     bool bEmptyChar =
         (chartype >= FX_CHARTYPE_Tab && chartype <= FX_CHARTYPE_Control);
-    if (wForm == 0xFEFF) {
+    if (wForm == 0xFEFF)
       bEmptyChar = true;
-    }
+
     int32_t iForms = bLam ? 3 : 1;
     iCount += (bEmptyChar && bSkipSpace) ? 0 : iForms;
     if (!pCharPos) {
-      if (iWidth > 0) {
+      if (iWidth > 0)
         wPrev = wch;
-      }
       wLast = wch;
       continue;
     }
+
     int32_t iCharWidth = iWidth;
-    if (iCharWidth < 0) {
+    if (iCharWidth < 0)
       iCharWidth = -iCharWidth;
-    }
+
     iCharWidth /= iFontSize;
     formChars[0].wch = wch;
     formChars[0].wForm = wForm;
@@ -1417,6 +1353,7 @@
       pFont->GetCharWidth(0x0670, iCharWidth, false);
       formChars[2].iWidth = iCharWidth;
     }
+
     for (int32_t j = 0; j < iForms; j++) {
       wForm = (FX_WCHAR)formChars[j].wForm;
       iCharWidth = formChars[j].iWidth;
@@ -1432,10 +1369,10 @@
         pCharPos->m_ExtGID = pCharPos->m_GlyphIndex;
 #endif
         pCharPos->m_FontCharWidth = iCharWidth;
-        if (pWSForms) {
+        if (pWSForms)
           *pWSForms += wForm;
-        }
       }
+
       int32_t iCharHeight;
       if (bVerticalDoc) {
         iCharHeight = iCharWidth;
@@ -1443,33 +1380,31 @@
       } else {
         iCharHeight = 1000;
       }
+
       fCharWidth = fFontSize * iCharWidth / 1000.0f;
       fCharHeight = fFontSize * iCharHeight / 1000.0f;
       if (bRTLPiece && chartype != FX_CHARTYPE_Combination) {
-        if (bVerticalDoc) {
+        if (bVerticalDoc)
           fY -= fCharHeight;
-        } else {
+        else
           fX -= fCharWidth;
-        }
       }
       if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) {
-        pCharPos->m_OriginX = fX;
-        pCharPos->m_OriginY = fY;
+        pCharPos->m_Origin = CFX_PointF(fX, fY);
         if ((dwStyles & FX_TXTLAYOUTSTYLE_CombText) != 0) {
           int32_t iFormWidth = iCharWidth;
           pFont->GetCharWidth(wForm, iFormWidth, false);
           FX_FLOAT fOffset = fFontSize * (iCharWidth - iFormWidth) / 2000.0f;
-          if (bVerticalDoc) {
-            pCharPos->m_OriginY += fOffset;
-          } else {
-            pCharPos->m_OriginX += fOffset;
-          }
+          if (bVerticalDoc)
+            pCharPos->m_Origin.y += fOffset;
+          else
+            pCharPos->m_Origin.x += fOffset;
         }
+
         if (chartype == FX_CHARTYPE_Combination) {
           CFX_Rect rtBBox;
-          rtBBox.Reset();
           if (pFont->GetCharBBox(wForm, &rtBBox, false)) {
-            pCharPos->m_OriginY =
+            pCharPos->m_Origin.y =
                 fYBase + fFontSize -
                 fFontSize * (FX_FLOAT)rtBBox.height / (FX_FLOAT)iMaxHeight;
           }
@@ -1478,37 +1413,29 @@
             if ((dwLastProps & FX_CHARTYPEBITSMASK) ==
                 FX_CHARTYPE_Combination) {
               CFX_Rect rtBox;
-              rtBox.Reset();
-              if (pFont->GetCharBBox(wLast, &rtBox, false)) {
-                pCharPos->m_OriginY -= fFontSize * rtBox.height / iMaxHeight;
-              }
+              if (pFont->GetCharBBox(wLast, &rtBox, false))
+                pCharPos->m_Origin.y -= fFontSize * rtBox.height / iMaxHeight;
             }
           }
         }
         CFX_PointF ptOffset;
-        bool bAdjusted = false;
-        if (pAdjustPos) {
-          bAdjusted = pAdjustPos(wForm, bCharCode, pFont, fFontSize,
-                                 bVerticalChar, ptOffset);
-        }
-        if (!bAdjusted && bVerticalChar && (dwProps & 0x00010000) != 0) {
+        if (bVerticalChar && (dwProps & 0x00010000) != 0) {
           CFX_Rect rtBBox;
-          rtBBox.Reset();
           if (pFont->GetCharBBox(wForm, &rtBBox, false)) {
             ptOffset.x = fFontSize * (850 - rtBBox.right()) / iMaxHeight;
             ptOffset.y = fFontSize * (iAscent - rtBBox.top - 150) / iMaxHeight;
           }
         }
-        pCharPos->m_OriginX += ptOffset.x;
-        pCharPos->m_OriginY -= ptOffset.y;
+        pCharPos->m_Origin.x += ptOffset.x;
+        pCharPos->m_Origin.y -= ptOffset.y;
       }
       if (!bRTLPiece && chartype != FX_CHARTYPE_Combination) {
-        if (bVerticalDoc) {
+        if (bVerticalDoc)
           fY += fCharHeight;
-        } else {
+        else
           fX += fCharWidth;
-        }
       }
+
       if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) {
         pCharPos->m_bGlyphAdjust = true;
         if (bVerticalDoc) {
@@ -1517,26 +1444,26 @@
             pCharPos->m_AdjustMatrix[1] = 0;
             pCharPos->m_AdjustMatrix[2] = 0;
             pCharPos->m_AdjustMatrix[3] = 1;
-            pCharPos->m_OriginY += fAscent;
+            pCharPos->m_Origin.y += fAscent;
           } else if (iCharRotation == 1) {
             pCharPos->m_AdjustMatrix[0] = 0;
             pCharPos->m_AdjustMatrix[1] = -1;
             pCharPos->m_AdjustMatrix[2] = -1;
             pCharPos->m_AdjustMatrix[3] = 0;
-            pCharPos->m_OriginX -= fDescent;
+            pCharPos->m_Origin.x -= fDescent;
           } else if (iCharRotation == 2) {
             pCharPos->m_AdjustMatrix[0] = 1;
             pCharPos->m_AdjustMatrix[1] = 0;
             pCharPos->m_AdjustMatrix[2] = 0;
             pCharPos->m_AdjustMatrix[3] = -1;
-            pCharPos->m_OriginX += fCharWidth;
-            pCharPos->m_OriginY += fAscent;
+            pCharPos->m_Origin.x += fCharWidth;
+            pCharPos->m_Origin.y += fAscent;
           } else {
             pCharPos->m_AdjustMatrix[0] = 0;
             pCharPos->m_AdjustMatrix[1] = 1;
             pCharPos->m_AdjustMatrix[2] = 1;
             pCharPos->m_AdjustMatrix[3] = 0;
-            pCharPos->m_OriginX += fAscent;
+            pCharPos->m_Origin.x += fAscent;
           }
         } else {
           if (iCharRotation == 0) {
@@ -1549,21 +1476,21 @@
             pCharPos->m_AdjustMatrix[1] = -1;
             pCharPos->m_AdjustMatrix[2] = -1;
             pCharPos->m_AdjustMatrix[3] = 0;
-            pCharPos->m_OriginX -= fDescent;
-            pCharPos->m_OriginY -= fAscent + fDescent;
+            pCharPos->m_Origin.x -= fDescent;
+            pCharPos->m_Origin.y -= fAscent + fDescent;
           } else if (iCharRotation == 2) {
             pCharPos->m_AdjustMatrix[0] = 1;
             pCharPos->m_AdjustMatrix[1] = 0;
             pCharPos->m_AdjustMatrix[2] = 0;
             pCharPos->m_AdjustMatrix[3] = -1;
-            pCharPos->m_OriginX += fCharWidth;
-            pCharPos->m_OriginY -= fAscent;
+            pCharPos->m_Origin.x += fCharWidth;
+            pCharPos->m_Origin.y -= fAscent;
           } else {
             pCharPos->m_AdjustMatrix[0] = 0;
             pCharPos->m_AdjustMatrix[1] = 1;
             pCharPos->m_AdjustMatrix[2] = 1;
             pCharPos->m_AdjustMatrix[3] = 0;
-            pCharPos->m_OriginX += fAscent;
+            pCharPos->m_Origin.x += fAscent;
           }
         }
         if (iHorScale != 100 || iVerScale != 100) {
@@ -1579,19 +1506,17 @@
         pCharPos++;
       }
     }
-    if (iWidth > 0) {
-      wPrev = (FX_WCHAR)formChars[0].wch;
-    }
+    if (iWidth > 0)
+      wPrev = static_cast<FX_WCHAR>(formChars[0].wch);
     wLast = wch;
   }
   return iCount;
 }
 
-int32_t CFX_TxtBreak::GetCharRects(const FX_TXTRUN* pTxtRun,
-                                   CFX_RectFArray& rtArray,
-                                   bool bCharBBox) const {
+std::vector<CFX_RectF> CFX_TxtBreak::GetCharRects(const FX_TXTRUN* pTxtRun,
+                                                  bool bCharBBox) const {
   if (!pTxtRun || pTxtRun->iLength < 1)
-    return 0;
+    return std::vector<CFX_RectF>();
 
   IFX_TxtAccess* pAccess = pTxtRun->pAccess;
   const FDE_TEXTEDITPIECE* pIdentity = pTxtRun->pIdentity;
@@ -1599,7 +1524,6 @@
   int32_t* pWidths = pTxtRun->pWidths;
   int32_t iLength = pTxtRun->iLength;
   CFX_RectF rect(*pTxtRun->pRect);
-  bool bRTLPiece = (pTxtRun->dwCharStyles & FX_TXTCHARSTYLE_OddBidiLevel) != 0;
   FX_FLOAT fFontSize = pTxtRun->fFontSize;
   int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
   FX_FLOAT fScale = fFontSize / 1000.0f;
@@ -1608,25 +1532,26 @@
     bCharBBox = false;
 
   CFX_Rect bbox;
-  bbox.Set(0, 0, 0, 0);
   if (bCharBBox)
     bCharBBox = pFont->GetBBox(&bbox);
 
   FX_FLOAT fLeft = std::max(0.0f, bbox.left * fScale);
   FX_FLOAT fHeight = FXSYS_fabs(bbox.height * fScale);
-  rtArray.RemoveAll();
-  rtArray.SetSize(iLength);
-  bool bVertical = (pTxtRun->dwStyles & FX_TXTLAYOUTSTYLE_VerticalLayout) != 0;
-  bool bSingleLine = (pTxtRun->dwStyles & FX_TXTLAYOUTSTYLE_SingleLine) != 0;
-  bool bCombText = (pTxtRun->dwStyles & FX_TXTLAYOUTSTYLE_CombText) != 0;
-  FX_WCHAR wch, wLineBreakChar = pTxtRun->wLineBreakChar;
+  bool bRTLPiece = !!(pTxtRun->dwCharStyles & FX_TXTCHARSTYLE_OddBidiLevel);
+  bool bVertical = !!(pTxtRun->dwStyles & FX_TXTLAYOUTSTYLE_VerticalLayout);
+  bool bSingleLine = !!(pTxtRun->dwStyles & FX_TXTLAYOUTSTYLE_SingleLine);
+  bool bCombText = !!(pTxtRun->dwStyles & FX_TXTLAYOUTSTYLE_CombText);
+  FX_WCHAR wch;
+  FX_WCHAR wLineBreakChar = pTxtRun->wLineBreakChar;
   int32_t iCharSize;
-  FX_FLOAT fCharSize, fStart;
-  if (bVertical) {
+  FX_FLOAT fCharSize;
+  FX_FLOAT fStart;
+  if (bVertical)
     fStart = bRTLPiece ? rect.bottom() : rect.top;
-  } else {
+  else
     fStart = bRTLPiece ? rect.right() : rect.left;
-  }
+
+  std::vector<CFX_RectF> rtArray(iLength);
   for (int32_t i = 0; i < iLength; i++) {
     if (pAccess) {
       wch = pAccess->GetChar(pIdentity, i);
@@ -1635,7 +1560,7 @@
       wch = *pStr++;
       iCharSize = *pWidths++;
     }
-    fCharSize = (FX_FLOAT)iCharSize / 20000.0f;
+    fCharSize = static_cast<FX_FLOAT>(iCharSize) / 20000.0f;
     bool bRet = (!bSingleLine && FX_IsCtrlCode(wch));
     if (!(wch == L'\v' || wch == L'\f' || wch == 0x2028 || wch == 0x2029 ||
           (wLineBreakChar != 0xFEFF && wch == wLineBreakChar))) {
@@ -1664,6 +1589,7 @@
       }
       rect.width = fCharSize;
     }
+
     if (bCharBBox && !bRet) {
       int32_t iCharWidth = 1000;
       pFont->GetCharWidth(wch, iCharWidth, false);
@@ -1671,9 +1597,8 @@
       if (iCharWidth > 0) {
         fCharWidth = iCharWidth * fScale;
         fRTLeft = fLeft;
-        if (bCombText) {
+        if (bCombText)
           fRTLeft = (rect.width - fCharWidth) / 2.0f;
-        }
       }
       CFX_RectF rtBBoxF;
       if (bVertical) {
@@ -1689,12 +1614,12 @@
         rtBBoxF.height = fHeight;
         rtBBoxF.top = std::max(rtBBoxF.top, 0.0f);
       }
-      rtArray.SetAt(i, rtBBoxF);
+      rtArray[i] = rtBBoxF;
       continue;
     }
-    rtArray.SetAt(i, rect);
+    rtArray[i] = rect;
   }
-  return iLength;
+  return rtArray;
 }
 
 FX_TXTRUN::FX_TXTRUN()
@@ -1732,7 +1657,7 @@
       m_pUserData(nullptr) {}
 
 CFX_TxtLine::CFX_TxtLine(int32_t iBlockSize)
-    : m_pLineChars(new CFX_TxtCharArray),
+    : m_pLineChars(new std::vector<CFX_TxtChar>),
       m_pLinePieces(new CFX_TxtPieceArray(16)),
       m_iStart(0),
       m_iWidth(0),
diff --git a/xfa/fgas/layout/fgas_textbreak.h b/xfa/fgas/layout/fgas_textbreak.h
index 7359600..69ca835 100644
--- a/xfa/fgas/layout/fgas_textbreak.h
+++ b/xfa/fgas/layout/fgas_textbreak.h
@@ -7,18 +7,21 @@
 #ifndef XFA_FGAS_LAYOUT_FGAS_TEXTBREAK_H_
 #define XFA_FGAS_LAYOUT_FGAS_TEXTBREAK_H_
 
+#include <deque>
 #include <memory>
+#include <vector>
 
 #include "core/fxcrt/fx_ucd.h"
 #include "core/fxge/cfx_renderdevice.h"
+#include "third_party/base/stl_util.h"
 #include "xfa/fgas/crt/fgas_utils.h"
-#include "xfa/fgas/layout/fgas_unicode.h"
 
 class CFX_Char;
 class CFGAS_GEFont;
 class CFX_TxtChar;
 class CFX_TxtPiece;
 class IFX_TxtAccess;
+struct FDE_TEXTEDITPIECE;
 
 #define FX_TXTBREAKPOLICY_None 0x00
 #define FX_TXTBREAKPOLICY_Pagination 0x01
@@ -72,7 +75,12 @@
 #define FX_TXTLINEALIGNMENT_HigherMask 0x0C
 #define FX_TXTBREAK_MinimumTabWidth 160000
 
-struct FDE_TEXTEDITPIECE;
+struct FX_TPO {
+  int32_t index;
+  int32_t pos;
+
+  bool operator<(const FX_TPO& that) const { return pos < that.pos; }
+};
 
 class IFX_TxtAccess {
  public:
@@ -116,16 +124,13 @@
   int32_t GetEndChar() const { return m_iStartChar + m_iChars; }
   CFX_TxtChar* GetCharPtr(int32_t index) const {
     ASSERT(index > -1 && index < m_iChars && m_pChars);
-    return m_pChars->GetDataPtr(m_iStartChar + index);
+    return &(*m_pChars)[m_iStartChar + index];
   }
   void GetString(FX_WCHAR* pText) const {
     ASSERT(pText);
     int32_t iEndChar = m_iStartChar + m_iChars;
-    CFX_Char* pChar;
-    for (int32_t i = m_iStartChar; i < iEndChar; i++) {
-      pChar = m_pChars->GetDataPtr(i);
-      *pText++ = (FX_WCHAR)pChar->m_wCharCode;
-    }
+    for (int32_t i = m_iStartChar; i < iEndChar; i++)
+      *pText++ = static_cast<FX_WCHAR>((*m_pChars)[i].m_wCharCode);
   }
   void GetString(CFX_WideString& wsText) const {
     FX_WCHAR* pText = wsText.GetBuffer(m_iChars);
@@ -135,11 +140,8 @@
   void GetWidths(int32_t* pWidths) const {
     ASSERT(pWidths);
     int32_t iEndChar = m_iStartChar + m_iChars;
-    CFX_Char* pChar;
-    for (int32_t i = m_iStartChar; i < iEndChar; i++) {
-      pChar = m_pChars->GetDataPtr(i);
-      *pWidths++ = pChar->m_iCharWidth;
-    }
+    for (int32_t i = m_iStartChar; i < iEndChar; i++)
+      *pWidths++ = (*m_pChars)[i].m_iCharWidth;
   }
 
   uint32_t m_dwStatus;
@@ -152,7 +154,7 @@
   int32_t m_iHorizontalScale;
   int32_t m_iVerticalScale;
   uint32_t m_dwCharStyles;
-  CFX_TxtCharArray* m_pChars;
+  std::vector<CFX_TxtChar>* m_pChars;
   void* m_pUserData;
 };
 
@@ -163,34 +165,38 @@
   explicit CFX_TxtLine(int32_t iBlockSize);
   ~CFX_TxtLine();
 
-  int32_t CountChars() const { return m_pLineChars->GetSize(); }
-  CFX_TxtChar* GetCharPtr(int32_t index) const {
-    ASSERT(index > -1 && index < m_pLineChars->GetSize());
-    return m_pLineChars->GetDataPtr(index);
+  int32_t CountChars() const {
+    return pdfium::CollectionSize<int32_t>(*m_pLineChars);
   }
+
+  CFX_TxtChar* GetCharPtr(int32_t index) const {
+    ASSERT(index >= 0 &&
+           index < pdfium::CollectionSize<int32_t>(*m_pLineChars));
+    return &(*m_pLineChars)[index];
+  }
+
   int32_t CountPieces() const { return m_pLinePieces->GetSize(); }
   CFX_TxtPiece* GetPiecePtr(int32_t index) const {
     ASSERT(index > -1 && index < m_pLinePieces->GetSize());
     return m_pLinePieces->GetPtrAt(index);
   }
+
   void GetString(CFX_WideString& wsStr) const {
-    int32_t iCount = m_pLineChars->GetSize();
+    int32_t iCount = pdfium::CollectionSize<int32_t>(*m_pLineChars);
     FX_WCHAR* pBuf = wsStr.GetBuffer(iCount);
-    CFX_Char* pChar;
-    for (int32_t i = 0; i < iCount; i++) {
-      pChar = m_pLineChars->GetDataPtr(i);
-      *pBuf++ = (FX_WCHAR)pChar->m_wCharCode;
-    }
+    for (int32_t i = 0; i < iCount; i++)
+      *pBuf++ = static_cast<FX_WCHAR>((*m_pLineChars)[i].m_wCharCode);
     wsStr.ReleaseBuffer(iCount);
   }
+
   void RemoveAll(bool bLeaveMemory = false) {
-    m_pLineChars->RemoveAll();
+    m_pLineChars->clear();
     m_pLinePieces->RemoveAll(bLeaveMemory);
     m_iWidth = 0;
     m_iArabicChars = 0;
   }
 
-  std::unique_ptr<CFX_TxtCharArray> m_pLineChars;
+  std::unique_ptr<std::vector<CFX_TxtChar>> m_pLineChars;
   std::unique_ptr<CFX_TxtPieceArray> m_pLinePieces;
   int32_t m_iStart;
   int32_t m_iWidth;
@@ -213,17 +219,13 @@
   void SetParagraphBreakChar(FX_WCHAR wch);
   void SetLineBreakTolerance(FX_FLOAT fTolerance);
   void SetHorizontalScale(int32_t iScale);
-  void SetVerticalScale(int32_t iScale);
   void SetCharRotation(int32_t iCharRotation);
   void SetCharSpace(FX_FLOAT fCharSpace);
   void SetAlignment(int32_t iAlignment);
-  uint32_t GetContextCharStyles() const;
-  void SetContextCharStyles(uint32_t dwCharStyles);
   void SetCombWidth(FX_FLOAT fCombWidth);
   void SetUserData(void* pUserData);
   uint32_t AppendChar(FX_WCHAR wch);
   uint32_t EndBreak(uint32_t dwStatus = FX_TXTBREAK_PieceBreak);
-  int32_t CountBreakChars() const;
   int32_t CountBreakPieces() const;
   const CFX_TxtPiece* GetBreakPiece(int32_t index) const;
   void ClearBreakPieces();
@@ -231,11 +233,9 @@
   int32_t GetDisplayPos(const FX_TXTRUN* pTxtRun,
                         FXTEXT_CHARPOS* pCharPos,
                         bool bCharCode = false,
-                        CFX_WideString* pWSForms = nullptr,
-                        FX_AdjustCharDisplayPos pAdjustPos = nullptr) const;
-  int32_t GetCharRects(const FX_TXTRUN* pTxtRun,
-                       CFX_RectFArray& rtArray,
-                       bool bCharBBox = false) const;
+                        CFX_WideString* pWSForms = nullptr) const;
+  std::vector<CFX_RectF> GetCharRects(const FX_TXTRUN* pTxtRun,
+                                      bool bCharBBox = false) const;
   void AppendChar_PageLoad(CFX_TxtChar* pCurChar, uint32_t dwProps);
   uint32_t AppendChar_Combination(CFX_TxtChar* pCurChar, int32_t iRotation);
   uint32_t AppendChar_Tab(CFX_TxtChar* pCurChar, int32_t iRotation);
@@ -244,11 +244,12 @@
   uint32_t AppendChar_Others(CFX_TxtChar* pCurChar, int32_t iRotation);
 
  private:
+  void FontChanged();
   void SetBreakStatus();
   int32_t GetLineRotation(uint32_t dwStyles) const;
   CFX_TxtChar* GetLastChar(int32_t index, bool bOmitChar = true) const;
-  CFX_TxtLine* GetTxtLine(bool bReady) const;
-  CFX_TxtPieceArray* GetTxtPieces(bool bReady) const;
+  CFX_TxtLine* GetTxtLine() const;
+  CFX_TxtPieceArray* GetTxtPieces() const;
   FX_CHARTYPE GetUnifiedCharType(FX_CHARTYPE dwType) const;
   void ResetArabicContext();
   void ResetContextCharStyles();
@@ -256,11 +257,11 @@
   bool EndBreak_SplitLine(CFX_TxtLine* pNextLine,
                           bool bAllChars,
                           uint32_t dwStatus);
-  void EndBreak_BidiLine(CFX_TPOArray& tpos, uint32_t dwStatus);
-  void EndBreak_Alignment(CFX_TPOArray& tpos,
+  void EndBreak_BidiLine(std::deque<FX_TPO>* tpos, uint32_t dwStatus);
+  void EndBreak_Alignment(const std::deque<FX_TPO>& tpos,
                           bool bAllChars,
                           uint32_t dwStatus);
-  int32_t GetBreakPos(CFX_TxtCharArray& ca,
+  int32_t GetBreakPos(std::vector<CFX_TxtChar>& ca,
                       int32_t& iEndPos,
                       bool bAllChars = false,
                       bool bOnlyBrk = false);
@@ -305,7 +306,6 @@
   int32_t m_iReady;
   int32_t m_iTolerance;
   int32_t m_iHorScale;
-  int32_t m_iVerScale;
   int32_t m_iCharSpace;
 };
 
diff --git a/xfa/fgas/layout/fgas_unicode.cpp b/xfa/fgas/layout/fgas_unicode.cpp
deleted file mode 100644
index 10fdbf0..0000000
--- a/xfa/fgas/layout/fgas_unicode.cpp
+++ /dev/null
@@ -1,49 +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/fgas_unicode.h"
-
-void FX_TEXTLAYOUT_PieceSort(CFX_TPOArray& tpos, int32_t iStart, int32_t iEnd) {
-  ASSERT(iStart > -1 && iStart < tpos.GetSize());
-  ASSERT(iEnd > -1 && iEnd < tpos.GetSize());
-  if (iStart >= iEnd) {
-    return;
-  }
-  int32_t i = iStart, j = iEnd;
-  FX_TPO *pCur = tpos.GetPtrAt(iStart), *pSort;
-  int32_t v = pCur->pos;
-  while (i < j) {
-    while (j > i) {
-      pSort = tpos.GetPtrAt(j);
-      if (pSort->pos < v) {
-        FX_TPO t = *pSort;
-        *pSort = *pCur;
-        *pCur = t;
-        pCur = pSort;
-        break;
-      }
-      j--;
-    }
-    while (i < j) {
-      pSort = tpos.GetPtrAt(i);
-      if (pSort->pos > v) {
-        FX_TPO t = *pSort;
-        *pSort = *pCur;
-        *pCur = t;
-        pCur = pSort;
-        break;
-      }
-      i++;
-    }
-  }
-  i--, j++;
-  if (iStart < i) {
-    FX_TEXTLAYOUT_PieceSort(tpos, iStart, i);
-  }
-  if (j < iEnd) {
-    FX_TEXTLAYOUT_PieceSort(tpos, j, iEnd);
-  }
-}
diff --git a/xfa/fgas/layout/fgas_unicode.h b/xfa/fgas/layout/fgas_unicode.h
deleted file mode 100644
index b404d67..0000000
--- a/xfa/fgas/layout/fgas_unicode.h
+++ /dev/null
@@ -1,29 +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_FGAS_UNICODE_H_
-#define XFA_FGAS_LAYOUT_FGAS_UNICODE_H_
-
-#include "xfa/fgas/crt/fgas_utils.h"
-#include "xfa/fgas/font/cfgas_fontmgr.h"
-
-struct FX_TPO {
-  int32_t index;
-  int32_t pos;
-};
-typedef CFX_MassArrayTemplate<FX_TPO> CFX_TPOArray;
-
-void FX_TEXTLAYOUT_PieceSort(CFX_TPOArray& tpos, int32_t iStart, int32_t iEnd);
-
-typedef bool (*FX_AdjustCharDisplayPos)(
-    FX_WCHAR wch,
-    bool bMBCSCode,
-    const CFX_RetainPtr<CFGAS_GEFont>& pFont,
-    FX_FLOAT fFontSize,
-    bool bVertical,
-    CFX_PointF& ptOffset);
-
-#endif  // XFA_FGAS_LAYOUT_FGAS_UNICODE_H_
diff --git a/xfa/fgas/localization/fgas_locale.cpp b/xfa/fgas/localization/fgas_locale.cpp
index d6ef628..7d53841 100644
--- a/xfa/fgas/localization/fgas_locale.cpp
+++ b/xfa/fgas/localization/fgas_locale.cpp
@@ -542,7 +542,7 @@
         wsCategory += pStr[ccf];
         ccf++;
       }
-      if (wsCategory != FX_WSTRC(L"num")) {
+      if (wsCategory != L"num") {
         bBrackOpen = true;
         ccf = 0;
         continue;
@@ -652,7 +652,7 @@
     return false;
   }
   CFX_WideString wsTextFormat;
-  GetTextFormat(wsPattern, FX_WSTRC(L"text"), wsTextFormat);
+  GetTextFormat(wsPattern, L"text", wsTextFormat);
   if (wsTextFormat.IsEmpty()) {
     return false;
   }
@@ -1942,16 +1942,16 @@
         wsCategory += pStr[ccf];
         ccf++;
       }
-      if (!(iFindCategory & 1) && wsCategory == FX_WSTRC(L"date")) {
+      if (!(iFindCategory & 1) && wsCategory == L"date") {
         iFindCategory |= 1;
         eCategory = FX_LOCALECATEGORY_Date;
         if (iFindCategory & 2) {
           iFindCategory = 4;
         }
-      } else if (!(iFindCategory & 2) && wsCategory == FX_WSTRC(L"time")) {
+      } else if (!(iFindCategory & 2) && wsCategory == L"time") {
         iFindCategory |= 2;
         eCategory = FX_LOCALECATEGORY_Time;
-      } else if (wsCategory == FX_WSTRC(L"datetime")) {
+      } else if (wsCategory == L"datetime") {
         iFindCategory = 3;
         eCategory = FX_LOCALECATEGORY_DateTime;
       } else {
@@ -2506,7 +2506,7 @@
 bool CFX_FormatString::ParseZero(const CFX_WideString& wsSrcText,
                                  const CFX_WideString& wsPattern) {
   CFX_WideString wsTextFormat;
-  GetTextFormat(wsPattern, FX_WSTRC(L"zero"), wsTextFormat);
+  GetTextFormat(wsPattern, L"zero", wsTextFormat);
   int32_t iText = 0, iPattern = 0;
   const FX_WCHAR* pStrText = wsSrcText.c_str();
   int32_t iLenText = wsSrcText.GetLength();
@@ -2536,7 +2536,7 @@
 bool CFX_FormatString::ParseNull(const CFX_WideString& wsSrcText,
                                  const CFX_WideString& wsPattern) {
   CFX_WideString wsTextFormat;
-  GetTextFormat(wsPattern, FX_WSTRC(L"null"), wsTextFormat);
+  GetTextFormat(wsPattern, L"null", wsTextFormat);
   int32_t iText = 0, iPattern = 0;
   const FX_WCHAR* pStrText = wsSrcText.c_str();
   int32_t iLenText = wsSrcText.GetLength();
@@ -2574,7 +2574,7 @@
     return false;
   }
   CFX_WideString wsTextFormat;
-  GetTextFormat(wsPattern, FX_WSTRC(L"text"), wsTextFormat);
+  GetTextFormat(wsPattern, L"text", wsTextFormat);
   int32_t iText = 0, iPattern = 0;
   const FX_WCHAR* pStrText = wsSrcText.c_str();
   const FX_WCHAR* pStrPattern = wsTextFormat.c_str();
@@ -3926,14 +3926,14 @@
       pLocale->GetMeridiemName(wsMeridiem, !bPM);
       wsResult += wsMeridiem;
     } else if (dwSymbol == FXBSTR_ID(0, 0, 'Z', '1')) {
-      wsResult += FX_WSTRC(L"GMT");
+      wsResult += L"GMT";
       FX_TIMEZONE tz;
       pLocale->GetTimeZone(&tz);
       if (!bGMT && (tz.tzHour != 0 || tz.tzMinute != 0)) {
         if (tz.tzHour < 0) {
-          wsResult += FX_WSTRC(L"-");
+          wsResult += L"-";
         } else {
-          wsResult += FX_WSTRC(L"+");
+          wsResult += L"+";
         }
         CFX_WideString wsTimezone;
         wsTimezone.Format(L"%02d:%02d", FXSYS_abs(tz.tzHour), tz.tzMinute);
@@ -3944,9 +3944,9 @@
       pLocale->GetTimeZone(&tz);
       if (!bGMT && tz.tzHour != 0 && tz.tzMinute != 0) {
         if (tz.tzHour < 0) {
-          wsResult += FX_WSTRC(L"-");
+          wsResult += L"-";
         } else {
-          wsResult += FX_WSTRC(L"+");
+          wsResult += L"+";
         }
         CFX_WideString wsTimezone;
         wsTimezone.Format(L"%02d:%02d", FXSYS_abs(tz.tzHour), tz.tzMinute);
@@ -4079,7 +4079,7 @@
     return false;
   }
   CFX_WideString wsTextFormat;
-  GetTextFormat(wsPattern, FX_WSTRC(L"zero"), wsTextFormat);
+  GetTextFormat(wsPattern, L"zero", wsTextFormat);
   int32_t iPattern = 0;
   const FX_WCHAR* pStrPattern = wsTextFormat.c_str();
   int32_t iLenPattern = wsTextFormat.GetLength();
@@ -4101,7 +4101,7 @@
     return false;
   }
   CFX_WideString wsTextFormat;
-  GetTextFormat(wsPattern, FX_WSTRC(L"null"), wsTextFormat);
+  GetTextFormat(wsPattern, L"null", wsTextFormat);
   int32_t iPattern = 0;
   const FX_WCHAR* pStrPattern = wsTextFormat.c_str();
   int32_t iLenPattern = wsTextFormat.GetLength();
diff --git a/xfa/fwl/cfwl_caret.cpp b/xfa/fwl/cfwl_caret.cpp
index 4a95b09..da57cb4 100644
--- a/xfa/fwl/cfwl_caret.cpp
+++ b/xfa/fwl/cfwl_caret.cpp
@@ -76,13 +76,10 @@
   if (!(m_pProperties->m_dwStates & FWL_STATE_CAT_HightLight))
     return;
 
-  CFX_RectF rect = GetWidgetRect();
-  rect.Set(0, 0, rect.width, rect.height);
-
   CFWL_ThemeBackground param;
   param.m_pWidget = this;
   param.m_pGraphics = pGraphics;
-  param.m_rtPart = rect;
+  param.m_rtPart = CFX_RectF(0, 0, GetWidgetRect().Size());
   param.m_iPart = CFWL_Part::Background;
   param.m_dwStates = CFWL_PartState_HightLight;
   if (pMatrix)
@@ -107,6 +104,5 @@
     pCaret->RemoveStates(FWL_STATE_CAT_HightLight);
 
   CFX_RectF rt = pCaret->GetWidgetRect();
-  rt.Set(0, 0, rt.width + 1, rt.height);
-  pCaret->RepaintRect(rt);
+  pCaret->RepaintRect(CFX_RectF(0, 0, rt.width + 1, rt.height));
 }
diff --git a/xfa/fwl/cfwl_checkbox.cpp b/xfa/fwl/cfwl_checkbox.cpp
index 5d40d8f..0102bc7 100644
--- a/xfa/fwl/cfwl_checkbox.cpp
+++ b/xfa/fwl/cfwl_checkbox.cpp
@@ -9,6 +9,7 @@
 #include <algorithm>
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "third_party/base/ptr_util.h"
 #include "xfa/fde/tto/fde_textout.h"
@@ -128,27 +129,21 @@
       FXSYS_round(m_pProperties->m_rtWidget.height);
   m_rtClient = GetClientRect();
 
-  FX_FLOAT fBoxTop = m_rtClient.top;
-  FX_FLOAT fBoxLeft = m_rtClient.left;
-  FX_FLOAT fTextLeft = fBoxLeft + m_fBoxHeight;
-  FX_FLOAT fTextRight = m_rtClient.right();
-  m_rtBox.Set(fBoxLeft, fBoxTop, m_fBoxHeight, m_fBoxHeight);
-  m_rtCaption.Set(fTextLeft, m_rtClient.top, fTextRight - fTextLeft,
-                  m_rtClient.height);
+  FX_FLOAT fTextLeft = m_rtClient.left + m_fBoxHeight;
+  m_rtBox = CFX_RectF(m_rtClient.TopLeft(), m_fBoxHeight, m_fBoxHeight);
+  m_rtCaption = CFX_RectF(fTextLeft, m_rtClient.top,
+                          m_rtClient.right() - fTextLeft, m_rtClient.height);
   m_rtCaption.Inflate(-kCaptionMargin, -kCaptionMargin);
 
-  CFX_RectF rtFocus;
-  rtFocus.Set(m_rtCaption.left, m_rtCaption.top, m_rtCaption.width,
-              m_rtCaption.height);
+  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);
 
-  FX_FLOAT fWidth = std::max(m_rtCaption.width, rtFocus.width);
-  FX_FLOAT fHeight = std::min(m_rtCaption.height, rtFocus.height);
-  FX_FLOAT fLeft = m_rtCaption.left;
-  FX_FLOAT fTop = m_rtCaption.top;
-  m_rtFocus.Set(fLeft, fTop, fWidth, fHeight);
+  m_rtFocus = CFX_RectF(m_rtCaption.TopLeft(),
+                        std::max(m_rtCaption.width, rtFocus.width),
+                        std::min(m_rtCaption.height, rtFocus.height));
   m_rtFocus.Inflate(1, 1);
 }
 
@@ -187,18 +182,15 @@
         FWL_STATE_CKB_Unchecked) {
       CFWL_WidgetMgr* pWidgetMgr = GetOwnerApp()->GetWidgetMgr();
       if (!pWidgetMgr->IsFormDisabled()) {
-        CFX_ArrayTemplate<CFWL_Widget*> radioarr;
-        pWidgetMgr->GetSameGroupRadioButton(this, radioarr);
-        CFWL_CheckBox* pCheckBox = nullptr;
-        int32_t iCount = radioarr.GetSize();
-        for (int32_t i = 0; i < iCount; i++) {
-          pCheckBox = static_cast<CFWL_CheckBox*>(radioarr[i]);
+        std::vector<CFWL_Widget*> radioarr =
+            pWidgetMgr->GetSameGroupRadioButton(this);
+        for (const auto& pWidget : radioarr) {
+          CFWL_CheckBox* pCheckBox = static_cast<CFWL_CheckBox*>(pWidget);
           if (pCheckBox != this &&
               pCheckBox->GetStates() & FWL_STATE_CKB_Checked) {
             pCheckBox->SetCheckState(0);
-            CFX_RectF rt = pCheckBox->GetWidgetRect();
-            rt.left = rt.top = 0;
-            m_pWidgetMgr->RepaintWidget(pCheckBox, rt);
+            m_pWidgetMgr->RepaintWidget(
+                pCheckBox, CFX_RectF(0, 0, pCheckBox->GetWidgetRect().Size()));
             break;
           }
         }
@@ -305,7 +297,7 @@
     return;
 
   m_bBtnDown = false;
-  if (!m_rtClient.Contains(pMsg->m_fx, pMsg->m_fy))
+  if (!m_rtClient.Contains(pMsg->m_pos))
     return;
 
   m_pProperties->m_dwStates |= FWL_STATE_CKB_Hovered;
@@ -319,7 +311,7 @@
 
   bool bRepaint = false;
   if (m_bBtnDown) {
-    if (m_rtClient.Contains(pMsg->m_fx, pMsg->m_fy)) {
+    if (m_rtClient.Contains(pMsg->m_pos)) {
       if ((m_pProperties->m_dwStates & FWL_STATE_CKB_Pressed) == 0) {
         bRepaint = true;
         m_pProperties->m_dwStates |= FWL_STATE_CKB_Pressed;
@@ -339,7 +331,7 @@
       }
     }
   } else {
-    if (m_rtClient.Contains(pMsg->m_fx, pMsg->m_fy)) {
+    if (m_rtClient.Contains(pMsg->m_pos)) {
       if ((m_pProperties->m_dwStates & FWL_STATE_CKB_Hovered) == 0) {
         bRepaint = true;
         m_pProperties->m_dwStates |= FWL_STATE_CKB_Hovered;
diff --git a/xfa/fwl/cfwl_combobox.cpp b/xfa/fwl/cfwl_combobox.cpp
index 03d2921..6083943 100644
--- a/xfa/fwl/cfwl_combobox.cpp
+++ b/xfa/fwl/cfwl_combobox.cpp
@@ -118,10 +118,10 @@
   Layout();
 }
 
-FWL_WidgetHit CFWL_ComboBox::HitTest(FX_FLOAT fx, FX_FLOAT fy) {
+FWL_WidgetHit CFWL_ComboBox::HitTest(const CFX_PointF& point) {
   if (m_pWidgetMgr->IsFormDisabled())
-    return DisForm_HitTest(fx, fy);
-  return CFWL_Widget::HitTest(fx, fy);
+    return DisForm_HitTest(point);
+  return CFWL_Widget::HitTest(point);
 }
 
 void CFWL_ComboBox::DrawWidget(CFX_Graphics* pGraphics,
@@ -326,9 +326,8 @@
   m_pListBox->ModifyStylesEx(dwStyleAdd, 0);
   m_rtList = m_pListBox->GetAutosizedWidgetRect();
 
-  CFX_RectF rtAnchor;
-  rtAnchor.Set(0, 0, m_pProperties->m_rtWidget.width,
-               m_pProperties->m_rtWidget.height);
+  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;
@@ -378,14 +377,13 @@
     return;
 
   FX_FLOAT fBtn = theme->GetScrollBarWidth();
-  m_rtBtn.Set(m_rtClient.right() - fBtn, m_rtClient.top, fBtn,
-              m_rtClient.height);
+  m_rtBtn = CFX_RectF(m_rtClient.right() - fBtn, m_rtClient.top, fBtn,
+                      m_rtClient.height);
   if (!IsDropDownStyle() || !m_pEdit)
     return;
 
-  CFX_RectF rtEdit;
-  rtEdit.Set(m_rtClient.left, m_rtClient.top, m_rtClient.width - fBtn,
-             m_rtClient.height);
+  CFX_RectF rtEdit(m_rtClient.left, m_rtClient.top, m_rtClient.width - fBtn,
+                   m_rtClient.height);
   m_pEdit->SetWidgetRect(rtEdit);
 
   if (m_iCurSel >= 0) {
@@ -552,11 +550,7 @@
       fPopupMin = fItemHeight * 3 + fBorder * 2;
 
     FX_FLOAT fPopupMax = fItemHeight * iItems + fBorder * 2;
-    CFX_RectF rtList;
-    rtList.left = m_rtClient.left;
-    rtList.width = m_pProperties->m_rtWidget.width;
-    rtList.top = 0;
-    rtList.height = 0;
+    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);
@@ -605,17 +599,16 @@
   Layout();
 }
 
-FWL_WidgetHit CFWL_ComboBox::DisForm_HitTest(FX_FLOAT fx, FX_FLOAT fy) {
-  CFX_RectF rect;
-  rect.Set(0, 0, m_pProperties->m_rtWidget.width - m_rtBtn.width,
-           m_pProperties->m_rtWidget.height);
-  if (rect.Contains(fx, fy))
+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(fx, fy))
+  if (m_rtBtn.Contains(point))
     return FWL_WidgetHit::Client;
   if (DisForm_IsDropListVisible()) {
     rect = m_pListBox->GetWidgetRect();
-    if (rect.Contains(fx, fy))
+    if (rect.Contains(point))
       return FWL_WidgetHit::Client;
   }
   return FWL_WidgetHit::Unknown;
@@ -624,8 +617,7 @@
 void CFWL_ComboBox::DisForm_DrawWidget(CFX_Graphics* pGraphics,
                                        const CFX_Matrix* pMatrix) {
   IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
-  CFX_Matrix mtOrg;
-  mtOrg.Set(1, 0, 0, 1, 0, 0);
+  CFX_Matrix mtOrg(1, 0, 0, 1, 0, 0);
   if (pMatrix)
     mtOrg = *pMatrix;
 
@@ -644,15 +636,13 @@
 
   if (m_pEdit) {
     CFX_RectF rtEdit = m_pEdit->GetWidgetRect();
-    CFX_Matrix mt;
-    mt.Set(1, 0, 0, 1, rtEdit.left, rtEdit.top);
+    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;
-    mt.Set(1, 0, 0, 1, rtList.left, rtList.top);
+    CFX_Matrix mt(1, 0, 0, 1, rtList.left, rtList.top);
     mt.Concat(mtOrg);
     m_pListBox->DrawWidget(pGraphics, &mt);
   }
@@ -679,8 +669,9 @@
   FX_FLOAT borderWidth = 1;
   FX_FLOAT fBtn = theme->GetScrollBarWidth();
   if (!(GetStylesEx() & FWL_STYLEEXT_CMB_ReadOnly)) {
-    m_rtBtn.Set(m_rtClient.right() - fBtn, m_rtClient.top + borderWidth,
-                fBtn - borderWidth, m_rtClient.height - 2 * borderWidth);
+    m_rtBtn =
+        CFX_RectF(m_rtClient.right() - fBtn, m_rtClient.top + borderWidth,
+                  fBtn - borderWidth, m_rtClient.height - 2 * borderWidth);
   }
 
   CFWL_ThemePart part;
@@ -692,9 +683,8 @@
   if (!IsDropDownStyle() || !m_pEdit)
     return;
 
-  CFX_RectF rtEdit;
-  rtEdit.Set(m_rtContent.left, m_rtContent.top, m_rtContent.width - fBtn,
-             m_rtContent.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) {
@@ -801,7 +791,7 @@
     return;
 
   CFX_RectF& rtBtn = IsDropDownStyle() ? m_rtBtn : m_rtClient;
-  if (!rtBtn.Contains(pMsg->m_fx, pMsg->m_fy))
+  if (!rtBtn.Contains(pMsg->m_pos))
     return;
 
   if (IsDropDownStyle() && m_pEdit)
@@ -818,7 +808,7 @@
 
 void CFWL_ComboBox::OnLButtonUp(CFWL_MessageMouse* pMsg) {
   m_bLButtonDown = false;
-  if (m_rtBtn.Contains(pMsg->m_fx, pMsg->m_fy))
+  if (m_rtBtn.Contains(pMsg->m_pos))
     m_iBtnState = CFWL_PartState_Hovered;
   else
     m_iBtnState = CFWL_PartState_Normal;
@@ -828,7 +818,7 @@
 
 void CFWL_ComboBox::OnMouseMove(CFWL_MessageMouse* pMsg) {
   int32_t iOldState = m_iBtnState;
-  if (m_rtBtn.Contains(pMsg->m_fx, pMsg->m_fy)) {
+  if (m_rtBtn.Contains(pMsg->m_pos)) {
     m_iBtnState =
         m_bLButtonDown ? CFWL_PartState_Pressed : CFWL_PartState_Hovered;
   } else {
@@ -960,7 +950,7 @@
 void CFWL_ComboBox::DisForm_OnLButtonDown(CFWL_MessageMouse* pMsg) {
   bool bDropDown = DisForm_IsDropListVisible();
   CFX_RectF& rtBtn = bDropDown ? m_rtBtn : m_rtClient;
-  if (!rtBtn.Contains(pMsg->m_fx, pMsg->m_fy))
+  if (!rtBtn.Contains(pMsg->m_pos))
     return;
 
   if (DisForm_IsDropListVisible()) {
diff --git a/xfa/fwl/cfwl_combobox.h b/xfa/fwl/cfwl_combobox.h
index d8db10d..168e203 100644
--- a/xfa/fwl/cfwl_combobox.h
+++ b/xfa/fwl/cfwl_combobox.h
@@ -51,7 +51,7 @@
   void SetStates(uint32_t dwStates) override;
   void RemoveStates(uint32_t dwStates) override;
   void Update() override;
-  FWL_WidgetHit HitTest(FX_FLOAT fx, FX_FLOAT fy) override;
+  FWL_WidgetHit HitTest(const CFX_PointF& point) override;
   void DrawWidget(CFX_Graphics* pGraphics, const CFX_Matrix* pMatrix) override;
   void SetThemeProvider(IFWL_ThemeProvider* pThemeProvider) override;
   void OnProcessMessage(CFWL_Message* pMessage) override;
@@ -135,7 +135,7 @@
   void DisForm_ModifyStylesEx(uint32_t dwStylesExAdded,
                               uint32_t dwStylesExRemoved);
   void DisForm_Update();
-  FWL_WidgetHit DisForm_HitTest(FX_FLOAT fx, FX_FLOAT fy);
+  FWL_WidgetHit DisForm_HitTest(const CFX_PointF& point);
   void DisForm_DrawWidget(CFX_Graphics* pGraphics, const CFX_Matrix* pMatrix);
   CFX_RectF DisForm_GetBBox() const;
   void DisForm_Layout();
diff --git a/xfa/fwl/cfwl_comboboxproxy.cpp b/xfa/fwl/cfwl_comboboxproxy.cpp
index 7bf311d..0e2779b 100644
--- a/xfa/fwl/cfwl_comboboxproxy.cpp
+++ b/xfa/fwl/cfwl_comboboxproxy.cpp
@@ -70,11 +70,8 @@
 
   CFWL_NoteDriver* pDriver =
       static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
-  CFX_RectF rtWidget = GetWidgetRect();
-  rtWidget.left = rtWidget.top = 0;
-
   CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
-  if (rtWidget.Contains(pMsg->m_fx, pMsg->m_fy)) {
+  if (CFX_RectF(0, 0, GetWidgetRect().Size()).Contains(pMsg->m_pos)) {
     m_bLButtonDown = true;
     pDriver->SetGrab(this, true);
   } else {
@@ -99,9 +96,7 @@
   }
 
   CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
-  CFX_RectF rect = GetWidgetRect();
-  rect.left = rect.top = 0;
-  if (!rect.Contains(pMsg->m_fx, pMsg->m_fy) &&
+  if (!CFX_RectF(0, 0, GetWidgetRect().Size()).Contains(pMsg->m_pos) &&
       m_pComboBox->IsDropListVisible()) {
     m_pComboBox->ShowDropList(false);
   }
diff --git a/xfa/fwl/cfwl_combolist.cpp b/xfa/fwl/cfwl_combolist.cpp
index e78372c..5b700a9 100644
--- a/xfa/fwl/cfwl_combolist.cpp
+++ b/xfa/fwl/cfwl_combolist.cpp
@@ -63,12 +63,11 @@
     RepaintRect(rtInvalidate);
 }
 
-void CFWL_ComboList::ClientToOuter(FX_FLOAT& fx, FX_FLOAT& fy) {
-  fx += m_pProperties->m_rtWidget.left, fy += m_pProperties->m_rtWidget.top;
+CFX_PointF CFWL_ComboList::ClientToOuter(const CFX_PointF& point) {
+  CFX_PointF ret = point + CFX_PointF(m_pProperties->m_rtWidget.left,
+                                      m_pProperties->m_rtWidget.top);
   CFWL_Widget* pOwner = GetOwner();
-  if (!pOwner)
-    return;
-  pOwner->TransformTo(m_pOuter, fx, fy);
+  return pOwner ? pOwner->TransformTo(m_pOuter, ret) : ret;
 }
 
 void CFWL_ComboList::OnProcessMessage(CFWL_Message* pMessage) {
@@ -85,9 +84,8 @@
     CFWL_ScrollBar* vertSB = GetVertScrollBar();
     if (IsShowScrollBar(true) && vertSB) {
       CFX_RectF rect = vertSB->GetWidgetRect();
-      if (rect.Contains(pMsg->m_fx, pMsg->m_fy)) {
-        pMsg->m_fx -= rect.left;
-        pMsg->m_fy -= rect.top;
+      if (rect.Contains(pMsg->m_pos)) {
+        pMsg->m_pos -= rect.TopLeft();
         vertSB->GetDelegate()->OnProcessMessage(pMsg);
         return;
       }
@@ -131,31 +129,32 @@
 }
 
 void CFWL_ComboList::OnDropListMouseMove(CFWL_MessageMouse* pMsg) {
-  if (GetRTClient().Contains(pMsg->m_fx, pMsg->m_fy)) {
+  if (GetRTClient().Contains(pMsg->m_pos)) {
     if (m_bNotifyOwner)
       m_bNotifyOwner = false;
 
     CFWL_ScrollBar* vertSB = GetVertScrollBar();
     if (IsShowScrollBar(true) && vertSB) {
       CFX_RectF rect = vertSB->GetWidgetRect();
-      if (rect.Contains(pMsg->m_fx, pMsg->m_fy))
+      if (rect.Contains(pMsg->m_pos))
         return;
     }
 
-    CFWL_ListItem* hItem = GetItemAtPoint(pMsg->m_fx, pMsg->m_fy);
+    CFWL_ListItem* hItem = GetItemAtPoint(pMsg->m_pos);
     if (!hItem)
       return;
 
     ChangeSelected(GetItemIndex(this, hItem));
   } else if (m_bNotifyOwner) {
-    ClientToOuter(pMsg->m_fx, pMsg->m_fy);
+    pMsg->m_pos = ClientToOuter(pMsg->m_pos);
+
     CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(m_pOuter);
     pOuter->GetDelegate()->OnProcessMessage(pMsg);
   }
 }
 
 void CFWL_ComboList::OnDropListLButtonDown(CFWL_MessageMouse* pMsg) {
-  if (GetRTClient().Contains(pMsg->m_fx, pMsg->m_fy))
+  if (GetRTClient().Contains(pMsg->m_pos))
     return;
 
   CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(m_pOuter);
@@ -165,7 +164,7 @@
 void CFWL_ComboList::OnDropListLButtonUp(CFWL_MessageMouse* pMsg) {
   CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(m_pOuter);
   if (m_bNotifyOwner) {
-    ClientToOuter(pMsg->m_fx, pMsg->m_fy);
+    pMsg->m_pos = ClientToOuter(pMsg->m_pos);
     pOuter->GetDelegate()->OnProcessMessage(pMsg);
     return;
   }
@@ -173,12 +172,12 @@
   CFWL_ScrollBar* vertSB = GetVertScrollBar();
   if (IsShowScrollBar(true) && vertSB) {
     CFX_RectF rect = vertSB->GetWidgetRect();
-    if (rect.Contains(pMsg->m_fx, pMsg->m_fy))
+    if (rect.Contains(pMsg->m_pos))
       return;
   }
   pOuter->ShowDropList(false);
 
-  CFWL_ListItem* hItem = GetItemAtPoint(pMsg->m_fx, pMsg->m_fy);
+  CFWL_ListItem* hItem = GetItemAtPoint(pMsg->m_pos);
   if (hItem)
     pOuter->ProcessSelChanged(true);
 }
@@ -231,9 +230,8 @@
 
       SetSelection(hItem, hItem, true);
       ScrollToVisible(hItem);
-      CFX_RectF rtInvalidate;
-      rtInvalidate.Set(0, 0, m_pProperties->m_rtWidget.width,
-                       m_pProperties->m_rtWidget.height);
+      CFX_RectF rtInvalidate(0, 0, m_pProperties->m_rtWidget.width,
+                             m_pProperties->m_rtWidget.height);
       RepaintRect(rtInvalidate);
       break;
     }
diff --git a/xfa/fwl/cfwl_combolist.h b/xfa/fwl/cfwl_combolist.h
index e1d5fd9..b7ba6b5 100644
--- a/xfa/fwl/cfwl_combolist.h
+++ b/xfa/fwl/cfwl_combolist.h
@@ -29,7 +29,7 @@
   void SetNotifyOwner(bool notify) { m_bNotifyOwner = notify; }
 
  private:
-  void ClientToOuter(FX_FLOAT& fx, FX_FLOAT& fy);
+  CFX_PointF ClientToOuter(const CFX_PointF& point);
   void OnDropListFocusChanged(CFWL_Message* pMsg, bool bSet);
   void OnDropListMouseMove(CFWL_MessageMouse* pMsg);
   void OnDropListLButtonDown(CFWL_MessageMouse* pMsg);
diff --git a/xfa/fwl/cfwl_datetimeedit.h b/xfa/fwl/cfwl_datetimeedit.h
index bde14dd..923ad05 100644
--- a/xfa/fwl/cfwl_datetimeedit.h
+++ b/xfa/fwl/cfwl_datetimeedit.h
@@ -12,7 +12,6 @@
 #include "xfa/fwl/cfwl_edit.h"
 #include "xfa/fwl/cfwl_widget.h"
 #include "xfa/fwl/cfwl_widgetproperties.h"
-#include "xfa/fwl/fwl_error.h"
 
 class CFWL_DateTimeEdit : public CFWL_Edit {
  public:
diff --git a/xfa/fwl/cfwl_datetimepicker.cpp b/xfa/fwl/cfwl_datetimepicker.cpp
index 861692f..a6ba65a 100644
--- a/xfa/fwl/cfwl_datetimepicker.cpp
+++ b/xfa/fwl/cfwl_datetimepicker.cpp
@@ -33,8 +33,6 @@
       m_iMonth(-1),
       m_iDay(-1),
       m_bLBtnDown(false) {
-  m_rtBtn.Set(0, 0, 0, 0);
-
   m_pProperties->m_dwStyleExes = FWL_STYLEEXT_DTP_ShortDateFormat;
 
   auto monthProp = pdfium::MakeUnique<CFWL_WidgetProperties>();
@@ -45,9 +43,8 @@
   m_pMonthCal.reset(
       new CFWL_MonthCalendar(m_pOwnerApp, std::move(monthProp), this));
 
-  CFX_RectF rtMonthCal = m_pMonthCal->GetAutosizedWidgetRect();
-  rtMonthCal.Set(0, 0, rtMonthCal.width, rtMonthCal.height);
-  m_pMonthCal->SetWidgetRect(rtMonthCal);
+  m_pMonthCal->SetWidgetRect(
+      CFX_RectF(0, 0, m_pMonthCal->GetAutosizedWidgetRect().Size()));
 
   auto editProp = pdfium::MakeUnique<CFWL_WidgetProperties>();
   editProp->m_pParent = this;
@@ -85,12 +82,11 @@
     return;
 
   FX_FLOAT fBtn = theme->GetScrollBarWidth();
-  m_rtBtn.Set(m_rtClient.right() - fBtn, m_rtClient.top, fBtn - 1,
-              m_rtClient.height - 1);
+  m_rtBtn = CFX_RectF(m_rtClient.right() - fBtn, m_rtClient.top, fBtn - 1,
+                      m_rtClient.height - 1);
 
-  CFX_RectF rtEdit;
-  rtEdit.Set(m_rtClient.left, m_rtClient.top, m_rtClient.width - fBtn,
-             m_rtClient.height);
+  CFX_RectF rtEdit(m_rtClient.left, m_rtClient.top, m_rtClient.width - fBtn,
+                   m_rtClient.height);
   m_pEdit->SetWidgetRect(rtEdit);
   ResetEditAlignment();
   m_pEdit->Update();
@@ -98,22 +94,21 @@
     m_pMonthCal->SetThemeProvider(m_pProperties->m_pThemeProvider);
 
   CFX_RectF rtMonthCal = m_pMonthCal->GetAutosizedWidgetRect();
-  CFX_RectF rtPopUp;
-  rtPopUp.Set(rtMonthCal.left, rtMonthCal.top + kDateTimePickerHeight,
-              rtMonthCal.width, rtMonthCal.height);
+  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(FX_FLOAT fx, FX_FLOAT fy) {
+FWL_WidgetHit CFWL_DateTimePicker::HitTest(const CFX_PointF& point) {
   if (m_pWidgetMgr->IsFormDisabled())
-    return DisForm_HitTest(fx, fy);
-  if (m_rtClient.Contains(fx, fy))
+    return DisForm_HitTest(point);
+  if (m_rtClient.Contains(point))
     return FWL_WidgetHit::Client;
   if (IsMonthCalendarVisible()) {
     CFX_RectF rect = m_pMonthCal->GetWidgetRect();
-    if (rect.Contains(fx, fy))
+    if (rect.Contains(point))
       return FWL_WidgetHit::Client;
   }
   return FWL_WidgetHit::Unknown;
@@ -242,9 +237,8 @@
 
   CFX_RectF rtMonth = m_pMonthCal->GetWidgetRect();
 
-  CFX_RectF rtAnchor;
-  rtAnchor.Set(0, 0, m_pProperties->m_rtWidget.width,
-               m_pProperties->m_rtWidget.height);
+  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);
 
@@ -377,9 +371,8 @@
     m_pEdit->GetDelegate()->OnProcessMessage(&msg);
   }
 
-  CFX_RectF rtInvalidate;
-  rtInvalidate.Set(0, 0, m_pProperties->m_rtWidget.width,
-                   m_pProperties->m_rtWidget.height);
+  CFX_RectF rtInvalidate(0, 0, m_pProperties->m_rtWidget.width,
+                         m_pProperties->m_rtWidget.height);
 
   CFX_RectF rtCal = m_pMonthCal->GetWidgetRect();
   rtInvalidate.Union(rtCal);
@@ -387,19 +380,18 @@
   RepaintRect(rtInvalidate);
 }
 
-FWL_WidgetHit CFWL_DateTimePicker::DisForm_HitTest(FX_FLOAT fx,
-                                                   FX_FLOAT fy) const {
-  CFX_RectF rect;
-  rect.Set(0, 0, m_pProperties->m_rtWidget.width,
-           m_pProperties->m_rtWidget.height);
-  if (rect.Contains(fx, fy))
+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(fx, fy))
+  if (rect.Contains(point))
     return FWL_WidgetHit::Client;
   if (IsMonthCalendarVisible()) {
-    if (m_pMonthCal->GetWidgetRect().Contains(fx, fy))
+    if (m_pMonthCal->GetWidgetRect().Contains(point))
       return FWL_WidgetHit::Client;
   }
   return FWL_WidgetHit::Unknown;
@@ -432,9 +424,8 @@
 
   m_fBtn = theme->GetScrollBarWidth();
   CFX_RectF rtMonthCal = m_pMonthCal->GetAutosizedWidgetRect();
-  CFX_RectF rtPopUp;
-  rtPopUp.Set(rtMonthCal.left, rtMonthCal.top + kDateTimePickerHeight,
-              rtMonthCal.width, rtMonthCal.height);
+  CFX_RectF rtPopUp(rtMonthCal.left, rtMonthCal.top + kDateTimePickerHeight,
+                    rtMonthCal.width, rtMonthCal.height);
   m_pMonthCal->SetWidgetRect(rtPopUp);
   m_pMonthCal->Update();
 }
@@ -459,8 +450,7 @@
   if (m_pEdit) {
     CFX_RectF rtEdit = m_pEdit->GetWidgetRect();
 
-    CFX_Matrix mt;
-    mt.Set(1, 0, 0, 1, rtEdit.left, rtEdit.top);
+    CFX_Matrix mt(1, 0, 0, 1, rtEdit.left, rtEdit.top);
     if (pMatrix)
       mt.Concat(*pMatrix);
     m_pEdit->DrawWidget(pGraphics, &mt);
@@ -469,8 +459,7 @@
     return;
 
   CFX_RectF rtMonth = m_pMonthCal->GetWidgetRect();
-  CFX_Matrix mt;
-  mt.Set(1, 0, 0, 1, rtMonth.left, rtMonth.top);
+  CFX_Matrix mt(1, 0, 0, 1, rtMonth.left, rtMonth.top);
   if (pMatrix)
     mt.Concat(*pMatrix);
   m_pMonthCal->DrawWidget(pGraphics, &mt);
@@ -550,7 +539,7 @@
     return;
   if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0)
     SetFocus(true);
-  if (!m_rtBtn.Contains(pMsg->m_fx, pMsg->m_fy))
+  if (!m_rtBtn.Contains(pMsg->m_pos))
     return;
 
   if (IsMonthCalendarVisible()) {
@@ -568,7 +557,7 @@
     return;
 
   m_bLBtnDown = false;
-  if (m_rtBtn.Contains(pMsg->m_fx, pMsg->m_fy))
+  if (m_rtBtn.Contains(pMsg->m_pos))
     m_iBtnState = CFWL_PartState_Hovered;
   else
     m_iBtnState = CFWL_PartState_Normal;
@@ -576,7 +565,7 @@
 }
 
 void CFWL_DateTimePicker::OnMouseMove(CFWL_MessageMouse* pMsg) {
-  if (!m_rtBtn.Contains(pMsg->m_fx, pMsg->m_fy))
+  if (!m_rtBtn.Contains(pMsg->m_pos))
     m_iBtnState = CFWL_PartState_Normal;
   RepaintRect(m_rtBtn);
 }
@@ -594,15 +583,16 @@
   if (bSet) {
     m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
     if (m_pEdit && !(m_pEdit->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly)) {
-      m_rtBtn.Set(m_pProperties->m_rtWidget.width, 0, m_fBtn,
-                  m_pProperties->m_rtWidget.height - 1);
+      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.Set(0, 0, 0, 0);
+    m_rtBtn.Reset();
+
     if (DisForm_IsMonthCalendarVisible())
       ShowMonthCalendar(false);
     if (m_pEdit->GetStates() & FWL_WGTSTATE_Focused) {
diff --git a/xfa/fwl/cfwl_datetimepicker.h b/xfa/fwl/cfwl_datetimepicker.h
index 47d1c70..2935ee8 100644
--- a/xfa/fwl/cfwl_datetimepicker.h
+++ b/xfa/fwl/cfwl_datetimepicker.h
@@ -38,7 +38,7 @@
   // CFWL_Widget
   FWL_Type GetClassID() const override;
   void Update() override;
-  FWL_WidgetHit HitTest(FX_FLOAT fx, FX_FLOAT fy) override;
+  FWL_WidgetHit HitTest(const CFX_PointF& point) override;
   void DrawWidget(CFX_Graphics* pGraphics, const CFX_Matrix* pMatrix) override;
   void SetThemeProvider(IFWL_ThemeProvider* pTP) override;
   void OnProcessMessage(CFWL_Message* pMessage) override;
@@ -84,7 +84,7 @@
 
   bool DisForm_IsMonthCalendarVisible() const;
   void DisForm_ShowMonthCalendar(bool bActivate);
-  FWL_WidgetHit DisForm_HitTest(FX_FLOAT fx, FX_FLOAT fy) const;
+  FWL_WidgetHit DisForm_HitTest(const CFX_PointF& point) const;
   bool DisForm_IsNeedShowButton() const;
   void DisForm_Update();
   CFX_RectF DisForm_GetBBox() const;
diff --git a/xfa/fwl/cfwl_edit.cpp b/xfa/fwl/cfwl_edit.cpp
index acd5672..d36e28a 100644
--- a/xfa/fwl/cfwl_edit.cpp
+++ b/xfa/fwl/cfwl_edit.cpp
@@ -49,10 +49,10 @@
                      FX_FLOAT fEndX,
                      FX_FLOAT fY,
                      FX_FLOAT fStep) {
-  pPathData->MoveTo(fStartX, fY);
+  pPathData->MoveTo(CFX_PointF(fStartX, fY));
   int i = 1;
   for (FX_FLOAT fx = fStartX + fStep; fx < fEndX; fx += fStep, ++i)
-    pPathData->LineTo(fx, fY + (i & 1) * fStep);
+    pPathData->LineTo(CFX_PointF(fx, fY + (i & 1) * fStep));
 }
 
 }  // namespace
@@ -112,7 +112,7 @@
     CFX_SizeF sz = CalcTextSize(
         m_EdtEngine.GetText(0, -1), m_pProperties->m_pThemeProvider,
         !!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_MultiLine));
-    rect.Set(0, 0, sz.x, sz.y);
+    rect = CFX_RectF(0, 0, sz);
   }
   InflateWidgetRect(rect);
   return rect;
@@ -142,18 +142,18 @@
   InitCaret();
 }
 
-FWL_WidgetHit CFWL_Edit::HitTest(FX_FLOAT fx, FX_FLOAT fy) {
+FWL_WidgetHit CFWL_Edit::HitTest(const CFX_PointF& point) {
   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
     if (IsShowScrollBar(true)) {
-      if (m_pVertScrollBar->GetWidgetRect().Contains(fx, fy))
+      if (m_pVertScrollBar->GetWidgetRect().Contains(point))
         return FWL_WidgetHit::VScrollBar;
     }
     if (IsShowScrollBar(false)) {
-      if (m_pHorzScrollBar->GetWidgetRect().Contains(fx, fy))
+      if (m_pHorzScrollBar->GetWidgetRect().Contains(point))
         return FWL_WidgetHit::HScrollBar;
     }
   }
-  if (m_rtClient.Contains(fx, fy))
+  if (m_rtClient.Contains(point))
     return FWL_WidgetHit::Edit;
   return FWL_WidgetHit::Unknown;
 }
@@ -168,15 +168,14 @@
   FX_FLOAT fY = 0.0f;
   FX_FLOAT fStep = 0.0f;
   IFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
-  CFX_RectFArray rectArray;
-  CFX_RectF rectText;
   const FDE_TXTEDTPARAMS* txtEdtParams = m_EdtEngine.GetEditParams();
   FX_FLOAT fAsent = static_cast<FX_FLOAT>(txtEdtParams->pFont->GetAscent()) *
                     txtEdtParams->fFontSize / 1000;
-  pPage->CalcRangeRectArray(nStart, nCount, rectArray);
 
-  for (int i = 0; i < rectArray.GetSize(); i++) {
-    rectText = rectArray.GetAt(i);
+  std::vector<CFX_RectF> rectArray;
+  pPage->CalcRangeRectArray(nStart, nCount, &rectArray);
+
+  for (const auto& rectText : rectArray) {
     fY = rectText.top + fAsent + fOffSetY;
     fStep = txtEdtParams->fFontSize / 16.0f;
     fStartX = rectText.left + fOffSetX;
@@ -193,15 +192,11 @@
 
   CFX_Color crLine(0xFFFF0000);
   CFWL_EventCheckWord checkWordEvent(this);
-
   CFX_ByteString sLatinWord;
   CFX_Path pathSpell;
-  pathSpell.Create();
-
   int32_t nStart = 0;
   FX_FLOAT fOffSetX = m_rtEngine.left - m_fScrollOffsetX;
   FX_FLOAT fOffSetY = m_rtEngine.top - m_fScrollOffsetY + m_fVAlignOffset;
-
   CFX_WideString wsSpell = GetText();
   int32_t nContentLen = wsSpell.GetLength();
   for (int i = 0; i < nContentLen; i++) {
@@ -232,8 +227,7 @@
   }
   if (!pathSpell.IsEmpty()) {
     CFX_RectF rtClip = m_rtEngine;
-    CFX_Matrix mt;
-    mt.Set(1, 0, 0, 1, fOffSetX, fOffSetY);
+    CFX_Matrix mt(1, 0, 0, 1, fOffSetX, fOffSetY);
     if (pMatrix) {
       pMatrix->TransformRect(rtClip);
       mt.Concat(*pMatrix);
@@ -409,7 +403,6 @@
   bool bRepaintContent = UpdateOffset();
   UpdateCaret();
   CFX_RectF rtInvalid;
-  rtInvalid.Set(0, 0, 0, 0);
   bool bRepaintScroll = false;
   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_MultiLine) {
     CFWL_ScrollBar* pScroll = UpdateScroll();
@@ -502,10 +495,9 @@
 
   CFX_RectF rtScroll = m_pHorzScrollBar->GetWidgetRect();
 
-  CFX_RectF rtStatic;
-  rtStatic.Set(m_rtClient.right() - rtScroll.height,
-               m_rtClient.bottom() - rtScroll.height, rtScroll.height,
-               rtScroll.height);
+  CFX_RectF rtStatic(m_rtClient.right() - rtScroll.height,
+                     m_rtClient.bottom() - rtScroll.height, rtScroll.height,
+                     rtScroll.height);
   param.m_bStaticBackground = true;
   param.m_bMaximize = true;
   param.m_rtPart = rtStatic;
@@ -526,8 +518,7 @@
   CFX_RectF rtClip = m_rtEngine;
   FX_FLOAT fOffSetX = m_rtEngine.left - m_fScrollOffsetX;
   FX_FLOAT fOffSetY = m_rtEngine.top - m_fScrollOffsetY + m_fVAlignOffset;
-  CFX_Matrix mt;
-  mt.Set(1, 0, 0, 1, fOffSetX, fOffSetY);
+  CFX_Matrix mt(1, 0, 0, 1, fOffSetX, fOffSetY);
   if (pMatrix) {
     pMatrix->TransformRect(rtClip);
     mt.Concat(*pMatrix);
@@ -541,9 +532,8 @@
     int32_t nPageCharEnd = nPageCharStart + nPageCharCount - 1;
     int32_t nCharCount;
     int32_t nCharStart;
-    CFX_RectFArray rectArr;
-    int32_t i = 0;
-    for (i = 0; i < nSelCount; i++) {
+    std::vector<CFX_RectF> rectArr;
+    for (int32_t i = 0; i < nSelCount; i++) {
       nCharCount = m_EdtEngine.GetSelRange(i, &nCharStart);
       int32_t nCharEnd = nCharStart + nCharCount - 1;
       if (nCharEnd < nPageCharStart || nCharStart > nPageCharEnd)
@@ -552,17 +542,14 @@
       int32_t nBgn = std::max(nCharStart, nPageCharStart);
       int32_t nEnd = std::min(nCharEnd, nPageCharEnd);
       pPage->CalcRangeRectArray(nBgn - nPageCharStart, nEnd - nBgn + 1,
-                                rectArr);
+                                &rectArr);
     }
 
-    int32_t nCount = rectArr.GetSize();
     CFX_Path path;
-    path.Create();
-    for (i = 0; i < nCount; i++) {
-      rectArr[i].left += fOffSetX;
-      rectArr[i].top += fOffSetY;
-      path.AddRectangle(rectArr[i].left, rectArr[i].top, rectArr[i].width,
-                        rectArr[i].height);
+    for (auto& rect : rectArr) {
+      rect.left += fOffSetX;
+      rect.top += fOffSetY;
+      path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
     }
     pGraphics->SetClipRect(rtClip);
 
@@ -589,13 +576,13 @@
   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_CombText) {
     pGraphics->RestoreGraphState();
     CFX_Path path;
-    path.Create();
     int32_t iLimit = m_nLimit > 0 ? m_nLimit : 1;
     FX_FLOAT fStep = m_rtEngine.width / iLimit;
     FX_FLOAT fLeft = m_rtEngine.left + 1;
     for (int32_t i = 1; i < iLimit; i++) {
       fLeft += fStep;
-      path.AddLine(fLeft, m_rtClient.top, fLeft, m_rtClient.bottom());
+      path.AddLine(CFX_PointF(fLeft, m_rtClient.top),
+                   CFX_PointF(fLeft, m_rtClient.bottom()));
     }
 
     CFWL_ThemeBackground param;
@@ -786,8 +773,8 @@
     part.m_pWidget = this;
 
     CFX_SizeF pSpace = theme->GetSpaceAboveBelow(&part);
-    fSpaceAbove = pSpace.x;
-    fSpaceBelow = pSpace.y;
+    fSpaceAbove = pSpace.width;
+    fSpaceBelow = pSpace.height;
   }
   if (fSpaceAbove < 0.1f)
     fSpaceAbove = 0;
@@ -816,8 +803,7 @@
 
   rtFDE.Offset(m_rtEngine.left - m_fScrollOffsetX,
                m_rtEngine.top - m_fScrollOffsetY + m_fVAlignOffset);
-  CFX_RectF rtCaret;
-  rtCaret.Set(rtFDE.left, rtFDE.top, rtFDE.width, rtFDE.height);
+  CFX_RectF rtCaret(rtFDE.left, rtFDE.top, rtFDE.width, rtFDE.height);
 
   CFX_RectF rtClient = GetClientRect();
   rtCaret.Intersect(rtClient);
@@ -970,11 +956,11 @@
 
     CFX_RectF rtVertScr;
     if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
-      rtVertScr.Set(m_rtClient.right() + kEditMargin, m_rtClient.top, fWidth,
-                    m_rtClient.height);
+      rtVertScr = CFX_RectF(m_rtClient.right() + kEditMargin, m_rtClient.top,
+                            fWidth, m_rtClient.height);
     } else {
-      rtVertScr.Set(m_rtClient.right() - fWidth, m_rtClient.top, fWidth,
-                    m_rtClient.height);
+      rtVertScr = CFX_RectF(m_rtClient.right() - fWidth, m_rtClient.top, fWidth,
+                            m_rtClient.height);
       if (bShowHorzScrollbar)
         rtVertScr.height -= fWidth;
       m_rtEngine.width -= fWidth;
@@ -992,11 +978,11 @@
 
     CFX_RectF rtHoriScr;
     if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
-      rtHoriScr.Set(m_rtClient.left, m_rtClient.bottom() + kEditMargin,
-                    m_rtClient.width, fWidth);
+      rtHoriScr = CFX_RectF(m_rtClient.left, m_rtClient.bottom() + kEditMargin,
+                            m_rtClient.width, fWidth);
     } else {
-      rtHoriScr.Set(m_rtClient.left, m_rtClient.bottom() - fWidth,
-                    m_rtClient.width, fWidth);
+      rtHoriScr = CFX_RectF(m_rtClient.left, m_rtClient.bottom() - fWidth,
+                            m_rtClient.width, fWidth);
       if (bShowVertScrollbar)
         rtHoriScr.width -= fWidth;
       m_rtEngine.height -= fWidth;
@@ -1025,11 +1011,11 @@
       InitVerticalScrollBar();
       CFX_RectF rtVertScr;
       if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
-        rtVertScr.Set(m_rtClient.right() + kEditMargin, m_rtClient.top, fWidth,
-                      m_rtClient.height);
+        rtVertScr = CFX_RectF(m_rtClient.right() + kEditMargin, m_rtClient.top,
+                              fWidth, m_rtClient.height);
       } else {
-        rtVertScr.Set(m_rtClient.right() - fWidth, m_rtClient.top, fWidth,
-                      m_rtClient.height);
+        rtVertScr = CFX_RectF(m_rtClient.right() - fWidth, m_rtClient.top,
+                              fWidth, m_rtClient.height);
         if (bShowHorzScrollbar)
           rtVertScr.height -= fWidth;
       }
@@ -1046,11 +1032,12 @@
       InitHorizontalScrollBar();
       CFX_RectF rtHoriScr;
       if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
-        rtHoriScr.Set(m_rtClient.left, m_rtClient.bottom() + kEditMargin,
+        rtHoriScr =
+            CFX_RectF(m_rtClient.left, m_rtClient.bottom() + kEditMargin,
                       m_rtClient.width, fWidth);
       } else {
-        rtHoriScr.Set(m_rtClient.left, m_rtClient.bottom() - fWidth,
-                      m_rtClient.width, fWidth);
+        rtHoriScr = CFX_RectF(m_rtClient.left, m_rtClient.bottom() - fWidth,
+                              m_rtClient.width, fWidth);
         if (bShowVertScrollbar)
           rtHoriScr.width -= (fWidth);
       }
@@ -1065,9 +1052,9 @@
     UpdateScroll();
 }
 
-void CFWL_Edit::DeviceToEngine(CFX_PointF& pt) {
-  pt.x += m_fScrollOffsetX - m_rtEngine.left;
-  pt.y += m_fScrollOffsetY - m_rtEngine.top - m_fVAlignOffset;
+CFX_PointF CFWL_Edit::DeviceToEngine(const CFX_PointF& pt) {
+  return pt + CFX_PointF(m_fScrollOffsetX - m_rtEngine.left,
+                         m_fScrollOffsetY - m_rtEngine.top - m_fVAlignOffset);
 }
 
 void CFWL_Edit::InitVerticalScrollBar() {
@@ -1123,11 +1110,8 @@
   if (!pDocEnvironment)
     return;
 
-  CFX_Matrix mt;
-  pXFAWidget->GetRotateMatrix(mt);
-
   CFX_RectF rt(*pRect);
-  mt.TransformRect(rt);
+  pXFAWidget->GetRotateMatrix().TransformRect(rt);
   pDocEnvironment->DisplayCaret(pXFAWidget, true, &rt);
 }
 
@@ -1279,10 +1263,8 @@
   if (!pPage)
     return;
 
-  CFX_PointF pt(pMsg->m_fx, pMsg->m_fy);
-  DeviceToEngine(pt);
   bool bBefore = true;
-  int32_t nIndex = pPage->GetCharIndex(pt, bBefore);
+  int32_t nIndex = pPage->GetCharIndex(DeviceToEngine(pMsg->m_pos), bBefore);
   if (nIndex < 0)
     nIndex = 0;
 
@@ -1316,9 +1298,8 @@
   if (!bRepaint)
     return;
 
-  CFX_RectF rtInvalidate;
-  rtInvalidate.Set(0, 0, m_pProperties->m_rtWidget.width,
-                   m_pProperties->m_rtWidget.height);
+  CFX_RectF rtInvalidate(0, 0, m_pProperties->m_rtWidget.width,
+                         m_pProperties->m_rtWidget.height);
   RepaintRect(rtInvalidate);
 }
 
@@ -1358,10 +1339,8 @@
   if (!pPage)
     return;
 
-  CFX_PointF pt(pMsg->m_fx, pMsg->m_fy);
-  DeviceToEngine(pt);
   int32_t nCount = 0;
-  int32_t nIndex = pPage->SelectWord(pt, nCount);
+  int32_t nIndex = pPage->SelectWord(DeviceToEngine(pMsg->m_pos), nCount);
   if (nIndex < 0)
     return;
 
@@ -1378,10 +1357,8 @@
   if (!pPage)
     return;
 
-  CFX_PointF pt(pMsg->m_fx, pMsg->m_fy);
-  DeviceToEngine(pt);
   bool bBefore = true;
-  int32_t nIndex = pPage->GetCharIndex(pt, bBefore);
+  int32_t nIndex = pPage->GetCharIndex(DeviceToEngine(pMsg->m_pos), bBefore);
   m_EdtEngine.SetCaretPos(nIndex, bBefore);
   nIndex = m_EdtEngine.GetCaretPos();
   m_EdtEngine.ClearSelection();
@@ -1509,43 +1486,43 @@
                          CFWL_EventScroll::Code dwCode,
                          FX_FLOAT fPos) {
   CFX_SizeF fs;
-  pScrollBar->GetRange(&fs.x, &fs.y);
+  pScrollBar->GetRange(&fs.width, &fs.height);
   FX_FLOAT iCurPos = pScrollBar->GetPos();
   FX_FLOAT fStep = pScrollBar->GetStepSize();
   switch (dwCode) {
     case CFWL_EventScroll::Code::Min: {
-      fPos = fs.x;
+      fPos = fs.width;
       break;
     }
     case CFWL_EventScroll::Code::Max: {
-      fPos = fs.y;
+      fPos = fs.height;
       break;
     }
     case CFWL_EventScroll::Code::StepBackward: {
       fPos -= fStep;
-      if (fPos < fs.x + fStep / 2) {
-        fPos = fs.x;
+      if (fPos < fs.width + fStep / 2) {
+        fPos = fs.width;
       }
       break;
     }
     case CFWL_EventScroll::Code::StepForward: {
       fPos += fStep;
-      if (fPos > fs.y - fStep / 2) {
-        fPos = fs.y;
+      if (fPos > fs.height - fStep / 2) {
+        fPos = fs.height;
       }
       break;
     }
     case CFWL_EventScroll::Code::PageBackward: {
       fPos -= pScrollBar->GetPageSize();
-      if (fPos < fs.x) {
-        fPos = fs.x;
+      if (fPos < fs.width) {
+        fPos = fs.width;
       }
       break;
     }
     case CFWL_EventScroll::Code::PageForward: {
       fPos += pScrollBar->GetPageSize();
-      if (fPos > fs.y) {
-        fPos = fs.y;
+      if (fPos > fs.height) {
+        fPos = fs.height;
       }
       break;
     }
@@ -1565,8 +1542,6 @@
   UpdateCaret();
 
   CFX_RectF rect = GetWidgetRect();
-  CFX_RectF rtInvalidate;
-  rtInvalidate.Set(0, 0, rect.width + 2, rect.height + 2);
-  RepaintRect(rtInvalidate);
+  RepaintRect(CFX_RectF(0, 0, rect.width + 2, rect.height + 2));
   return true;
 }
diff --git a/xfa/fwl/cfwl_edit.h b/xfa/fwl/cfwl_edit.h
index 4193e73..154e286 100644
--- a/xfa/fwl/cfwl_edit.h
+++ b/xfa/fwl/cfwl_edit.h
@@ -59,7 +59,7 @@
   CFX_RectF GetAutosizedWidgetRect() override;
   CFX_RectF GetWidgetRect() override;
   void Update() override;
-  FWL_WidgetHit HitTest(FX_FLOAT fx, FX_FLOAT fy) override;
+  FWL_WidgetHit HitTest(const CFX_PointF& point) override;
   void SetStates(uint32_t dwStates) override;
   void DrawWidget(CFX_Graphics* pGraphics, const CFX_Matrix* pMatrix) override;
   void SetThemeProvider(IFWL_ThemeProvider* pThemeProvider) override;
@@ -127,7 +127,7 @@
   CFWL_ScrollBar* UpdateScroll();
   void Layout();
   void LayoutScrollBar();
-  void DeviceToEngine(CFX_PointF& pt);
+  CFX_PointF DeviceToEngine(const CFX_PointF& pt);
   void InitVerticalScrollBar();
   void InitHorizontalScrollBar();
   void InitEngine();
diff --git a/xfa/fwl/cfwl_event.h b/xfa/fwl/cfwl_event.h
index 9a9f30a..e326ab3 100644
--- a/xfa/fwl/cfwl_event.h
+++ b/xfa/fwl/cfwl_event.h
@@ -12,7 +12,6 @@
 #include "core/fxcrt/fx_system.h"
 #include "xfa/fwl/cfwl_messagekey.h"
 #include "xfa/fwl/cfwl_messagemouse.h"
-#include "xfa/fwl/fwl_error.h"
 
 class CFX_Graphics;
 class CFWL_Widget;
diff --git a/xfa/fwl/cfwl_form.cpp b/xfa/fwl/cfwl_form.cpp
index d0d6ef2..5e956ad 100644
--- a/xfa/fwl/cfwl_form.cpp
+++ b/xfa/fwl/cfwl_form.cpp
@@ -67,13 +67,12 @@
   Layout();
 }
 
-FWL_WidgetHit CFWL_Form::HitTest(FX_FLOAT fx, FX_FLOAT fy) {
+FWL_WidgetHit CFWL_Form::HitTest(const CFX_PointF& point) {
   GetAvailableTheme();
 
-  CFX_RectF rtCap;
-  rtCap.Set(m_fCYBorder, m_fCXBorder, -2 * m_fCYBorder, 0 - m_fCXBorder);
-  return rtCap.Contains(fx, fy) ? FWL_WidgetHit::Titlebar
-                                : FWL_WidgetHit::Client;
+  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(CFX_Graphics* pGraphics, const CFX_Matrix* pMatrix) {
diff --git a/xfa/fwl/cfwl_form.h b/xfa/fwl/cfwl_form.h
index 4297fde..7202cb2 100644
--- a/xfa/fwl/cfwl_form.h
+++ b/xfa/fwl/cfwl_form.h
@@ -37,7 +37,7 @@
   bool IsInstance(const CFX_WideStringC& wsClass) const override;
   CFX_RectF GetClientRect() override;
   void Update() override;
-  FWL_WidgetHit HitTest(FX_FLOAT fx, FX_FLOAT fy) override;
+  FWL_WidgetHit HitTest(const CFX_PointF& point) override;
   void DrawWidget(CFX_Graphics* pGraphics, const CFX_Matrix* pMatrix) override;
   void OnProcessMessage(CFWL_Message* pMessage) override;
   void OnDrawWidget(CFX_Graphics* pGraphics,
diff --git a/xfa/fwl/cfwl_listbox.cpp b/xfa/fwl/cfwl_listbox.cpp
index a7a568c..0b82709 100644
--- a/xfa/fwl/cfwl_listbox.cpp
+++ b/xfa/fwl/cfwl_listbox.cpp
@@ -75,18 +75,18 @@
   CalcSize(false);
 }
 
-FWL_WidgetHit CFWL_ListBox::HitTest(FX_FLOAT fx, FX_FLOAT fy) {
+FWL_WidgetHit CFWL_ListBox::HitTest(const CFX_PointF& point) {
   if (IsShowScrollBar(false)) {
     CFX_RectF rect = m_pHorzScrollBar->GetWidgetRect();
-    if (rect.Contains(fx, fy))
+    if (rect.Contains(point))
       return FWL_WidgetHit::HScrollBar;
   }
   if (IsShowScrollBar(true)) {
     CFX_RectF rect = m_pVertScrollBar->GetWidgetRect();
-    if (rect.Contains(fx, fy))
+    if (rect.Contains(point))
       return FWL_WidgetHit::VScrollBar;
   }
-  if (m_rtClient.Contains(fx, fy))
+  if (m_rtClient.Contains(point))
     return FWL_WidgetHit::Client;
   return FWL_WidgetHit::Unknown;
 }
@@ -304,8 +304,8 @@
   }
 }
 
-CFWL_ListItem* CFWL_ListBox::GetItemAtPoint(FX_FLOAT fx, FX_FLOAT fy) {
-  fx -= m_rtConent.left, fy -= m_rtConent.top;
+CFWL_ListItem* CFWL_ListBox::GetItemAtPoint(const CFX_PointF& point) {
+  CFX_PointF pos = point - m_rtConent.TopLeft();
   FX_FLOAT fPosX = 0.0f;
   if (m_pHorzScrollBar)
     fPosX = m_pHorzScrollBar->GetPos();
@@ -322,7 +322,7 @@
 
     CFX_RectF rtItem = pItem->GetRect();
     rtItem.Offset(-fPosX, -fPosY);
-    if (rtItem.Contains(fx, fy))
+    if (rtItem.Contains(pos))
       return pItem;
   }
   return nullptr;
@@ -475,7 +475,6 @@
   m_rtClient = GetClientRect();
   m_rtConent = m_rtClient;
   CFX_RectF rtUIMargin;
-  rtUIMargin.Set(0, 0, 0, 0);
   if (!m_pOuter) {
     CFWL_ThemePart part;
     part.m_pWidget = this;
@@ -507,29 +506,29 @@
   bool bShowVertScr = false;
   bool bShowHorzScr = false;
   if (!bShowVertScr && (m_pProperties->m_dwStyles & FWL_WGTSTYLE_VScroll))
-    bShowVertScr = (fs.y > iHeight);
+    bShowVertScr = (fs.height > iHeight);
 
   CFX_SizeF szRange;
   if (bShowVertScr) {
     if (!m_pVertScrollBar)
       InitVerticalScrollBar();
 
-    CFX_RectF rtScrollBar;
-    rtScrollBar.Set(m_rtClient.right() - m_fScorllBarWidth, m_rtClient.top,
-                    m_fScorllBarWidth, m_rtClient.height - 1);
+    CFX_RectF rtScrollBar(m_rtClient.right() - m_fScorllBarWidth,
+                          m_rtClient.top, m_fScorllBarWidth,
+                          m_rtClient.height - 1);
     if (bShowHorzScr)
       rtScrollBar.height -= m_fScorllBarWidth;
 
     m_pVertScrollBar->SetWidgetRect(rtScrollBar);
-    szRange.x = 0, szRange.y = fs.y - m_rtConent.height;
-    szRange.y = std::max(szRange.y, m_fItemHeight);
+    szRange.width = 0;
+    szRange.height = std::max(fs.height - m_rtConent.height, m_fItemHeight);
 
-    m_pVertScrollBar->SetRange(szRange.x, szRange.y);
+    m_pVertScrollBar->SetRange(szRange.width, szRange.height);
     m_pVertScrollBar->SetPageSize(rtScrollBar.height * 9 / 10);
     m_pVertScrollBar->SetStepSize(m_fItemHeight);
 
     FX_FLOAT fPos =
-        std::min(std::max(m_pVertScrollBar->GetPos(), 0.f), szRange.y);
+        std::min(std::max(m_pVertScrollBar->GetPos(), 0.f), szRange.height);
     m_pVertScrollBar->SetPos(fPos);
     m_pVertScrollBar->SetTrackPos(fPos);
     if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_ShowScrollBarFocus) ==
@@ -547,20 +546,21 @@
     if (!m_pHorzScrollBar)
       InitHorizontalScrollBar();
 
-    CFX_RectF rtScrollBar;
-    rtScrollBar.Set(m_rtClient.left, m_rtClient.bottom() - m_fScorllBarWidth,
-                    m_rtClient.width, m_fScorllBarWidth);
+    CFX_RectF rtScrollBar(m_rtClient.left,
+                          m_rtClient.bottom() - m_fScorllBarWidth,
+                          m_rtClient.width, m_fScorllBarWidth);
     if (bShowVertScr)
       rtScrollBar.width -= m_fScorllBarWidth;
 
     m_pHorzScrollBar->SetWidgetRect(rtScrollBar);
-    szRange.x = 0, szRange.y = fs.x - rtScrollBar.width;
-    m_pHorzScrollBar->SetRange(szRange.x, szRange.y);
+    szRange.width = 0;
+    szRange.height = fs.width - rtScrollBar.width;
+    m_pHorzScrollBar->SetRange(szRange.width, szRange.height);
     m_pHorzScrollBar->SetPageSize(fWidth * 9 / 10);
     m_pHorzScrollBar->SetStepSize(fWidth / 10);
 
     FX_FLOAT fPos =
-        std::min(std::max(m_pHorzScrollBar->GetPos(), 0.f), szRange.y);
+        std::min(std::max(m_pHorzScrollBar->GetPos(), 0.f), szRange.height);
     m_pHorzScrollBar->SetPos(fPos);
     m_pHorzScrollBar->SetTrackPos(fPos);
     if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_ShowScrollBarFocus) ==
@@ -575,9 +575,9 @@
     m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Invisible);
   }
   if (bShowVertScr && bShowHorzScr) {
-    m_rtStatic.Set(m_rtClient.right() - m_fScorllBarWidth,
-                   m_rtClient.bottom() - m_fScorllBarWidth, m_fScorllBarWidth,
-                   m_fScorllBarWidth);
+    m_rtStatic = CFX_RectF(m_rtClient.right() - m_fScorllBarWidth,
+                           m_rtClient.bottom() - m_fScorllBarWidth,
+                           m_fScorllBarWidth, m_fScorllBarWidth);
   }
   return fs;
 }
@@ -588,12 +588,11 @@
                                   FX_FLOAT fItemHeight,
                                   bool bAutoSize) const {
   if (!bAutoSize && pItem) {
-    CFX_RectF rtItem;
-    rtItem.Set(0, size.y, fWidth, fItemHeight);
+    CFX_RectF rtItem(0, size.height, fWidth, fItemHeight);
     pItem->SetRect(rtItem);
   }
-  size.x = fWidth;
-  size.y += fItemHeight;
+  size.width = fWidth;
+  size.height += fItemHeight;
 }
 
 FX_FLOAT CFWL_ListBox::GetMaxTextWidth() {
@@ -606,7 +605,7 @@
 
     CFX_SizeF sz =
         CalcTextSize(pItem->GetText(), m_pProperties->m_pThemeProvider, false);
-    fRet = std::max(fRet, sz.x);
+    fRet = std::max(fRet, sz.width);
   }
   return fRet;
 }
@@ -749,7 +748,7 @@
   if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0)
     SetFocus(true);
 
-  CFWL_ListItem* pItem = GetItemAtPoint(pMsg->m_fx, pMsg->m_fy);
+  CFWL_ListItem* pItem = GetItemAtPoint(pMsg->m_pos);
   if (!pItem)
     return;
 
@@ -833,50 +832,48 @@
   SetFocusItem(pItem);
   ScrollToVisible(pItem);
 
-  CFX_RectF rtInvalidate;
-  rtInvalidate.Set(0, 0, m_pProperties->m_rtWidget.width,
-                   m_pProperties->m_rtWidget.height);
-  RepaintRect(rtInvalidate);
+  RepaintRect(CFX_RectF(0, 0, m_pProperties->m_rtWidget.width,
+                        m_pProperties->m_rtWidget.height));
 }
 
 bool CFWL_ListBox::OnScroll(CFWL_ScrollBar* pScrollBar,
                             CFWL_EventScroll::Code dwCode,
                             FX_FLOAT fPos) {
   CFX_SizeF fs;
-  pScrollBar->GetRange(&fs.x, &fs.y);
+  pScrollBar->GetRange(&fs.width, &fs.height);
   FX_FLOAT iCurPos = pScrollBar->GetPos();
   FX_FLOAT fStep = pScrollBar->GetStepSize();
   switch (dwCode) {
     case CFWL_EventScroll::Code::Min: {
-      fPos = fs.x;
+      fPos = fs.width;
       break;
     }
     case CFWL_EventScroll::Code::Max: {
-      fPos = fs.y;
+      fPos = fs.height;
       break;
     }
     case CFWL_EventScroll::Code::StepBackward: {
       fPos -= fStep;
-      if (fPos < fs.x + fStep / 2)
-        fPos = fs.x;
+      if (fPos < fs.width + fStep / 2)
+        fPos = fs.width;
       break;
     }
     case CFWL_EventScroll::Code::StepForward: {
       fPos += fStep;
-      if (fPos > fs.y - fStep / 2)
-        fPos = fs.y;
+      if (fPos > fs.height - fStep / 2)
+        fPos = fs.height;
       break;
     }
     case CFWL_EventScroll::Code::PageBackward: {
       fPos -= pScrollBar->GetPageSize();
-      if (fPos < fs.x)
-        fPos = fs.x;
+      if (fPos < fs.width)
+        fPos = fs.width;
       break;
     }
     case CFWL_EventScroll::Code::PageForward: {
       fPos += pScrollBar->GetPageSize();
-      if (fPos > fs.y)
-        fPos = fs.y;
+      if (fPos > fs.height)
+        fPos = fs.height;
       break;
     }
     case CFWL_EventScroll::Code::Pos:
diff --git a/xfa/fwl/cfwl_listbox.h b/xfa/fwl/cfwl_listbox.h
index 95d8ad9..caa4f50 100644
--- a/xfa/fwl/cfwl_listbox.h
+++ b/xfa/fwl/cfwl_listbox.h
@@ -41,7 +41,7 @@
   // CFWL_Widget
   FWL_Type GetClassID() const override;
   void Update() override;
-  FWL_WidgetHit HitTest(FX_FLOAT fx, FX_FLOAT fy) override;
+  FWL_WidgetHit HitTest(const CFX_PointF& point) override;
   void DrawWidget(CFX_Graphics* pGraphics, const CFX_Matrix* pMatrix) override;
   void SetThemeProvider(IFWL_ThemeProvider* pThemeProvider) override;
   void OnProcessMessage(CFWL_Message* pMessage) override;
@@ -69,7 +69,7 @@
  protected:
   CFWL_ListItem* GetListItem(CFWL_ListItem* hItem, uint32_t dwKeyCode);
   void SetSelection(CFWL_ListItem* hStart, CFWL_ListItem* hEnd, bool bSelected);
-  CFWL_ListItem* GetItemAtPoint(FX_FLOAT fx, FX_FLOAT fy);
+  CFWL_ListItem* GetItemAtPoint(const CFX_PointF& point);
   bool ScrollToVisible(CFWL_ListItem* hItem);
   void InitVerticalScrollBar();
   void InitHorizontalScrollBar();
diff --git a/xfa/fwl/cfwl_message.h b/xfa/fwl/cfwl_message.h
index 67e1f05..778e1e2 100644
--- a/xfa/fwl/cfwl_message.h
+++ b/xfa/fwl/cfwl_message.h
@@ -12,7 +12,6 @@
 #include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
-#include "xfa/fwl/fwl_error.h"
 
 class CFWL_Widget;
 
diff --git a/xfa/fwl/cfwl_messagemouse.cpp b/xfa/fwl/cfwl_messagemouse.cpp
index 110292a..1d56b0f 100644
--- a/xfa/fwl/cfwl_messagemouse.cpp
+++ b/xfa/fwl/cfwl_messagemouse.cpp
@@ -14,6 +14,8 @@
                                      CFWL_Widget* pDstTarget)
     : CFWL_Message(CFWL_Message::Type::Mouse, pSrcTarget, pDstTarget) {}
 
+CFWL_MessageMouse::CFWL_MessageMouse(const CFWL_MessageMouse& other) = default;
+
 CFWL_MessageMouse::~CFWL_MessageMouse() {}
 
 std::unique_ptr<CFWL_Message> CFWL_MessageMouse::Clone() {
diff --git a/xfa/fwl/cfwl_messagemouse.h b/xfa/fwl/cfwl_messagemouse.h
index ac45745..a2b0d39 100644
--- a/xfa/fwl/cfwl_messagemouse.h
+++ b/xfa/fwl/cfwl_messagemouse.h
@@ -9,6 +9,7 @@
 
 #include <memory>
 
+#include "core/fxcrt/fx_coordinates.h"
 #include "xfa/fwl/cfwl_message.h"
 
 enum class FWL_MouseCommand {
@@ -27,13 +28,13 @@
 class CFWL_MessageMouse : public CFWL_Message {
  public:
   CFWL_MessageMouse(CFWL_Widget* pSrcTarget, CFWL_Widget* pDstTarget);
+  CFWL_MessageMouse(const CFWL_MessageMouse& other);
   ~CFWL_MessageMouse() override;
 
   // CFWL_Message
   std::unique_ptr<CFWL_Message> Clone() override;
 
-  FX_FLOAT m_fx;
-  FX_FLOAT m_fy;
+  CFX_PointF m_pos;
   uint32_t m_dwFlags;
   FWL_MouseCommand m_dwCmd;
 };
diff --git a/xfa/fwl/cfwl_messagemousewheel.cpp b/xfa/fwl/cfwl_messagemousewheel.cpp
index 3646b6c..8996f65 100644
--- a/xfa/fwl/cfwl_messagemousewheel.cpp
+++ b/xfa/fwl/cfwl_messagemousewheel.cpp
@@ -14,6 +14,9 @@
                                                CFWL_Widget* pDstTarget)
     : CFWL_Message(CFWL_Message::Type::MouseWheel, pSrcTarget, pDstTarget) {}
 
+CFWL_MessageMouseWheel::CFWL_MessageMouseWheel(const CFWL_MessageMouseWheel&) =
+    default;
+
 CFWL_MessageMouseWheel::~CFWL_MessageMouseWheel() {}
 
 std::unique_ptr<CFWL_Message> CFWL_MessageMouseWheel::Clone() {
diff --git a/xfa/fwl/cfwl_messagemousewheel.h b/xfa/fwl/cfwl_messagemousewheel.h
index 4d568c8..f969b9a 100644
--- a/xfa/fwl/cfwl_messagemousewheel.h
+++ b/xfa/fwl/cfwl_messagemousewheel.h
@@ -9,20 +9,20 @@
 
 #include <memory>
 
+#include "core/fxcrt/fx_coordinates.h"
 #include "xfa/fwl/cfwl_message.h"
 
 class CFWL_MessageMouseWheel : public CFWL_Message {
  public:
   CFWL_MessageMouseWheel(CFWL_Widget* pSrcTarget, CFWL_Widget* pDstTarget);
+  CFWL_MessageMouseWheel(const CFWL_MessageMouseWheel&);
   ~CFWL_MessageMouseWheel() override;
 
   // CFWL_Message
   std::unique_ptr<CFWL_Message> Clone() override;
 
-  FX_FLOAT m_fx;
-  FX_FLOAT m_fy;
-  FX_FLOAT m_fDeltaX;
-  FX_FLOAT m_fDeltaY;
+  CFX_PointF m_pos;
+  CFX_PointF m_delta;
   uint32_t m_dwFlags;
 };
 
diff --git a/xfa/fwl/cfwl_monthcalendar.cpp b/xfa/fwl/cfwl_monthcalendar.cpp
index b79dc3e..6882d70 100644
--- a/xfa/fwl/cfwl_monthcalendar.cpp
+++ b/xfa/fwl/cfwl_monthcalendar.cpp
@@ -11,6 +11,7 @@
 #include <utility>
 
 #include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
 #include "xfa/fde/tto/fde_textout.h"
 #include "xfa/fwl/cfwl_datetimepicker.h"
 #include "xfa/fwl/cfwl_formproxy.h"
@@ -115,7 +116,7 @@
 
 CFWL_MonthCalendar::~CFWL_MonthCalendar() {
   ClearDateItem();
-  m_arrSelDays.RemoveAll();
+  m_arrSelDays.clear();
 }
 
 FWL_Type CFWL_MonthCalendar::GetClassID() const {
@@ -124,8 +125,7 @@
 
 CFX_RectF CFWL_MonthCalendar::GetAutosizedWidgetRect() {
   CFX_SizeF fs = CalcSize();
-  CFX_RectF rect;
-  rect.Set(0, 0, fs.x, fs.y);
+  CFX_RectF rect(0, 0, fs.width, fs.height);
   InflateWidgetRect(rect);
   return rect;
 }
@@ -279,9 +279,9 @@
   if (pMatrix)
     params.m_matrix.Concat(*pMatrix);
 
-  int32_t iCount = m_arrDates.GetSize();
+  int32_t iCount = pdfium::CollectionSize<int32_t>(m_arrDates);
   for (int32_t j = 0; j < iCount; j++) {
-    DATEINFO* pDataInfo = m_arrDates.GetAt(j);
+    DATEINFO* pDataInfo = m_arrDates[j].get();
     if (pDataInfo->dwStates & FWL_ITEMSTATE_MCD_Selected) {
       params.m_dwStates |= CFWL_PartState_Selected;
       if (pDataInfo->dwStates & FWL_ITEMSTATE_MCD_Flag) {
@@ -313,8 +313,10 @@
     params.m_matrix.Concat(*pMatrix);
 
   for (int32_t i = 0; i < 7; i++) {
-    rtDayOfWeek.Set(m_rtWeek.left + i * (m_szCell.x + MONTHCAL_HMARGIN * 2),
-                    m_rtWeek.top, m_szCell.x, m_szCell.y);
+    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);
     params.m_dwTTOStyles = FDE_TTOSTYLE_SingleLine;
@@ -355,9 +357,9 @@
   if (pMatrix)
     params.m_matrix.Concat(*pMatrix);
 
-  int32_t iCount = m_arrDates.GetSize();
+  int32_t iCount = pdfium::CollectionSize<int32_t>(m_arrDates);
   for (int32_t j = 0; j < iCount; j++) {
-    DATEINFO* pDataInfo = m_arrDates.GetAt(j);
+    DATEINFO* pDataInfo = m_arrDates[j].get();
     params.m_wsText = pDataInfo->wsDay;
     params.m_rtPart = pDataInfo->rect;
     params.m_dwStates = pDataInfo->dwStates;
@@ -387,10 +389,11 @@
                                            const CFX_Matrix* pMatrix) {
   if (m_iMonth != m_iCurMonth || m_iYear != m_iCurYear)
     return;
-  if (m_iDay < 1 || m_iDay > m_arrDates.GetSize())
+
+  if (m_iDay < 1 || m_iDay > pdfium::CollectionSize<int32_t>(m_arrDates))
     return;
 
-  DATEINFO* pDate = m_arrDates[m_iDay - 1];
+  DATEINFO* pDate = m_arrDates[m_iDay - 1].get();
   if (!pDate)
     return;
 
@@ -409,7 +412,6 @@
   if (!m_pProperties->m_pThemeProvider)
     return CFX_SizeF();
 
-  CFX_SizeF fs;
   CFWL_ThemePart params;
   params.m_pWidget = this;
   IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
@@ -419,8 +421,8 @@
   for (uint32_t i = 0; i < 7; ++i) {
     CFX_SizeF sz = CalcTextSize(GetCapacityForDay(pTheme, params, i),
                                 m_pProperties->m_pThemeProvider, false);
-    fMaxWeekW = (fMaxWeekW >= sz.x) ? fMaxWeekW : sz.x;
-    fMaxWeekH = (fMaxWeekH >= sz.y) ? fMaxWeekH : sz.y;
+    fMaxWeekW = (fMaxWeekW >= sz.width) ? fMaxWeekW : sz.width;
+    fMaxWeekH = (fMaxWeekH >= sz.height) ? fMaxWeekH : sz.height;
   }
 
   FX_FLOAT fDayMaxW = 0.0f;
@@ -429,89 +431,95 @@
     CFX_WideString wsDay;
     wsDay.Format(L"%d", day);
     CFX_SizeF sz = CalcTextSize(wsDay, m_pProperties->m_pThemeProvider, false);
-    fDayMaxW = (fDayMaxW >= sz.x) ? fDayMaxW : sz.x;
-    fDayMaxH = (fDayMaxH >= sz.y) ? fDayMaxH : sz.y;
+    fDayMaxW = (fDayMaxW >= sz.width) ? fDayMaxW : sz.width;
+    fDayMaxH = (fDayMaxH >= sz.height) ? fDayMaxH : sz.height;
   }
-  m_szCell.x = FX_FLOAT((fMaxWeekW >= fDayMaxW) ? (int)(fMaxWeekW + 0.5)
-                                                : (int)(fDayMaxW + 0.5));
-  m_szCell.y = (fMaxWeekH >= fDayMaxH) ? fMaxWeekH : fDayMaxH;
-  fs.x = m_szCell.x * MONTHCAL_COLUMNS +
-         MONTHCAL_HMARGIN * MONTHCAL_COLUMNS * 2 +
-         MONTHCAL_HEADER_BTN_HMARGIN * 2;
+  m_szCell.width = FX_FLOAT((fMaxWeekW >= fDayMaxW) ? (int)(fMaxWeekW + 0.5)
+                                                    : (int)(fDayMaxW + 0.5));
+  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;
   FX_FLOAT fMonthMaxW = 0.0f;
   FX_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);
-    fMonthMaxW = (fMonthMaxW >= sz.x) ? fMonthMaxW : sz.x;
-    fMonthMaxH = (fMonthMaxH >= sz.y) ? fMonthMaxH : sz.y;
+    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);
-  fMonthMaxH = std::max(fMonthMaxH, szYear.y);
-  m_szHead = CFX_SizeF(fMonthMaxW + szYear.x, fMonthMaxH);
-  fMonthMaxW = m_szHead.x + MONTHCAL_HEADER_BTN_HMARGIN * 2 + m_szCell.x * 2;
-  fs.x = std::max(fs.x, fMonthMaxW);
+  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);
 
   CFX_WideString wsToday = GetTodayText(m_iYear, m_iMonth, m_iDay);
   m_wsToday = L"Today" + wsToday;
   m_szToday = CalcTextSize(wsToday, m_pProperties->m_pThemeProvider, false);
-  m_szToday.y = (m_szToday.y >= m_szCell.y) ? m_szToday.y : m_szCell.y;
-  fs.y = m_szCell.x + m_szCell.y * (MONTHCAL_ROWS - 2) + m_szToday.y +
-         MONTHCAL_VMARGIN * MONTHCAL_ROWS * 2 + MONTHCAL_HEADER_BTN_VMARGIN * 4;
+  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) +
+              m_szToday.height + MONTHCAL_VMARGIN * MONTHCAL_ROWS * 2 +
+              MONTHCAL_HEADER_BTN_VMARGIN * 4;
   return fs;
 }
 
 void CFWL_MonthCalendar::CalcHeadSize() {
-  FX_FLOAT fHeadHMargin = (m_rtClient.width - m_szHead.x) / 2;
-  FX_FLOAT fHeadVMargin = (m_szCell.x - m_szHead.y) / 2;
-  m_rtHeadText.Set(m_rtClient.left + fHeadHMargin,
-                   m_rtClient.top + MONTHCAL_HEADER_BTN_VMARGIN +
-                       MONTHCAL_VMARGIN + fHeadVMargin,
-                   m_szHead.x, m_szHead.y);
+  FX_FLOAT fHeadHMargin = (m_rtClient.width - m_szHead.width) / 2;
+  FX_FLOAT fHeadVMargin = (m_szCell.width - m_szHead.height) / 2;
+  m_rtHeadText = CFX_RectF(m_rtClient.left + fHeadHMargin,
+                           m_rtClient.top + MONTHCAL_HEADER_BTN_VMARGIN +
+                               MONTHCAL_VMARGIN + fHeadVMargin,
+                           m_szHead);
 }
 
 void CFWL_MonthCalendar::CalcTodaySize() {
-  m_rtTodayFlag.Set(
+  m_rtTodayFlag = CFX_RectF(
       m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN + MONTHCAL_HMARGIN,
       m_rtDates.bottom() + MONTHCAL_HEADER_BTN_VMARGIN + MONTHCAL_VMARGIN,
-      m_szCell.x, m_szToday.y);
-  m_rtToday.Set(
-      m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN + m_szCell.x +
+      m_szCell.width, m_szToday.height);
+  m_rtToday = CFX_RectF(
+      m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN + m_szCell.width +
           MONTHCAL_HMARGIN * 2,
       m_rtDates.bottom() + MONTHCAL_HEADER_BTN_VMARGIN + MONTHCAL_VMARGIN,
-      m_szToday.x, m_szToday.y);
+      m_szToday);
 }
 
 void CFWL_MonthCalendar::Layout() {
   m_rtClient = GetClientRect();
 
-  m_rtHead.Set(
+  m_rtHead = CFX_RectF(
       m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN, m_rtClient.top,
       m_rtClient.width - MONTHCAL_HEADER_BTN_HMARGIN * 2,
-      m_szCell.x + (MONTHCAL_HEADER_BTN_VMARGIN + MONTHCAL_VMARGIN) * 2);
-  m_rtWeek.Set(m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN, m_rtHead.bottom(),
-               m_rtClient.width - MONTHCAL_HEADER_BTN_HMARGIN * 2,
-               m_szCell.y + MONTHCAL_VMARGIN * 2);
-  m_rtLBtn.Set(m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN,
-               m_rtClient.top + MONTHCAL_HEADER_BTN_VMARGIN, m_szCell.x,
-               m_szCell.x);
-  m_rtRBtn.Set(m_rtClient.left + m_rtClient.width -
-                   MONTHCAL_HEADER_BTN_HMARGIN - m_szCell.x,
-               m_rtClient.top + MONTHCAL_HEADER_BTN_VMARGIN, m_szCell.x,
-               m_szCell.x);
-  m_rtHSep.Set(
+      m_szCell.width + (MONTHCAL_HEADER_BTN_VMARGIN + MONTHCAL_VMARGIN) * 2);
+  m_rtWeek = CFX_RectF(m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN,
+                       m_rtHead.bottom(),
+                       m_rtClient.width - MONTHCAL_HEADER_BTN_HMARGIN * 2,
+                       m_szCell.height + MONTHCAL_VMARGIN * 2);
+  m_rtLBtn = CFX_RectF(m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN,
+                       m_rtClient.top + MONTHCAL_HEADER_BTN_VMARGIN,
+                       m_szCell.width, m_szCell.width);
+  m_rtRBtn = CFX_RectF(m_rtClient.left + m_rtClient.width -
+                           MONTHCAL_HEADER_BTN_HMARGIN - m_szCell.width,
+                       m_rtClient.top + MONTHCAL_HEADER_BTN_VMARGIN,
+                       m_szCell.width, m_szCell.width);
+  m_rtHSep = CFX_RectF(
       m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN + MONTHCAL_HMARGIN,
       m_rtWeek.bottom() - MONTHCAL_VMARGIN,
       m_rtClient.width - (MONTHCAL_HEADER_BTN_HMARGIN + MONTHCAL_HMARGIN) * 2,
       MONTHCAL_HSEP_HEIGHT);
-  m_rtDates.Set(m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN,
-                m_rtWeek.bottom(),
-                m_rtClient.width - MONTHCAL_HEADER_BTN_HMARGIN * 2,
-                m_szCell.y * (MONTHCAL_ROWS - 3) +
-                    MONTHCAL_VMARGIN * (MONTHCAL_ROWS - 3) * 2);
+  m_rtDates = CFX_RectF(m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN,
+                        m_rtWeek.bottom(),
+                        m_rtClient.width - MONTHCAL_HEADER_BTN_HMARGIN * 2,
+                        m_szCell.height * (MONTHCAL_ROWS - 3) +
+                            MONTHCAL_VMARGIN * (MONTHCAL_ROWS - 3) * 2);
 
   CalDateItem();
 }
@@ -521,18 +529,17 @@
   int32_t iWeekOfMonth = 0;
   FX_FLOAT fLeft = m_rtDates.left;
   FX_FLOAT fTop = m_rtDates.top;
-  int32_t iCount = m_arrDates.GetSize();
-  for (int32_t i = 0; i < iCount; i++) {
-    DATEINFO* pDateInfo = m_arrDates.GetAt(i);
+  for (const auto& pDateInfo : m_arrDates) {
     if (bNewWeek) {
       iWeekOfMonth++;
       bNewWeek = false;
     }
-    pDateInfo->rect.Set(
-        fLeft + pDateInfo->iDayOfWeek * (m_szCell.x + (MONTHCAL_HMARGIN * 2)),
-        fTop + iWeekOfMonth * (m_szCell.y + (MONTHCAL_VMARGIN * 2)),
-        m_szCell.x + (MONTHCAL_HMARGIN * 2),
-        m_szCell.y + (MONTHCAL_VMARGIN * 2));
+    pDateInfo->rect = CFX_RectF(
+        fLeft +
+            pDateInfo->iDayOfWeek * (m_szCell.width + (MONTHCAL_HMARGIN * 2)),
+        fTop + iWeekOfMonth * (m_szCell.height + (MONTHCAL_VMARGIN * 2)),
+        m_szCell.width + (MONTHCAL_HMARGIN * 2),
+        m_szCell.height + (MONTHCAL_VMARGIN * 2));
     if (pDateInfo->iDayOfWeek >= 6)
       bNewWeek = true;
   }
@@ -559,9 +566,7 @@
 }
 
 void CFWL_MonthCalendar::ClearDateItem() {
-  for (int32_t i = 0; i < m_arrDates.GetSize(); i++)
-    delete m_arrDates.GetAt(i);
-  m_arrDates.RemoveAll();
+  m_arrDates.clear();
 }
 
 void CFWL_MonthCalendar::ResetDateItem() {
@@ -577,12 +582,12 @@
     uint32_t dwStates = 0;
     if (m_iYear == m_iCurYear && m_iMonth == m_iCurMonth && m_iDay == (i + 1))
       dwStates |= FWL_ITEMSTATE_MCD_Flag;
-    if (m_arrSelDays.Find(i + 1) != -1)
+    if (pdfium::ContainsValue(m_arrSelDays, i + 1))
       dwStates |= FWL_ITEMSTATE_MCD_Selected;
 
     CFX_RectF rtDate;
-    rtDate.Set(0, 0, 0, 0);
-    m_arrDates.Add(new DATEINFO(i + 1, iDayOfWeek, dwStates, rtDate, wsDay));
+    m_arrDates.push_back(pdfium::MakeUnique<DATEINFO>(i + 1, iDayOfWeek,
+                                                      dwStates, rtDate, wsDay));
     iDayOfWeek++;
   }
 }
@@ -634,30 +639,24 @@
 }
 
 void CFWL_MonthCalendar::RemoveSelDay() {
-  int32_t iCount = m_arrSelDays.GetSize();
-  int32_t iDatesCount = m_arrDates.GetSize();
-  for (int32_t i = 0; i < iCount; i++) {
-    int32_t iSelDay = m_arrSelDays.GetAt(i);
-    if (iSelDay <= iDatesCount) {
-      DATEINFO* pDateInfo = m_arrDates.GetAt(iSelDay - 1);
-      pDateInfo->dwStates &= ~FWL_ITEMSTATE_MCD_Selected;
-    }
+  int32_t iDatesCount = pdfium::CollectionSize<int32_t>(m_arrDates);
+  for (int32_t iSelDay : m_arrSelDays) {
+    if (iSelDay <= iDatesCount)
+      m_arrDates[iSelDay - 1]->dwStates &= ~FWL_ITEMSTATE_MCD_Selected;
   }
-  m_arrSelDays.RemoveAll();
-  return;
+  m_arrSelDays.clear();
 }
 
 void CFWL_MonthCalendar::AddSelDay(int32_t iDay) {
   ASSERT(iDay > 0);
-  if (m_arrSelDays.Find(iDay) != -1)
+  if (!pdfium::ContainsValue(m_arrSelDays, iDay))
     return;
 
   RemoveSelDay();
-  if (iDay <= m_arrDates.GetSize()) {
-    DATEINFO* pDateInfo = m_arrDates.GetAt(iDay - 1);
-    pDateInfo->dwStates |= FWL_ITEMSTATE_MCD_Selected;
-  }
-  m_arrSelDays.Add(iDay);
+  if (iDay <= pdfium::CollectionSize<int32_t>(m_arrDates))
+    m_arrDates[iDay - 1]->dwStates |= FWL_ITEMSTATE_MCD_Selected;
+
+  m_arrSelDays.push_back(iDay);
 }
 
 void CFWL_MonthCalendar::JumpToToday() {
@@ -669,7 +668,7 @@
     return;
   }
 
-  if (m_arrSelDays.Find(m_iDay) == -1)
+  if (!pdfium::ContainsValue(m_arrSelDays, m_iDay))
     AddSelDay(m_iDay);
 }
 
@@ -692,24 +691,22 @@
   return wsToday;
 }
 
-int32_t CFWL_MonthCalendar::GetDayAtPoint(FX_FLOAT x, FX_FLOAT y) {
-  int32_t iCount = m_arrDates.GetSize();
-  for (int32_t i = 0; i < iCount; i++) {
-    DATEINFO* pDateInfo = m_arrDates.GetAt(i);
-    if (pDateInfo->rect.Contains(x, y))
-      return ++i;
+int32_t CFWL_MonthCalendar::GetDayAtPoint(const CFX_PointF& point) const {
+  int i = 1;  // one-based day values.
+  for (const auto& pDateInfo : m_arrDates) {
+    if (pDateInfo->rect.Contains(point))
+      return i;
+    ++i;
   }
   return -1;
 }
 
 CFX_RectF CFWL_MonthCalendar::GetDayRect(int32_t iDay) {
-  if (iDay <= 0 || iDay > m_arrDates.GetSize())
+  if (iDay <= 0 || iDay > pdfium::CollectionSize<int32_t>(m_arrDates))
     return CFX_RectF();
 
-  DATEINFO* pDateInfo = m_arrDates[iDay - 1];
-  if (!pDateInfo)
-    return CFX_RectF();
-  return pDateInfo->rect;
+  DATEINFO* pDateInfo = m_arrDates[iDay - 1].get();
+  return pDateInfo ? pDateInfo->rect : CFX_RectF();
 }
 
 void CFWL_MonthCalendar::OnProcessMessage(CFWL_Message* pMessage) {
@@ -755,15 +752,15 @@
 }
 
 void CFWL_MonthCalendar::OnLButtonDown(CFWL_MessageMouse* pMsg) {
-  if (m_rtLBtn.Contains(pMsg->m_fx, pMsg->m_fy)) {
+  if (m_rtLBtn.Contains(pMsg->m_pos)) {
     m_iLBtnPartStates = CFWL_PartState_Pressed;
     PrevMonth();
     RepaintRect(m_rtClient);
-  } else if (m_rtRBtn.Contains(pMsg->m_fx, pMsg->m_fy)) {
+  } else if (m_rtRBtn.Contains(pMsg->m_pos)) {
     m_iRBtnPartStates |= CFWL_PartState_Pressed;
     NextMonth();
     RepaintRect(m_rtClient);
-  } else if (m_rtToday.Contains(pMsg->m_fx, pMsg->m_fy)) {
+  } else if (m_rtToday.Contains(pMsg->m_pos)) {
     JumpToToday();
     RepaintRect(m_rtClient);
   } else {
@@ -777,32 +774,30 @@
   if (m_pWidgetMgr->IsFormDisabled())
     return DisForm_OnLButtonUp(pMsg);
 
-  if (m_rtLBtn.Contains(pMsg->m_fx, pMsg->m_fy)) {
+  if (m_rtLBtn.Contains(pMsg->m_pos)) {
     m_iLBtnPartStates = 0;
     RepaintRect(m_rtLBtn);
     return;
   }
-  if (m_rtRBtn.Contains(pMsg->m_fx, pMsg->m_fy)) {
+  if (m_rtRBtn.Contains(pMsg->m_pos)) {
     m_iRBtnPartStates = 0;
     RepaintRect(m_rtRBtn);
     return;
   }
-  if (m_rtToday.Contains(pMsg->m_fx, pMsg->m_fy))
+  if (m_rtToday.Contains(pMsg->m_pos))
     return;
 
   int32_t iOldSel = 0;
-  if (m_arrSelDays.GetSize() > 0)
+  if (!m_arrSelDays.empty())
     iOldSel = m_arrSelDays[0];
 
-  int32_t iCurSel = GetDayAtPoint(pMsg->m_fx, pMsg->m_fy);
+  int32_t iCurSel = GetDayAtPoint(pMsg->m_pos);
   CFWL_DateTimePicker* pIPicker = static_cast<CFWL_DateTimePicker*>(m_pOuter);
-  CFX_RectF rt = pIPicker->GetFormProxy()->GetWidgetRect();
-  rt.Set(0, 0, rt.width, rt.height);
   if (iCurSel > 0) {
-    DATEINFO* lpDatesInfo = m_arrDates.GetAt(iCurSel - 1);
+    DATEINFO* lpDatesInfo = m_arrDates[iCurSel - 1].get();
     CFX_RectF rtInvalidate(lpDatesInfo->rect);
-    if (iOldSel > 0 && iOldSel <= m_arrDates.GetSize()) {
-      lpDatesInfo = m_arrDates.GetAt(iOldSel - 1);
+    if (iOldSel > 0 && iOldSel <= pdfium::CollectionSize<int32_t>(m_arrDates)) {
+      lpDatesInfo = m_arrDates[iOldSel - 1].get();
       rtInvalidate.Union(lpDatesInfo->rect);
     }
     AddSelDay(iCurSel);
@@ -811,36 +806,38 @@
 
     pIPicker->ProcessSelChanged(m_iCurYear, m_iCurMonth, iCurSel);
     pIPicker->ShowMonthCalendar(false);
-  } else if (m_bFlag && (!rt.Contains(pMsg->m_fx, pMsg->m_fy))) {
+  } 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_fx, pMsg->m_fy)) {
+  if (m_rtLBtn.Contains(pMsg->m_pos)) {
     m_iLBtnPartStates = 0;
     RepaintRect(m_rtLBtn);
     return;
   }
-  if (m_rtRBtn.Contains(pMsg->m_fx, pMsg->m_fy)) {
+  if (m_rtRBtn.Contains(pMsg->m_pos)) {
     m_iRBtnPartStates = 0;
     RepaintRect(m_rtRBtn);
     return;
   }
-  if (m_rtToday.Contains(pMsg->m_fx, pMsg->m_fy))
+  if (m_rtToday.Contains(pMsg->m_pos))
     return;
 
   int32_t iOldSel = 0;
-  if (m_arrSelDays.GetSize() > 0)
+  if (!m_arrSelDays.empty())
     iOldSel = m_arrSelDays[0];
 
-  int32_t iCurSel = GetDayAtPoint(pMsg->m_fx, pMsg->m_fy);
+  int32_t iCurSel = GetDayAtPoint(pMsg->m_pos);
   if (iCurSel > 0) {
-    DATEINFO* lpDatesInfo = m_arrDates.GetAt(iCurSel - 1);
+    DATEINFO* lpDatesInfo = m_arrDates[iCurSel - 1].get();
     CFX_RectF rtInvalidate(lpDatesInfo->rect);
-    if (iOldSel > 0 && iOldSel <= m_arrDates.GetSize()) {
-      lpDatesInfo = m_arrDates.GetAt(iOldSel - 1);
+    if (iOldSel > 0 && iOldSel <= pdfium::CollectionSize<int32_t>(m_arrDates)) {
+      lpDatesInfo = m_arrDates[iOldSel - 1].get();
       rtInvalidate.Union(lpDatesInfo->rect);
     }
     AddSelDay(iCurSel);
@@ -854,9 +851,8 @@
 void CFWL_MonthCalendar::OnMouseMove(CFWL_MessageMouse* pMsg) {
   bool bRepaint = false;
   CFX_RectF rtInvalidate;
-  rtInvalidate.Set(0, 0, 0, 0);
-  if (m_rtDates.Contains(pMsg->m_fx, pMsg->m_fy)) {
-    int32_t iHover = GetDayAtPoint(pMsg->m_fx, pMsg->m_fy);
+  if (m_rtDates.Contains(pMsg->m_pos)) {
+    int32_t iHover = GetDayAtPoint(pMsg->m_pos);
     bRepaint = m_iHovered != iHover;
     if (bRepaint) {
       if (m_iHovered > 0)
diff --git a/xfa/fwl/cfwl_monthcalendar.h b/xfa/fwl/cfwl_monthcalendar.h
index 6c1d0d9..a110ee8 100644
--- a/xfa/fwl/cfwl_monthcalendar.h
+++ b/xfa/fwl/cfwl_monthcalendar.h
@@ -8,6 +8,7 @@
 #define XFA_FWL_CFWL_MONTHCALENDAR_H_
 
 #include <memory>
+#include <vector>
 
 #include "xfa/fgas/localization/fgas_datetime.h"
 #include "xfa/fwl/cfwl_event.h"
@@ -142,7 +143,7 @@
   void JumpToToday();
   CFX_WideString GetHeadText(int32_t iYear, int32_t iMonth);
   CFX_WideString GetTodayText(int32_t iYear, int32_t iMonth, int32_t iDay);
-  int32_t GetDayAtPoint(FX_FLOAT x, FX_FLOAT y);
+  int32_t GetDayAtPoint(const CFX_PointF& point) const;
   CFX_RectF GetDayRect(int32_t iDay);
   void OnLButtonDown(CFWL_MessageMouse* pMsg);
   void OnLButtonUp(CFWL_MessageMouse* pMsg);
@@ -165,7 +166,7 @@
   CFX_WideString m_wsHead;
   CFX_WideString m_wsToday;
   std::unique_ptr<CFX_DateTime> m_pDateTime;
-  CFX_ArrayTemplate<DATEINFO*> m_arrDates;
+  std::vector<std::unique_ptr<DATEINFO>> m_arrDates;
   int32_t m_iCurYear;
   int32_t m_iCurMonth;
   int32_t m_iYear;
@@ -179,7 +180,7 @@
   CFX_SizeF m_szHead;
   CFX_SizeF m_szCell;
   CFX_SizeF m_szToday;
-  CFX_ArrayTemplate<int32_t> m_arrSelDays;
+  std::vector<int32_t> m_arrSelDays;
   CFX_RectF m_rtClient;
   bool m_bFlag;
 };
diff --git a/xfa/fwl/cfwl_notedriver.cpp b/xfa/fwl/cfwl_notedriver.cpp
index f4db9b1..8feb0fb 100644
--- a/xfa/fwl/cfwl_notedriver.cpp
+++ b/xfa/fwl/cfwl_notedriver.cpp
@@ -342,7 +342,7 @@
     return !!pMsg->m_pDstTarget;
   }
   if (pMsg->m_pDstTarget != pMessageForm)
-    pMsg->m_pDstTarget->TransformTo(pMessageForm, pMsg->m_fx, pMsg->m_fy);
+    pMsg->m_pos = pMsg->m_pDstTarget->TransformTo(pMessageForm, pMsg->m_pos);
   if (!DoMouseEx(pMsg, pMessageForm))
     pMsg->m_pDstTarget = pMessageForm;
   return true;
@@ -355,12 +355,11 @@
     return false;
 
   CFWL_MessageMouseWheel* pMsg = static_cast<CFWL_MessageMouseWheel*>(pMessage);
-  CFWL_Widget* pDst =
-      pWidgetMgr->GetWidgetAtPoint(pMessageForm, pMsg->m_fx, pMsg->m_fy);
+  CFWL_Widget* pDst = pWidgetMgr->GetWidgetAtPoint(pMessageForm, pMsg->m_pos);
   if (!pDst)
     return false;
 
-  pMessageForm->TransformTo(pDst, pMsg->m_fx, pMsg->m_fy);
+  pMsg->m_pos = pMessageForm->TransformTo(pDst, pMsg->m_pos);
   pMsg->m_pDstTarget = pDst;
   return true;
 }
@@ -375,16 +374,12 @@
     pTarget = m_pGrab;
 
   CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
-  if (!pTarget) {
-    pTarget =
-        pWidgetMgr->GetWidgetAtPoint(pMessageForm, pMsg->m_fx, pMsg->m_fy);
-  }
-  if (pTarget) {
-    if (pMessageForm != pTarget)
-      pMessageForm->TransformTo(pTarget, pMsg->m_fx, pMsg->m_fy);
-  }
+  if (!pTarget)
+    pTarget = pWidgetMgr->GetWidgetAtPoint(pMessageForm, pMsg->m_pos);
   if (!pTarget)
     return false;
+  if (pTarget && pMessageForm != pTarget)
+    pMsg->m_pos = pMessageForm->TransformTo(pTarget, pMsg->m_pos);
 
   pMsg->m_pDstTarget = pTarget;
   return true;
@@ -398,10 +393,7 @@
   CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
   if (m_pHover) {
     CFWL_MessageMouse msLeave(nullptr, m_pHover);
-    msLeave.m_fx = pMsg->m_fx;
-    msLeave.m_fy = pMsg->m_fy;
-    pTarget->TransformTo(m_pHover, msLeave.m_fx, msLeave.m_fy);
-
+    msLeave.m_pos = pTarget->TransformTo(m_pHover, pMsg->m_pos);
     msLeave.m_dwFlags = 0;
     msLeave.m_dwCmd = FWL_MouseCommand::Leave;
     DispatchMessage(&msLeave, nullptr);
@@ -413,8 +405,7 @@
   m_pHover = pTarget;
 
   CFWL_MessageMouse msHover(nullptr, pTarget);
-  msHover.m_fx = pMsg->m_fx;
-  msHover.m_fy = pMsg->m_fy;
+  msHover.m_pos = pMsg->m_pos;
   msHover.m_dwFlags = 0;
   msHover.m_dwCmd = FWL_MouseCommand::Hover;
   DispatchMessage(&msHover, nullptr);
diff --git a/xfa/fwl/cfwl_pushbutton.cpp b/xfa/fwl/cfwl_pushbutton.cpp
index 3f0be45..fe4c3f6 100644
--- a/xfa/fwl/cfwl_pushbutton.cpp
+++ b/xfa/fwl/cfwl_pushbutton.cpp
@@ -24,10 +24,7 @@
     : CFWL_Widget(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr),
       m_bBtnDown(false),
       m_dwTTOStyles(FDE_TTOSTYLE_SingleLine),
-      m_iTTOAlign(FDE_TTOALIGNMENT_Center) {
-  m_rtClient.Set(0, 0, 0, 0);
-  m_rtCaption.Set(0, 0, 0, 0);
-}
+      m_iTTOAlign(FDE_TTOALIGNMENT_Center) {}
 
 CFWL_PushButton::~CFWL_PushButton() {}
 
@@ -173,14 +170,14 @@
 
 void CFWL_PushButton::OnLButtonUp(CFWL_MessageMouse* pMsg) {
   m_bBtnDown = false;
-  if (m_rtClient.Contains(pMsg->m_fx, pMsg->m_fy)) {
+  if (m_rtClient.Contains(pMsg->m_pos)) {
     m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Pressed;
     m_pProperties->m_dwStates |= FWL_STATE_PSB_Hovered;
   } else {
     m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Hovered;
     m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Pressed;
   }
-  if (m_rtClient.Contains(pMsg->m_fx, pMsg->m_fy)) {
+  if (m_rtClient.Contains(pMsg->m_pos)) {
     CFWL_Event wmClick(CFWL_Event::Type::Click, this);
     DispatchEvent(&wmClick);
   }
@@ -190,7 +187,7 @@
 void CFWL_PushButton::OnMouseMove(CFWL_MessageMouse* pMsg) {
   bool bRepaint = false;
   if (m_bBtnDown) {
-    if (m_rtClient.Contains(pMsg->m_fx, pMsg->m_fy)) {
+    if (m_rtClient.Contains(pMsg->m_pos)) {
       if ((m_pProperties->m_dwStates & FWL_STATE_PSB_Pressed) == 0) {
         m_pProperties->m_dwStates |= FWL_STATE_PSB_Pressed;
         bRepaint = true;
@@ -210,7 +207,7 @@
       }
     }
   } else {
-    if (!m_rtClient.Contains(pMsg->m_fx, pMsg->m_fy))
+    if (!m_rtClient.Contains(pMsg->m_pos))
       return;
     if ((m_pProperties->m_dwStates & FWL_STATE_PSB_Hovered) == 0) {
       m_pProperties->m_dwStates |= FWL_STATE_PSB_Hovered;
diff --git a/xfa/fwl/cfwl_scrollbar.cpp b/xfa/fwl/cfwl_scrollbar.cpp
index d4dd888..1da2674 100644
--- a/xfa/fwl/cfwl_scrollbar.cpp
+++ b/xfa/fwl/cfwl_scrollbar.cpp
@@ -45,8 +45,6 @@
       m_iMinTrackState(CFWL_PartState_Normal),
       m_iMaxTrackState(CFWL_PartState_Normal),
       m_fLastTrackPos(0),
-      m_cpTrackPointX(0),
-      m_cpTrackPointY(0),
       m_iMouseWheel(0),
       m_bMouseDown(false),
       m_fButtonLen(0),
@@ -176,30 +174,22 @@
 }
 
 CFX_RectF CFWL_ScrollBar::CalcMinButtonRect() {
-  CFX_RectF rect;
   if (IsVertical())
-    rect.Set(m_rtClient.left, m_rtClient.top, m_rtClient.width, m_fButtonLen);
-  else
-    rect.Set(m_rtClient.left, m_rtClient.top, m_fButtonLen, m_rtClient.height);
-  return rect;
+    return CFX_RectF(m_rtClient.TopLeft(), m_rtClient.width, m_fButtonLen);
+  return CFX_RectF(m_rtClient.TopLeft(), m_fButtonLen, m_rtClient.height);
 }
 
 CFX_RectF CFWL_ScrollBar::CalcMaxButtonRect() {
-  CFX_RectF rect;
   if (IsVertical()) {
-    rect.Set(m_rtClient.left, m_rtClient.bottom() - m_fButtonLen,
-             m_rtClient.width, m_fButtonLen);
-  } else {
-    rect.Set(m_rtClient.right() - m_fButtonLen, m_rtClient.top, m_fButtonLen,
-             m_rtClient.height);
+    return CFX_RectF(m_rtClient.left, m_rtClient.bottom() - m_fButtonLen,
+                     m_rtClient.width, m_fButtonLen);
   }
-  return rect;
+  return CFX_RectF(m_rtClient.right() - m_fButtonLen, m_rtClient.top,
+                   m_fButtonLen, m_rtClient.height);
 }
 
 CFX_RectF CFWL_ScrollBar::CalcThumbButtonRect(const CFX_RectF& rtThumb) {
   CFX_RectF rect;
-  rect.Reset();
-
   if (!IsEnabled())
     return rect;
 
@@ -211,11 +201,11 @@
 
   FX_FLOAT fRange = m_fRangeMax - m_fRangeMin;
   if (fRange < 0) {
-    if (IsVertical())
-      rect.Set(m_rtClient.left, m_rtMaxBtn.bottom(), m_rtClient.width, 0);
-    else
-      rect.Set(m_rtMaxBtn.right(), m_rtClient.top, 0, m_rtClient.height);
-    return rect;
+    if (IsVertical()) {
+      return CFX_RectF(m_rtClient.left, m_rtMaxBtn.bottom(), m_rtClient.width,
+                       0);
+    }
+    return CFX_RectF(m_rtMaxBtn.right(), m_rtClient.top, 0, m_rtClient.height);
   }
 
   CFX_RectF rtClient = m_rtClient;
@@ -251,8 +241,6 @@
 
 CFX_RectF CFWL_ScrollBar::CalcMinTrackRect(const CFX_RectF& rtMinRect) {
   CFX_RectF rect;
-  rect.Reset();
-
   if (m_bMinSize) {
     rect.left = rtMinRect.left;
     rect.top = rtMinRect.top;
@@ -272,33 +260,30 @@
 }
 
 CFX_RectF CFWL_ScrollBar::CalcMaxTrackRect(const CFX_RectF& rtMaxRect) {
-  CFX_RectF rect;
-  if (m_bMinSize) {
-    rect.Set(rtMaxRect.left, rtMaxRect.top, 0, 0);
-    return rect;
-  }
+  if (m_bMinSize)
+    return CFX_RectF(rtMaxRect.TopLeft(), 0, 0);
 
   if (IsVertical()) {
     FX_FLOAT iy = (m_rtThumb.top + m_rtThumb.bottom()) / 2;
-    rect.Set(m_rtClient.left, iy, m_rtClient.width, m_rtClient.bottom() - iy);
-  } else {
-    FX_FLOAT ix = (m_rtThumb.left + m_rtThumb.right()) / 2;
-    rect.Set(ix, m_rtClient.top, m_rtClient.height - ix, m_rtClient.height);
+    return CFX_RectF(m_rtClient.left, iy, m_rtClient.width,
+                     m_rtClient.bottom() - iy);
   }
-  return rect;
+
+  FX_FLOAT ix = (m_rtThumb.left + m_rtThumb.right()) / 2;
+  return CFX_RectF(ix, m_rtClient.top, m_rtClient.height - ix,
+                   m_rtClient.height);
 }
 
-FX_FLOAT CFWL_ScrollBar::GetTrackPointPos(FX_FLOAT fx, FX_FLOAT fy) {
-  FX_FLOAT fDiffX = fx - m_cpTrackPointX;
-  FX_FLOAT fDiffY = fy - m_cpTrackPointY;
+FX_FLOAT CFWL_ScrollBar::GetTrackPointPos(const CFX_PointF& point) {
+  CFX_PointF diff = point - m_cpTrackPoint;
   FX_FLOAT fRange = m_fRangeMax - m_fRangeMin;
   FX_FLOAT fPos;
 
   if (IsVertical()) {
-    fPos = fRange * fDiffY /
+    fPos = fRange * diff.y /
            (m_rtMaxBtn.top - m_rtMinBtn.bottom() - m_rtThumb.height);
   } else {
-    fPos = fRange * fDiffX /
+    fPos = fRange * diff.x /
            (m_rtMaxBtn.left - m_rtMinBtn.right() - m_rtThumb.width);
   }
 
@@ -317,11 +302,11 @@
   }
   if (m_iMinTrackState == CFWL_PartState_Pressed) {
     DoScroll(CFWL_EventScroll::Code::PageBackward, m_fTrackPos);
-    return m_rtThumb.Contains(m_cpTrackPointX, m_cpTrackPointY);
+    return m_rtThumb.Contains(m_cpTrackPoint);
   }
   if (m_iMaxTrackState == CFWL_PartState_Pressed) {
     DoScroll(CFWL_EventScroll::Code::PageForward, m_fTrackPos);
-    return m_rtThumb.Contains(m_cpTrackPointX, m_cpTrackPointY);
+    return m_rtThumb.Contains(m_cpTrackPoint);
   }
   if (m_iMouseWheel) {
     CFWL_EventScroll::Code dwCode = m_iMouseWheel < 0
@@ -349,13 +334,13 @@
     CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
     switch (pMsg->m_dwCmd) {
       case FWL_MouseCommand::LeftButtonDown:
-        OnLButtonDown(pMsg->m_dwFlags, pMsg->m_fx, pMsg->m_fy);
+        OnLButtonDown(pMsg->m_pos);
         break;
       case FWL_MouseCommand::LeftButtonUp:
-        OnLButtonUp(pMsg->m_dwFlags, pMsg->m_fx, pMsg->m_fy);
+        OnLButtonUp(pMsg->m_pos);
         break;
       case FWL_MouseCommand::Move:
-        OnMouseMove(pMsg->m_dwFlags, pMsg->m_fx, pMsg->m_fy);
+        OnMouseMove(pMsg->m_pos);
         break;
       case FWL_MouseCommand::Leave:
         OnMouseLeave();
@@ -366,8 +351,7 @@
   } else if (type == CFWL_Message::Type::MouseWheel) {
     CFWL_MessageMouseWheel* pMsg =
         static_cast<CFWL_MessageMouseWheel*>(pMessage);
-    OnMouseWheel(pMsg->m_fx, pMsg->m_fy, pMsg->m_dwFlags, pMsg->m_fDeltaX,
-                 pMsg->m_fDeltaY);
+    OnMouseWheel(pMsg->m_delta);
   }
 }
 
@@ -376,47 +360,47 @@
   DrawWidget(pGraphics, pMatrix);
 }
 
-void CFWL_ScrollBar::OnLButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
+void CFWL_ScrollBar::OnLButtonDown(const CFX_PointF& point) {
   if (!IsEnabled())
     return;
 
   m_bMouseDown = true;
   SetGrab(true);
-  m_cpTrackPointX = fx;
-  m_cpTrackPointY = fy;
+
+  m_cpTrackPoint = point;
   m_fLastTrackPos = m_fTrackPos;
-  if (m_rtMinBtn.Contains(fx, fy))
-    DoMouseDown(0, m_rtMinBtn, m_iMinButtonState, fx, fy);
-  else if (m_rtThumb.Contains(fx, fy))
-    DoMouseDown(1, m_rtThumb, m_iThumbButtonState, fx, fy);
-  else if (m_rtMaxBtn.Contains(fx, fy))
-    DoMouseDown(2, m_rtMaxBtn, m_iMaxButtonState, fx, fy);
-  else if (m_rtMinTrack.Contains(fx, fy))
-    DoMouseDown(3, m_rtMinTrack, m_iMinTrackState, fx, fy);
+  if (m_rtMinBtn.Contains(point))
+    DoMouseDown(0, m_rtMinBtn, m_iMinButtonState, point);
+  else if (m_rtThumb.Contains(point))
+    DoMouseDown(1, m_rtThumb, m_iThumbButtonState, point);
+  else if (m_rtMaxBtn.Contains(point))
+    DoMouseDown(2, m_rtMaxBtn, m_iMaxButtonState, point);
+  else if (m_rtMinTrack.Contains(point))
+    DoMouseDown(3, m_rtMinTrack, m_iMinTrackState, point);
   else
-    DoMouseDown(4, m_rtMaxTrack, m_iMaxTrackState, fx, fy);
+    DoMouseDown(4, m_rtMaxTrack, m_iMaxTrackState, point);
 
   if (!SendEvent())
     m_pTimerInfo = m_Timer.StartTimer(FWL_SCROLLBAR_Elapse, true);
 }
 
-void CFWL_ScrollBar::OnLButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
+void CFWL_ScrollBar::OnLButtonUp(const CFX_PointF& point) {
   m_pTimerInfo->StopTimer();
   m_bMouseDown = false;
-  DoMouseUp(0, m_rtMinBtn, m_iMinButtonState, fx, fy);
-  DoMouseUp(1, m_rtThumb, m_iThumbButtonState, fx, fy);
-  DoMouseUp(2, m_rtMaxBtn, m_iMaxButtonState, fx, fy);
-  DoMouseUp(3, m_rtMinTrack, m_iMinTrackState, fx, fy);
-  DoMouseUp(4, m_rtMaxTrack, m_iMaxTrackState, fx, fy);
+  DoMouseUp(0, m_rtMinBtn, m_iMinButtonState, point);
+  DoMouseUp(1, m_rtThumb, m_iThumbButtonState, point);
+  DoMouseUp(2, m_rtMaxBtn, m_iMaxButtonState, point);
+  DoMouseUp(3, m_rtMinTrack, m_iMinTrackState, point);
+  DoMouseUp(4, m_rtMaxTrack, m_iMaxTrackState, point);
   SetGrab(false);
 }
 
-void CFWL_ScrollBar::OnMouseMove(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
-  DoMouseMove(0, m_rtMinBtn, m_iMinButtonState, fx, fy);
-  DoMouseMove(1, m_rtThumb, m_iThumbButtonState, fx, fy);
-  DoMouseMove(2, m_rtMaxBtn, m_iMaxButtonState, fx, fy);
-  DoMouseMove(3, m_rtMinTrack, m_iMinTrackState, fx, fy);
-  DoMouseMove(4, m_rtMaxTrack, m_iMaxTrackState, fx, fy);
+void CFWL_ScrollBar::OnMouseMove(const CFX_PointF& point) {
+  DoMouseMove(0, m_rtMinBtn, m_iMinButtonState, point);
+  DoMouseMove(1, m_rtThumb, m_iThumbButtonState, point);
+  DoMouseMove(2, m_rtMaxBtn, m_iMaxButtonState, point);
+  DoMouseMove(3, m_rtMinTrack, m_iMinTrackState, point);
+  DoMouseMove(4, m_rtMaxTrack, m_iMaxTrackState, point);
 }
 
 void CFWL_ScrollBar::OnMouseLeave() {
@@ -427,12 +411,8 @@
   DoMouseLeave(4, m_rtMaxTrack, m_iMaxTrackState);
 }
 
-void CFWL_ScrollBar::OnMouseWheel(FX_FLOAT fx,
-                                  FX_FLOAT fy,
-                                  uint32_t dwFlags,
-                                  FX_FLOAT fDeltaX,
-                                  FX_FLOAT fDeltaY) {
-  m_iMouseWheel = (int32_t)fDeltaX;
+void CFWL_ScrollBar::OnMouseWheel(const CFX_PointF& delta) {
+  m_iMouseWheel = static_cast<int32_t>(delta.x);
   SendEvent();
   m_iMouseWheel = 0;
 }
@@ -440,9 +420,8 @@
 void CFWL_ScrollBar::DoMouseDown(int32_t iItem,
                                  const CFX_RectF& rtItem,
                                  int32_t& iState,
-                                 FX_FLOAT fx,
-                                 FX_FLOAT fy) {
-  if (!rtItem.Contains(fx, fy))
+                                 const CFX_PointF& point) {
+  if (!rtItem.Contains(point))
     return;
   if (iState == CFWL_PartState_Pressed)
     return;
@@ -454,10 +433,9 @@
 void CFWL_ScrollBar::DoMouseUp(int32_t iItem,
                                const CFX_RectF& rtItem,
                                int32_t& iState,
-                               FX_FLOAT fx,
-                               FX_FLOAT fy) {
+                               const CFX_PointF& point) {
   int32_t iNewState =
-      rtItem.Contains(fx, fy) ? CFWL_PartState_Hovered : CFWL_PartState_Normal;
+      rtItem.Contains(point) ? CFWL_PartState_Hovered : CFWL_PartState_Normal;
   if (iState == iNewState)
     return;
 
@@ -469,20 +447,18 @@
 void CFWL_ScrollBar::DoMouseMove(int32_t iItem,
                                  const CFX_RectF& rtItem,
                                  int32_t& iState,
-                                 FX_FLOAT fx,
-                                 FX_FLOAT fy) {
+                                 const CFX_PointF& point) {
   if (!m_bMouseDown) {
-    int32_t iNewState = rtItem.Contains(fx, fy) ? CFWL_PartState_Hovered
-                                                : CFWL_PartState_Normal;
+    int32_t iNewState =
+        rtItem.Contains(point) ? CFWL_PartState_Hovered : CFWL_PartState_Normal;
     if (iState == iNewState)
       return;
 
     iState = iNewState;
     RepaintRect(rtItem);
   } else if ((2 == iItem) && (m_iThumbButtonState == CFWL_PartState_Pressed)) {
-    FX_FLOAT fPos = GetTrackPointPos(fx, fy);
-    m_fTrackPos = fPos;
-    OnScroll(CFWL_EventScroll::Code::TrackPos, fPos);
+    m_fTrackPos = GetTrackPointPos(point);
+    OnScroll(CFWL_EventScroll::Code::TrackPos, m_fTrackPos);
   }
 }
 
diff --git a/xfa/fwl/cfwl_scrollbar.h b/xfa/fwl/cfwl_scrollbar.h
index 62ce523..6a67fa8 100644
--- a/xfa/fwl/cfwl_scrollbar.h
+++ b/xfa/fwl/cfwl_scrollbar.h
@@ -84,35 +84,28 @@
   CFX_RectF CalcThumbButtonRect(const CFX_RectF& rtThumbRect);
   CFX_RectF CalcMinTrackRect(const CFX_RectF& rtMinRect);
   CFX_RectF CalcMaxTrackRect(const CFX_RectF& rtMaxRect);
-  FX_FLOAT GetTrackPointPos(FX_FLOAT fx, FX_FLOAT fy);
+  FX_FLOAT GetTrackPointPos(const CFX_PointF& point);
 
   bool SendEvent();
   bool OnScroll(CFWL_EventScroll::Code dwCode, FX_FLOAT fPos);
-  void OnLButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy);
-  void OnLButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy);
-  void OnMouseMove(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy);
+  void OnLButtonDown(const CFX_PointF& point);
+  void OnLButtonUp(const CFX_PointF& point);
+  void OnMouseMove(const CFX_PointF& point);
   void OnMouseLeave();
-  void OnMouseWheel(FX_FLOAT fx,
-                    FX_FLOAT fy,
-                    uint32_t dwFlags,
-                    FX_FLOAT fDeltaX,
-                    FX_FLOAT fDeltaY);
+  void OnMouseWheel(const CFX_PointF& delta);
   bool DoScroll(CFWL_EventScroll::Code dwCode, FX_FLOAT fPos);
   void DoMouseDown(int32_t iItem,
                    const CFX_RectF& rtItem,
                    int32_t& iState,
-                   FX_FLOAT fx,
-                   FX_FLOAT fy);
+                   const CFX_PointF& point);
   void DoMouseUp(int32_t iItem,
                  const CFX_RectF& rtItem,
                  int32_t& iState,
-                 FX_FLOAT fx,
-                 FX_FLOAT fy);
+                 const CFX_PointF& point);
   void DoMouseMove(int32_t iItem,
                    const CFX_RectF& rtItem,
                    int32_t& iState,
-                   FX_FLOAT fx,
-                   FX_FLOAT fy);
+                   const CFX_PointF& point);
   void DoMouseLeave(int32_t iItem, const CFX_RectF& rtItem, int32_t& iState);
   void DoMouseHover(int32_t iItem, const CFX_RectF& rtItem, int32_t& iState);
 
@@ -129,8 +122,7 @@
   int32_t m_iMinTrackState;
   int32_t m_iMaxTrackState;
   FX_FLOAT m_fLastTrackPos;
-  FX_FLOAT m_cpTrackPointX;
-  FX_FLOAT m_cpTrackPointY;
+  CFX_PointF m_cpTrackPoint;
   int32_t m_iMouseWheel;
   bool m_bMouseDown;
   FX_FLOAT m_fButtonLen;
diff --git a/xfa/fwl/cfwl_spinbutton.cpp b/xfa/fwl/cfwl_spinbutton.cpp
index 3748d36..6e58b69 100644
--- a/xfa/fwl/cfwl_spinbutton.cpp
+++ b/xfa/fwl/cfwl_spinbutton.cpp
@@ -52,26 +52,28 @@
 
   m_rtClient = GetClientRect();
   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXE_SPB_Vert) {
-    m_rtUpButton.Set(m_rtClient.top, m_rtClient.left, m_rtClient.width,
-                     m_rtClient.height / 2);
-    m_rtDnButton.Set(m_rtClient.left, m_rtClient.top + m_rtClient.height / 2,
-                     m_rtClient.width, m_rtClient.height / 2);
+    m_rtUpButton = CFX_RectF(m_rtClient.top, m_rtClient.left, m_rtClient.width,
+                             m_rtClient.height / 2);
+    m_rtDnButton =
+        CFX_RectF(m_rtClient.left, m_rtClient.top + m_rtClient.height / 2,
+                  m_rtClient.width, m_rtClient.height / 2);
   } else {
-    m_rtUpButton.Set(m_rtClient.left, m_rtClient.top, m_rtClient.width / 2,
-                     m_rtClient.height);
-    m_rtDnButton.Set(m_rtClient.left + m_rtClient.width / 2, m_rtClient.top,
-                     m_rtClient.width / 2, m_rtClient.height);
+    m_rtUpButton = CFX_RectF(m_rtClient.TopLeft(), m_rtClient.width / 2,
+                             m_rtClient.height);
+    m_rtDnButton =
+        CFX_RectF(m_rtClient.left + m_rtClient.width / 2, m_rtClient.top,
+                  m_rtClient.width / 2, m_rtClient.height);
   }
 }
 
-FWL_WidgetHit CFWL_SpinButton::HitTest(FX_FLOAT fx, FX_FLOAT fy) {
-  if (m_rtClient.Contains(fx, fy))
+FWL_WidgetHit CFWL_SpinButton::HitTest(const CFX_PointF& point) {
+  if (m_rtClient.Contains(point))
     return FWL_WidgetHit::Client;
-  if (HasBorder() && (m_rtClient.Contains(fx, fy)))
+  if (HasBorder() && (m_rtClient.Contains(point)))
     return FWL_WidgetHit::Border;
-  if (m_rtUpButton.Contains(fx, fy))
+  if (m_rtUpButton.Contains(point))
     return FWL_WidgetHit::UpButton;
-  if (m_rtDnButton.Contains(fx, fy))
+  if (m_rtDnButton.Contains(point))
     return FWL_WidgetHit::DownButton;
   return FWL_WidgetHit::Unknown;
 }
@@ -199,10 +201,8 @@
   SetGrab(true);
   SetFocus(true);
 
-  bool bUpPress =
-      (m_rtUpButton.Contains(pMsg->m_fx, pMsg->m_fy) && IsUpButtonEnabled());
-  bool bDnPress =
-      (m_rtDnButton.Contains(pMsg->m_fx, pMsg->m_fy) && IsDownButtonEnabled());
+  bool bUpPress = m_rtUpButton.Contains(pMsg->m_pos) && IsUpButtonEnabled();
+  bool bDnPress = m_rtDnButton.Contains(pMsg->m_pos) && IsDownButtonEnabled();
   if (!bUpPress && !bDnPress)
     return;
   if (bUpPress) {
@@ -253,8 +253,7 @@
 
   bool bRepaint = false;
   CFX_RectF rtInvlidate;
-  rtInvlidate.Reset();
-  if (m_rtUpButton.Contains(pMsg->m_fx, pMsg->m_fy)) {
+  if (m_rtUpButton.Contains(pMsg->m_pos)) {
     if (IsUpButtonEnabled()) {
       if (m_dwUpState == CFWL_PartState_Hovered) {
         m_dwUpState = CFWL_PartState_Hovered;
@@ -274,7 +273,7 @@
     if (!IsDownButtonEnabled())
       DisableButton();
 
-  } else if (m_rtDnButton.Contains(pMsg->m_fx, pMsg->m_fy)) {
+  } else if (m_rtDnButton.Contains(pMsg->m_pos)) {
     if (IsDownButtonEnabled()) {
       if (m_dwDnState != CFWL_PartState_Hovered) {
         m_dwDnState = CFWL_PartState_Hovered;
diff --git a/xfa/fwl/cfwl_spinbutton.h b/xfa/fwl/cfwl_spinbutton.h
index 4794461..3cda761 100644
--- a/xfa/fwl/cfwl_spinbutton.h
+++ b/xfa/fwl/cfwl_spinbutton.h
@@ -27,7 +27,7 @@
   // CFWL_Widget
   FWL_Type GetClassID() const override;
   void Update() override;
-  FWL_WidgetHit HitTest(FX_FLOAT fx, FX_FLOAT fy) override;
+  FWL_WidgetHit HitTest(const CFX_PointF& point) override;
   void DrawWidget(CFX_Graphics* pGraphics, const CFX_Matrix* pMatrix) override;
   void OnProcessMessage(CFWL_Message* pMessage) override;
   void OnDrawWidget(CFX_Graphics* pGraphics,
diff --git a/xfa/fwl/cfwl_widget.cpp b/xfa/fwl/cfwl_widget.cpp
index 301ad5f..b5b8bf4 100644
--- a/xfa/fwl/cfwl_widget.cpp
+++ b/xfa/fwl/cfwl_widget.cpp
@@ -8,7 +8,9 @@
 
 #include <algorithm>
 #include <utility>
+#include <vector>
 
+#include "third_party/base/stl_util.h"
 #include "xfa/fde/tto/fde_textout.h"
 #include "xfa/fwl/cfwl_app.h"
 #include "xfa/fwl/cfwl_combobox.h"
@@ -149,70 +151,55 @@
   m_pProperties->m_dwStates &= ~dwStates;
 }
 
-FWL_WidgetHit CFWL_Widget::HitTest(FX_FLOAT fx, FX_FLOAT fy) {
-  if (GetClientRect().Contains(fx, fy))
+FWL_WidgetHit CFWL_Widget::HitTest(const CFX_PointF& point) {
+  if (GetClientRect().Contains(point))
     return FWL_WidgetHit::Client;
-  if (HasBorder() && GetRelativeRect().Contains(fx, fy))
+  if (HasBorder() && GetRelativeRect().Contains(point))
     return FWL_WidgetHit::Border;
   return FWL_WidgetHit::Unknown;
 }
 
-void CFWL_Widget::TransformTo(CFWL_Widget* pWidget,
-                              FX_FLOAT& fx,
-                              FX_FLOAT& fy) {
+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.x = -szOffset.x;
-      szOffset.y = -szOffset.y;
+      szOffset.width = -szOffset.width;
+      szOffset.height = -szOffset.height;
     }
-    fx += szOffset.x;
-    fy += szOffset.y;
-    return;
+    return point + CFX_PointF(szOffset.width, szOffset.height);
   }
-  CFX_RectF r;
-  CFX_Matrix m;
+
+  CFX_PointF ret = point;
   CFWL_Widget* parent = GetParent();
-  if (parent) {
-    r = GetWidgetRect();
-    fx += r.left;
-    fy += r.top;
-    m = GetMatrix();
-    m.TransformPoint(fx, fy);
-  }
+  if (parent)
+    ret = GetMatrix().Transform(ret + GetWidgetRect().TopLeft());
+
   CFWL_Widget* form1 = m_pWidgetMgr->GetSystemFormWidget(this);
   if (!form1)
-    return;
+    return ret;
 
-  if (!pWidget) {
-    r = form1->GetWidgetRect();
-    fx += r.left;
-    fy += r.top;
-    return;
-  }
+  if (!pWidget)
+    return ret + form1->GetWidgetRect().TopLeft();
+
   CFWL_Widget* form2 = m_pWidgetMgr->GetSystemFormWidget(pWidget);
   if (!form2)
-    return;
+    return ret;
   if (form1 != form2) {
-    r = form1->GetWidgetRect();
-    fx += r.left;
-    fy += r.top;
-    r = form2->GetWidgetRect();
-    fx -= r.left;
-    fy -= r.top;
+    ret += form1->GetWidgetRect().TopLeft();
+    ret -= form2->GetWidgetRect().TopLeft();
   }
+
   parent = pWidget->GetParent();
-  if (parent) {
-    CFX_Matrix m1;
-    m1.SetReverse(pWidget->GetMatrix());
-    m1.TransformPoint(fx, fy);
-    r = pWidget->GetWidgetRect();
-    fx -= r.left;
-    fy -= r.top;
-  }
+  if (!parent)
+    return ret;
+
+  CFX_Matrix m;
+  m.SetReverse(pWidget->GetMatrix());
+  return m.Transform(ret) - pWidget->GetWidgetRect().TopLeft();
 }
 
 CFX_Matrix CFWL_Widget::GetMatrix() {
@@ -220,19 +207,18 @@
     return CFX_Matrix();
 
   CFWL_Widget* parent = GetParent();
-  CFX_ArrayTemplate<CFWL_Widget*> parents;
+  std::vector<CFWL_Widget*> parents;
   while (parent) {
-    parents.Add(parent);
+    parents.push_back(parent);
     parent = parent->GetParent();
   }
 
   CFX_Matrix matrix;
   CFX_Matrix ctmOnParent;
   CFX_RectF rect;
-  int32_t count = parents.GetSize();
+  int32_t count = pdfium::CollectionSize<int32_t>(parents);
   for (int32_t i = count - 2; i >= 0; i--) {
-    parent = parents.GetAt(i);
-
+    parent = parents[i];
     if (parent->m_pProperties)
       ctmOnParent.SetIdentity();
     rect = parent->GetWidgetRect();
@@ -242,8 +228,7 @@
   CFX_Matrix m;
   m.SetIdentity();
   matrix.Concat(m, true);
-  parents.RemoveAll();
-
+  parents.clear();
   return matrix;
 }
 
@@ -281,8 +266,8 @@
 }
 
 CFX_RectF CFWL_Widget::GetEdgeRect() {
-  CFX_RectF rtEdge = m_pProperties->m_rtWidget;
-  rtEdge.left = rtEdge.top = 0;
+  CFX_RectF rtEdge(0, 0, m_pProperties->m_rtWidget.width,
+                   m_pProperties->m_rtWidget.height);
   if (HasBorder()) {
     FX_FLOAT fCX = GetBorderSize(true);
     FX_FLOAT fCY = GetBorderSize(false);
@@ -299,10 +284,8 @@
 }
 
 CFX_RectF CFWL_Widget::GetRelativeRect() {
-  CFX_RectF rect = m_pProperties->m_rtWidget;
-  rect.left = 0;
-  rect.top = 0;
-  return rect;
+  return CFX_RectF(0, 0, m_pProperties->m_rtWidget.width,
+                   m_pProperties->m_rtWidget.height);
 }
 
 IFWL_ThemeProvider* CFWL_Widget::GetAvailableTheme() {
@@ -345,10 +328,9 @@
   calPart.m_dwTTOStyles =
       bMultiLine ? FDE_TTOSTYLE_LineWrap : FDE_TTOSTYLE_SingleLine;
   calPart.m_iTTOAlign = FDE_TTOALIGNMENT_TopLeft;
-  CFX_RectF rect;
   FX_FLOAT fWidth =
       bMultiLine ? FWL_WGT_CalcMultiLineDefWidth : FWL_WGT_CalcWidth;
-  rect.Set(0, 0, fWidth, FWL_WGT_CalcHeight);
+  CFX_RectF rect(0, 0, fWidth, FWL_WGT_CalcHeight);
   pTheme->CalcTextRect(&calPart, rect);
   return CFX_SizeF(rect.width, rect.height);
 }
@@ -422,32 +404,31 @@
                                   FX_FLOAT fMaxHeight,
                                   const CFX_RectF& rtAnchor,
                                   CFX_RectF& rtPopup) {
-  FX_FLOAT fx = 0;
-  FX_FLOAT fy = 0;
-
   if (GetStylesEx() & FWL_STYLEEXT_MNU_Vert) {
     bool bLeft = m_pProperties->m_rtWidget.left < 0;
     FX_FLOAT fRight = rtAnchor.right() + rtPopup.width;
-    TransformTo(nullptr, fx, fy);
-    if (fRight + fx > 0.0f || bLeft) {
-      rtPopup.Set(rtAnchor.left - rtPopup.width, rtAnchor.top, rtPopup.width,
-                  rtPopup.height);
+    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.Set(rtAnchor.right(), rtAnchor.top, rtPopup.width,
-                  rtPopup.height);
+      rtPopup = CFX_RectF(rtAnchor.right(), rtAnchor.top, rtPopup.width,
+                          rtPopup.height);
     }
-  } else {
-    FX_FLOAT fBottom = rtAnchor.bottom() + rtPopup.height;
-    TransformTo(nullptr, fx, fy);
-    if (fBottom + fy > 0.0f) {
-      rtPopup.Set(rtAnchor.left, rtAnchor.top - rtPopup.height, rtPopup.width,
-                  rtPopup.height);
-    } else {
-      rtPopup.Set(rtAnchor.left, rtAnchor.bottom(), rtPopup.width,
-                  rtPopup.height);
-    }
+    rtPopup.Offset(point.x, point.y);
+    return true;
   }
-  rtPopup.Offset(fx, fy);
+
+  FX_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;
 }
 
@@ -455,9 +436,6 @@
                                       FX_FLOAT fMaxHeight,
                                       const CFX_RectF& rtAnchor,
                                       CFX_RectF& rtPopup) {
-  FX_FLOAT fx = 0;
-  FX_FLOAT fy = 0;
-
   FX_FLOAT fPopHeight = rtPopup.height;
   if (rtPopup.height > fMaxHeight)
     fPopHeight = fMaxHeight;
@@ -466,13 +444,15 @@
 
   FX_FLOAT fWidth = std::max(rtAnchor.width, rtPopup.width);
   FX_FLOAT fBottom = rtAnchor.bottom() + fPopHeight;
-  TransformTo(nullptr, fx, fy);
-  if (fBottom + fy > 0.0f)
-    rtPopup.Set(rtAnchor.left, rtAnchor.top - fPopHeight, fWidth, fPopHeight);
-  else
-    rtPopup.Set(rtAnchor.left, rtAnchor.bottom(), fWidth, 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(fx, fy);
+  rtPopup.Offset(point.x, point.y);
   return true;
 }
 
@@ -480,18 +460,15 @@
                                      FX_FLOAT fMaxHeight,
                                      const CFX_RectF& rtAnchor,
                                      CFX_RectF& rtPopup) {
-  FX_FLOAT fx = 0;
-  FX_FLOAT fy = 0;
-
-  TransformTo(nullptr, fx, fy);
-  if (rtAnchor.bottom() + fy > 0.0f) {
-    rtPopup.Set(rtAnchor.left, rtAnchor.top - rtPopup.height, rtPopup.width,
-                rtPopup.height);
+  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.Set(rtAnchor.left, rtAnchor.bottom(), rtPopup.width,
-                rtPopup.height);
+    rtPopup = CFX_RectF(rtAnchor.left, rtAnchor.bottom(), rtPopup.width,
+                        rtPopup.height);
   }
-  rtPopup.Offset(fx, fy);
+  rtPopup.Offset(point.x, point.y);
   return true;
 }
 
@@ -535,11 +512,8 @@
 }
 
 void CFWL_Widget::Repaint() {
-  CFX_RectF rect;
-  rect = m_pProperties->m_rtWidget;
-  rect.left = 0;
-  rect.top = 0;
-  RepaintRect(rect);
+  RepaintRect(CFX_RectF(0, 0, m_pProperties->m_rtWidget.width,
+                        m_pProperties->m_rtWidget.height));
 }
 
 void CFWL_Widget::RepaintRect(const CFX_RectF& pRect) {
diff --git a/xfa/fwl/cfwl_widget.h b/xfa/fwl/cfwl_widget.h
index 74fa314..2387b75 100644
--- a/xfa/fwl/cfwl_widget.h
+++ b/xfa/fwl/cfwl_widget.h
@@ -60,7 +60,7 @@
   virtual void SetStates(uint32_t dwStates);
   virtual void RemoveStates(uint32_t dwStates);
   virtual void Update() = 0;
-  virtual FWL_WidgetHit HitTest(FX_FLOAT fx, FX_FLOAT fy);
+  virtual FWL_WidgetHit HitTest(const CFX_PointF& point);
   virtual void DrawWidget(CFX_Graphics* pGraphics,
                           const CFX_Matrix* pMatrix) = 0;
   virtual void SetThemeProvider(IFWL_ThemeProvider* pThemeProvider);
@@ -90,7 +90,7 @@
       m_iLock--;
   }
 
-  void TransformTo(CFWL_Widget* pWidget, FX_FLOAT& fx, FX_FLOAT& fy);
+  CFX_PointF TransformTo(CFWL_Widget* pWidget, const CFX_PointF& point);
   CFX_Matrix GetMatrix();
   IFWL_ThemeProvider* GetThemeProvider() const;
 
@@ -173,7 +173,6 @@
                           FX_FLOAT fMaxHeight,
                           const CFX_RectF& rtAnchor,
                           CFX_RectF& rtPopup);
-  bool GetScreenSize(FX_FLOAT& fx, FX_FLOAT& fy);
   void DrawBackground(CFX_Graphics* pGraphics,
                       CFWL_Part iPartBk,
                       IFWL_ThemeProvider* pTheme,
diff --git a/xfa/fwl/cfwl_widgetmgr.cpp b/xfa/fwl/cfwl_widgetmgr.cpp
index dc3b383..7c0fddd 100644
--- a/xfa/fwl/cfwl_widgetmgr.cpp
+++ b/xfa/fwl/cfwl_widgetmgr.cpp
@@ -160,7 +160,10 @@
     if (!pNative)
       return;
 
-    pWidget->TransformTo(pNative, transformedRect.left, transformedRect.top);
+    CFX_PointF pos = pWidget->TransformTo(
+        pNative, CFX_PointF(transformedRect.left, transformedRect.top));
+    transformedRect.left = pos.x;
+    transformedRect.top = pos.y;
   }
   AddRedrawCounts(pNative);
   m_pAdapter->RepaintWidget(pNative);
@@ -255,28 +258,25 @@
 }
 
 CFWL_Widget* CFWL_WidgetMgr::GetWidgetAtPoint(CFWL_Widget* parent,
-                                              FX_FLOAT x,
-                                              FX_FLOAT y) {
+                                              const CFX_PointF& point) const {
   if (!parent)
     return nullptr;
 
-  FX_FLOAT x1;
-  FX_FLOAT y1;
+  CFX_PointF pos;
   CFWL_Widget* child = GetLastChildWidget(parent);
   while (child) {
     if ((child->GetStates() & FWL_WGTSTATE_Invisible) == 0) {
-      x1 = x;
-      y1 = y;
-      CFX_Matrix matrixOnParent;
       CFX_Matrix m;
       m.SetIdentity();
+
+      CFX_Matrix matrixOnParent;
       m.SetReverse(matrixOnParent);
-      m.TransformPoint(x1, y1);
+      pos = m.Transform(point);
+
       CFX_RectF bounds = child->GetWidgetRect();
-      if (bounds.Contains(x1, y1)) {
-        x1 -= bounds.left;
-        y1 -= bounds.top;
-        return GetWidgetAtPoint(child, x1, y1);
+      if (bounds.Contains(pos)) {
+        pos -= bounds.TopLeft();
+        return GetWidgetAtPoint(child, pos);
       }
     }
     child = GetPriorSiblingWidget(child);
@@ -320,17 +320,18 @@
   return nullptr;
 }
 
-void CFWL_WidgetMgr::GetSameGroupRadioButton(
-    CFWL_Widget* pRadioButton,
-    CFX_ArrayTemplate<CFWL_Widget*>& group) const {
+std::vector<CFWL_Widget*> CFWL_WidgetMgr::GetSameGroupRadioButton(
+    CFWL_Widget* pRadioButton) const {
   CFWL_Widget* pFirst = GetFirstSiblingWidget(pRadioButton);
   if (!pFirst)
     pFirst = pRadioButton;
 
-  int32_t iGroup = CountRadioButtonGroup(pFirst);
-  if (iGroup < 2)
-    return;
-  group.Add(GetRadioButtonGroupHeader(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 {
@@ -372,7 +373,7 @@
 bool CFWL_WidgetMgr::IsAbleNative(CFWL_Widget* pWidget) const {
   if (!pWidget)
     return false;
-  if (!pWidget->IsInstance(FX_WSTRC(FWL_CLASS_Form)))
+  if (!pWidget->IsInstance(FWL_CLASS_Form))
     return false;
 
   uint32_t dwStyles = pWidget->GetStyles();
@@ -427,23 +428,20 @@
   if (!pWidget || !pGraphics)
     return;
 
-  CFX_RectF clipCopy = pWidget->GetWidgetRect();
-  clipCopy.left = clipCopy.top = 0;
-
+  CFX_RectF clipCopy(0, 0, pWidget->GetWidgetRect().Size());
   CFX_RectF clipBounds;
 
-#if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_ || \
-    _FX_OS_ == _FX_LINUX_DESKTOP_ || _FX_OS_ == _FX_ANDROID_
-  pWidget->GetDelegate()->OnDrawWidget(pGraphics, pMatrix);
-  pGraphics->GetClipRect(clipBounds);
-  clipCopy = clipBounds;
-#elif _FX_OS_ == _FX_MACOSX_
+#if _FX_OS_ == _FX_MACOSX_
   if (IsFormDisabled()) {
+#endif  // _FX_OS_ == _FX_MACOSX_
+
     pWidget->GetDelegate()->OnDrawWidget(pGraphics, pMatrix);
-    pGraphics->GetClipRect(clipBounds);
+    clipBounds = pGraphics->GetClipRect();
     clipCopy = clipBounds;
+
+#if _FX_OS_ == _FX_MACOSX_
   } else {
-    clipBounds.Set(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d);
+    clipBounds = CFX_RectF(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d);
     const_cast<CFX_Matrix*>(pMatrix)->SetIdentity();  // FIXME: const cast.
     pWidget->GetDelegate()->OnDrawWidget(pGraphics, pMatrix);
   }
@@ -485,7 +483,9 @@
       widgetMatrix.Concat(*pMatrix);
 
     if (!bFormDisable) {
-      widgetMatrix.TransformPoint(clipBounds.left, clipBounds.top);
+      CFX_PointF pos = widgetMatrix.Transform(clipBounds.TopLeft());
+      clipBounds.left = pos.x;
+      clipBounds.top = pos.y;
       clipBounds.Intersect(rtClip);
       if (clipBounds.IsEmpty())
         continue;
@@ -517,8 +517,7 @@
     return true;
   }
 
-  CFX_RectF rtWidget = pWidget->GetWidgetRect();
-  rtWidget.left = rtWidget.top = 0;
+  CFX_RectF rtWidget(0, 0, pWidget->GetWidgetRect().Size());
   pMatrix->TransformRect(rtWidget);
   if (!rtWidget.IntersectWith(rtDirty))
     return false;
@@ -529,11 +528,9 @@
     return true;
 
   CFX_RectF rtChilds;
-  rtChilds.Empty();
   bool bChildIntersectWithDirty = false;
   bool bOrginPtIntersectWidthChild = false;
-  bool bOrginPtIntersectWidthDirty =
-      rtDirty.Contains(rtWidget.left, rtWidget.top);
+  bool bOrginPtIntersectWidthDirty = rtDirty.Contains(rtWidget.TopLeft());
   static FWL_NEEDREPAINTHITDATA hitPoint[kNeedRepaintHitPoints];
   FXSYS_memset(hitPoint, 0, sizeof(hitPoint));
   FX_FLOAT fxPiece = rtWidget.width / kNeedRepaintHitPiece;
@@ -554,9 +551,8 @@
       rtWidget.height + rtWidget.top;
   do {
     CFX_RectF rect = pChild->GetWidgetRect();
-    CFX_RectF r = rect;
-    r.left += rtWidget.left;
-    r.top += rtWidget.top;
+    CFX_RectF r(rect.left + rtWidget.left, rect.top + rtWidget.top, rect.width,
+                rect.height);
     if (r.IsEmpty())
       continue;
     if (r.Contains(rtDirty))
@@ -564,7 +560,7 @@
     if (!bChildIntersectWithDirty && r.IntersectWith(rtDirty))
       bChildIntersectWithDirty = true;
     if (bOrginPtIntersectWidthDirty && !bOrginPtIntersectWidthChild)
-      bOrginPtIntersectWidthChild = rect.Contains(0, 0);
+      bOrginPtIntersectWidthChild = rect.Contains(CFX_PointF(0, 0));
 
     if (rtChilds.IsEmpty())
       rtChilds = rect;
diff --git a/xfa/fwl/cfwl_widgetmgr.h b/xfa/fwl/cfwl_widgetmgr.h
index 62ea60a..2d436bd 100644
--- a/xfa/fwl/cfwl_widgetmgr.h
+++ b/xfa/fwl/cfwl_widgetmgr.h
@@ -9,9 +9,9 @@
 
 #include <map>
 #include <memory>
+#include <vector>
 
 #include "core/fxcrt/fx_system.h"
-#include "xfa/fwl/fwl_error.h"
 #include "xfa/fwl/ifwl_widgetmgrdelegate.h"
 #include "xfa/fxgraphics/cfx_graphics.h"
 
@@ -49,12 +49,13 @@
   void SetOwner(CFWL_Widget* pOwner, CFWL_Widget* pOwned);
   void SetParent(CFWL_Widget* pParent, CFWL_Widget* pChild);
 
-  CFWL_Widget* GetWidgetAtPoint(CFWL_Widget* pParent, FX_FLOAT fx, FX_FLOAT fy);
-
+  CFWL_Widget* GetWidgetAtPoint(CFWL_Widget* pParent,
+                                const CFX_PointF& point) const;
   CFWL_Widget* NextTab(CFWL_Widget* parent, CFWL_Widget* focus, bool& bFind);
 
-  void GetSameGroupRadioButton(CFWL_Widget* pRadioButton,
-                               CFX_ArrayTemplate<CFWL_Widget*>& group) const;
+  std::vector<CFWL_Widget*> GetSameGroupRadioButton(
+      CFWL_Widget* pRadioButton) const;
+
   CFWL_Widget* GetDefaultButton(CFWL_Widget* pParent) const;
   void AddRedrawCounts(CFWL_Widget* pWidget);
 
diff --git a/xfa/fwl/cfwl_widgetproperties.cpp b/xfa/fwl/cfwl_widgetproperties.cpp
index 1b41105..fee957a 100644
--- a/xfa/fwl/cfwl_widgetproperties.cpp
+++ b/xfa/fwl/cfwl_widgetproperties.cpp
@@ -12,8 +12,6 @@
       m_dwStates(0),
       m_pThemeProvider(nullptr),
       m_pParent(nullptr),
-      m_pOwner(nullptr) {
-  m_rtWidget.Set(0, 0, 0, 0);
-}
+      m_pOwner(nullptr) {}
 
 CFWL_WidgetProperties::~CFWL_WidgetProperties() {}
diff --git a/xfa/fwl/fwl_error.h b/xfa/fwl/fwl_error.h
deleted file mode 100644
index 8ef56d9..0000000
--- a/xfa/fwl/fwl_error.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_FWL_FWL_ERROR_H_
-#define XFA_FWL_FWL_ERROR_H_
-
-enum class FWL_Error {
-  Succeeded = 0,
-  Indefinite,
-  ParameterInvalid,
-  PropertyInvalid,
-  IntermediateValueInvalid,
-  MethodNotSupported
-};
-
-#endif  // XFA_FWL_FWL_ERROR_H_
diff --git a/xfa/fwl/theme/cfwl_carettp.cpp b/xfa/fwl/theme/cfwl_carettp.cpp
index 06df3f5..4a04f86 100644
--- a/xfa/fwl/theme/cfwl_carettp.cpp
+++ b/xfa/fwl/theme/cfwl_carettp.cpp
@@ -40,7 +40,6 @@
                                CFX_Color* crFill,
                                CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
   CFX_RectF rect = *pRect;
   path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
   if (crFill) {
diff --git a/xfa/fwl/theme/cfwl_checkboxtp.cpp b/xfa/fwl/theme/cfwl_checkboxtp.cpp
index 0bc75ec..1d185b4 100644
--- a/xfa/fwl/theme/cfwl_checkboxtp.cpp
+++ b/xfa/fwl/theme/cfwl_checkboxtp.cpp
@@ -79,7 +79,6 @@
                                      FX_ARGB argbFill,
                                      CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
   path.AddEllipse(*pRtSign);
   CFX_Color crFill(argbFill);
   pGraphics->SaveGraphState();
@@ -93,11 +92,12 @@
                                     FX_ARGB argbFill,
                                     CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
   FX_FLOAT fRight = pRtSign->right();
   FX_FLOAT fBottom = pRtSign->bottom();
-  path.AddLine(pRtSign->left, pRtSign->top, fRight, fBottom);
-  path.AddLine(pRtSign->left, fBottom, fRight, pRtSign->top);
+  path.AddLine(pRtSign->TopLeft(), CFX_PointF(fRight, fBottom));
+  path.AddLine(CFX_PointF(pRtSign->left, fBottom),
+               CFX_PointF(fRight, pRtSign->top));
+
   CFX_Color crFill(argbFill);
   pGraphics->SaveGraphState();
   pGraphics->SetStrokeColor(&crFill);
@@ -111,15 +111,15 @@
                                       FX_ARGB argbFill,
                                       CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
   FX_FLOAT fWidth = pRtSign->width;
   FX_FLOAT fHeight = pRtSign->height;
   FX_FLOAT fBottom = pRtSign->bottom();
-  path.MoveTo(pRtSign->left + fWidth / 2, pRtSign->top);
-  path.LineTo(pRtSign->left, pRtSign->top + fHeight / 2);
-  path.LineTo(pRtSign->left + fWidth / 2, fBottom);
-  path.LineTo(pRtSign->right(), pRtSign->top + fHeight / 2);
-  path.LineTo(pRtSign->left + fWidth / 2, pRtSign->top);
+  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));
+
   CFX_Color crFill(argbFill);
   pGraphics->SaveGraphState();
   pGraphics->SetFillColor(&crFill);
@@ -132,7 +132,6 @@
                                      FX_ARGB argbFill,
                                      CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
   path.AddRectangle(pRtSign->left, pRtSign->top, pRtSign->width,
                     pRtSign->height);
   CFX_Color crFill(argbFill);
@@ -147,28 +146,31 @@
                                    FX_ARGB argbFill,
                                    CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
   FX_FLOAT fBottom = pRtSign->bottom();
   FX_FLOAT fRadius =
-      (pRtSign->top - fBottom) / (1 + (FX_FLOAT)cos(FX_PI / 5.0f));
+      (pRtSign->top - fBottom) / (1 + static_cast<FX_FLOAT>(cos(FX_PI / 5.0f)));
   CFX_PointF ptCenter((pRtSign->left + pRtSign->right()) / 2.0f,
                       (pRtSign->top + fBottom) / 2.0f);
-  FX_FLOAT px[5], py[5];
+
+  CFX_PointF points[5];
   FX_FLOAT fAngel = FX_PI / 10.0f;
   for (int32_t i = 0; i < 5; i++) {
-    px[i] = ptCenter.x + fRadius * (FX_FLOAT)cos(fAngel);
-    py[i] = ptCenter.y + fRadius * (FX_FLOAT)sin(fAngel);
+    points[i] =
+        ptCenter + CFX_PointF(fRadius * static_cast<FX_FLOAT>(cos(fAngel)),
+                              fRadius * static_cast<FX_FLOAT>(sin(fAngel)));
     fAngel += FX_PI * 2 / 5.0f;
   }
-  path.MoveTo(px[0], py[0]);
+
+  path.MoveTo(points[0]);
   int32_t nNext = 0;
   for (int32_t j = 0; j < 5; j++) {
     nNext += 2;
-    if (nNext >= 5) {
+    if (nNext >= 5)
       nNext -= 5;
-    }
-    path.LineTo(px[nNext], py[nNext]);
+
+    path.LineTo(points[nNext]);
   }
+
   CFX_Color crFill(argbFill);
   pGraphics->SaveGraphState();
   pGraphics->SetFillColor(&crFill);
@@ -217,7 +219,7 @@
 void CFWL_CheckBoxTP::InitCheckPath(FX_FLOAT fCheckLen) {
   if (!m_pCheckPath) {
     m_pCheckPath = pdfium::MakeUnique<CFX_Path>();
-    m_pCheckPath->Create();
+
     FX_FLOAT fWidth = kSignPath;
     FX_FLOAT fHeight = -kSignPath;
     FX_FLOAT fBottom = kSignPath;
@@ -238,48 +240,33 @@
     CFX_PointF pt54(fWidth / 3.4f, fBottom + fHeight / 3.5f);
     CFX_PointF pt51(fWidth / 3.6f, fBottom + fHeight / 4.0f);
     CFX_PointF pt15(fWidth / 3.5f, fBottom + fHeight * 3.5f / 5.0f);
-    m_pCheckPath->MoveTo(pt1.x, pt1.y);
-    FX_FLOAT px1 = pt12.x - pt1.x;
-    FX_FLOAT py1 = pt12.y - pt1.y;
-    FX_FLOAT px2 = pt21.x - pt2.x;
-    FX_FLOAT py2 = pt21.y - pt2.y;
-    m_pCheckPath->BezierTo(pt1.x + px1 * FX_BEZIER, pt1.y + py1 * FX_BEZIER,
-                           pt2.x + px2 * FX_BEZIER, pt2.y + py2 * FX_BEZIER,
-                           pt2.x, pt2.y);
-    px1 = pt23.x - pt2.x;
-    py1 = pt23.y - pt2.y;
-    px2 = pt32.x - pt3.x;
-    py2 = pt32.y - pt3.y;
-    m_pCheckPath->BezierTo(pt2.x + px1 * FX_BEZIER, pt2.y + py1 * FX_BEZIER,
-                           pt3.x + px2 * FX_BEZIER, pt3.y + py2 * FX_BEZIER,
-                           pt3.x, pt3.y);
-    px1 = pt34.x - pt3.x;
-    py1 = pt34.y - pt3.y;
-    px2 = pt43.x - pt4.x;
-    py2 = pt43.y - pt4.y;
-    m_pCheckPath->BezierTo(pt3.x + px1 * FX_BEZIER, pt3.y + py1 * FX_BEZIER,
-                           pt4.x + px2 * FX_BEZIER, pt4.y + py2 * FX_BEZIER,
-                           pt4.x, pt4.y);
-    px1 = pt45.x - pt4.x;
-    py1 = pt45.y - pt4.y;
-    px2 = pt54.x - pt5.x;
-    py2 = pt54.y - pt5.y;
-    m_pCheckPath->BezierTo(pt4.x + px1 * FX_BEZIER, pt4.y + py1 * FX_BEZIER,
-                           pt5.x + px2 * FX_BEZIER, pt5.y + py2 * FX_BEZIER,
-                           pt5.x, pt5.y);
-    px1 = pt51.x - pt5.x;
-    py1 = pt51.y - pt5.y;
-    px2 = pt15.x - pt1.x;
-    py2 = pt15.y - pt1.y;
-    m_pCheckPath->BezierTo(pt5.x + px1 * FX_BEZIER, pt5.y + py1 * FX_BEZIER,
-                           pt1.x + px2 * FX_BEZIER, pt1.y + py2 * FX_BEZIER,
-                           pt1.x, pt1.y);
+    m_pCheckPath->MoveTo(pt1);
+
+    CFX_PointF p1 = CFX_PointF(pt12.x - pt1.x, pt12.y - pt1.y) * FX_BEZIER;
+    CFX_PointF p2 = CFX_PointF(pt21.x - pt2.x, pt21.y - pt2.y) * FX_BEZIER;
+    m_pCheckPath->BezierTo(pt1 + p1, pt2 + p2, pt2);
+
+    p1 = CFX_PointF(pt23.x - pt2.x, pt23.y - pt2.y) * FX_BEZIER;
+    p2 = CFX_PointF(pt32.x - pt3.x, pt32.y - pt3.y) * FX_BEZIER;
+    m_pCheckPath->BezierTo(pt2 + p1, pt3 + p2, pt3);
+
+    p1 = CFX_PointF(pt34.x - pt3.x, pt34.y - pt3.y) * FX_BEZIER;
+    p2 = CFX_PointF(pt43.x - pt4.x, pt43.y - pt4.y) * FX_BEZIER;
+    m_pCheckPath->BezierTo(pt3 + p1, pt4 + p2, pt4);
+
+    p1 = CFX_PointF(pt45.x - pt4.x, pt45.y - pt4.y) * FX_BEZIER;
+    p2 = CFX_PointF(pt54.x - pt5.x, pt54.y - pt5.y) * FX_BEZIER;
+    m_pCheckPath->BezierTo(pt4 + p1, pt5 + p2, pt5);
+
+    p1 = CFX_PointF(pt51.x - pt5.x, pt51.y - pt5.y) * FX_BEZIER;
+    p2 = CFX_PointF(pt15.x - pt1.x, pt15.y - pt1.y) * FX_BEZIER;
+    m_pCheckPath->BezierTo(pt5 + p1, pt1 + p2, pt1);
+
     FX_FLOAT fScale = fCheckLen / kSignPath;
-    CFX_Matrix mt;
-    mt.Set(1, 0, 0, 1, 0, 0);
+    CFX_Matrix mt(1, 0, 0, 1, 0, 0);
     mt.Scale(fScale, fScale);
-    CFX_PathData* pData = m_pCheckPath->GetPathData();
-    pData->Transform(&mt);
+
+    m_pCheckPath->TransformBy(mt);
   }
 }
 
diff --git a/xfa/fwl/theme/cfwl_comboboxtp.cpp b/xfa/fwl/theme/cfwl_comboboxtp.cpp
index 567cb2e..53a6eae 100644
--- a/xfa/fwl/theme/cfwl_comboboxtp.cpp
+++ b/xfa/fwl/theme/cfwl_comboboxtp.cpp
@@ -28,7 +28,6 @@
     }
     case CFWL_Part::Background: {
       CFX_Path path;
-      path.Create();
       CFX_RectF& rect = pParams->m_rtPart;
       path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
       FX_ARGB argb_color;
@@ -66,7 +65,6 @@
                                         uint32_t dwStates,
                                         CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
   path.AddRectangle(pParams->m_rtPart.left, pParams->m_rtPart.top,
                     pParams->m_rtPart.width - 1, pParams->m_rtPart.height);
   CFX_Color cr(ArgbEncode(0xff, 0xff, 0, 0));
diff --git a/xfa/fwl/theme/cfwl_edittp.cpp b/xfa/fwl/theme/cfwl_edittp.cpp
index eee5423..4316017 100644
--- a/xfa/fwl/theme/cfwl_edittp.cpp
+++ b/xfa/fwl/theme/cfwl_edittp.cpp
@@ -53,7 +53,6 @@
         pGraphics->RestoreGraphState();
       } else {
         CFX_Path path;
-        path.Create();
         path.AddRectangle(pParams->m_rtPart.left, pParams->m_rtPart.top,
                           pParams->m_rtPart.width, pParams->m_rtPart.height);
         CFX_Color cr(FWLTHEME_COLOR_Background);
diff --git a/xfa/fwl/theme/cfwl_listboxtp.cpp b/xfa/fwl/theme/cfwl_listboxtp.cpp
index 7a9ba92..4e00420 100644
--- a/xfa/fwl/theme/cfwl_listboxtp.cpp
+++ b/xfa/fwl/theme/cfwl_listboxtp.cpp
@@ -70,7 +70,6 @@
     pGraphics->SetFillColor(&crFill);
     CFX_RectF rt(*prtItem);
     CFX_Path path;
-    path.Create();
 #if (_FX_OS_ == _FX_MACOSX_)
     path.AddRectangle(rt.left, rt.top, rt.width - 1, rt.height - 1);
 #else
diff --git a/xfa/fwl/theme/cfwl_monthcalendartp.cpp b/xfa/fwl/theme/cfwl_monthcalendartp.cpp
index d98cf24..b14109d 100644
--- a/xfa/fwl/theme/cfwl_monthcalendartp.cpp
+++ b/xfa/fwl/theme/cfwl_monthcalendartp.cpp
@@ -105,10 +105,10 @@
 void CFWL_MonthCalendarTP::DrawTotalBK(CFWL_ThemeBackground* pParams,
                                        CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
   CFX_RectF rtTotal(pParams->m_rtPart);
   path.AddRectangle(rtTotal.left, rtTotal.top, rtTotal.width, rtTotal.height);
   pParams->m_pGraphics->SaveGraphState();
+
   CFX_Color clrBK(m_pThemeData->clrBK);
   pParams->m_pGraphics->SetFillColor(&clrBK);
   pParams->m_pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
@@ -118,10 +118,10 @@
 void CFWL_MonthCalendarTP::DrawHeadBk(CFWL_ThemeBackground* pParams,
                                       CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
   CFX_RectF rtHead = pParams->m_rtPart;
   path.AddRectangle(rtHead.left, rtHead.top, rtHead.width, rtHead.height);
   pParams->m_pGraphics->SaveGraphState();
+
   CFX_Color clrHeadBK(m_pThemeData->clrBK);
   pParams->m_pGraphics->SetFillColor(&clrHeadBK);
   pParams->m_pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
@@ -131,11 +131,10 @@
 void CFWL_MonthCalendarTP::DrawLButton(CFWL_ThemeBackground* pParams,
                                        CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
-  CFX_RectF rtLBtn;
-  rtLBtn = pParams->m_rtPart;
+  CFX_RectF rtLBtn = pParams->m_rtPart;
   path.AddRectangle(rtLBtn.left, rtLBtn.top, rtLBtn.width, rtLBtn.height);
   pParams->m_pGraphics->SaveGraphState();
+
   CFX_Color clrLBtnEdge(ArgbEncode(0xff, 205, 219, 243));
   pParams->m_pGraphics->SetStrokeColor(&clrLBtnEdge);
   pParams->m_pGraphics->StrokePath(&path, pMatrix);
@@ -148,12 +147,15 @@
     pParams->m_pGraphics->SetFillColor(&clrLBtnFill);
     pParams->m_pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
   }
+
   path.Clear();
-  path.MoveTo(rtLBtn.left + rtLBtn.Width() / 3 * 2,
-              rtLBtn.top + rtLBtn.height / 4);
-  path.LineTo(rtLBtn.left + rtLBtn.Width() / 3, rtLBtn.top + rtLBtn.height / 2);
-  path.LineTo(rtLBtn.left + rtLBtn.Width() / 3 * 2,
-              rtLBtn.bottom() - rtLBtn.height / 4);
+  path.MoveTo(CFX_PointF(rtLBtn.left + rtLBtn.Width() / 3 * 2,
+                         rtLBtn.top + rtLBtn.height / 4));
+  path.LineTo(CFX_PointF(rtLBtn.left + rtLBtn.Width() / 3,
+                         rtLBtn.top + rtLBtn.height / 2));
+  path.LineTo(CFX_PointF(rtLBtn.left + rtLBtn.Width() / 3 * 2,
+                         rtLBtn.bottom() - rtLBtn.height / 4));
+
   CFX_Color clrFlag(ArgbEncode(0xff, 50, 104, 205));
   pParams->m_pGraphics->SetStrokeColor(&clrFlag);
   pParams->m_pGraphics->StrokePath(&path, pMatrix);
@@ -163,11 +165,10 @@
 void CFWL_MonthCalendarTP::DrawRButton(CFWL_ThemeBackground* pParams,
                                        CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
-  CFX_RectF rtRBtn;
-  rtRBtn = pParams->m_rtPart;
+  CFX_RectF rtRBtn = pParams->m_rtPart;
   path.AddRectangle(rtRBtn.left, rtRBtn.top, rtRBtn.width, rtRBtn.height);
   pParams->m_pGraphics->SaveGraphState();
+
   CFX_Color clrRBtnEdge(ArgbEncode(0xff, 205, 219, 243));
   pParams->m_pGraphics->SetStrokeColor(&clrRBtnEdge);
   pParams->m_pGraphics->StrokePath(&path, pMatrix);
@@ -180,12 +181,15 @@
     pParams->m_pGraphics->SetFillColor(&clrRBtnFill);
     pParams->m_pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
   }
+
   path.Clear();
-  path.MoveTo(rtRBtn.left + rtRBtn.Width() / 3, rtRBtn.top + rtRBtn.height / 4);
-  path.LineTo(rtRBtn.left + rtRBtn.Width() / 3 * 2,
-              rtRBtn.top + rtRBtn.height / 2);
-  path.LineTo(rtRBtn.left + rtRBtn.Width() / 3,
-              rtRBtn.bottom() - rtRBtn.height / 4);
+  path.MoveTo(CFX_PointF(rtRBtn.left + rtRBtn.Width() / 3,
+                         rtRBtn.top + rtRBtn.height / 4));
+  path.LineTo(CFX_PointF(rtRBtn.left + rtRBtn.Width() / 3 * 2,
+                         rtRBtn.top + rtRBtn.height / 2));
+  path.LineTo(CFX_PointF(rtRBtn.left + rtRBtn.Width() / 3,
+                         rtRBtn.bottom() - rtRBtn.height / 4));
+
   CFX_Color clrFlag(ArgbEncode(0xff, 50, 104, 205));
   pParams->m_pGraphics->SetStrokeColor(&clrFlag);
   pParams->m_pGraphics->StrokePath(&path, pMatrix);
@@ -195,12 +199,11 @@
 void CFWL_MonthCalendarTP::DrawHSeperator(CFWL_ThemeBackground* pParams,
                                           CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
-  CFX_RectF rtHSep;
-  rtHSep = pParams->m_rtPart;
-  path.MoveTo(rtHSep.left, rtHSep.top + rtHSep.height / 2);
-  path.LineTo(rtHSep.right(), rtHSep.top + rtHSep.height / 2);
+  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();
+
   CFX_Color clrHSep(m_pThemeData->clrSeperator);
   pParams->m_pGraphics->SetStrokeColor(&clrHSep);
   pParams->m_pGraphics->StrokePath(&path, pMatrix);
@@ -210,12 +213,11 @@
 void CFWL_MonthCalendarTP::DrawWeekNumSep(CFWL_ThemeBackground* pParams,
                                           CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
-  CFX_RectF rtWeekSep;
-  rtWeekSep = pParams->m_rtPart;
-  path.MoveTo(rtWeekSep.left, rtWeekSep.top);
-  path.LineTo(rtWeekSep.left, rtWeekSep.bottom());
+  CFX_RectF rtWeekSep = pParams->m_rtPart;
+  path.MoveTo(rtWeekSep.TopLeft());
+  path.LineTo(rtWeekSep.BottomLeft());
   pParams->m_pGraphics->SaveGraphState();
+
   CFX_Color clrHSep(m_pThemeData->clrSeperator);
   pParams->m_pGraphics->SetStrokeColor(&clrHSep);
   pParams->m_pGraphics->StrokePath(&path, pMatrix);
@@ -227,9 +229,7 @@
   pParams->m_pGraphics->SaveGraphState();
   if (pParams->m_dwStates & CFWL_PartState_Selected) {
     CFX_Path path;
-    path.Create();
-    CFX_RectF rtSelDay;
-    rtSelDay = pParams->m_rtPart;
+    CFX_RectF rtSelDay = pParams->m_rtPart;
     path.AddRectangle(rtSelDay.left, rtSelDay.top, rtSelDay.width,
                       rtSelDay.height);
     CFX_Color clrSelDayBK(m_pThemeData->clrDatesSelectedBK);
@@ -237,9 +237,7 @@
     pParams->m_pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
   } else if (pParams->m_dwStates & CFWL_PartState_Hovered) {
     CFX_Path path;
-    path.Create();
-    CFX_RectF rtSelDay;
-    rtSelDay = pParams->m_rtPart;
+    CFX_RectF rtSelDay = pParams->m_rtPart;
     path.AddRectangle(rtSelDay.left, rtSelDay.top, rtSelDay.width,
                       rtSelDay.height);
     CFX_Color clrSelDayBK(m_pThemeData->clrDatesHoverBK);
@@ -252,9 +250,7 @@
 void CFWL_MonthCalendarTP::DrawDatesInCircle(CFWL_ThemeBackground* pParams,
                                              CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
-  CFX_RectF rtSelDay;
-  rtSelDay = pParams->m_rtPart;
+  CFX_RectF rtSelDay = pParams->m_rtPart;
   path.AddRectangle(rtSelDay.left, rtSelDay.top, rtSelDay.width,
                     rtSelDay.height);
   pParams->m_pGraphics->SaveGraphState();
@@ -267,9 +263,7 @@
 void CFWL_MonthCalendarTP::DrawTodayCircle(CFWL_ThemeBackground* pParams,
                                            CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
-  CFX_RectF rtTodayCircle;
-  rtTodayCircle = pParams->m_rtPart;
+  CFX_RectF rtTodayCircle = pParams->m_rtPart;
   path.AddRectangle(rtTodayCircle.left, rtTodayCircle.top, rtTodayCircle.width,
                     rtTodayCircle.height);
   pParams->m_pGraphics->SaveGraphState();
diff --git a/xfa/fwl/theme/cfwl_pushbuttontp.cpp b/xfa/fwl/theme/cfwl_pushbuttontp.cpp
index a1e5783..56268a8 100644
--- a/xfa/fwl/theme/cfwl_pushbuttontp.cpp
+++ b/xfa/fwl/theme/cfwl_pushbuttontp.cpp
@@ -31,39 +31,50 @@
       CFX_RectF& rect = pParams->m_rtPart;
       FX_FLOAT fRight = rect.right();
       FX_FLOAT fBottom = rect.bottom();
+
       CFX_Path strokePath;
-      strokePath.Create();
-      strokePath.MoveTo(rect.left + PUSHBUTTON_SIZE_Corner, rect.top);
-      strokePath.LineTo(fRight - PUSHBUTTON_SIZE_Corner, rect.top);
-      strokePath.LineTo(fRight, rect.top + PUSHBUTTON_SIZE_Corner);
-      strokePath.LineTo(fRight, fBottom - PUSHBUTTON_SIZE_Corner);
-      strokePath.LineTo(fRight - PUSHBUTTON_SIZE_Corner, fBottom);
-      strokePath.LineTo(rect.left + PUSHBUTTON_SIZE_Corner, fBottom);
-      strokePath.LineTo(rect.left, fBottom - PUSHBUTTON_SIZE_Corner);
-      strokePath.LineTo(rect.left, rect.top + PUSHBUTTON_SIZE_Corner);
-      strokePath.LineTo(rect.left + PUSHBUTTON_SIZE_Corner, rect.top);
+      strokePath.MoveTo(
+          CFX_PointF(rect.left + PUSHBUTTON_SIZE_Corner, rect.top));
+      strokePath.LineTo(CFX_PointF(fRight - PUSHBUTTON_SIZE_Corner, rect.top));
+      strokePath.LineTo(CFX_PointF(fRight, rect.top + PUSHBUTTON_SIZE_Corner));
+      strokePath.LineTo(CFX_PointF(fRight, fBottom - PUSHBUTTON_SIZE_Corner));
+      strokePath.LineTo(CFX_PointF(fRight - PUSHBUTTON_SIZE_Corner, fBottom));
+      strokePath.LineTo(
+          CFX_PointF(rect.left + PUSHBUTTON_SIZE_Corner, fBottom));
+      strokePath.LineTo(
+          CFX_PointF(rect.left, fBottom - PUSHBUTTON_SIZE_Corner));
+      strokePath.LineTo(
+          CFX_PointF(rect.left, rect.top + PUSHBUTTON_SIZE_Corner));
+      strokePath.LineTo(
+          CFX_PointF(rect.left + PUSHBUTTON_SIZE_Corner, rect.top));
+
       CFX_Path fillPath;
-      fillPath.Create();
       fillPath.AddSubpath(&strokePath);
+
       CFX_Graphics* pGraphics = pParams->m_pGraphics;
       pGraphics->SaveGraphState();
+
       CFX_RectF rtInner(rect);
       rtInner.Deflate(PUSHBUTTON_SIZE_Corner + 1, PUSHBUTTON_SIZE_Corner + 1,
                       PUSHBUTTON_SIZE_Corner, PUSHBUTTON_SIZE_Corner);
       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);
+
       CFX_Color crStroke(m_pThemeData->clrBorder[iColor]);
       pGraphics->SetStrokeColor(&crStroke);
       pGraphics->StrokePath(&strokePath, &pParams->m_matrix);
+
       fillPath.Clear();
       fillPath.AddRectangle(rtInner.left, rtInner.top, rtInner.width,
                             rtInner.height);
+
       CFX_Color crFill(m_pThemeData->clrFill[iColor]);
       pGraphics->SetFillColor(&crFill);
       pGraphics->FillPath(&fillPath, FXFILL_WINDING, &pParams->m_matrix);
diff --git a/xfa/fwl/theme/cfwl_scrollbartp.cpp b/xfa/fwl/theme/cfwl_scrollbartp.cpp
index 4cd2fb3..121d4de 100644
--- a/xfa/fwl/theme/cfwl_scrollbartp.cpp
+++ b/xfa/fwl/theme/cfwl_scrollbartp.cpp
@@ -81,7 +81,6 @@
     return;
 
   CFX_Path path;
-  path.Create();
   CFX_RectF rect(*pRect);
   if (bVert) {
     rect.Deflate(1, 0);
@@ -124,36 +123,39 @@
                                FWLTHEME_STATE eState,
                                CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
   if (bVert) {
     FX_FLOAT fPawLen = kPawLength;
     if (pRect->width / 2 <= fPawLen) {
       fPawLen = (pRect->width - 6) / 2;
     }
+
     FX_FLOAT fX = pRect->left + pRect->width / 4;
     FX_FLOAT fY = pRect->top + pRect->height / 2;
-    path.MoveTo(fX, fY - 4);
-    path.LineTo(fX + fPawLen, fY - 4);
-    path.MoveTo(fX, fY - 2);
-    path.LineTo(fX + fPawLen, fY - 2);
-    path.MoveTo(fX, fY);
-    path.LineTo(fX + fPawLen, fY);
-    path.MoveTo(fX, fY + 2);
-    path.LineTo(fX + fPawLen, fY + 2);
+    path.MoveTo(CFX_PointF(fX, fY - 4));
+    path.LineTo(CFX_PointF(fX + fPawLen, fY - 4));
+    path.MoveTo(CFX_PointF(fX, fY - 2));
+    path.LineTo(CFX_PointF(fX + fPawLen, fY - 2));
+    path.MoveTo(CFX_PointF(fX, fY));
+    path.LineTo(CFX_PointF(fX + fPawLen, fY));
+    path.MoveTo(CFX_PointF(fX, fY + 2));
+    path.LineTo(CFX_PointF(fX + fPawLen, fY + 2));
+
     CFX_Color clrLight(m_pThemeData->clrPawColorLight[eState - 1]);
     pGraphics->SetLineWidth(1);
     pGraphics->SetStrokeColor(&clrLight);
     pGraphics->StrokePath(&path);
     fX++;
+
     path.Clear();
-    path.MoveTo(fX, fY - 3);
-    path.LineTo(fX + fPawLen, fY - 3);
-    path.MoveTo(fX, fY - 1);
-    path.LineTo(fX + fPawLen, fY - 1);
-    path.MoveTo(fX, fY + 1);
-    path.LineTo(fX + fPawLen, fY + 1);
-    path.MoveTo(fX, fY + 3);
-    path.LineTo(fX + fPawLen, fY + 3);
+    path.MoveTo(CFX_PointF(fX, fY - 3));
+    path.LineTo(CFX_PointF(fX + fPawLen, fY - 3));
+    path.MoveTo(CFX_PointF(fX, fY - 1));
+    path.LineTo(CFX_PointF(fX + fPawLen, fY - 1));
+    path.MoveTo(CFX_PointF(fX, fY + 1));
+    path.LineTo(CFX_PointF(fX + fPawLen, fY + 1));
+    path.MoveTo(CFX_PointF(fX, fY + 3));
+    path.LineTo(CFX_PointF(fX + fPawLen, fY + 3));
+
     CFX_Color clrDark(m_pThemeData->clrPawColorDark[eState - 1]);
     pGraphics->SetLineWidth(1);
     pGraphics->SetStrokeColor(&clrDark);
@@ -163,30 +165,34 @@
     if (pRect->height / 2 <= fPawLen) {
       fPawLen = (pRect->height - 6) / 2;
     }
+
     FX_FLOAT fX = pRect->left + pRect->width / 2;
     FX_FLOAT fY = pRect->top + pRect->height / 4;
-    path.MoveTo(fX - 4, fY);
-    path.LineTo(fX - 4, fY + fPawLen);
-    path.MoveTo(fX - 2, fY);
-    path.LineTo(fX - 2, fY + fPawLen);
-    path.MoveTo(fX, fY);
-    path.LineTo(fX, fY + fPawLen);
-    path.MoveTo(fX + 2, fY);
-    path.LineTo(fX + 2, fY + fPawLen);
+    path.MoveTo(CFX_PointF(fX - 4, fY));
+    path.LineTo(CFX_PointF(fX - 4, fY + fPawLen));
+    path.MoveTo(CFX_PointF(fX - 2, fY));
+    path.LineTo(CFX_PointF(fX - 2, fY + fPawLen));
+    path.MoveTo(CFX_PointF(fX, fY));
+    path.LineTo(CFX_PointF(fX, fY + fPawLen));
+    path.MoveTo(CFX_PointF(fX + 2, fY));
+    path.LineTo(CFX_PointF(fX + 2, fY + fPawLen));
+
     CFX_Color clrLight(m_pThemeData->clrPawColorLight[eState - 1]);
     pGraphics->SetLineWidth(1);
     pGraphics->SetStrokeColor(&clrLight);
     pGraphics->StrokePath(&path, pMatrix);
     fY++;
+
     path.Clear();
-    path.MoveTo(fX - 3, fY);
-    path.LineTo(fX - 3, fY + fPawLen);
-    path.MoveTo(fX - 1, fY);
-    path.LineTo(fX - 1, fY + fPawLen);
-    path.MoveTo(fX + 1, fY);
-    path.LineTo(fX + 1, fY + fPawLen);
-    path.MoveTo(fX + 3, fY);
-    path.LineTo(fX + 3, fY + fPawLen);
+    path.MoveTo(CFX_PointF(fX - 3, fY));
+    path.LineTo(CFX_PointF(fX - 3, fY + fPawLen));
+    path.MoveTo(CFX_PointF(fX - 1, fY));
+    path.LineTo(CFX_PointF(fX - 1, fY + fPawLen));
+    path.MoveTo(CFX_PointF(fX + 1, fY));
+    path.LineTo(CFX_PointF(fX + 1, fY + fPawLen));
+    path.MoveTo(CFX_PointF(fX + 3, fY));
+    path.LineTo(CFX_PointF(fX + 3, fY + fPawLen));
+
     CFX_Color clrDark(m_pThemeData->clrPawColorDark[eState - 1]);
     pGraphics->SetLineWidth(1);
     pGraphics->SetStrokeColor(&clrDark);
@@ -206,7 +212,6 @@
   pGraphics->SaveGraphState();
   CFX_Color colorLine(ArgbEncode(255, 238, 237, 229));
   CFX_Path path;
-  path.Create();
   FX_FLOAT fRight = pRect->right();
   FX_FLOAT fBottom = pRect->bottom();
   if (bVert) {
diff --git a/xfa/fwl/theme/cfwl_widgettp.cpp b/xfa/fwl/theme/cfwl_widgettp.cpp
index a0d6b4c..fbcbcff 100644
--- a/xfa/fwl/theme/cfwl_widgettp.cpp
+++ b/xfa/fwl/theme/cfwl_widgettp.cpp
@@ -84,8 +84,7 @@
   if (m_pTextOut)
     return;
 
-  m_pFDEFont =
-      CFWL_FontManager::GetInstance()->FindFont(FX_WSTRC(L"Helvetica"), 0, 0);
+  m_pFDEFont = CFWL_FontManager::GetInstance()->FindFont(L"Helvetica", 0, 0);
   m_pTextOut = pdfium::MakeUnique<CFDE_TextOut>();
   m_pTextOut->SetFont(m_pFDEFont);
   m_pTextOut->SetFontSize(FWLTHEME_CAPACITY_FontSize);
@@ -105,7 +104,6 @@
   if (!pRect)
     return;
   CFX_Path path;
-  path.Create();
   path.AddRectangle(pRect->left, pRect->top, pRect->width, pRect->height);
   path.AddRectangle(pRect->left + 1, pRect->top + 1, pRect->width - 2,
                     pRect->height - 2);
@@ -134,7 +132,6 @@
   CFX_Color crFill(fillColor);
   pGraphics->SetFillColor(&crFill);
   CFX_Path path;
-  path.Create();
   path.AddRectangle(pRect->left, pRect->top, pRect->width, pRect->height);
   pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
   pGraphics->RestoreGraphState();
@@ -176,7 +173,6 @@
   FX_FLOAT DashPattern[2] = {1, 1};
   pGraphics->SetLineDash(0.0f, DashPattern, 2);
   CFX_Path path;
-  path.Create();
   path.AddRectangle(pRect->left, pRect->top, pRect->width, pRect->height);
   pGraphics->StrokePath(&path, pMatrix);
   pGraphics->RestoreGraphState();
@@ -194,42 +190,41 @@
   FX_FLOAT fTop =
       (FX_FLOAT)(((pRect->height - (bVert ? 6 : 9)) / 2 + pRect->top) + 0.5);
   CFX_Path path;
-  path.Create();
   switch (eDict) {
     case FWLTHEME_DIRECTION_Down: {
-      path.MoveTo(fLeft, fTop + 1);
-      path.LineTo(fLeft + 4, fTop + 5);
-      path.LineTo(fLeft + 8, fTop + 1);
-      path.LineTo(fLeft + 7, fTop);
-      path.LineTo(fLeft + 4, fTop + 3);
-      path.LineTo(fLeft + 1, fTop);
+      path.MoveTo(CFX_PointF(fLeft, fTop + 1));
+      path.LineTo(CFX_PointF(fLeft + 4, fTop + 5));
+      path.LineTo(CFX_PointF(fLeft + 8, fTop + 1));
+      path.LineTo(CFX_PointF(fLeft + 7, fTop));
+      path.LineTo(CFX_PointF(fLeft + 4, fTop + 3));
+      path.LineTo(CFX_PointF(fLeft + 1, fTop));
       break;
     }
     case FWLTHEME_DIRECTION_Up: {
-      path.MoveTo(fLeft, fTop + 4);
-      path.LineTo(fLeft + 4, fTop);
-      path.LineTo(fLeft + 8, fTop + 4);
-      path.LineTo(fLeft + 7, fTop + 5);
-      path.LineTo(fLeft + 4, fTop + 2);
-      path.LineTo(fLeft + 1, fTop + 5);
+      path.MoveTo(CFX_PointF(fLeft, fTop + 4));
+      path.LineTo(CFX_PointF(fLeft + 4, fTop));
+      path.LineTo(CFX_PointF(fLeft + 8, fTop + 4));
+      path.LineTo(CFX_PointF(fLeft + 7, fTop + 5));
+      path.LineTo(CFX_PointF(fLeft + 4, fTop + 2));
+      path.LineTo(CFX_PointF(fLeft + 1, fTop + 5));
       break;
     }
     case FWLTHEME_DIRECTION_Right: {
-      path.MoveTo(fLeft + 1, fTop);
-      path.LineTo(fLeft + 5, fTop + 4);
-      path.LineTo(fLeft + 1, fTop + 8);
-      path.LineTo(fLeft, fTop + 7);
-      path.LineTo(fLeft + 3, fTop + 4);
-      path.LineTo(fLeft, fTop + 1);
+      path.MoveTo(CFX_PointF(fLeft + 1, fTop));
+      path.LineTo(CFX_PointF(fLeft + 5, fTop + 4));
+      path.LineTo(CFX_PointF(fLeft + 1, fTop + 8));
+      path.LineTo(CFX_PointF(fLeft, fTop + 7));
+      path.LineTo(CFX_PointF(fLeft + 3, fTop + 4));
+      path.LineTo(CFX_PointF(fLeft, fTop + 1));
       break;
     }
     case FWLTHEME_DIRECTION_Left: {
-      path.MoveTo(fLeft, fTop + 4);
-      path.LineTo(fLeft + 4, fTop);
-      path.LineTo(fLeft + 5, fTop + 1);
-      path.LineTo(fLeft + 2, fTop + 4);
-      path.LineTo(fLeft + 5, fTop + 7);
-      path.LineTo(fLeft + 4, fTop + 8);
+      path.MoveTo(CFX_PointF(fLeft, fTop + 4));
+      path.LineTo(CFX_PointF(fLeft + 4, fTop));
+      path.LineTo(CFX_PointF(fLeft + 5, fTop + 1));
+      path.LineTo(CFX_PointF(fLeft + 2, fTop + 4));
+      path.LineTo(CFX_PointF(fLeft + 5, fTop + 7));
+      path.LineTo(CFX_PointF(fLeft + 4, fTop + 8));
       break;
     }
   }
@@ -243,8 +238,6 @@
                             FWLTHEME_STATE eState,
                             CFX_Matrix* pMatrix) {
   CFX_Path path;
-  path.Create();
-
   InitializeArrowColorData();
 
   FX_FLOAT fRight = pRect->right();
diff --git a/xfa/fwl/theme/cfwl_widgettp.h b/xfa/fwl/theme/cfwl_widgettp.h
index 794c67b..c819507 100644
--- a/xfa/fwl/theme/cfwl_widgettp.h
+++ b/xfa/fwl/theme/cfwl_widgettp.h
@@ -14,7 +14,6 @@
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_system.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
-#include "xfa/fwl/fwl_error.h"
 #include "xfa/fwl/theme/cfwl_utils.h"
 #include "xfa/fxgraphics/cfx_graphics.h"
 
diff --git a/xfa/fxbarcode/BC_TwoDimWriter.cpp b/xfa/fxbarcode/BC_TwoDimWriter.cpp
index 84678a8..b9aae36 100644
--- a/xfa/fxbarcode/BC_TwoDimWriter.cpp
+++ b/xfa/fxbarcode/BC_TwoDimWriter.cpp
@@ -145,7 +145,8 @@
          inputX++, outputX += multiX) {
       if (code[inputX + inputY * inputWidth] == 1) {
         m_output->SetRegion(outputX, outputY, multiX, multiY, e);
-        BC_EXCEPTION_CHECK_ReturnVoid(e);
+        if (e != BCExceptionNO)
+          return;
       }
     }
   }
diff --git a/xfa/fxbarcode/BC_UtilCodingConvert.cpp b/xfa/fxbarcode/BC_UtilCodingConvert.cpp
index 7347575..c06cffc 100644
--- a/xfa/fxbarcode/BC_UtilCodingConvert.cpp
+++ b/xfa/fxbarcode/BC_UtilCodingConvert.cpp
@@ -22,7 +22,7 @@
 }
 
 void CBC_UtilCodingConvert::LocaleToUtf8(const CFX_ByteString& src,
-                                         CFX_ByteArray& dst) {
+                                         CFX_ArrayTemplate<uint8_t>& dst) {
   CFX_WideString unicode = CFX_WideString::FromLocal(src.AsStringC());
   CFX_ByteString utf8 = unicode.UTF8Encode();
   for (int32_t i = 0; i < utf8.GetLength(); i++) {
@@ -30,7 +30,7 @@
   }
 }
 
-void CBC_UtilCodingConvert::Utf8ToLocale(const CFX_ByteArray& src,
+void CBC_UtilCodingConvert::Utf8ToLocale(const CFX_ArrayTemplate<uint8_t>& src,
                                          CFX_ByteString& dst) {
   CFX_ByteString utf8;
   for (int32_t i = 0; i < src.GetSize(); i++) {
diff --git a/xfa/fxbarcode/BC_UtilCodingConvert.h b/xfa/fxbarcode/BC_UtilCodingConvert.h
index 698cd85..859eeea 100644
--- a/xfa/fxbarcode/BC_UtilCodingConvert.h
+++ b/xfa/fxbarcode/BC_UtilCodingConvert.h
@@ -17,8 +17,10 @@
                               CFX_ByteString& result);
   static void LocaleToUtf8(const CFX_ByteString& source,
                            CFX_ByteString& result);
-  static void LocaleToUtf8(const CFX_ByteString& source, CFX_ByteArray& result);
-  static void Utf8ToLocale(const CFX_ByteArray& source, CFX_ByteString& result);
+  static void LocaleToUtf8(const CFX_ByteString& source,
+                           CFX_ArrayTemplate<uint8_t>& result);
+  static void Utf8ToLocale(const CFX_ArrayTemplate<uint8_t>& source,
+                           CFX_ByteString& result);
   static void Utf8ToLocale(const uint8_t* source,
                            int32_t count,
                            CFX_ByteString& result);
diff --git a/xfa/fxbarcode/BC_Utils.cpp b/xfa/fxbarcode/BC_Utils.cpp
index 807b048..5d881c7 100644
--- a/xfa/fxbarcode/BC_Utils.cpp
+++ b/xfa/fxbarcode/BC_Utils.cpp
@@ -26,7 +26,8 @@
     dst += c;
   }
 }
-void BC_FX_ByteString_Append(CFX_ByteString& dst, const CFX_ByteArray& ba) {
+void BC_FX_ByteString_Append(CFX_ByteString& dst,
+                             const CFX_ArrayTemplate<uint8_t>& ba) {
   for (int32_t i = 0; i < ba.GetSize(); i++) {
     dst += ba[i];
   }
diff --git a/xfa/fxbarcode/cbc_codabar.cpp b/xfa/fxbarcode/cbc_codabar.cpp
index e8e8cdc..6f6ab4a 100644
--- a/xfa/fxbarcode/cbc_codabar.cpp
+++ b/xfa/fxbarcode/cbc_codabar.cpp
@@ -70,11 +70,13 @@
   m_renderContents = filtercontents;
   uint8_t* data = static_cast<CBC_OnedCodaBarWriter*>(m_pBCWriter.get())
                       ->Encode(byteString, format, outWidth, outHeight, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderResult(filtercontents.AsStringC(), data, outWidth, isDevice, e);
   FX_Free(data);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
@@ -86,7 +88,8 @@
           ->encodedContents(m_renderContents.AsStringC());
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderDeviceResult(device, matrix, renderCon.AsStringC(), e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
@@ -96,7 +99,8 @@
           ->encodedContents(m_renderContents.AsStringC());
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderBitmapResult(pOutBitmap, renderCon.AsStringC(), e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
diff --git a/xfa/fxbarcode/cbc_code128.cpp b/xfa/fxbarcode/cbc_code128.cpp
index 99c3c21..35bd136 100644
--- a/xfa/fxbarcode/cbc_code128.cpp
+++ b/xfa/fxbarcode/cbc_code128.cpp
@@ -58,11 +58,13 @@
   CFX_ByteString byteString = encodeContents.UTF8Encode();
   uint8_t* data = static_cast<CBC_OnedCode128Writer*>(m_pBCWriter.get())
                       ->Encode(byteString, format, outWidth, outHeight, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderResult(encodeContents.AsStringC(), data, outWidth, isDevice, e);
   FX_Free(data);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
@@ -71,14 +73,16 @@
                                int32_t& e) {
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderDeviceResult(device, matrix, m_renderContents.AsStringC(), e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
 bool CBC_Code128::RenderBitmap(CFX_DIBitmap*& pOutBitmap, int32_t& e) {
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderBitmapResult(pOutBitmap, m_renderContents.AsStringC(), e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
diff --git a/xfa/fxbarcode/cbc_code39.cpp b/xfa/fxbarcode/cbc_code39.cpp
index e90abb9..af45ad4 100644
--- a/xfa/fxbarcode/cbc_code39.cpp
+++ b/xfa/fxbarcode/cbc_code39.cpp
@@ -47,11 +47,13 @@
   CFX_ByteString byteString = filtercontents.UTF8Encode();
   uint8_t* data = static_cast<CBC_OnedCode39Writer*>(m_pBCWriter.get())
                       ->Encode(byteString, format, outWidth, outHeight, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderResult(renderContents.AsStringC(), data, outWidth, isDevice, e);
   FX_Free(data);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
@@ -63,7 +65,8 @@
           ->encodedContents(m_renderContents.AsStringC(), e);
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderDeviceResult(device, matrix, renderCon.AsStringC(), e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
@@ -73,7 +76,8 @@
           ->encodedContents(m_renderContents.AsStringC(), e);
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderBitmapResult(pOutBitmap, renderCon.AsStringC(), e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
diff --git a/xfa/fxbarcode/cbc_datamatrix.cpp b/xfa/fxbarcode/cbc_datamatrix.cpp
index 86ca75d..6122368 100644
--- a/xfa/fxbarcode/cbc_datamatrix.cpp
+++ b/xfa/fxbarcode/cbc_datamatrix.cpp
@@ -35,11 +35,13 @@
   uint8_t* data =
       static_cast<CBC_DataMatrixWriter*>(m_pBCWriter.get())
           ->Encode(CFX_WideString(contents), outWidth, outHeight, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   static_cast<CBC_TwoDimWriter*>(m_pBCWriter.get())
       ->RenderResult(data, outWidth, outHeight, e);
   FX_Free(data);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
@@ -54,7 +56,8 @@
 bool CBC_DataMatrix::RenderBitmap(CFX_DIBitmap*& pOutBitmap, int32_t& e) {
   static_cast<CBC_TwoDimWriter*>(m_pBCWriter.get())
       ->RenderBitmapResult(pOutBitmap, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
diff --git a/xfa/fxbarcode/cbc_ean13.cpp b/xfa/fxbarcode/cbc_ean13.cpp
index d696897..450fba0 100644
--- a/xfa/fxbarcode/cbc_ean13.cpp
+++ b/xfa/fxbarcode/cbc_ean13.cpp
@@ -63,11 +63,13 @@
   m_renderContents = encodeContents;
   uint8_t* data = static_cast<CBC_OnedEAN13Writer*>(m_pBCWriter.get())
                       ->Encode(byteString, format, outWidth, outHeight, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderResult(encodeContents.AsStringC(), data, outWidth, isDevice, e);
   FX_Free(data);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
@@ -76,14 +78,16 @@
                              int32_t& e) {
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderDeviceResult(device, matrix, m_renderContents.AsStringC(), e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
 bool CBC_EAN13::RenderBitmap(CFX_DIBitmap*& pOutBitmap, int32_t& e) {
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderBitmapResult(pOutBitmap, m_renderContents.AsStringC(), e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
diff --git a/xfa/fxbarcode/cbc_ean8.cpp b/xfa/fxbarcode/cbc_ean8.cpp
index 2c1ce24..64ba617 100644
--- a/xfa/fxbarcode/cbc_ean8.cpp
+++ b/xfa/fxbarcode/cbc_ean8.cpp
@@ -62,11 +62,13 @@
   m_renderContents = encodeContents;
   uint8_t* data = static_cast<CBC_OnedEAN8Writer*>(m_pBCWriter.get())
                       ->Encode(byteString, format, outWidth, outHeight, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderResult(encodeContents.AsStringC(), data, outWidth, isDevice, e);
   FX_Free(data);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
@@ -75,14 +77,16 @@
                             int32_t& e) {
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderDeviceResult(device, matrix, m_renderContents.AsStringC(), e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
 bool CBC_EAN8::RenderBitmap(CFX_DIBitmap*& pOutBitmap, int32_t& e) {
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderBitmapResult(pOutBitmap, m_renderContents.AsStringC(), e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
diff --git a/xfa/fxbarcode/cbc_pdf417i.cpp b/xfa/fxbarcode/cbc_pdf417i.cpp
index 1e147d9..1c5547d 100644
--- a/xfa/fxbarcode/cbc_pdf417i.cpp
+++ b/xfa/fxbarcode/cbc_pdf417i.cpp
@@ -45,11 +45,13 @@
   uint8_t* data =
       static_cast<CBC_PDF417Writer*>(m_pBCWriter.get())
           ->Encode(CFX_WideString(contents), outWidth, outHeight, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   static_cast<CBC_TwoDimWriter*>(m_pBCWriter.get())
       ->RenderResult(data, outWidth, outHeight, e);
   FX_Free(data);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
@@ -64,7 +66,8 @@
 bool CBC_PDF417I::RenderBitmap(CFX_DIBitmap*& pOutBitmap, int32_t& e) {
   static_cast<CBC_TwoDimWriter*>(m_pBCWriter.get())
       ->RenderBitmapResult(pOutBitmap, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
diff --git a/xfa/fxbarcode/cbc_qrcode.cpp b/xfa/fxbarcode/cbc_qrcode.cpp
index 507b8f9..26b74ca 100644
--- a/xfa/fxbarcode/cbc_qrcode.cpp
+++ b/xfa/fxbarcode/cbc_qrcode.cpp
@@ -52,10 +52,12 @@
   uint8_t* data = pWriter->Encode(CFX_WideString(contents),
                                   pWriter->GetErrorCorrectionLevel(), outWidth,
                                   outHeight, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   pWriter->RenderResult(data, outWidth, outHeight, e);
   FX_Free(data);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
@@ -70,7 +72,8 @@
 bool CBC_QRCode::RenderBitmap(CFX_DIBitmap*& pOutBitmap, int32_t& e) {
   static_cast<CBC_TwoDimWriter*>(m_pBCWriter.get())
       ->RenderBitmapResult(pOutBitmap, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
diff --git a/xfa/fxbarcode/cbc_upca.cpp b/xfa/fxbarcode/cbc_upca.cpp
index db8f722..b282d5c 100644
--- a/xfa/fxbarcode/cbc_upca.cpp
+++ b/xfa/fxbarcode/cbc_upca.cpp
@@ -66,11 +66,13 @@
 
   pWriter->Init();
   uint8_t* data = pWriter->Encode(byteString, format, outWidth, outHeight, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   pWriter->RenderResult(encodeContents.AsStringC(), data, outWidth, isDevice,
                         e);
   FX_Free(data);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
@@ -79,14 +81,16 @@
                             int32_t& e) {
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderDeviceResult(device, matrix, m_renderContents.AsStringC(), e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
 bool CBC_UPCA::RenderBitmap(CFX_DIBitmap*& pOutBitmap, int32_t& e) {
   static_cast<CBC_OneDimWriter*>(m_pBCWriter.get())
       ->RenderBitmapResult(pOutBitmap, m_renderContents.AsStringC(), e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, false);
+  if (e != BCExceptionNO)
+    return false;
   return true;
 }
 
diff --git a/xfa/fxbarcode/common/BC_CommonBitArray.cpp b/xfa/fxbarcode/common/BC_CommonBitArray.cpp
index 722bbc5..0371837 100644
--- a/xfa/fxbarcode/common/BC_CommonBitArray.cpp
+++ b/xfa/fxbarcode/common/BC_CommonBitArray.cpp
@@ -41,7 +41,7 @@
 int32_t CBC_CommonBitArray::GetSize() {
   return m_size;
 }
-CFX_Int32Array& CBC_CommonBitArray::GetBits() {
+CFX_ArrayTemplate<int32_t>& CBC_CommonBitArray::GetBits() {
   return m_bits;
 }
 int32_t CBC_CommonBitArray::GetSizeInBytes() {
diff --git a/xfa/fxbarcode/common/BC_CommonBitArray.h b/xfa/fxbarcode/common/BC_CommonBitArray.h
index 80a56d1..6ad8ab3 100644
--- a/xfa/fxbarcode/common/BC_CommonBitArray.h
+++ b/xfa/fxbarcode/common/BC_CommonBitArray.h
@@ -17,7 +17,7 @@
   virtual ~CBC_CommonBitArray();
 
   int32_t GetSize();
-  CFX_Int32Array& GetBits();
+  CFX_ArrayTemplate<int32_t>& GetBits();
   int32_t GetSizeInBytes();
   bool Get(int32_t i);
   void Set(int32_t i);
@@ -30,7 +30,7 @@
 
  private:
   int32_t m_size;
-  CFX_Int32Array m_bits;
+  CFX_ArrayTemplate<int32_t> m_bits;
 };
 
 #endif  // XFA_FXBARCODE_COMMON_BC_COMMONBITARRAY_H_
diff --git a/xfa/fxbarcode/common/BC_CommonByteArray.cpp b/xfa/fxbarcode/common/BC_CommonByteArray.cpp
index 71fa85f..050ecb0 100644
--- a/xfa/fxbarcode/common/BC_CommonByteArray.cpp
+++ b/xfa/fxbarcode/common/BC_CommonByteArray.cpp
@@ -85,7 +85,7 @@
   FXSYS_memcpy(m_bytes, source + offset, count);
   m_index = count;
 }
-void CBC_CommonByteArray::Set(CFX_ByteArray* source,
+void CBC_CommonByteArray::Set(CFX_ArrayTemplate<uint8_t>* source,
                               int32_t offset,
                               int32_t count) {
   FX_Free(m_bytes);
diff --git a/xfa/fxbarcode/common/BC_CommonByteArray.h b/xfa/fxbarcode/common/BC_CommonByteArray.h
index dd6ee58..009f625 100644
--- a/xfa/fxbarcode/common/BC_CommonByteArray.h
+++ b/xfa/fxbarcode/common/BC_CommonByteArray.h
@@ -25,7 +25,7 @@
   void AppendByte(int32_t value);
   void Reserve(int32_t capacity);
   void Set(uint8_t* source, int32_t offset, int32_t count);
-  void Set(CFX_ByteArray* source, int32_t offset, int32_t count);
+  void Set(CFX_ArrayTemplate<uint8_t>* source, int32_t offset, int32_t count);
 
  private:
   int32_t m_size;
diff --git a/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomon.cpp b/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomon.cpp
index 352dc3d..7698890 100644
--- a/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomon.cpp
+++ b/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomon.cpp
@@ -39,51 +39,57 @@
     CBC_ReedSolomonGF256Poly* lastGenerator =
         m_cachedGenerators[m_cachedGenerators.GetSize() - 1];
     for (int32_t d = m_cachedGenerators.GetSize(); d <= degree; d++) {
-      CFX_Int32Array temp;
+      CFX_ArrayTemplate<int32_t> temp;
       temp.Add(1);
       temp.Add(m_field->Exp(d - 1));
       CBC_ReedSolomonGF256Poly temp_poly;
       temp_poly.Init(m_field, &temp, e);
-      BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+      if (e != BCExceptionNO)
+        return nullptr;
       CBC_ReedSolomonGF256Poly* nextGenerator =
           lastGenerator->Multiply(&temp_poly, e);
-      BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+      if (e != BCExceptionNO)
+        return nullptr;
       m_cachedGenerators.Add(nextGenerator);
       lastGenerator = nextGenerator;
     }
   }
   return m_cachedGenerators[degree];
 }
-void CBC_ReedSolomonEncoder::Encode(CFX_Int32Array* toEncode,
+void CBC_ReedSolomonEncoder::Encode(CFX_ArrayTemplate<int32_t>* toEncode,
                                     int32_t ecBytes,
                                     int32_t& e) {
   if (ecBytes == 0) {
     e = BCExceptionNoCorrectionBytes;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   int32_t dataBytes = toEncode->GetSize() - ecBytes;
   if (dataBytes <= 0) {
     e = BCExceptionNoDataBytesProvided;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   CBC_ReedSolomonGF256Poly* generator = BuildGenerator(ecBytes, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
-  CFX_Int32Array infoCoefficients;
+  if (e != BCExceptionNO)
+    return;
+  CFX_ArrayTemplate<int32_t> infoCoefficients;
   infoCoefficients.SetSize(dataBytes);
   for (int32_t x = 0; x < dataBytes; x++) {
     infoCoefficients[x] = toEncode->operator[](x);
   }
   CBC_ReedSolomonGF256Poly info;
   info.Init(m_field, &infoCoefficients, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   std::unique_ptr<CBC_ReedSolomonGF256Poly> infoTemp(
       info.MultiplyByMonomial(ecBytes, 1, e));
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   std::unique_ptr<CFX_ArrayTemplate<CBC_ReedSolomonGF256Poly*>> temp(
       infoTemp->Divide(generator, e));
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   CBC_ReedSolomonGF256Poly* remainder = (*temp)[1];
-  CFX_Int32Array* coefficients = remainder->GetCoefficients();
+  CFX_ArrayTemplate<int32_t>* coefficients = remainder->GetCoefficients();
   int32_t numZeroCoefficients = ecBytes - coefficients->GetSize();
   for (int32_t i = 0; i < numZeroCoefficients; i++) {
     (*toEncode)[dataBytes + i] = 0;
diff --git a/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomon.h b/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomon.h
index b71cfb4..95828f1 100644
--- a/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomon.h
+++ b/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomon.h
@@ -17,7 +17,9 @@
   explicit CBC_ReedSolomonEncoder(CBC_ReedSolomonGF256* field);
   virtual ~CBC_ReedSolomonEncoder();
 
-  void Encode(CFX_Int32Array* toEncode, int32_t ecBytes, int32_t& e);
+  void Encode(CFX_ArrayTemplate<int32_t>* toEncode,
+              int32_t ecBytes,
+              int32_t& e);
   virtual void Init();
 
  private:
diff --git a/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomonGF256.cpp b/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomonGF256.cpp
index 33b828c..ce84d8e 100644
--- a/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomonGF256.cpp
+++ b/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomonGF256.cpp
@@ -78,19 +78,21 @@
     int32_t& e) {
   if (degree < 0) {
     e = BCExceptionDegreeIsNegative;
-    BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+    return nullptr;
   }
   if (coefficient == 0) {
     CBC_ReedSolomonGF256Poly* temp = m_zero->Clone(e);
-    BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+    if (e != BCExceptionNO)
+      return nullptr;
     return temp;
   }
-  CFX_Int32Array coefficients;
+  CFX_ArrayTemplate<int32_t> coefficients;
   coefficients.SetSize(degree + 1);
   coefficients[0] = coefficient;
   CBC_ReedSolomonGF256Poly* temp = new CBC_ReedSolomonGF256Poly();
   temp->Init(this, &coefficients, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return temp;
 }
 
@@ -105,7 +107,7 @@
 int32_t CBC_ReedSolomonGF256::Log(int32_t a, int32_t& e) {
   if (a == 0) {
     e = BCExceptionAIsZero;
-    BC_EXCEPTION_CHECK_ReturnValue(e, 0);
+    return 0;
   }
   return m_logTable[a];
 }
@@ -113,7 +115,7 @@
 int32_t CBC_ReedSolomonGF256::Inverse(int32_t a, int32_t& e) {
   if (a == 0) {
     e = BCExceptionAIsZero;
-    BC_EXCEPTION_CHECK_ReturnValue(e, 0);
+    return 0;
   }
   return m_expTable[255 - m_logTable[a]];
 }
diff --git a/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomonGF256Poly.cpp b/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomonGF256Poly.cpp
index 60f1f1b..a0bbc02 100644
--- a/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomonGF256Poly.cpp
+++ b/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomonGF256Poly.cpp
@@ -38,11 +38,11 @@
   m_field = nullptr;
 }
 void CBC_ReedSolomonGF256Poly::Init(CBC_ReedSolomonGF256* field,
-                                    CFX_Int32Array* coefficients,
+                                    CFX_ArrayTemplate<int32_t>* coefficients,
                                     int32_t& e) {
   if (!coefficients || coefficients->GetSize() == 0) {
     e = BCExceptionCoefficientsSizeIsNull;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   m_field = field;
   int32_t coefficientsLength = coefficients->GetSize();
@@ -64,7 +64,7 @@
     m_coefficients.Copy(*coefficients);
   }
 }
-CFX_Int32Array* CBC_ReedSolomonGF256Poly::GetCoefficients() {
+CFX_ArrayTemplate<int32_t>* CBC_ReedSolomonGF256Poly::GetCoefficients() {
   return &m_coefficients;
 }
 int32_t CBC_ReedSolomonGF256Poly::GetDegree() {
@@ -98,7 +98,8 @@
 CBC_ReedSolomonGF256Poly* CBC_ReedSolomonGF256Poly::Clone(int32_t& e) {
   CBC_ReedSolomonGF256Poly* temp = new CBC_ReedSolomonGF256Poly();
   temp->Init(m_field, &m_coefficients, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return temp;
 }
 CBC_ReedSolomonGF256Poly* CBC_ReedSolomonGF256Poly::AddOrSubtract(
@@ -109,17 +110,17 @@
   if (other->IsZero())
     return Clone(e);
 
-  CFX_Int32Array smallerCoefficients;
+  CFX_ArrayTemplate<int32_t> smallerCoefficients;
   smallerCoefficients.Copy(m_coefficients);
-  CFX_Int32Array largerCoefficients;
+  CFX_ArrayTemplate<int32_t> largerCoefficients;
   largerCoefficients.Copy(*(other->GetCoefficients()));
   if (smallerCoefficients.GetSize() > largerCoefficients.GetSize()) {
-    CFX_Int32Array temp;
+    CFX_ArrayTemplate<int32_t> temp;
     temp.Copy(smallerCoefficients);
     smallerCoefficients.Copy(largerCoefficients);
     largerCoefficients.Copy(temp);
   }
-  CFX_Int32Array sumDiff;
+  CFX_ArrayTemplate<int32_t> sumDiff;
   sumDiff.SetSize(largerCoefficients.GetSize());
   int32_t lengthDiff =
       largerCoefficients.GetSize() - smallerCoefficients.GetSize();
@@ -132,7 +133,8 @@
   }
   CBC_ReedSolomonGF256Poly* temp = new CBC_ReedSolomonGF256Poly();
   temp->Init(m_field, &sumDiff, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return temp;
 }
 CBC_ReedSolomonGF256Poly* CBC_ReedSolomonGF256Poly::Multiply(
@@ -141,13 +143,13 @@
   if (IsZero() || other->IsZero())
     return m_field->GetZero()->Clone(e);
 
-  CFX_Int32Array aCoefficients;
+  CFX_ArrayTemplate<int32_t> aCoefficients;
   aCoefficients.Copy(m_coefficients);
   int32_t aLength = m_coefficients.GetSize();
-  CFX_Int32Array bCoefficients;
+  CFX_ArrayTemplate<int32_t> bCoefficients;
   bCoefficients.Copy(*(other->GetCoefficients()));
   int32_t bLength = other->GetCoefficients()->GetSize();
-  CFX_Int32Array product;
+  CFX_ArrayTemplate<int32_t> product;
   product.SetSize(aLength + bLength - 1);
   for (int32_t i = 0; i < aLength; i++) {
     int32_t aCoeff = m_coefficients[i];
@@ -159,7 +161,8 @@
   }
   CBC_ReedSolomonGF256Poly* temp = new CBC_ReedSolomonGF256Poly();
   temp->Init(m_field, &product, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return temp;
 }
 CBC_ReedSolomonGF256Poly* CBC_ReedSolomonGF256Poly::Multiply(int32_t scalar,
@@ -170,14 +173,15 @@
     return Clone(e);
 
   int32_t size = m_coefficients.GetSize();
-  CFX_Int32Array product;
+  CFX_ArrayTemplate<int32_t> product;
   product.SetSize(size);
   for (int32_t i = 0; i < size; i++) {
     product[i] = m_field->Multiply(m_coefficients[i], scalar);
   }
   CBC_ReedSolomonGF256Poly* temp = new CBC_ReedSolomonGF256Poly();
   temp->Init(m_field, &product, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return temp;
 }
 CBC_ReedSolomonGF256Poly* CBC_ReedSolomonGF256Poly::MultiplyByMonomial(
@@ -192,14 +196,15 @@
     return m_field->GetZero()->Clone(e);
 
   int32_t size = m_coefficients.GetSize();
-  CFX_Int32Array product;
+  CFX_ArrayTemplate<int32_t> product;
   product.SetSize(size + degree);
   for (int32_t i = 0; i < size; i++) {
     product[i] = (m_field->Multiply(m_coefficients[i], coefficient));
   }
   CBC_ReedSolomonGF256Poly* temp = new CBC_ReedSolomonGF256Poly();
   temp->Init(m_field, &product, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return temp;
 }
 
@@ -212,13 +217,16 @@
   }
   std::unique_ptr<CBC_ReedSolomonGF256Poly> quotient(
       m_field->GetZero()->Clone(e));
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   std::unique_ptr<CBC_ReedSolomonGF256Poly> remainder(Clone(e));
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   int32_t denominatorLeadingTerm = other->GetCoefficients(other->GetDegree());
   int32_t inverseDenominatorLeadingTeam =
       m_field->Inverse(denominatorLeadingTerm, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   while (remainder->GetDegree() >= other->GetDegree() && !remainder->IsZero()) {
     int32_t degreeDifference = remainder->GetDegree() - other->GetDegree();
     int32_t scale =
@@ -226,14 +234,18 @@
                           inverseDenominatorLeadingTeam);
     std::unique_ptr<CBC_ReedSolomonGF256Poly> term(
         other->MultiplyByMonomial(degreeDifference, scale, e));
-    BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+    if (e != BCExceptionNO)
+      return nullptr;
     std::unique_ptr<CBC_ReedSolomonGF256Poly> iteratorQuotient(
         m_field->BuildMonomial(degreeDifference, scale, e));
-    BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+    if (e != BCExceptionNO)
+      return nullptr;
     quotient.reset(quotient->AddOrSubtract(iteratorQuotient.get(), e));
-    BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+    if (e != BCExceptionNO)
+      return nullptr;
     remainder.reset(remainder->AddOrSubtract(term.get(), e));
-    BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+    if (e != BCExceptionNO)
+      return nullptr;
   }
   CFX_ArrayTemplate<CBC_ReedSolomonGF256Poly*>* tempPtrA =
       new CFX_ArrayTemplate<CBC_ReedSolomonGF256Poly*>();
diff --git a/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomonGF256Poly.h b/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomonGF256Poly.h
index 3eff31b..ff93264 100644
--- a/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomonGF256Poly.h
+++ b/xfa/fxbarcode/common/reedsolomon/BC_ReedSolomonGF256Poly.h
@@ -17,11 +17,11 @@
   CBC_ReedSolomonGF256Poly();
   ~CBC_ReedSolomonGF256Poly();
   void Init(CBC_ReedSolomonGF256* field,
-            CFX_Int32Array* coefficients,
+            CFX_ArrayTemplate<int32_t>* coefficients,
             int32_t& e);
 
   int32_t GetCoefficients(int32_t degree);
-  CFX_Int32Array* GetCoefficients();
+  CFX_ArrayTemplate<int32_t>* GetCoefficients();
   int32_t GetDegree();
   bool IsZero();
   int32_t EvaluateAt(int32_t a);
@@ -41,7 +41,7 @@
 
  private:
   CBC_ReedSolomonGF256* m_field;
-  CFX_Int32Array m_coefficients;
+  CFX_ArrayTemplate<int32_t> m_coefficients;
 };
 
 #endif  // XFA_FXBARCODE_COMMON_REEDSOLOMON_BC_REEDSOLOMONGF256POLY_H_
diff --git a/xfa/fxbarcode/datamatrix/BC_C40Encoder.cpp b/xfa/fxbarcode/datamatrix/BC_C40Encoder.cpp
index 8858f60..50f02ca 100644
--- a/xfa/fxbarcode/datamatrix/BC_C40Encoder.cpp
+++ b/xfa/fxbarcode/datamatrix/BC_C40Encoder.cpp
@@ -163,7 +163,8 @@
     sb += (FX_WCHAR)0x001e;
     int32_t len = 2;
     len += encodeChar((c - 128), sb, e);
-    BC_EXCEPTION_CHECK_ReturnValue(e, 0);
+    if (e != BCExceptionNO)
+      return 0;
     return len;
   } else {
     e = BCExceptionIllegalArgument;
@@ -180,7 +181,8 @@
   context.m_pos--;
   FX_WCHAR c = context.getCurrentChar();
   lastCharSize = encodeChar(c, removed, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, -1);
+  if (e != BCExceptionNO)
+    return -1;
   context.resetSymbolInfo();
   return lastCharSize;
 }
diff --git a/xfa/fxbarcode/datamatrix/BC_DataMatrixWriter.cpp b/xfa/fxbarcode/datamatrix/BC_DataMatrixWriter.cpp
index 1fe8018..f1ce798 100644
--- a/xfa/fxbarcode/datamatrix/BC_DataMatrixWriter.cpp
+++ b/xfa/fxbarcode/datamatrix/BC_DataMatrixWriter.cpp
@@ -54,7 +54,7 @@
                                       int32_t& e) {
   if (outWidth < 0 || outHeight < 0) {
     e = BCExceptionHeightAndWidthMustBeAtLeast1;
-    BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+    return nullptr;
   }
   CBC_SymbolShapeHint::SymbolShapeHint shape =
       CBC_SymbolShapeHint::FORCE_SQUARE;
@@ -63,20 +63,25 @@
   CFX_WideString ecLevel;
   CFX_WideString encoded = CBC_HighLevelEncoder::encodeHighLevel(
       contents, ecLevel, shape, minSize, maxSize, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   CBC_SymbolInfo* symbolInfo = CBC_SymbolInfo::lookup(
       encoded.GetLength(), shape, minSize, maxSize, true, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   CFX_WideString codewords =
       CBC_ErrorCorrection::encodeECC200(encoded, symbolInfo, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   CBC_DefaultPlacement* placement =
       new CBC_DefaultPlacement(codewords, symbolInfo->getSymbolDataWidth(e),
                                symbolInfo->getSymbolDataHeight(e));
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   placement->place();
   CBC_CommonByteMatrix* bytematrix = encodeLowLevel(placement, symbolInfo, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   outWidth = bytematrix->GetWidth();
   outHeight = bytematrix->GetHeight();
   uint8_t* result = FX_Alloc2D(uint8_t, outWidth, outHeight);
@@ -90,12 +95,15 @@
     CBC_SymbolInfo* symbolInfo,
     int32_t& e) {
   int32_t symbolWidth = symbolInfo->getSymbolDataWidth(e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   int32_t symbolHeight = symbolInfo->getSymbolDataHeight(e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   CBC_CommonByteMatrix* matrix = new CBC_CommonByteMatrix(
       symbolInfo->getSymbolWidth(e), symbolInfo->getSymbolHeight(e));
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   matrix->Init();
   int32_t matrixY = 0;
   for (int32_t y = 0; y < symbolHeight; y++) {
diff --git a/xfa/fxbarcode/datamatrix/BC_DefaultPlacement.cpp b/xfa/fxbarcode/datamatrix/BC_DefaultPlacement.cpp
index bc0aa72..e7eef07 100644
--- a/xfa/fxbarcode/datamatrix/BC_DefaultPlacement.cpp
+++ b/xfa/fxbarcode/datamatrix/BC_DefaultPlacement.cpp
@@ -43,7 +43,7 @@
 int32_t CBC_DefaultPlacement::getNumcols() {
   return m_numcols;
 }
-CFX_ByteArray& CBC_DefaultPlacement::getBits() {
+CFX_ArrayTemplate<uint8_t>& CBC_DefaultPlacement::getBits() {
   return m_bits;
 }
 bool CBC_DefaultPlacement::getBit(int32_t col, int32_t row) {
diff --git a/xfa/fxbarcode/datamatrix/BC_DefaultPlacement.h b/xfa/fxbarcode/datamatrix/BC_DefaultPlacement.h
index 64d0288..36a7ab2 100644
--- a/xfa/fxbarcode/datamatrix/BC_DefaultPlacement.h
+++ b/xfa/fxbarcode/datamatrix/BC_DefaultPlacement.h
@@ -18,7 +18,7 @@
 
   int32_t getNumrows();
   int32_t getNumcols();
-  CFX_ByteArray& getBits();
+  CFX_ArrayTemplate<uint8_t>& getBits();
   bool getBit(int32_t col, int32_t row);
   void setBit(int32_t col, int32_t row, bool bit);
   bool hasBit(int32_t col, int32_t row);
@@ -28,7 +28,7 @@
   CFX_WideString m_codewords;
   int32_t m_numrows;
   int32_t m_numcols;
-  CFX_ByteArray m_bits;
+  CFX_ArrayTemplate<uint8_t> m_bits;
   void module(int32_t row, int32_t col, int32_t pos, int32_t bit);
   void utah(int32_t row, int32_t col, int32_t pos);
   void corner1(int32_t pos);
diff --git a/xfa/fxbarcode/datamatrix/BC_EncoderContext.cpp b/xfa/fxbarcode/datamatrix/BC_EncoderContext.cpp
index c395f3a..b01b312 100644
--- a/xfa/fxbarcode/datamatrix/BC_EncoderContext.cpp
+++ b/xfa/fxbarcode/datamatrix/BC_EncoderContext.cpp
@@ -100,7 +100,8 @@
   if (!m_symbolInfo || len > m_symbolInfo->m_dataCapacity) {
     m_symbolInfo =
         CBC_SymbolInfo::lookup(len, m_shape, m_minSize, m_maxSize, true, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
   }
 }
 void CBC_EncoderContext::resetSymbolInfo() {
diff --git a/xfa/fxbarcode/datamatrix/BC_ErrorCorrection.cpp b/xfa/fxbarcode/datamatrix/BC_ErrorCorrection.cpp
index f52f0ff..17eec1e 100644
--- a/xfa/fxbarcode/datamatrix/BC_ErrorCorrection.cpp
+++ b/xfa/fxbarcode/datamatrix/BC_ErrorCorrection.cpp
@@ -129,14 +129,15 @@
   if (blockCount == 1) {
     CFX_WideString ecc =
         createECCBlock(codewords, symbolInfo->m_errorCodewords, e);
-    BC_EXCEPTION_CHECK_ReturnValue(e, CFX_WideString());
+    if (e != BCExceptionNO)
+      return CFX_WideString();
     sb += ecc;
   } else {
-    CFX_Int32Array dataSizes;
+    CFX_ArrayTemplate<int32_t> dataSizes;
     dataSizes.SetSize(blockCount);
-    CFX_Int32Array errorSizes;
+    CFX_ArrayTemplate<int32_t> errorSizes;
     errorSizes.SetSize(blockCount);
-    CFX_Int32Array startPos;
+    CFX_ArrayTemplate<int32_t> startPos;
     startPos.SetSize(blockCount);
     for (int32_t i = 0; i < blockCount; i++) {
       dataSizes[i] = symbolInfo->getDataLengthForInterleavedBlock(i + 1);
@@ -152,7 +153,8 @@
         temp += (FX_WCHAR)codewords.GetAt(d);
       }
       CFX_WideString ecc = createECCBlock(temp, errorSizes[block], e);
-      BC_EXCEPTION_CHECK_ReturnValue(e, CFX_WideString());
+      if (e != BCExceptionNO)
+        return CFX_WideString();
       int32_t pos = 0;
       for (int32_t l = block; l < errorSizes[block] * blockCount;
            l += blockCount) {
diff --git a/xfa/fxbarcode/datamatrix/BC_HighLevelEncoder.cpp b/xfa/fxbarcode/datamatrix/BC_HighLevelEncoder.cpp
index fcd668a..abd3584 100644
--- a/xfa/fxbarcode/datamatrix/BC_HighLevelEncoder.cpp
+++ b/xfa/fxbarcode/datamatrix/BC_HighLevelEncoder.cpp
@@ -58,7 +58,8 @@
 CBC_HighLevelEncoder::CBC_HighLevelEncoder() {}
 CBC_HighLevelEncoder::~CBC_HighLevelEncoder() {}
 
-CFX_ByteArray& CBC_HighLevelEncoder::getBytesForMessage(CFX_WideString msg) {
+CFX_ArrayTemplate<uint8_t>& CBC_HighLevelEncoder::getBytesForMessage(
+    CFX_WideString msg) {
   CFX_ByteString bytestr;
   CBC_UtilCodingConvert::UnicodeToUTF8(msg, bytestr);
   for (int32_t i = 0; i < bytestr.GetLength(); i++) {
@@ -78,7 +79,8 @@
                                                      CBC_Dimension* maxSize,
                                                      int32_t& e) {
   CBC_EncoderContext context(msg, ecLevel, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, CFX_WideString());
+  if (e != BCExceptionNO)
+    return CFX_WideString();
   context.setSymbolShape(shape);
   context.setSizeConstraints(minSize, maxSize);
   if ((msg.Mid(0, 6) == MACRO_05_HEADER) &&
@@ -159,9 +161,9 @@
   while (true) {
     if ((startpos + charsProcessed) == msg.GetLength()) {
       int32_t min = std::numeric_limits<int32_t>::max();
-      CFX_ByteArray mins;
+      CFX_ArrayTemplate<uint8_t> mins;
       mins.SetSize(6);
-      CFX_Int32Array intCharCounts;
+      CFX_ArrayTemplate<int32_t> intCharCounts;
       intCharCounts.SetSize(6);
       min = findMinimums(charCounts, intCharCounts, min, mins);
       int32_t minCount = getMinimumCount(mins);
@@ -229,9 +231,9 @@
       charCounts[BASE256_ENCODATION]++;
     }
     if (charsProcessed >= 4) {
-      CFX_Int32Array intCharCounts;
+      CFX_ArrayTemplate<int32_t> intCharCounts;
       intCharCounts.SetSize(6);
-      CFX_ByteArray mins;
+      CFX_ArrayTemplate<uint8_t> mins;
       mins.SetSize(6);
       findMinimums(charCounts, intCharCounts,
                    std::numeric_limits<int32_t>::max(), mins);
@@ -317,10 +319,11 @@
   return tempVariable <= 254 ? (FX_WCHAR)tempVariable
                              : (FX_WCHAR)(tempVariable - 254);
 }
-int32_t CBC_HighLevelEncoder::findMinimums(std::vector<FX_FLOAT>& charCounts,
-                                           CFX_Int32Array& intCharCounts,
-                                           int32_t min,
-                                           CFX_ByteArray& mins) {
+int32_t CBC_HighLevelEncoder::findMinimums(
+    std::vector<FX_FLOAT>& charCounts,
+    CFX_ArrayTemplate<int32_t>& intCharCounts,
+    int32_t min,
+    CFX_ArrayTemplate<uint8_t>& mins) {
   for (int32_t l = 0; l < mins.GetSize(); l++) {
     mins[l] = (uint8_t)0;
   }
@@ -339,7 +342,8 @@
   }
   return min;
 }
-int32_t CBC_HighLevelEncoder::getMinimumCount(CFX_ByteArray& mins) {
+int32_t CBC_HighLevelEncoder::getMinimumCount(
+    CFX_ArrayTemplate<uint8_t>& mins) {
   int32_t minCount = 0;
   for (int32_t i = 0; i < 6; i++) {
     minCount += mins[i];
diff --git a/xfa/fxbarcode/datamatrix/BC_HighLevelEncoder.h b/xfa/fxbarcode/datamatrix/BC_HighLevelEncoder.h
index 3b88f88..5d72f10 100644
--- a/xfa/fxbarcode/datamatrix/BC_HighLevelEncoder.h
+++ b/xfa/fxbarcode/datamatrix/BC_HighLevelEncoder.h
@@ -23,7 +23,7 @@
   CBC_HighLevelEncoder();
   ~CBC_HighLevelEncoder() override;
 
-  CFX_ByteArray& getBytesForMessage(CFX_WideString msg);
+  CFX_ArrayTemplate<uint8_t>& getBytesForMessage(CFX_WideString msg);
   static CFX_WideString encodeHighLevel(CFX_WideString msg,
                                         CFX_WideString ecLevel,
                                         int32_t& e);
@@ -59,15 +59,15 @@
   static const wchar_t* MACRO_05_HEADER;
   static const wchar_t* MACRO_06_HEADER;
   static const wchar_t MACRO_TRAILER;
-  CFX_ByteArray m_bytearray;
+  CFX_ArrayTemplate<uint8_t> m_bytearray;
 
  private:
   static FX_WCHAR randomize253State(FX_WCHAR ch, int32_t codewordPosition);
   static int32_t findMinimums(std::vector<FX_FLOAT>& charCounts,
-                              CFX_Int32Array& intCharCounts,
+                              CFX_ArrayTemplate<int32_t>& intCharCounts,
                               int32_t min,
-                              CFX_ByteArray& mins);
-  static int32_t getMinimumCount(CFX_ByteArray& mins);
+                              CFX_ArrayTemplate<uint8_t>& mins);
+  static int32_t getMinimumCount(CFX_ArrayTemplate<uint8_t>& mins);
   static bool isNativeC40(FX_WCHAR ch);
   static bool isNativeText(FX_WCHAR ch);
   static bool isNativeX12(FX_WCHAR ch);
diff --git a/xfa/fxbarcode/datamatrix/BC_SymbolInfo.cpp b/xfa/fxbarcode/datamatrix/BC_SymbolInfo.cpp
index 77a809a..ae74b8b 100644
--- a/xfa/fxbarcode/datamatrix/BC_SymbolInfo.cpp
+++ b/xfa/fxbarcode/datamatrix/BC_SymbolInfo.cpp
@@ -151,12 +151,14 @@
     }
     if (minSize && (symbol->getSymbolWidth(e) < minSize->getWidth() ||
                     symbol->getSymbolHeight(e) < minSize->getHeight())) {
-      BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+      if (e != BCExceptionNO)
+        return nullptr;
       continue;
     }
     if (maxSize && (symbol->getSymbolWidth(e) > maxSize->getWidth() ||
                     symbol->getSymbolHeight(e) > maxSize->getHeight())) {
-      BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+      if (e != BCExceptionNO)
+        return nullptr;
       continue;
     }
     if (dataCodewords <= symbol->m_dataCapacity) {
diff --git a/xfa/fxbarcode/datamatrix/BC_TextEncoder.cpp b/xfa/fxbarcode/datamatrix/BC_TextEncoder.cpp
index c8b37e9..e3eb4a8 100644
--- a/xfa/fxbarcode/datamatrix/BC_TextEncoder.cpp
+++ b/xfa/fxbarcode/datamatrix/BC_TextEncoder.cpp
@@ -90,7 +90,8 @@
     sb += (FX_WCHAR)0x001e;
     int32_t len = 2;
     len += encodeChar((FX_WCHAR)(c - 128), sb, e);
-    BC_EXCEPTION_CHECK_ReturnValue(e, -1);
+    if (e != BCExceptionNO)
+      return -1;
     return len;
   }
   CBC_HighLevelEncoder::illegalCharacter(c, e);
diff --git a/xfa/fxbarcode/datamatrix/BC_X12Encoder.cpp b/xfa/fxbarcode/datamatrix/BC_X12Encoder.cpp
index 9ebfc46..d77af93 100644
--- a/xfa/fxbarcode/datamatrix/BC_X12Encoder.cpp
+++ b/xfa/fxbarcode/datamatrix/BC_X12Encoder.cpp
@@ -94,7 +94,8 @@
     sb += (FX_WCHAR)(c - 65 + 14);
   } else {
     CBC_HighLevelEncoder::illegalCharacter(c, e);
-    BC_EXCEPTION_CHECK_ReturnValue(e, -1);
+    if (e != BCExceptionNO)
+      return -1;
   }
   return 1;
 }
diff --git a/xfa/fxbarcode/oned/BC_OneDimWriter.cpp b/xfa/fxbarcode/oned/BC_OneDimWriter.cpp
index 24d257a..bc0d61f 100644
--- a/xfa/fxbarcode/oned/BC_OneDimWriter.cpp
+++ b/xfa/fxbarcode/oned/BC_OneDimWriter.cpp
@@ -103,7 +103,8 @@
   } else {
     ret = Encode(contents, outWidth, e);
   }
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return ret;
 }
 
@@ -113,7 +114,8 @@
                                   int32_t& outHeight,
                                   int32_t& e) {
   uint8_t* ret = Encode(contents, format, outWidth, outHeight, 0, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return ret;
 }
 
@@ -175,8 +177,7 @@
       (FX_FLOAT)FXSYS_abs(cFont->GetDescent()) * (FX_FLOAT)fontSize / 1000.0f;
   FX_FLOAT left = leftPositon;
   FX_FLOAT top = 0.0;
-  charPos[0].m_OriginX = penX + left;
-  charPos[0].m_OriginY = penY + top;
+  charPos[0].m_Origin = CFX_PointF(penX + left, penY + top);
   charPos[0].m_GlyphIndex = encoding->GlyphFromCharCode(pCharCode[0]);
   charPos[0].m_FontCharWidth = cFont->GetGlyphWidth(charPos[0].m_GlyphIndex);
 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
@@ -184,8 +185,7 @@
 #endif
   penX += (FX_FLOAT)(charPos[0].m_FontCharWidth) * (FX_FLOAT)fontSize / 1000.0f;
   for (int32_t i = 1; i < length; i++) {
-    charPos[i].m_OriginX = penX + left;
-    charPos[i].m_OriginY = penY + top;
+    charPos[i].m_Origin = CFX_PointF(penX + left, penY + top);
     charPos[i].m_GlyphIndex = encoding->GlyphFromCharCode(pCharCode[i]);
     charPos[i].m_FontCharWidth = cFont->GetGlyphWidth(charPos[i].m_GlyphIndex);
 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
@@ -221,8 +221,8 @@
     affine_matrix.Concat(*matrix);
   }
   device->DrawNormalText(str.GetLength(), pCharPos, m_pFont,
-                         (FX_FLOAT)iFontSize, &affine_matrix, m_fontColor,
-                         FXTEXT_CLEARTYPE);
+                         static_cast<FX_FLOAT>(iFontSize), &affine_matrix,
+                         m_fontColor, FXTEXT_CLEARTYPE);
 }
 
 void CBC_OneDimWriter::ShowBitmapChars(CFX_DIBitmap* pOutBitmap,
@@ -238,9 +238,11 @@
   ge.Create((int)geWidth, iTextHeight, m_colorSpace, nullptr);
   FX_RECT geRect(0, 0, (int)geWidth, iTextHeight);
   ge.FillRect(&geRect, m_backgroundColor);
-  CFX_Matrix affine_matrix(1.0, 0.0, 0.0, -1.0, 0.0, (FX_FLOAT)iFontSize);
-  ge.DrawNormalText(str.GetLength(), pCharPos, m_pFont, (FX_FLOAT)iFontSize,
-                    &affine_matrix, m_fontColor, FXTEXT_CLEARTYPE);
+  CFX_Matrix affine_matrix(1.0, 0.0, 0.0, -1.0, 0.0,
+                           static_cast<FX_FLOAT>(iFontSize));
+  ge.DrawNormalText(str.GetLength(), pCharPos, m_pFont,
+                    static_cast<FX_FLOAT>(iFontSize), &affine_matrix,
+                    m_fontColor, FXTEXT_CLEARTYPE);
   CFX_FxgeDevice geBitmap;
   geBitmap.Attach(pOutBitmap, false, nullptr, false);
   geBitmap.SetDIBits(ge.GetBitmap(), (int)locX, (int)locY);
@@ -319,7 +321,8 @@
                                           const CFX_WideStringC& contents,
                                           int32_t& e) {
   if (!m_output)
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
 
   pOutBitmap = CreateDIBitmap(m_output->GetWidth(), m_output->GetHeight());
   pOutBitmap->Clear(m_backgroundColor);
@@ -342,7 +345,8 @@
   if (m_locTextLoc != BC_TEXT_LOC_NONE && i < contents.GetLength()) {
     ShowChars(contents, pOutBitmap, nullptr, nullptr, m_barWidth, m_multiple,
               e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
   }
   std::unique_ptr<CFX_DIBitmap> pStretchBitmap =
       pOutBitmap->StretchTo(m_Width, m_Height);
@@ -355,7 +359,8 @@
                                           const CFX_WideStringC& contents,
                                           int32_t& e) {
   if (!m_output)
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
 
   CFX_GraphStateData stateData;
   CFX_PathData path;
@@ -382,7 +387,8 @@
     }
   if (m_locTextLoc != BC_TEXT_LOC_NONE && i < contents.GetLength()) {
     ShowChars(contents, nullptr, device, matrix, m_barWidth, m_multiple, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
   }
 }
 
@@ -392,7 +398,8 @@
                                     bool isDevice,
                                     int32_t& e) {
   if (codeLength < 1) {
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
   }
   if (m_ModuleHeight < 20.0) {
     m_ModuleHeight = 20;
@@ -456,7 +463,8 @@
         break;
       }
       m_output->SetRegion(outputX, 0, m_multiple, outputHeight, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
     }
     outputX += m_multiple;
   }
diff --git a/xfa/fxbarcode/oned/BC_OnedCodaBarWriter.cpp b/xfa/fxbarcode/oned/BC_OnedCodaBarWriter.cpp
index fb0d7dc..399e5e7 100644
--- a/xfa/fxbarcode/oned/BC_OnedCodaBarWriter.cpp
+++ b/xfa/fxbarcode/oned/BC_OnedCodaBarWriter.cpp
@@ -144,7 +144,8 @@
                                        int32_t& outHeight,
                                        int32_t& e) {
   uint8_t* ret = Encode(contents, format, outWidth, outHeight, 0, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return ret;
 }
 uint8_t* CBC_OnedCodaBarWriter::Encode(const CFX_ByteString& contents,
@@ -159,7 +160,8 @@
   }
   uint8_t* ret =
       CBC_OneDimWriter::Encode(contents, format, outWidth, outHeight, hints, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return ret;
 }
 uint8_t* CBC_OnedCodaBarWriter::Encode(const CFX_ByteString& contents,
diff --git a/xfa/fxbarcode/oned/BC_OnedCode128Writer.cpp b/xfa/fxbarcode/oned/BC_OnedCode128Writer.cpp
index ed2d2c1..f163b18 100644
--- a/xfa/fxbarcode/oned/BC_OnedCode128Writer.cpp
+++ b/xfa/fxbarcode/oned/BC_OnedCode128Writer.cpp
@@ -154,7 +154,8 @@
   }
   uint8_t* ret =
       CBC_OneDimWriter::Encode(contents, format, outWidth, outHeight, hints, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return ret;
 }
 uint8_t* CBC_OnedCode128Writer::Encode(const CFX_ByteString& contents,
@@ -163,7 +164,8 @@
                                        int32_t& outHeight,
                                        int32_t& e) {
   uint8_t* ret = Encode(contents, format, outWidth, outHeight, 0, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return ret;
 }
 bool CBC_OnedCode128Writer::IsDigits(const CFX_ByteString& contents,
diff --git a/xfa/fxbarcode/oned/BC_OnedCode39Writer.cpp b/xfa/fxbarcode/oned/BC_OnedCode39Writer.cpp
index 9d5fdda..a1ba5c8 100644
--- a/xfa/fxbarcode/oned/BC_OnedCode39Writer.cpp
+++ b/xfa/fxbarcode/oned/BC_OnedCode39Writer.cpp
@@ -130,7 +130,8 @@
                                       int32_t& outHeight,
                                       int32_t& e) {
   uint8_t* ret = Encode(contents, format, outWidth, outHeight, 0, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return ret;
 }
 uint8_t* CBC_OnedCode39Writer::Encode(const CFX_ByteString& contents,
@@ -145,7 +146,8 @@
   }
   uint8_t* ret =
       CBC_OneDimWriter::Encode(contents, format, outWidth, outHeight, hints, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return ret;
 }
 void CBC_OnedCode39Writer::ToIntArray(int32_t a, int32_t* toReturn) {
@@ -263,7 +265,8 @@
     CFX_ByteString str = checksumContent.UTF8Encode();
     FX_CHAR checksum;
     checksum = CalcCheckSum(str, e);
-    BC_EXCEPTION_CHECK_ReturnValue(e, CFX_WideString());
+    if (e != BCExceptionNO)
+      return CFX_WideString();
     str += checksum;
     encodedContents += checksum;
   }
@@ -275,7 +278,8 @@
                                         bool isDevice,
                                         int32_t& e) {
   CFX_WideString encodedCon = encodedContents(contents, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   CBC_OneDimWriter::RenderResult(encodedCon.AsStringC(), code, codeLength,
                                  isDevice, e);
 }
diff --git a/xfa/fxbarcode/oned/BC_OnedEAN13Writer.cpp b/xfa/fxbarcode/oned/BC_OnedEAN13Writer.cpp
index 71d9ac6..bcbc80a 100644
--- a/xfa/fxbarcode/oned/BC_OnedEAN13Writer.cpp
+++ b/xfa/fxbarcode/oned/BC_OnedEAN13Writer.cpp
@@ -97,7 +97,8 @@
                                      int32_t& outHeight,
                                      int32_t& e) {
   uint8_t* ret = Encode(contents, format, outWidth, outHeight, 0, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return ret;
 }
 uint8_t* CBC_OnedEAN13Writer::Encode(const CFX_ByteString& contents,
@@ -111,7 +112,8 @@
   }
   uint8_t* ret =
       CBC_OneDimWriter::Encode(contents, format, outWidth, outHeight, hints, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return ret;
 }
 uint8_t* CBC_OnedEAN13Writer::Encode(const CFX_ByteString& contents,
@@ -231,8 +233,9 @@
     ge.Create(strWidth, iTextHeight, FXDIB_Argb, nullptr);
     FX_RECT rect(0, 0, strWidth, iTextHeight);
     ge.FillRect(&rect, m_backgroundColor);
-    ge.DrawNormalText(iLen, pCharPos + 1, m_pFont, (FX_FLOAT)iFontSize,
-                      &affine_matrix, m_fontColor, FXTEXT_CLEARTYPE);
+    ge.DrawNormalText(iLen, pCharPos + 1, m_pFont,
+                      static_cast<FX_FLOAT>(iFontSize), &affine_matrix,
+                      m_fontColor, FXTEXT_CLEARTYPE);
     geBitmap.SetDIBits(ge.GetBitmap(), leftPosition, m_Height - iTextHeight);
   } else {
     CFX_Matrix affine_matrix1(1.0, 0.0, 0.0, -1.0,
@@ -241,8 +244,9 @@
     if (matrix) {
       affine_matrix1.Concat(*matrix);
     }
-    device->DrawNormalText(iLen, pCharPos + 1, m_pFont, (FX_FLOAT)iFontSize,
-                           &affine_matrix1, m_fontColor, FXTEXT_CLEARTYPE);
+    device->DrawNormalText(iLen, pCharPos + 1, m_pFont,
+                           static_cast<FX_FLOAT>(iFontSize), &affine_matrix1,
+                           m_fontColor, FXTEXT_CLEARTYPE);
   }
   tempStr = str.Mid(7, 6);
   iLen = tempStr.GetLength();
@@ -251,8 +255,9 @@
   if (pOutBitmap) {
     FX_RECT rect1(0, 0, strWidth, iTextHeight);
     ge.FillRect(&rect1, m_backgroundColor);
-    ge.DrawNormalText(iLen, pCharPos + 7, m_pFont, (FX_FLOAT)iFontSize,
-                      &affine_matrix, m_fontColor, FXTEXT_CLEARTYPE);
+    ge.DrawNormalText(iLen, pCharPos + 7, m_pFont,
+                      static_cast<FX_FLOAT>(iFontSize), &affine_matrix,
+                      m_fontColor, FXTEXT_CLEARTYPE);
     geBitmap.SetDIBits(ge.GetBitmap(), leftPosition + 47 * multiple,
                        m_Height - iTextHeight);
   } else {
@@ -263,8 +268,9 @@
     if (matrix) {
       affine_matrix1.Concat(*matrix);
     }
-    device->DrawNormalText(iLen, pCharPos + 7, m_pFont, (FX_FLOAT)iFontSize,
-                           &affine_matrix1, m_fontColor, FXTEXT_CLEARTYPE);
+    device->DrawNormalText(iLen, pCharPos + 7, m_pFont,
+                           static_cast<FX_FLOAT>(iFontSize), &affine_matrix1,
+                           m_fontColor, FXTEXT_CLEARTYPE);
   }
   tempStr = str.Mid(0, 1);
   iLen = tempStr.GetLength();
@@ -278,7 +284,7 @@
     delete ge.GetBitmap();
     ge.Create(strWidth, iTextHeight, FXDIB_Argb, nullptr);
     ge.GetBitmap()->Clear(m_backgroundColor);
-    ge.DrawNormalText(iLen, pCharPos, m_pFont, (FX_FLOAT)iFontSize,
+    ge.DrawNormalText(iLen, pCharPos, m_pFont, static_cast<FX_FLOAT>(iFontSize),
                       &affine_matrix, m_fontColor, FXTEXT_CLEARTYPE);
     geBitmap.SetDIBits(ge.GetBitmap(), 0, m_Height - iTextHeight);
   } else {
@@ -287,8 +293,9 @@
     if (matrix) {
       affine_matrix1.Concat(*matrix);
     }
-    device->DrawNormalText(iLen, pCharPos, m_pFont, (FX_FLOAT)iFontSize,
-                           &affine_matrix1, m_fontColor, FXTEXT_CLEARTYPE);
+    device->DrawNormalText(iLen, pCharPos, m_pFont,
+                           static_cast<FX_FLOAT>(iFontSize), &affine_matrix1,
+                           m_fontColor, FXTEXT_CLEARTYPE);
   }
   FX_Free(pCharPos);
 }
diff --git a/xfa/fxbarcode/oned/BC_OnedEAN8Writer.cpp b/xfa/fxbarcode/oned/BC_OnedEAN8Writer.cpp
index ad3ee61..c402238 100644
--- a/xfa/fxbarcode/oned/BC_OnedEAN8Writer.cpp
+++ b/xfa/fxbarcode/oned/BC_OnedEAN8Writer.cpp
@@ -100,7 +100,8 @@
                                     int32_t& outHeight,
                                     int32_t& e) {
   uint8_t* ret = Encode(contents, format, outWidth, outHeight, 0, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return ret;
 }
 uint8_t* CBC_OnedEAN8Writer::Encode(const CFX_ByteString& contents,
@@ -115,7 +116,8 @@
   }
   uint8_t* ret =
       CBC_OneDimWriter::Encode(contents, format, outWidth, outHeight, hints, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return ret;
 }
 uint8_t* CBC_OnedEAN8Writer::Encode(const CFX_ByteString& contents,
@@ -221,7 +223,7 @@
     delete ge.GetBitmap();
     ge.Create(strWidth, iTextHeight, FXDIB_Argb, nullptr);
     ge.GetBitmap()->Clear(m_backgroundColor);
-    ge.DrawNormalText(iLen, pCharPos, m_pFont, (FX_FLOAT)iFontSize,
+    ge.DrawNormalText(iLen, pCharPos, m_pFont, static_cast<FX_FLOAT>(iFontSize),
                       &affine_matrix, m_fontColor, FXTEXT_CLEARTYPE);
     geBitmap.SetDIBits(ge.GetBitmap(), leftPosition, m_Height - iTextHeight);
   } else {
@@ -229,8 +231,9 @@
                               (FX_FLOAT)leftPosition * m_outputHScale,
                               (FX_FLOAT)(m_Height - iTextHeight + iFontSize));
     affine_matrix1.Concat(*matrix);
-    device->DrawNormalText(iLen, pCharPos, m_pFont, (FX_FLOAT)iFontSize,
-                           &affine_matrix1, m_fontColor, FXTEXT_CLEARTYPE);
+    device->DrawNormalText(iLen, pCharPos, m_pFont,
+                           static_cast<FX_FLOAT>(iFontSize), &affine_matrix1,
+                           m_fontColor, FXTEXT_CLEARTYPE);
   }
   tempStr = str.Mid(4, 4);
   iLen = tempStr.GetLength();
@@ -240,8 +243,9 @@
     delete ge.GetBitmap();
     ge.Create(strWidth, iTextHeight, FXDIB_Argb, nullptr);
     ge.GetBitmap()->Clear(m_backgroundColor);
-    ge.DrawNormalText(iLen, pCharPos + 4, m_pFont, (FX_FLOAT)iFontSize,
-                      &affine_matrix, m_fontColor, FXTEXT_CLEARTYPE);
+    ge.DrawNormalText(iLen, pCharPos + 4, m_pFont,
+                      static_cast<FX_FLOAT>(iFontSize), &affine_matrix,
+                      m_fontColor, FXTEXT_CLEARTYPE);
     geBitmap.SetDIBits(ge.GetBitmap(), leftPosition + 33 * multiple,
                        m_Height - iTextHeight);
   } else {
@@ -252,8 +256,9 @@
     if (matrix) {
       affine_matrix1.Concat(*matrix);
     }
-    device->DrawNormalText(iLen, pCharPos + 4, m_pFont, (FX_FLOAT)iFontSize,
-                           &affine_matrix1, m_fontColor, FXTEXT_CLEARTYPE);
+    device->DrawNormalText(iLen, pCharPos + 4, m_pFont,
+                           static_cast<FX_FLOAT>(iFontSize), &affine_matrix1,
+                           m_fontColor, FXTEXT_CLEARTYPE);
   }
   FX_Free(pCharPos);
 }
diff --git a/xfa/fxbarcode/oned/BC_OnedUPCAWriter.cpp b/xfa/fxbarcode/oned/BC_OnedUPCAWriter.cpp
index 42e84b7..6d6e796 100644
--- a/xfa/fxbarcode/oned/BC_OnedUPCAWriter.cpp
+++ b/xfa/fxbarcode/oned/BC_OnedUPCAWriter.cpp
@@ -87,7 +87,8 @@
                                     int32_t& outHeight,
                                     int32_t& e) {
   uint8_t* ret = Encode(contents, format, outWidth, outHeight, 0, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return ret;
 }
 
@@ -105,7 +106,8 @@
   m_iDataLenth = 13;
   uint8_t* ret = m_subWriter->Encode(toEAN13String, BCFORMAT_EAN_13, outWidth,
                                      outHeight, hints, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return ret;
 }
 
@@ -190,8 +192,9 @@
   if (pOutBitmap) {
     ge.Create((int)strWidth, iTextHeight, FXDIB_Argb, nullptr);
     ge.GetBitmap()->Clear(m_backgroundColor);
-    ge.DrawNormalText(iLen, pCharPos + 1, m_pFont, (FX_FLOAT)iFontSize,
-                      &affine_matrix, m_fontColor, FXTEXT_CLEARTYPE);
+    ge.DrawNormalText(iLen, pCharPos + 1, m_pFont,
+                      static_cast<FX_FLOAT>(iFontSize), &affine_matrix,
+                      m_fontColor, FXTEXT_CLEARTYPE);
     geBitmap.SetDIBits(ge.GetBitmap(), leftPosition, m_Height - iTextHeight);
   } else {
     CFX_Matrix affine_matrix1(1.0, 0.0, 0.0, -1.0,
@@ -200,8 +203,9 @@
     if (matrix) {
       affine_matrix1.Concat(*matrix);
     }
-    device->DrawNormalText(iLen, pCharPos + 1, m_pFont, (FX_FLOAT)iFontSize,
-                           &affine_matrix1, m_fontColor, FXTEXT_CLEARTYPE);
+    device->DrawNormalText(iLen, pCharPos + 1, m_pFont,
+                           static_cast<FX_FLOAT>(iFontSize), &affine_matrix1,
+                           m_fontColor, FXTEXT_CLEARTYPE);
   }
   tempStr = str.Mid(6, 5);
   iLen = tempStr.GetLength();
@@ -209,8 +213,9 @@
   if (pOutBitmap) {
     FX_RECT rect2(0, 0, (int)strWidth, iTextHeight);
     ge.FillRect(&rect2, m_backgroundColor);
-    ge.DrawNormalText(iLen, pCharPos + 6, m_pFont, (FX_FLOAT)iFontSize,
-                      &affine_matrix, m_fontColor, FXTEXT_CLEARTYPE);
+    ge.DrawNormalText(iLen, pCharPos + 6, m_pFont,
+                      static_cast<FX_FLOAT>(iFontSize), &affine_matrix,
+                      m_fontColor, FXTEXT_CLEARTYPE);
     geBitmap.SetDIBits(ge.GetBitmap(), leftPosition + 40 * multiple,
                        m_Height - iTextHeight);
   } else {
@@ -221,8 +226,9 @@
     if (matrix) {
       affine_matrix1.Concat(*matrix);
     }
-    device->DrawNormalText(iLen, pCharPos + 6, m_pFont, (FX_FLOAT)iFontSize,
-                           &affine_matrix1, m_fontColor, FXTEXT_CLEARTYPE);
+    device->DrawNormalText(iLen, pCharPos + 6, m_pFont,
+                           static_cast<FX_FLOAT>(iFontSize), &affine_matrix1,
+                           m_fontColor, FXTEXT_CLEARTYPE);
   }
   tempStr = str.Mid(0, 1);
   iLen = tempStr.GetLength();
@@ -235,7 +241,7 @@
     delete ge.GetBitmap();
     ge.Create((int)strWidth, iTextHeight, FXDIB_Argb, nullptr);
     ge.GetBitmap()->Clear(m_backgroundColor);
-    ge.DrawNormalText(iLen, pCharPos, m_pFont, (FX_FLOAT)iFontSize,
+    ge.DrawNormalText(iLen, pCharPos, m_pFont, static_cast<FX_FLOAT>(iFontSize),
                       &affine_matrix, m_fontColor, FXTEXT_CLEARTYPE);
     geBitmap.SetDIBits(ge.GetBitmap(), 0, m_Height - iTextHeight);
   } else {
@@ -244,8 +250,9 @@
     if (matrix) {
       affine_matrix1.Concat(*matrix);
     }
-    device->DrawNormalText(iLen, pCharPos, m_pFont, (FX_FLOAT)iFontSize,
-                           &affine_matrix1, m_fontColor, FXTEXT_CLEARTYPE);
+    device->DrawNormalText(iLen, pCharPos, m_pFont,
+                           static_cast<FX_FLOAT>(iFontSize), &affine_matrix1,
+                           m_fontColor, FXTEXT_CLEARTYPE);
   }
   tempStr = str.Mid(11, 1);
   iLen = tempStr.GetLength();
@@ -254,8 +261,9 @@
     delete ge.GetBitmap();
     ge.Create((int)strWidth, iTextHeight, FXDIB_Argb, nullptr);
     ge.GetBitmap()->Clear(m_backgroundColor);
-    ge.DrawNormalText(iLen, pCharPos + 11, m_pFont, (FX_FLOAT)iFontSize,
-                      &affine_matrix, m_fontColor, FXTEXT_CLEARTYPE);
+    ge.DrawNormalText(iLen, pCharPos + 11, m_pFont,
+                      static_cast<FX_FLOAT>(iFontSize), &affine_matrix,
+                      m_fontColor, FXTEXT_CLEARTYPE);
     geBitmap.SetDIBits(ge.GetBitmap(), leftPosition + 85 * multiple,
                        m_Height - iTextHeight);
   } else {
@@ -266,8 +274,9 @@
     if (matrix) {
       affine_matrix1.Concat(*matrix);
     }
-    device->DrawNormalText(iLen, pCharPos + 11, m_pFont, (FX_FLOAT)iFontSize,
-                           &affine_matrix1, m_fontColor, FXTEXT_CLEARTYPE);
+    device->DrawNormalText(iLen, pCharPos + 11, m_pFont,
+                           static_cast<FX_FLOAT>(iFontSize), &affine_matrix1,
+                           m_fontColor, FXTEXT_CLEARTYPE);
   }
   FX_Free(pCharPos);
 }
diff --git a/xfa/fxbarcode/pdf417/BC_PDF417.cpp b/xfa/fxbarcode/pdf417/BC_PDF417.cpp
index 9b8d0c1..2f01564 100644
--- a/xfa/fxbarcode/pdf417/BC_PDF417.cpp
+++ b/xfa/fxbarcode/pdf417/BC_PDF417.cpp
@@ -405,14 +405,17 @@
   int32_t errorCorrectionCodeWords =
       CBC_PDF417ErrorCorrection::getErrorCorrectionCodewordCount(
           errorCorrectionLevel, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   CFX_WideString highLevel =
       CBC_PDF417HighLevelEncoder::encodeHighLevel(msg, m_compaction, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   int32_t sourceCodeWords = highLevel.GetLength();
-  CFX_Int32Array* dimension =
+  CFX_ArrayTemplate<int32_t>* dimension =
       determineDimensions(sourceCodeWords, errorCorrectionCodeWords, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   int32_t cols = dimension->GetAt(0);
   int32_t rows = dimension->GetAt(1);
   delete dimension;
@@ -432,7 +435,8 @@
   CFX_WideString dataCodewords(sb);
   CFX_WideString ec = CBC_PDF417ErrorCorrection::generateErrorCorrection(
       dataCodewords, errorCorrectionLevel, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   CFX_WideString fullCodewords = dataCodewords + ec;
   m_barcodeMatrix = pdfium::MakeUnique<CBC_BarcodeMatrix>(rows, cols);
   encodeLowLevel(fullCodewords, cols, rows, errorCorrectionLevel,
@@ -532,12 +536,12 @@
   }
 }
 
-CFX_Int32Array* CBC_PDF417::determineDimensions(
+CFX_ArrayTemplate<int32_t>* CBC_PDF417::determineDimensions(
     int32_t sourceCodeWords,
     int32_t errorCorrectionCodeWords,
     int32_t& e) {
   FX_FLOAT ratio = 0.0f;
-  CFX_Int32Array* dimension = nullptr;
+  CFX_ArrayTemplate<int32_t>* dimension = nullptr;
   for (int32_t cols = m_minCols; cols <= m_maxCols; cols++) {
     int32_t rows =
         calculateNumberOfRows(sourceCodeWords, errorCorrectionCodeWords, cols);
@@ -555,7 +559,7 @@
     }
     ratio = newRatio;
     delete dimension;
-    dimension = new CFX_Int32Array;
+    dimension = new CFX_ArrayTemplate<int32_t>;
     dimension->Add(cols);
     dimension->Add(rows);
   }
@@ -563,11 +567,11 @@
     int32_t rows = calculateNumberOfRows(sourceCodeWords,
                                          errorCorrectionCodeWords, m_minCols);
     if (rows < m_minRows) {
-      dimension = new CFX_Int32Array;
+      dimension = new CFX_ArrayTemplate<int32_t>;
       dimension->Add(m_minCols);
       dimension->Add(m_minRows);
     } else if (rows >= 3 && rows <= 90) {
-      dimension = new CFX_Int32Array;
+      dimension = new CFX_ArrayTemplate<int32_t>;
       dimension->Add(m_minCols);
       dimension->Add(rows);
     }
diff --git a/xfa/fxbarcode/pdf417/BC_PDF417.h b/xfa/fxbarcode/pdf417/BC_PDF417.h
index 5f7c2d4..3ba5aa2 100644
--- a/xfa/fxbarcode/pdf417/BC_PDF417.h
+++ b/xfa/fxbarcode/pdf417/BC_PDF417.h
@@ -51,9 +51,10 @@
                       int32_t r,
                       int32_t errorCorrectionLevel,
                       CBC_BarcodeMatrix* logic);
-  CFX_Int32Array* determineDimensions(int32_t sourceCodeWords,
-                                      int32_t errorCorrectionCodeWords,
-                                      int32_t& e);
+  CFX_ArrayTemplate<int32_t>* determineDimensions(
+      int32_t sourceCodeWords,
+      int32_t errorCorrectionCodeWords,
+      int32_t& e);
 
   std::unique_ptr<CBC_BarcodeMatrix> m_barcodeMatrix;
   bool m_compact;
diff --git a/xfa/fxbarcode/pdf417/BC_PDF417BarcodeMatrix.cpp b/xfa/fxbarcode/pdf417/BC_PDF417BarcodeMatrix.cpp
index f348d2c..c1f4da1 100644
--- a/xfa/fxbarcode/pdf417/BC_PDF417BarcodeMatrix.cpp
+++ b/xfa/fxbarcode/pdf417/BC_PDF417BarcodeMatrix.cpp
@@ -59,16 +59,16 @@
 int32_t CBC_BarcodeMatrix::getHeight() {
   return m_outHeight;
 }
-CFX_ByteArray& CBC_BarcodeMatrix::getMatrix() {
+CFX_ArrayTemplate<uint8_t>& CBC_BarcodeMatrix::getMatrix() {
   return getScaledMatrix(1, 1);
 }
-CFX_ByteArray& CBC_BarcodeMatrix::getScaledMatrix(int32_t scale) {
+CFX_ArrayTemplate<uint8_t>& CBC_BarcodeMatrix::getScaledMatrix(int32_t scale) {
   return getScaledMatrix(scale, scale);
 }
-CFX_ByteArray& CBC_BarcodeMatrix::getScaledMatrix(int32_t xScale,
-                                                  int32_t yScale) {
+CFX_ArrayTemplate<uint8_t>& CBC_BarcodeMatrix::getScaledMatrix(int32_t xScale,
+                                                               int32_t yScale) {
   int32_t yMax = m_height * yScale;
-  CFX_ByteArray bytearray;
+  CFX_ArrayTemplate<uint8_t> bytearray;
   bytearray.Copy(m_matrix[0]->getScaledRow(xScale));
   int32_t xMax = bytearray.GetSize();
   m_matrixOut.SetSize(xMax * yMax);
diff --git a/xfa/fxbarcode/pdf417/BC_PDF417BarcodeMatrix.h b/xfa/fxbarcode/pdf417/BC_PDF417BarcodeMatrix.h
index 0f69222..95ab547 100644
--- a/xfa/fxbarcode/pdf417/BC_PDF417BarcodeMatrix.h
+++ b/xfa/fxbarcode/pdf417/BC_PDF417BarcodeMatrix.h
@@ -21,15 +21,15 @@
   void setMatrix(int32_t x, int32_t y, bool black);
   void startRow();
   CBC_BarcodeRow* getCurrentRow();
-  CFX_ByteArray& getMatrix();
-  CFX_ByteArray& getScaledMatrix(int32_t scale);
-  CFX_ByteArray& getScaledMatrix(int32_t xScale, int32_t yScale);
+  CFX_ArrayTemplate<uint8_t>& getMatrix();
+  CFX_ArrayTemplate<uint8_t>& getScaledMatrix(int32_t scale);
+  CFX_ArrayTemplate<uint8_t>& getScaledMatrix(int32_t xScale, int32_t yScale);
   int32_t getWidth();
   int32_t getHeight();
 
  private:
   CFX_ArrayTemplate<CBC_BarcodeRow*> m_matrix;
-  CFX_ByteArray m_matrixOut;
+  CFX_ArrayTemplate<uint8_t> m_matrixOut;
   int32_t m_currentRow;
   int32_t m_height;
   int32_t m_width;
diff --git a/xfa/fxbarcode/pdf417/BC_PDF417BarcodeRow.cpp b/xfa/fxbarcode/pdf417/BC_PDF417BarcodeRow.cpp
index b721ffc..243af70 100644
--- a/xfa/fxbarcode/pdf417/BC_PDF417BarcodeRow.cpp
+++ b/xfa/fxbarcode/pdf417/BC_PDF417BarcodeRow.cpp
@@ -41,10 +41,10 @@
     set(m_currentLocation++, black);
   }
 }
-CFX_ByteArray& CBC_BarcodeRow::getRow() {
+CFX_ArrayTemplate<uint8_t>& CBC_BarcodeRow::getRow() {
   return m_row;
 }
-CFX_ByteArray& CBC_BarcodeRow::getScaledRow(int32_t scale) {
+CFX_ArrayTemplate<uint8_t>& CBC_BarcodeRow::getScaledRow(int32_t scale) {
   m_output.SetSize(m_row.GetSize() * scale);
   for (int32_t i = 0; i < m_output.GetSize(); i++) {
     m_output[i] = (m_row[i / scale]);
diff --git a/xfa/fxbarcode/pdf417/BC_PDF417BarcodeRow.h b/xfa/fxbarcode/pdf417/BC_PDF417BarcodeRow.h
index 90e76ac..7d9d19c 100644
--- a/xfa/fxbarcode/pdf417/BC_PDF417BarcodeRow.h
+++ b/xfa/fxbarcode/pdf417/BC_PDF417BarcodeRow.h
@@ -17,12 +17,12 @@
   void set(int32_t x, uint8_t value);
   void set(int32_t x, bool black);
   void addBar(bool black, int32_t width);
-  CFX_ByteArray& getRow();
-  CFX_ByteArray& getScaledRow(int32_t scale);
+  CFX_ArrayTemplate<uint8_t>& getRow();
+  CFX_ArrayTemplate<uint8_t>& getScaledRow(int32_t scale);
 
  private:
-  CFX_ByteArray m_row;
-  CFX_ByteArray m_output;
+  CFX_ArrayTemplate<uint8_t> m_row;
+  CFX_ArrayTemplate<uint8_t> m_output;
   int32_t m_currentLocation;
 };
 
diff --git a/xfa/fxbarcode/pdf417/BC_PDF417ErrorCorrection.cpp b/xfa/fxbarcode/pdf417/BC_PDF417ErrorCorrection.cpp
index cbdfffa..bdec403 100644
--- a/xfa/fxbarcode/pdf417/BC_PDF417ErrorCorrection.cpp
+++ b/xfa/fxbarcode/pdf417/BC_PDF417ErrorCorrection.cpp
@@ -161,7 +161,8 @@
     int32_t errorCorrectionLevel,
     int32_t& e) {
   int32_t k = getErrorCorrectionCodewordCount(errorCorrectionLevel, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, (FX_WCHAR)' ');
+  if (e != BCExceptionNO)
+    return L" ";
   FX_WCHAR* ech = FX_Alloc(FX_WCHAR, k);
   FXSYS_memset(ech, 0, k * sizeof(FX_WCHAR));
   int32_t sld = dataCodewords.GetLength();
diff --git a/xfa/fxbarcode/pdf417/BC_PDF417HighLevelEncoder.cpp b/xfa/fxbarcode/pdf417/BC_PDF417HighLevelEncoder.cpp
index fa0e9bc..08a40c5 100644
--- a/xfa/fxbarcode/pdf417/BC_PDF417HighLevelEncoder.cpp
+++ b/xfa/fxbarcode/pdf417/BC_PDF417HighLevelEncoder.cpp
@@ -71,7 +71,7 @@
     }
     msg += ch;
   }
-  CFX_ByteArray byteArr;
+  CFX_ArrayTemplate<uint8_t> byteArr;
   for (int32_t k = 0; k < bytes.GetLength(); k++) {
     byteArr.Add(bytes.GetAt(k));
   }
@@ -108,7 +108,8 @@
           p += t;
         } else {
           int32_t b = determineConsecutiveBinaryCount(msg, &byteArr, p, e);
-          BC_EXCEPTION_CHECK_ReturnValue(e, (FX_WCHAR)' ');
+          if (e != BCExceptionNO)
+            return L" ";
           if (b == 0) {
             b = 1;
           }
@@ -260,7 +261,7 @@
   }
   return submode;
 }
-void CBC_PDF417HighLevelEncoder::encodeBinary(CFX_ByteArray* bytes,
+void CBC_PDF417HighLevelEncoder::encodeBinary(CFX_ArrayTemplate<uint8_t>* bytes,
                                               int32_t startpos,
                                               int32_t count,
                                               int32_t startmode,
@@ -387,7 +388,7 @@
 }
 int32_t CBC_PDF417HighLevelEncoder::determineConsecutiveBinaryCount(
     CFX_WideString msg,
-    CFX_ByteArray* bytes,
+    CFX_ArrayTemplate<uint8_t>* bytes,
     int32_t startpos,
     int32_t& e) {
   int32_t len = msg.GetLength();
diff --git a/xfa/fxbarcode/pdf417/BC_PDF417HighLevelEncoder.h b/xfa/fxbarcode/pdf417/BC_PDF417HighLevelEncoder.h
index 39abe0f..38382c8 100644
--- a/xfa/fxbarcode/pdf417/BC_PDF417HighLevelEncoder.h
+++ b/xfa/fxbarcode/pdf417/BC_PDF417HighLevelEncoder.h
@@ -39,7 +39,7 @@
                             int32_t count,
                             CFX_WideString& sb,
                             int32_t initialSubmode);
-  static void encodeBinary(CFX_ByteArray* bytes,
+  static void encodeBinary(CFX_ArrayTemplate<uint8_t>* bytes,
                            int32_t startpos,
                            int32_t count,
                            int32_t startmode,
@@ -58,10 +58,11 @@
                                                 int32_t startpos);
   static int32_t determineConsecutiveTextCount(CFX_WideString msg,
                                                int32_t startpos);
-  static int32_t determineConsecutiveBinaryCount(CFX_WideString msg,
-                                                 CFX_ByteArray* bytes,
-                                                 int32_t startpos,
-                                                 int32_t& e);
+  static int32_t determineConsecutiveBinaryCount(
+      CFX_WideString msg,
+      CFX_ArrayTemplate<uint8_t>* bytes,
+      int32_t startpos,
+      int32_t& e);
 
   friend class PDF417HighLevelEncoder_EncodeNumeric_Test;
   friend class PDF417HighLevelEncoder_EncodeBinary_Test;
diff --git a/xfa/fxbarcode/pdf417/BC_PDF417HighLevelEncoder_unittest.cpp b/xfa/fxbarcode/pdf417/BC_PDF417HighLevelEncoder_unittest.cpp
index a1b753e..2cd60fe 100644
--- a/xfa/fxbarcode/pdf417/BC_PDF417HighLevelEncoder_unittest.cpp
+++ b/xfa/fxbarcode/pdf417/BC_PDF417HighLevelEncoder_unittest.cpp
@@ -43,7 +43,7 @@
   CBC_PDF417HighLevelEncoder::Initialize();
   for (size_t i = 0; i < FX_ArraySize(encode_binary_cases); ++i) {
     EncodeBinaryCase* ptr = &encode_binary_cases[i];
-    CFX_ByteArray input_array;
+    CFX_ArrayTemplate<uint8_t> input_array;
     size_t input_length = strlen(ptr->input);
     input_array.SetSize(input_length);
     for (size_t j = 0; j < input_length; ++j) {
diff --git a/xfa/fxbarcode/pdf417/BC_PDF417Writer.cpp b/xfa/fxbarcode/pdf417/BC_PDF417Writer.cpp
index 4c9b5cb..2c75a14 100644
--- a/xfa/fxbarcode/pdf417/BC_PDF417Writer.cpp
+++ b/xfa/fxbarcode/pdf417/BC_PDF417Writer.cpp
@@ -59,11 +59,12 @@
     encoder.setDimensions(30, 1, row, row);
   }
   encoder.generateBarcodeLogic(contents, m_iCorrectLevel, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   int32_t lineThickness = 2;
   int32_t aspectRatio = 4;
   CBC_BarcodeMatrix* barcodeMatrix = encoder.getBarcodeMatrix();
-  CFX_ByteArray originalScale;
+  CFX_ArrayTemplate<uint8_t> originalScale;
   originalScale.Copy(barcodeMatrix->getScaledMatrix(
       lineThickness, aspectRatio * lineThickness));
   int32_t width = outWidth;
@@ -101,10 +102,10 @@
   FXSYS_memcpy(result, originalScale.GetData(), outHeight * outWidth);
   return result;
 }
-void CBC_PDF417Writer::rotateArray(CFX_ByteArray& bitarray,
+void CBC_PDF417Writer::rotateArray(CFX_ArrayTemplate<uint8_t>& bitarray,
                                    int32_t height,
                                    int32_t width) {
-  CFX_ByteArray temp;
+  CFX_ArrayTemplate<uint8_t> temp;
   temp.Copy(bitarray);
   for (int32_t ii = 0; ii < height; ii++) {
     int32_t inverseii = height - ii - 1;
diff --git a/xfa/fxbarcode/pdf417/BC_PDF417Writer.h b/xfa/fxbarcode/pdf417/BC_PDF417Writer.h
index 178d251..420c441 100644
--- a/xfa/fxbarcode/pdf417/BC_PDF417Writer.h
+++ b/xfa/fxbarcode/pdf417/BC_PDF417Writer.h
@@ -27,7 +27,9 @@
   void SetTruncated(bool truncated);
 
  private:
-  void rotateArray(CFX_ByteArray& bitarray, int32_t width, int32_t height);
+  void rotateArray(CFX_ArrayTemplate<uint8_t>& bitarray,
+                   int32_t width,
+                   int32_t height);
   bool m_bTruncated;
 };
 
diff --git a/xfa/fxbarcode/qrcode/BC_QRCodeWriter.cpp b/xfa/fxbarcode/qrcode/BC_QRCodeWriter.cpp
index adb12f2..8a6499c 100644
--- a/xfa/fxbarcode/qrcode/BC_QRCodeWriter.cpp
+++ b/xfa/fxbarcode/qrcode/BC_QRCodeWriter.cpp
@@ -85,7 +85,7 @@
       break;
     default: {
       e = BCExceptionUnSupportEclevel;
-      BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+      return nullptr;
     }
   }
   CBC_QRCoder qr;
@@ -95,7 +95,8 @@
   } else {
     CBC_QRCoderEncoder::Encode(contents, ec, &qr, e);
   }
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   outWidth = qr.GetMatrixWidth();
   outHeight = qr.GetMatrixWidth();
   uint8_t* result = FX_Alloc2D(uint8_t, outWidth, outHeight);
diff --git a/xfa/fxbarcode/qrcode/BC_QRCoder.cpp b/xfa/fxbarcode/qrcode/BC_QRCoder.cpp
index c473749..a5c8497 100644
--- a/xfa/fxbarcode/qrcode/BC_QRCoder.cpp
+++ b/xfa/fxbarcode/qrcode/BC_QRCoder.cpp
@@ -85,7 +85,7 @@
   int32_t value = m_matrix->Get(x, y);
   if (!(value == 0 || value == 1)) {
     e = BCExceptionValueMustBeEither0or1;
-    BC_EXCEPTION_CHECK_ReturnValue(e, 0);
+    return 0;
   }
   return value;
 }
diff --git a/xfa/fxbarcode/qrcode/BC_QRCoderBitVector.cpp b/xfa/fxbarcode/qrcode/BC_QRCoderBitVector.cpp
index c770c15..e4140a8 100644
--- a/xfa/fxbarcode/qrcode/BC_QRCoderBitVector.cpp
+++ b/xfa/fxbarcode/qrcode/BC_QRCoderBitVector.cpp
@@ -43,7 +43,7 @@
 int32_t CBC_QRCoderBitVector::At(int32_t index, int32_t& e) {
   if (index < 0 || index >= m_sizeInBits) {
     e = BCExceptionBadIndexException;
-    BC_EXCEPTION_CHECK_ReturnValue(e, 0);
+    return 0;
   }
   int32_t value = m_array[index >> 3] & 0xff;
   return (value >> (7 - (index & 0x7))) & 1;
@@ -57,7 +57,7 @@
 void CBC_QRCoderBitVector::AppendBit(int32_t bit, int32_t& e) {
   if (!(bit == 0 || bit == 1)) {
     e = BCExceptionBadValueException;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   int32_t numBitsInLastByte = m_sizeInBits & 0x7;
   if (numBitsInLastByte == 0) {
@@ -72,7 +72,7 @@
                                       int32_t& e) {
   if (numBits < 0 || numBits > 32) {
     e = BCExceptionBadNumBitsException;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   int32_t numBitsLeft = numBits;
   while (numBitsLeft > 0) {
@@ -83,7 +83,8 @@
     } else {
       int32_t bit = (value >> (numBitsLeft - 1)) & 1;
       AppendBit(bit, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
       --numBitsLeft;
     }
   }
@@ -93,15 +94,17 @@
   int32_t size = bits->Size();
   for (int32_t i = 0; i < size; i++) {
     int32_t num = bits->At(i, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
     AppendBit(num, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e)
+    if (e != BCExceptionNO)
+      return;
   }
 }
 void CBC_QRCoderBitVector::XOR(CBC_QRCoderBitVector* other, int32_t& e) {
   if (m_sizeInBits != other->Size()) {
     e = BCExceptioncanNotOperatexorOperator;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   int32_t sizeInBytes = (m_sizeInBits + 7) >> 3;
   for (int32_t i = 0; i < sizeInBytes; ++i) {
diff --git a/xfa/fxbarcode/qrcode/BC_QRCoderEncoder.cpp b/xfa/fxbarcode/qrcode/BC_QRCoderEncoder.cpp
index 332f1de..2c262f0 100644
--- a/xfa/fxbarcode/qrcode/BC_QRCoderEncoder.cpp
+++ b/xfa/fxbarcode/qrcode/BC_QRCoderEncoder.cpp
@@ -63,13 +63,16 @@
                                 int32_t versionSpecify) {
   if (versionSpecify == 0) {
     EncodeWithAutoVersion(content, ecLevel, qrCode, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e)
+    if (e != BCExceptionNO)
+      return;
   } else if (versionSpecify > 0 && versionSpecify <= 40) {
     EncodeWithSpecifyVersion(content, ecLevel, qrCode, versionSpecify, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
   } else {
     e = BCExceptionVersionMust1_40;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
   }
 }
 
@@ -87,44 +90,56 @@
     tempMode = splitResult.first;
     if (tempMode == CBC_QRCoderMode::sGBK) {
       AppendModeInfo(tempMode, &headerAndDataBits, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
       AppendLengthInfo(splitResult.second.GetLength(), qrCode->GetVersion(),
                        tempMode, &headerAndDataBits, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
       AppendBytes(splitResult.second, tempMode, &headerAndDataBits, encoding,
                   e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
     } else if (tempMode == CBC_QRCoderMode::sBYTE) {
-      CFX_ByteArray bytes;
+      CFX_ArrayTemplate<uint8_t> bytes;
       CBC_UtilCodingConvert::LocaleToUtf8(splitResult.second, bytes);
       AppendModeInfo(tempMode, &headerAndDataBits, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
       AppendLengthInfo(bytes.GetSize(), qrCode->GetVersion(), tempMode,
                        &headerAndDataBits, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
       Append8BitBytes(bytes, &headerAndDataBits, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
     } else if (tempMode == CBC_QRCoderMode::sALPHANUMERIC) {
       AppendModeInfo(tempMode, &headerAndDataBits, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
       AppendLengthInfo(splitResult.second.GetLength(), qrCode->GetVersion(),
                        tempMode, &headerAndDataBits, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
       AppendBytes(splitResult.second, tempMode, &headerAndDataBits, encoding,
                   e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
     } else if (tempMode == CBC_QRCoderMode::sNUMERIC) {
       AppendModeInfo(tempMode, &headerAndDataBits, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
       AppendLengthInfo(splitResult.second.GetLength(), qrCode->GetVersion(),
                        tempMode, &headerAndDataBits, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
       AppendBytes(splitResult.second, tempMode, &headerAndDataBits, encoding,
                   e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
     } else {
       e = BCExceptionUnknown;
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      return;
     }
   }
 }
@@ -199,45 +214,41 @@
                                              CBC_QRCoderMode* modeSecond,
                                              int32_t versionNum,
                                              int32_t& e) {
-  if (versionNum == 0) {
+  if (versionNum == 0)
+    return 0;
+
+  if (modeFirst == CBC_QRCoderMode::sALPHANUMERIC &&
+      modeSecond == CBC_QRCoderMode::sBYTE) {
+    if (versionNum >= 1 && versionNum <= 9)
+      return 11;
+    if (versionNum >= 10 && versionNum <= 26)
+      return 15;
+    if (versionNum >= 27 && versionNum <= 40)
+      return 16;
+    e = BCExceptionNoSuchVersion;
     return 0;
   }
-  if ((modeFirst == CBC_QRCoderMode::sALPHANUMERIC) &&
-      (modeSecond == CBC_QRCoderMode::sBYTE)) {
-    if (versionNum >= 1 && versionNum <= 9) {
-      return 11;
-    } else if (versionNum >= 10 && versionNum <= 26) {
-      return 15;
-    } else if (versionNum >= 27 && versionNum <= 40) {
-      return 16;
-    } else {
-      e = BCExceptionNoSuchVersion;
-      BC_EXCEPTION_CHECK_ReturnValue(e, 0);
-    }
-  } else if ((modeSecond == CBC_QRCoderMode::sALPHANUMERIC) &&
-             (modeFirst == CBC_QRCoderMode::sNUMERIC)) {
-    if (versionNum >= 1 && versionNum <= 9) {
+  if (modeSecond == CBC_QRCoderMode::sALPHANUMERIC &&
+      modeFirst == CBC_QRCoderMode::sNUMERIC) {
+    if (versionNum >= 1 && versionNum <= 9)
       return 13;
-    } else if (versionNum >= 10 && versionNum <= 26) {
+    if (versionNum >= 10 && versionNum <= 26)
       return 15;
-    } else if (versionNum >= 27 && versionNum <= 40) {
+    if (versionNum >= 27 && versionNum <= 40)
       return 17;
-    } else {
-      e = BCExceptionNoSuchVersion;
-      BC_EXCEPTION_CHECK_ReturnValue(e, 0);
-    }
-  } else if ((modeSecond == CBC_QRCoderMode::sBYTE) &&
-             (modeFirst == CBC_QRCoderMode::sNUMERIC)) {
-    if (versionNum >= 1 && versionNum <= 9) {
+    e = BCExceptionNoSuchVersion;
+    return 0;
+  }
+  if (modeSecond == CBC_QRCoderMode::sBYTE &&
+      modeFirst == CBC_QRCoderMode::sNUMERIC) {
+    if (versionNum >= 1 && versionNum <= 9)
       return 6;
-    } else if (versionNum >= 10 && versionNum <= 26) {
+    if (versionNum >= 10 && versionNum <= 26)
       return 8;
-    } else if (versionNum >= 27 && versionNum <= 40) {
+    if (versionNum >= 27 && versionNum <= 40)
       return 9;
-    } else {
-      e = BCExceptionNoSuchVersion;
-      BC_EXCEPTION_CHECK_ReturnValue(e, 0);
-    }
+    e = BCExceptionNoSuchVersion;
+    return 0;
   }
   return -1;
 }
@@ -253,7 +264,8 @@
     if (element1->first == CBC_QRCoderMode::sALPHANUMERIC) {
       int32_t tmp = GetSpanByVersion(CBC_QRCoderMode::sALPHANUMERIC,
                                      CBC_QRCoderMode::sBYTE, versionNum, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
       if (element2->first == CBC_QRCoderMode::sBYTE &&
           element1->second.GetLength() < tmp) {
         element2->second = element1->second + element2->second;
@@ -271,7 +283,8 @@
     } else if (element1->first == CBC_QRCoderMode::sNUMERIC) {
       int32_t tmp = GetSpanByVersion(CBC_QRCoderMode::sNUMERIC,
                                      CBC_QRCoderMode::sBYTE, versionNum, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
       if (element2->first == CBC_QRCoderMode::sBYTE &&
           element1->second.GetLength() < tmp) {
         element2->second = element1->second + element2->second;
@@ -281,7 +294,8 @@
       }
       tmp = GetSpanByVersion(CBC_QRCoderMode::sNUMERIC,
                              CBC_QRCoderMode::sALPHANUMERIC, versionNum, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
       if (element2->first == CBC_QRCoderMode::sALPHANUMERIC &&
           element1->second.GetLength() < tmp) {
         element2->second = element1->second + element2->second;
@@ -295,7 +309,8 @@
     return;
   }
   MergeString(result, versionNum, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
 }
 
 void CBC_QRCoderEncoder::InitQRCode(int32_t numInputBytes,
@@ -308,23 +323,23 @@
   qrCode->SetMode(mode);
   CBC_QRCoderVersion* version =
       CBC_QRCoderVersion::GetVersionForNumber(versionNumber, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   int32_t numBytes = version->GetTotalCodeWords();
   CBC_QRCoderECBlocks* ecBlocks = version->GetECBlocksForLevel(ecLevel);
   int32_t numEcBytes = ecBlocks->GetTotalECCodeWords();
   int32_t numRSBlocks = ecBlocks->GetNumBlocks();
   int32_t numDataBytes = numBytes - numEcBytes;
-  if (numDataBytes >= numInputBytes + 3) {
-    qrCode->SetVersion(versionNumber);
-    qrCode->SetNumTotalBytes(numBytes);
-    qrCode->SetNumDataBytes(numDataBytes);
-    qrCode->SetNumRSBlocks(numRSBlocks);
-    qrCode->SetNumECBytes(numEcBytes);
-    qrCode->SetMatrixWidth(version->GetDimensionForVersion());
+  if (numDataBytes < numInputBytes + 3) {
+    e = BCExceptionCannotFindBlockInfo;
     return;
   }
-  e = BCExceptionCannotFindBlockInfo;
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  qrCode->SetVersion(versionNumber);
+  qrCode->SetNumTotalBytes(numBytes);
+  qrCode->SetNumDataBytes(numDataBytes);
+  qrCode->SetNumRSBlocks(numRSBlocks);
+  qrCode->SetNumECBytes(numEcBytes);
+  qrCode->SetMatrixWidth(version->GetDimensionForVersion());
 }
 
 void CBC_QRCoderEncoder::EncodeWithSpecifyVersion(
@@ -340,7 +355,9 @@
   dataBits.Init();
   SplitString(content, &splitResult);
   MergeString(&splitResult, versionSpecify, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e) CBC_QRCoderMode* tempMode = nullptr;
+  if (e != BCExceptionNO)
+    return;
+  CBC_QRCoderMode* tempMode = nullptr;
   for (const auto& result : splitResult) {
     AppendBytes(result.second, result.first, &dataBits, encoding, e);
     if (e != BCExceptionNO)
@@ -368,23 +385,27 @@
   InterleaveWithECBytes(&headerAndDataBits, qrCode->GetNumTotalBytes(),
                         qrCode->GetNumDataBytes(), qrCode->GetNumRSBlocks(),
                         &finalBits, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
+
   std::unique_ptr<CBC_CommonByteMatrix> matrix(new CBC_CommonByteMatrix(
       qrCode->GetMatrixWidth(), qrCode->GetMatrixWidth()));
   matrix->Init();
   int32_t maskPattern = ChooseMaskPattern(
       &finalBits, qrCode->GetECLevel(), qrCode->GetVersion(), matrix.get(), e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
+
   qrCode->SetMaskPattern(maskPattern);
   CBC_QRCoderMatrixUtil::BuildMatrix(&finalBits, qrCode->GetECLevel(),
                                      qrCode->GetVersion(),
                                      qrCode->GetMaskPattern(), matrix.get(), e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
+
   qrCode->SetMatrix(std::move(matrix));
-  if (!qrCode->IsValid()) {
+  if (!qrCode->IsValid())
     e = BCExceptionInvalidQRCode;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
-  }
 }
 
 void CBC_QRCoderEncoder::EncodeWithAutoVersion(
@@ -399,7 +420,8 @@
   dataBits.Init();
   SplitString(content, &splitResult);
   MergeString(&splitResult, 8, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   CBC_QRCoderMode* tempMode = nullptr;
   for (const auto& result : splitResult) {
     AppendBytes(result.second, result.first, &dataBits, encoding, e);
@@ -408,7 +430,9 @@
   }
   int32_t numInputBytes = dataBits.sizeInBytes();
   InitQRCode(numInputBytes, ecLevel, mode, qrCode, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e) CBC_QRCoderBitVector headerAndDataBits;
+  if (e != BCExceptionNO)
+    return;
+  CBC_QRCoderBitVector headerAndDataBits;
   headerAndDataBits.Init();
   tempMode = nullptr;
   int32_t versionNum = qrCode->GetVersion();
@@ -446,22 +470,26 @@
   InterleaveWithECBytes(&headerAndDataBits, qrCode->GetNumTotalBytes(),
                         qrCode->GetNumDataBytes(), qrCode->GetNumRSBlocks(),
                         &finalBits, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
+
   std::unique_ptr<CBC_CommonByteMatrix> matrix(new CBC_CommonByteMatrix(
       qrCode->GetMatrixWidth(), qrCode->GetMatrixWidth()));
   matrix->Init();
   int32_t maskPattern = ChooseMaskPattern(
       &finalBits, qrCode->GetECLevel(), qrCode->GetVersion(), matrix.get(), e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
+
   qrCode->SetMaskPattern(maskPattern);
   CBC_QRCoderMatrixUtil::BuildMatrix(&finalBits, qrCode->GetECLevel(),
                                      qrCode->GetVersion(),
                                      qrCode->GetMaskPattern(), matrix.get(), e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e) qrCode->SetMatrix(std::move(matrix));
-  if (!qrCode->IsValid()) {
+  if (e != BCExceptionNO)
+    return qrCode->SetMatrix(std::move(matrix));
+
+  if (!qrCode->IsValid())
     e = BCExceptionInvalidQRCode;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
-  }
 }
 
 void CBC_QRCoderEncoder::Encode(const CFX_WideString& content,
@@ -475,44 +503,53 @@
   CBC_QRCoderBitVector dataBits;
   dataBits.Init();
   AppendBytes(utf8Data, mode, &dataBits, encoding, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   int32_t numInputBytes = dataBits.sizeInBytes();
   InitQRCode(numInputBytes, ecLevel, mode, qrCode, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   CBC_QRCoderBitVector headerAndDataBits;
   headerAndDataBits.Init();
   AppendModeInfo(mode, &headerAndDataBits, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   int32_t numLetters = mode == CBC_QRCoderMode::sBYTE ? dataBits.sizeInBytes()
                                                       : content.GetLength();
   AppendLengthInfo(numLetters, qrCode->GetVersion(), mode, &headerAndDataBits,
                    e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   headerAndDataBits.AppendBitVector(&dataBits, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e)
-      TerminateBits(qrCode->GetNumDataBytes(), &headerAndDataBits, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return TerminateBits(qrCode->GetNumDataBytes(), &headerAndDataBits, e);
+  if (e != BCExceptionNO)
+    return;
   CBC_QRCoderBitVector finalBits;
   finalBits.Init();
   InterleaveWithECBytes(&headerAndDataBits, qrCode->GetNumTotalBytes(),
                         qrCode->GetNumDataBytes(), qrCode->GetNumRSBlocks(),
                         &finalBits, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
+
   std::unique_ptr<CBC_CommonByteMatrix> matrix(new CBC_CommonByteMatrix(
       qrCode->GetMatrixWidth(), qrCode->GetMatrixWidth()));
   matrix->Init();
   int32_t maskPattern = ChooseMaskPattern(
       &finalBits, qrCode->GetECLevel(), qrCode->GetVersion(), matrix.get(), e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
+
   qrCode->SetMaskPattern(maskPattern);
   CBC_QRCoderMatrixUtil::BuildMatrix(&finalBits, qrCode->GetECLevel(),
                                      qrCode->GetVersion(),
                                      qrCode->GetMaskPattern(), matrix.get(), e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e) qrCode->SetMatrix(std::move(matrix));
-  if (!qrCode->IsValid()) {
+  if (e != BCExceptionNO)
+    return qrCode->SetMatrix(std::move(matrix));
+
+  if (!qrCode->IsValid())
     e = BCExceptionInvalidQRCode;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
-  }
 }
 
 void CBC_QRCoderEncoder::TerminateBits(int32_t numDataBytes,
@@ -521,38 +558,40 @@
   int32_t capacity = numDataBytes << 3;
   if (bits->Size() > capacity) {
     e = BCExceptionDataTooMany;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   for (int32_t i = 0; i < 4 && bits->Size() < capacity; ++i) {
     bits->AppendBit(0, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
   }
   int32_t numBitsInLastByte = bits->Size() % 8;
   if (numBitsInLastByte > 0) {
     int32_t numPaddingBits = 8 - numBitsInLastByte;
     for (int32_t j = 0; j < numPaddingBits; ++j) {
       bits->AppendBit(0, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e)
+      if (e != BCExceptionNO)
+        return;
     }
   }
   if (bits->Size() % 8 != 0) {
     e = BCExceptionDigitLengthMustBe8;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   int32_t numPaddingBytes = numDataBytes - bits->sizeInBytes();
   for (int32_t k = 0; k < numPaddingBytes; ++k) {
     if (k % 2 == 0) {
       bits->AppendBits(0xec, 8, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
     } else {
       bits->AppendBits(0x11, 8, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
     }
   }
-  if (bits->Size() != capacity) {
+  if (bits->Size() != capacity)
     e = BCExceptionBitsNotEqualCacity;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
-  }
 }
 
 int32_t CBC_QRCoderEncoder::ChooseMaskPattern(
@@ -567,7 +606,8 @@
        maskPattern++) {
     CBC_QRCoderMatrixUtil::BuildMatrix(bits, ecLevel, version, maskPattern,
                                        matrix, e);
-    BC_EXCEPTION_CHECK_ReturnValue(e, 0);
+    if (e != BCExceptionNO)
+      return 0;
     int32_t penalty = CalculateMaskPenalty(matrix);
     if (penalty < minPenalty) {
       minPenalty = penalty;
@@ -619,25 +659,18 @@
                                      CBC_QRCoderBitVector* bits,
                                      CFX_ByteString encoding,
                                      int32_t& e) {
-  if (mode == CBC_QRCoderMode::sNUMERIC) {
+  if (mode == CBC_QRCoderMode::sNUMERIC)
     AppendNumericBytes(content, bits, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
-  } else if (mode == CBC_QRCoderMode::sALPHANUMERIC) {
+  else if (mode == CBC_QRCoderMode::sALPHANUMERIC)
     AppendAlphaNumericBytes(content, bits, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
-  } else if (mode == CBC_QRCoderMode::sBYTE) {
+  else if (mode == CBC_QRCoderMode::sBYTE)
     Append8BitBytes(content, bits, encoding, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
-  } else if (mode == CBC_QRCoderMode::sKANJI) {
+  else if (mode == CBC_QRCoderMode::sKANJI)
     AppendKanjiBytes(content, bits, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
-  } else if (mode == CBC_QRCoderMode::sGBK) {
+  else if (mode == CBC_QRCoderMode::sGBK)
     AppendGBKBytes(content, bits, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
-  } else {
+  else
     e = BCExceptionUnsupportedMode;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
-  }
 }
 
 void CBC_QRCoderEncoder::AppendNumericBytes(const CFX_ByteString& content,
@@ -651,14 +684,19 @@
       int32_t num2 = content[i + 1] - '0';
       int32_t num3 = content[i + 2] - '0';
       bits->AppendBits(num1 * 100 + num2 * 10 + num3, 10, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e) i += 3;
+      if (e != BCExceptionNO)
+        return;
+      i += 3;
     } else if (i + 1 < length) {
       int32_t num2 = content[i + 1] - '0';
       bits->AppendBits(num1 * 10 + num2, 7, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e) i += 2;
+      if (e != BCExceptionNO)
+        return;
+      i += 2;
     } else {
       bits->AppendBits(num1, 4, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
       i++;
     }
   }
@@ -673,20 +711,23 @@
     int32_t code1 = GetAlphaNumericCode(content[i]);
     if (code1 == -1) {
       e = BCExceptionInvalidateCharacter;
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      return;
     }
     if (i + 1 < length) {
       int32_t code2 = GetAlphaNumericCode(content[i + 1]);
       if (code2 == -1) {
         e = BCExceptionInvalidateCharacter;
-        BC_EXCEPTION_CHECK_ReturnVoid(e);
+        return;
       }
       bits->AppendBits(code1 * 45 + code2, 11, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
       i += 2;
     } else {
       bits->AppendBits(code1, 6, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e) i++;
+      if (e != BCExceptionNO)
+        return;
+      i++;
     }
   }
 }
@@ -704,11 +745,12 @@
       value -= 0xA6A1;
     } else {
       e = BCExceptionInvalidateCharacter;
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      return;
     }
     value = (uint32_t)((value >> 8) * 0x60) + (uint32_t)(value & 0xff);
     bits->AppendBits(value, 13, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
   }
 }
 
@@ -718,23 +760,25 @@
                                          int32_t& e) {
   for (int32_t i = 0; i < content.GetLength(); i++) {
     bits->AppendBits(content[i], 8, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
   }
 }
 
-void CBC_QRCoderEncoder::Append8BitBytes(CFX_ByteArray& bytes,
+void CBC_QRCoderEncoder::Append8BitBytes(CFX_ArrayTemplate<uint8_t>& bytes,
                                          CBC_QRCoderBitVector* bits,
                                          int32_t& e) {
   for (int32_t i = 0; i < bytes.GetSize(); i++) {
     bits->AppendBits(bytes[i], 8, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
   }
 }
 
 void CBC_QRCoderEncoder::AppendKanjiBytes(const CFX_ByteString& content,
                                           CBC_QRCoderBitVector* bits,
                                           int32_t& e) {
-  CFX_ByteArray bytes;
+  CFX_ArrayTemplate<uint8_t> bytes;
   uint32_t value = 0;
   for (int32_t i = 0; i < bytes.GetSize(); i += 2) {
     value = (uint32_t)((uint8_t)(content[i] << 8) | (uint8_t)content[i + 1]);
@@ -744,11 +788,12 @@
       value -= 0xc140;
     } else {
       e = BCExceptionInvalidateCharacter;
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      return;
     }
     value = (uint32_t)((value >> 8) * 0xc0) + (uint32_t)(value & 0xff);
     bits->AppendBits(value, 13, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
   }
 }
 
@@ -762,7 +807,8 @@
   for (int32_t versionNum = 1; versionNum <= 40; versionNum++) {
     CBC_QRCoderVersion* version =
         CBC_QRCoderVersion::GetVersionForNumber(versionNum, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
     int32_t numBytes = version->GetTotalCodeWords();
     CBC_QRCoderECBlocks* ecBlocks = version->GetECBlocksForLevel(ecLevel);
     int32_t numEcBytes = ecBlocks->GetTotalECCodeWords();
@@ -779,17 +825,14 @@
     }
   }
   e = BCExceptionCannotFindBlockInfo;
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
 }
 
 void CBC_QRCoderEncoder::AppendModeInfo(CBC_QRCoderMode* mode,
                                         CBC_QRCoderBitVector* bits,
                                         int32_t& e) {
   bits->AppendBits(mode->GetBits(), 4, e);
-  if (mode == CBC_QRCoderMode::sGBK) {
+  if (mode == CBC_QRCoderMode::sGBK)
     bits->AppendBits(1, 4, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
-  }
 }
 
 void CBC_QRCoderEncoder::AppendLengthInfo(int32_t numLetters,
@@ -798,18 +841,20 @@
                                           CBC_QRCoderBitVector* bits,
                                           int32_t& e) {
   CBC_QRCoderVersion* qcv = CBC_QRCoderVersion::GetVersionForNumber(version, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   int32_t numBits = mode->GetCharacterCountBits(qcv, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   if (numBits > ((1 << numBits) - 1)) {
     return;
   }
   if (mode == CBC_QRCoderMode::sGBK) {
     bits->AppendBits(numLetters / 2, numBits, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
   }
   bits->AppendBits(numLetters, numBits, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
 }
 
 void CBC_QRCoderEncoder::InterleaveWithECBytes(CBC_QRCoderBitVector* bits,
@@ -820,7 +865,7 @@
                                                int32_t& e) {
   if (bits->sizeInBytes() != numDataBytes) {
     e = BCExceptionBitsBytesNotMatch;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   int32_t dataBytesOffset = 0;
   int32_t maxNumDataBytes = 0;
@@ -837,7 +882,8 @@
     dataBytes->Set(bits->GetArray(), dataBytesOffset, numDataBytesInBlock);
     std::unique_ptr<CBC_CommonByteArray> ecBytes(
         GenerateECBytes(dataBytes.get(), numEcBytesInBlosk, e));
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
     maxNumDataBytes = std::max(maxNumDataBytes, dataBytes->Size());
     maxNumEcBytes = std::max(maxNumEcBytes, ecBytes->Size());
     blocks.Add(
@@ -846,14 +892,15 @@
   }
   if (numDataBytes != dataBytesOffset) {
     e = BCExceptionBytesNotMatchOffset;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   for (int32_t x = 0; x < maxNumDataBytes; x++) {
     for (int32_t j = 0; j < blocks.GetSize(); j++) {
       const CBC_CommonByteArray* dataBytes = blocks[j]->GetDataBytes();
       if (x < dataBytes->Size()) {
         result->AppendBits(dataBytes->At(x), 8, e);
-        BC_EXCEPTION_CHECK_ReturnVoid(e);
+        if (e != BCExceptionNO)
+          return;
       }
     }
   }
@@ -862,17 +909,16 @@
       const CBC_CommonByteArray* ecBytes = blocks[l]->GetErrorCorrectionBytes();
       if (y < ecBytes->Size()) {
         result->AppendBits(ecBytes->At(y), 8, e);
-        BC_EXCEPTION_CHECK_ReturnVoid(e);
+        if (e != BCExceptionNO)
+          return;
       }
     }
   }
   for (int32_t k = 0; k < blocks.GetSize(); k++) {
     delete blocks[k];
   }
-  if (numTotalBytes != result->sizeInBytes()) {
+  if (numTotalBytes != result->sizeInBytes())
     e = BCExceptionSizeInBytesDiffer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
-  }
 }
 
 void CBC_QRCoderEncoder::GetNumDataBytesAndNumECBytesForBlockID(
@@ -907,7 +953,7 @@
     int32_t numEcBytesInBlock,
     int32_t& e) {
   int32_t numDataBytes = dataBytes->Size();
-  CFX_Int32Array toEncode;
+  CFX_ArrayTemplate<int32_t> toEncode;
   toEncode.SetSize(numDataBytes + numEcBytesInBlock);
   for (int32_t i = 0; i < numDataBytes; i++) {
     toEncode[i] = (dataBytes->At(i));
@@ -915,7 +961,8 @@
   CBC_ReedSolomonEncoder encode(CBC_ReedSolomonGF256::QRCodeField);
   encode.Init();
   encode.Encode(&toEncode, numEcBytesInBlock, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   CBC_CommonByteArray* ecBytes = new CBC_CommonByteArray(numEcBytesInBlock);
   for (int32_t j = 0; j < numEcBytesInBlock; j++) {
     ecBytes->Set(j, toEncode[numDataBytes + j]);
diff --git a/xfa/fxbarcode/qrcode/BC_QRCoderEncoder.h b/xfa/fxbarcode/qrcode/BC_QRCoderEncoder.h
index 649938a..a1b078f 100644
--- a/xfa/fxbarcode/qrcode/BC_QRCoderEncoder.h
+++ b/xfa/fxbarcode/qrcode/BC_QRCoderEncoder.h
@@ -62,7 +62,7 @@
                               CBC_QRCoderBitVector* bits,
                               CFX_ByteString encoding,
                               int32_t& e);
-  static void Append8BitBytes(CFX_ByteArray& bytes,
+  static void Append8BitBytes(CFX_ArrayTemplate<uint8_t>& bytes,
                               CBC_QRCoderBitVector* bits,
                               int32_t& e);
   static void AppendKanjiBytes(const CFX_ByteString& content,
diff --git a/xfa/fxbarcode/qrcode/BC_QRCoderMaskUtil.cpp b/xfa/fxbarcode/qrcode/BC_QRCoderMaskUtil.cpp
index 8342b9b..7953701 100644
--- a/xfa/fxbarcode/qrcode/BC_QRCoderMaskUtil.cpp
+++ b/xfa/fxbarcode/qrcode/BC_QRCoderMaskUtil.cpp
@@ -128,7 +128,7 @@
                                          int32_t& e) {
   if (!CBC_QRCoder::IsValidMaskPattern(maskPattern)) {
     e = (BCExceptionInvalidateMaskPattern);
-    BC_EXCEPTION_CHECK_ReturnValue(e, false);
+    return false;
   }
   int32_t intermediate = 0, temp = 0;
   switch (maskPattern) {
@@ -161,7 +161,7 @@
       break;
     default: {
       e = BCExceptionInvalidateMaskPattern;
-      BC_EXCEPTION_CHECK_ReturnValue(e, false);
+      return false;
     }
   }
   return intermediate == 0;
diff --git a/xfa/fxbarcode/qrcode/BC_QRCoderMatrixUtil.cpp b/xfa/fxbarcode/qrcode/BC_QRCoderMatrixUtil.cpp
index ca44e01..d48d81c 100644
--- a/xfa/fxbarcode/qrcode/BC_QRCoderMatrixUtil.cpp
+++ b/xfa/fxbarcode/qrcode/BC_QRCoderMatrixUtil.cpp
@@ -79,7 +79,7 @@
                                         int32_t& e) {
   if (!matrix) {
     e = BCExceptionNullPointer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   matrix->clear((uint8_t)-1);
 }
@@ -92,34 +92,43 @@
     int32_t& e) {
   if (!matrix) {
     e = BCExceptionNullPointer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   ClearMatrix(matrix, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   EmbedBasicPatterns(version, matrix, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   EmbedTypeInfo(ecLevel, maskPattern, matrix, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   MaybeEmbedVersionInfo(version, matrix, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   EmbedDataBits(dataBits, maskPattern, matrix, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
 }
 void CBC_QRCoderMatrixUtil::EmbedBasicPatterns(int32_t version,
                                                CBC_CommonByteMatrix* matrix,
                                                int32_t& e) {
   if (!matrix) {
     e = BCExceptionNullPointer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   EmbedPositionDetectionPatternsAndSeparators(matrix, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   EmbedDarkDotAtLeftBottomCorner(matrix, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   MaybeEmbedPositionAdjustmentPatterns(version, matrix, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   EmbedTimingPatterns(matrix, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
 }
 void CBC_QRCoderMatrixUtil::EmbedTypeInfo(
     CBC_QRCoderErrorCorrectionLevel* ecLevel,
@@ -128,15 +137,17 @@
     int32_t& e) {
   if (!matrix) {
     e = BCExceptionNullPointer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   CBC_QRCoderBitVector typeInfoBits;
   typeInfoBits.Init();
   MakeTypeInfoBits(ecLevel, maskPattern, &typeInfoBits, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   for (int32_t i = 0; i < typeInfoBits.Size(); i++) {
     int32_t bit = typeInfoBits.At(typeInfoBits.Size() - 1 - i, e);
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
     int32_t x1 = TYPE_INFO_COORDINATES[i][0];
     int32_t y1 = TYPE_INFO_COORDINATES[i][1];
     matrix->Set(x1, y1, bit);
@@ -156,7 +167,7 @@
                                                   int32_t& e) {
   if (!matrix) {
     e = BCExceptionNullPointer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   if (version < 7) {
     return;
@@ -164,12 +175,14 @@
   CBC_QRCoderBitVector versionInfoBits;
   versionInfoBits.Init();
   MakeVersionInfoBits(version, &versionInfoBits, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   int32_t bitIndex = 6 * 3 - 1;
   for (int32_t i = 0; i < 6; i++) {
     for (int32_t j = 0; j < 3; j++) {
       int32_t bit = versionInfoBits.At(bitIndex, e);
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      if (e != BCExceptionNO)
+        return;
       bitIndex--;
       matrix->Set(i, matrix->GetHeight() - 11 + j, bit);
       matrix->Set(matrix->GetHeight() - 11 + j, i, bit);
@@ -182,7 +195,7 @@
                                           int32_t& e) {
   if (!matrix || !dataBits) {
     e = BCExceptionNullPointer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   int32_t bitIndex = 0;
   int32_t direction = -1;
@@ -205,14 +218,16 @@
         int32_t bit;
         if (bitIndex < dataBits->Size()) {
           bit = dataBits->At(bitIndex, e);
-          BC_EXCEPTION_CHECK_ReturnVoid(e);
+          if (e != BCExceptionNO)
+            return;
           bitIndex++;
         } else {
           bit = 0;
         }
         if (maskPattern != -1) {
           bool bol = CBC_QRCoderMaskUtil::GetDataMaskBit(maskPattern, xx, y, e);
-          BC_EXCEPTION_CHECK_ReturnVoid(e);
+          if (e != BCExceptionNO)
+            return;
           if (bol) {
             bit ^= 0x01;
           }
@@ -244,46 +259,52 @@
     int32_t& e) {
   if (!bits) {
     e = BCExceptionNullPointer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   if (!CBC_QRCoder::IsValidMaskPattern(maskPattern)) {
     e = BCExceptionBadMask;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   int32_t typeInfo = (ecLevel->GetBits() << 3) | maskPattern;
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   bits->AppendBits(typeInfo, 5, e);
   int32_t bchCode = CalculateBCHCode(typeInfo, TYPE_INFO_POLY);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   bits->AppendBits(bchCode, 10, e);
   CBC_QRCoderBitVector maskBits;
   maskBits.Init();
   maskBits.AppendBits(TYPE_INFO_MASK_PATTERN, 15, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   bits->XOR(&maskBits, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
-  if (bits->Size() != 15) {
+  if (e != BCExceptionNO)
+    return;
+  if (bits->Size() != 15)
     e = BCExceptionBitSizeNot15;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
-  }
 }
+
 void CBC_QRCoderMatrixUtil::MakeVersionInfoBits(int32_t version,
                                                 CBC_QRCoderBitVector* bits,
                                                 int32_t& e) {
   if (!bits) {
     e = BCExceptionNullPointer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   bits->AppendBits(version, 6, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
+
   int32_t bchCode = CalculateBCHCode(version, VERSION_INFO_POLY);
   bits->AppendBits(bchCode, 12, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
-  if (bits->Size() != 18) {
+  if (e != BCExceptionNO)
+    return;
+
+  if (bits->Size() != 18)
     e = BCExceptionBitSizeNot18;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
-  }
 }
+
 bool CBC_QRCoderMatrixUtil::IsEmpty(int32_t value) {
   return (uint8_t)value == 0xff;
 }
@@ -291,24 +312,25 @@
   return ((uint8_t)value == 0xff || (uint8_t)value == 0x00 ||
           (uint8_t)value == 0x01);
 }
+
 void CBC_QRCoderMatrixUtil::EmbedTimingPatterns(CBC_CommonByteMatrix* matrix,
                                                 int32_t& e) {
   if (!matrix) {
     e = BCExceptionNullPointer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   for (int32_t i = 8; i < matrix->GetWidth() - 8; i++) {
     int32_t bit = (i + 1) % 2;
     if (!IsValidValue(matrix->Get(i, 6))) {
       e = BCExceptionInvalidateImageData;
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      return;
     }
     if (IsEmpty(matrix->Get(i, 6))) {
       matrix->Set(i, 6, bit);
     }
     if (!IsValidValue(matrix->Get(6, i))) {
       e = BCExceptionInvalidateImageData;
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      return;
     }
     if (IsEmpty(matrix->Get(6, i))) {
       matrix->Set(6, i, bit);
@@ -320,11 +342,11 @@
     int32_t& e) {
   if (!matrix) {
     e = BCExceptionNullPointer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   if (matrix->Get(8, matrix->GetHeight() - 8) == 0) {
     e = BCExceptionHeight_8BeZero;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   matrix->Set(8, matrix->GetHeight() - 8, 1);
 }
@@ -335,12 +357,12 @@
     int32_t& e) {
   if (!matrix) {
     e = BCExceptionNullPointer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   for (int32_t x = 0; x < 8; x++) {
     if (!IsEmpty(matrix->Get(xStart + x, yStart))) {
       e = BCExceptionInvalidateData;
-      BC_EXCEPTION_CHECK_ReturnVoid(e)
+      return;
     }
     matrix->Set(xStart + x, yStart, HORIZONTAL_SEPARATION_PATTERN[0][x]);
   }
@@ -352,12 +374,12 @@
     int32_t& e) {
   if (!matrix) {
     e = BCExceptionNullPointer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   for (int32_t y = 0; y < 7; y++) {
     if (!IsEmpty(matrix->Get(xStart, yStart + y))) {
       e = BCExceptionInvalidateData;
-      BC_EXCEPTION_CHECK_ReturnVoid(e);
+      return;
     }
     matrix->Set(xStart, yStart + y, VERTICAL_SEPARATION_PATTERN[y][0]);
   }
@@ -369,13 +391,14 @@
     int32_t& e) {
   if (!matrix) {
     e = BCExceptionNullPointer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    if (e != BCExceptionNO)
+      return;
   }
   for (int32_t y = 0; y < 5; y++) {
     for (int32_t x = 0; x < 5; x++) {
       if (!IsEmpty(matrix->Get(xStart + x, y + yStart))) {
         e = BCExceptionInvalidateData;
-        BC_EXCEPTION_CHECK_ReturnVoid(e);
+        return;
       }
       matrix->Set(xStart + x, yStart + y, POSITION_ADJUSTMENT_PATTERN[y][x]);
     }
@@ -388,13 +411,13 @@
     int32_t& e) {
   if (!matrix) {
     e = BCExceptionNullPointer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   for (int32_t y = 0; y < 7; y++) {
     for (int32_t x = 0; x < 7; x++) {
       if (!IsEmpty(matrix->Get(xStart + x, yStart + y))) {
         e = BCExceptionInvalidateData;
-        BC_EXCEPTION_CHECK_ReturnVoid(e);
+        return;
       }
       matrix->Set(xStart + x, yStart + y, POSITION_DETECTION_PATTERN[y][x]);
     }
@@ -405,32 +428,41 @@
     int32_t& e) {
   if (!matrix) {
     e = BCExceptionNullPointer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   int32_t pdpWidth = 7;
   EmbedPositionDetectionPattern(0, 0, matrix, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   EmbedPositionDetectionPattern(matrix->GetWidth() - pdpWidth, 0, matrix, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   EmbedPositionDetectionPattern(0, matrix->GetWidth() - pdpWidth, matrix, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   int32_t hspWidth = 8;
   EmbedHorizontalSeparationPattern(0, hspWidth - 1, matrix, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   EmbedHorizontalSeparationPattern(matrix->GetWidth() - hspWidth, hspWidth - 1,
                                    matrix, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   EmbedHorizontalSeparationPattern(0, matrix->GetWidth() - hspWidth, matrix, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   int32_t vspSize = 7;
   EmbedVerticalSeparationPattern(vspSize, 0, matrix, e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   EmbedVerticalSeparationPattern(matrix->GetHeight() - vspSize - 1, 0, matrix,
                                  e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
   EmbedVerticalSeparationPattern(vspSize, matrix->GetHeight() - vspSize, matrix,
                                  e);
-  BC_EXCEPTION_CHECK_ReturnVoid(e);
+  if (e != BCExceptionNO)
+    return;
 }
 void CBC_QRCoderMatrixUtil::MaybeEmbedPositionAdjustmentPatterns(
     int32_t version,
@@ -438,7 +470,7 @@
     int32_t& e) {
   if (!matrix) {
     e = BCExceptionNullPointer;
-    BC_EXCEPTION_CHECK_ReturnVoid(e);
+    return;
   }
   if (version < 2) {
     return;
@@ -456,7 +488,8 @@
       }
       if (IsEmpty(matrix->Get(x, y))) {
         EmbedPositionAdjustmentPattern(x - 2, y - 2, matrix, e);
-        BC_EXCEPTION_CHECK_ReturnVoid(e);
+        if (e != BCExceptionNO)
+          return;
       }
     }
   }
diff --git a/xfa/fxbarcode/qrcode/BC_QRCoderMode.cpp b/xfa/fxbarcode/qrcode/BC_QRCoderMode.cpp
index 74c5563..a1283dd 100644
--- a/xfa/fxbarcode/qrcode/BC_QRCoderMode.cpp
+++ b/xfa/fxbarcode/qrcode/BC_QRCoderMode.cpp
@@ -98,12 +98,10 @@
       return sFNC1_SECOND_POSITION;
     case 0x0D:
       return sGBK;
-    default: {
+    default:
       e = BCExceptionUnsupportedMode;
-      BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
-    }
+      return nullptr;
   }
-  return nullptr;
 }
 
 int32_t CBC_QRCoderMode::GetBits() const {
@@ -118,7 +116,7 @@
                                                int32_t& e) const {
   if (m_characterCountBitsForVersions.empty()) {
     e = BCExceptionCharacterNotThisMode;
-    BC_EXCEPTION_CHECK_ReturnValue(e, 0);
+    return 0;
   }
   int32_t number = version->GetVersionNumber();
   int32_t offset;
diff --git a/xfa/fxbarcode/qrcode/BC_QRCoderVersion.cpp b/xfa/fxbarcode/qrcode/BC_QRCoderVersion.cpp
index b0b445b..befdc17 100644
--- a/xfa/fxbarcode/qrcode/BC_QRCoderVersion.cpp
+++ b/xfa/fxbarcode/qrcode/BC_QRCoderVersion.cpp
@@ -354,7 +354,7 @@
 int32_t CBC_QRCoderVersion::GetVersionNumber() {
   return m_versionNumber;
 }
-CFX_Int32Array* CBC_QRCoderVersion::GetAlignmentPatternCenters() {
+CFX_ArrayTemplate<int32_t>* CBC_QRCoderVersion::GetAlignmentPatternCenters() {
   return &m_alignmentPatternCenters;
 }
 int32_t CBC_QRCoderVersion::GetTotalCodeWords() {
@@ -372,10 +372,11 @@
     int32_t& e) {
   if ((dimension % 4) != 1) {
     e = BCExceptionRead;
-    BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+    return nullptr;
   }
   CBC_QRCoderVersion* qcv = GetVersionForNumber((dimension - 17) >> 2, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   return qcv;
 }
 CBC_QRCoderVersion* CBC_QRCoderVersion::DecodeVersionInformation(
@@ -387,7 +388,8 @@
     int32_t targetVersion = VERSION_DECODE_INFO[i];
     if (targetVersion == versionBits) {
       CBC_QRCoderVersion* qcv = GetVersionForNumber(i + 7, e);
-      BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+      if (e != BCExceptionNO)
+        return nullptr;
       return qcv;
     }
     int32_t bitsDifference = NumBitsDiffering(versionBits, targetVersion);
@@ -398,7 +400,8 @@
   }
   if (bestDifference <= 3) {
     CBC_QRCoderVersion* qcv = GetVersionForNumber(bestVersion, e);
-    BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+    if (e != BCExceptionNO)
+      return nullptr;
     return qcv;
   }
   return nullptr;
@@ -408,11 +411,14 @@
   CBC_CommonBitMatrix* bitMatrix = new CBC_CommonBitMatrix();
   bitMatrix->Init(dimension);
   bitMatrix->SetRegion(0, 0, 9, 9, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   bitMatrix->SetRegion(dimension - 8, 0, 8, 9, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   bitMatrix->SetRegion(0, dimension - 8, 9, 8, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   int32_t max = m_alignmentPatternCenters.GetSize();
   for (int32_t x = 0; x < max; x++) {
     int32_t i = m_alignmentPatternCenters[x] - 2;
@@ -421,18 +427,23 @@
         continue;
       }
       bitMatrix->SetRegion(m_alignmentPatternCenters[y] - 2, i, 5, 5, e);
-      BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+      if (e != BCExceptionNO)
+        return nullptr;
     }
   }
   bitMatrix->SetRegion(6, 9, 1, dimension - 17, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   bitMatrix->SetRegion(9, 6, dimension - 17, 1, e);
-  BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+  if (e != BCExceptionNO)
+    return nullptr;
   if (m_versionNumber > 6) {
     bitMatrix->SetRegion(dimension - 11, 0, 3, 6, e);
-    BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+    if (e != BCExceptionNO)
+      return nullptr;
     bitMatrix->SetRegion(0, dimension - 11, 6, 3, e);
-    BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+    if (e != BCExceptionNO)
+      return nullptr;
   }
   return bitMatrix;
 }
@@ -771,7 +782,7 @@
   }
   if (versionNumber < 1 || versionNumber > 40) {
     e = BCExceptionIllegalArgument;
-    BC_EXCEPTION_CHECK_ReturnValue(e, nullptr);
+    return nullptr;
   }
   return (*VERSION)[versionNumber - 1];
 }
diff --git a/xfa/fxbarcode/qrcode/BC_QRCoderVersion.h b/xfa/fxbarcode/qrcode/BC_QRCoderVersion.h
index 43b4b60..030dd51 100644
--- a/xfa/fxbarcode/qrcode/BC_QRCoderVersion.h
+++ b/xfa/fxbarcode/qrcode/BC_QRCoderVersion.h
@@ -23,7 +23,7 @@
   int32_t GetTotalCodeWords();
   int32_t GetDimensionForVersion();
   CBC_CommonBitMatrix* BuildFunctionPattern(int32_t& e);
-  CFX_Int32Array* GetAlignmentPatternCenters();
+  CFX_ArrayTemplate<int32_t>* GetAlignmentPatternCenters();
   CBC_QRCoderECBlocks* GetECBlocksForLevel(
       CBC_QRCoderErrorCorrectionLevel* ecLevel);
   static CBC_QRCoderVersion* GetVersionForNumber(int32_t versionNumber,
@@ -48,7 +48,7 @@
 
   int32_t m_versionNumber;
   int32_t m_totalCodeWords;
-  CFX_Int32Array m_alignmentPatternCenters;
+  CFX_ArrayTemplate<int32_t> m_alignmentPatternCenters;
   CFX_ArrayTemplate<CBC_QRCoderECBlocks*> m_ecBlocksArray;
 };
 
diff --git a/xfa/fxbarcode/utils.h b/xfa/fxbarcode/utils.h
index 7473d41..1cb8d85 100644
--- a/xfa/fxbarcode/utils.h
+++ b/xfa/fxbarcode/utils.h
@@ -15,7 +15,8 @@
                               int32_t count,
                               FX_CHAR c);
 void BC_FX_ByteString_Append(CFX_ByteString& dst, int32_t count, FX_CHAR c);
-void BC_FX_ByteString_Append(CFX_ByteString& dst, const CFX_ByteArray& ba);
+void BC_FX_ByteString_Append(CFX_ByteString& dst,
+                             const CFX_ArrayTemplate<uint8_t>& ba);
 
 #if (_FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_)
 #include <limits>
@@ -164,15 +165,5 @@
 #define BCExceptiontNotFoundInstance 104
 #define BCExceptionNotFoundInstance 105
 #define BCExceptionCannotMetadata 106
-#define TWO_DIGIT_DATA_LENGTH_SIZE 24
-#define THREE_DIGIT_DATA_LENGTH_SIZE 23
-#define THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH_SIZE 57
-#define FOUR_DIGIT_DATA_LENGTH_SIZE 17
-#define BC_EXCEPTION_CHECK_ReturnVoid(e) \
-  if (e != BCExceptionNO)                \
-    return;
-#define BC_EXCEPTION_CHECK_ReturnValue(e, v) \
-  if (e != BCExceptionNO)                    \
-    return v;
 
 #endif  // XFA_FXBARCODE_UTILS_H_
diff --git a/xfa/fxfa/app/cxfa_csstagprovider.h b/xfa/fxfa/app/cxfa_csstagprovider.h
index 3c23784..f5db867 100644
--- a/xfa/fxfa/app/cxfa_csstagprovider.h
+++ b/xfa/fxfa/app/cxfa_csstagprovider.h
@@ -13,30 +13,27 @@
 
 class CXFA_CSSTagProvider {
  public:
-  using AttributeMap = std::map<CFX_WideString, CFX_WideString>;
-
   CXFA_CSSTagProvider();
   ~CXFA_CSSTagProvider();
 
   CFX_WideString GetTagName() { return m_wsTagName; }
 
-  AttributeMap::iterator begin() { return m_Attributes.begin(); }
-  AttributeMap::iterator end() { return m_Attributes.end(); }
-
-  bool empty() const { return m_Attributes.empty(); }
-
-  void SetTagNameObj(const CFX_WideString& wsName) { m_wsTagName = wsName; }
+  void SetTagName(const CFX_WideString& wsName) { m_wsTagName = wsName; }
   void SetAttribute(const CFX_WideString& wsAttr,
                     const CFX_WideString& wsValue) {
     m_Attributes.insert({wsAttr, wsValue});
   }
 
+  CFX_WideString GetAttribute(const CFX_WideString& wsAttr) {
+    return m_Attributes[wsAttr];
+  }
+
   bool m_bTagAvailable;
   bool m_bContent;
 
- protected:
+ private:
   CFX_WideString m_wsTagName;
-  AttributeMap m_Attributes;
+  std::map<CFX_WideString, CFX_WideString> m_Attributes;
 };
 
 #endif  // XFA_FXFA_APP_CXFA_CSSTAGPROVIDER_H_
diff --git a/xfa/fxfa/app/cxfa_linkuserdata.cpp b/xfa/fxfa/app/cxfa_linkuserdata.cpp
index f1e15f4..4128cd8 100644
--- a/xfa/fxfa/app/cxfa_linkuserdata.cpp
+++ b/xfa/fxfa/app/cxfa_linkuserdata.cpp
@@ -7,21 +7,6 @@
 #include "xfa/fxfa/app/cxfa_linkuserdata.h"
 
 CXFA_LinkUserData::CXFA_LinkUserData(FX_WCHAR* pszText)
-    : m_dwRefCount(1), m_wsURLContent(pszText) {}
+    : m_wsURLContent(pszText) {}
 
 CXFA_LinkUserData::~CXFA_LinkUserData() {}
-
-uint32_t CXFA_LinkUserData::Retain() {
-  return ++m_dwRefCount;
-}
-
-uint32_t CXFA_LinkUserData::Release() {
-  uint32_t dwRefCount = --m_dwRefCount;
-  if (dwRefCount <= 0)
-    delete this;
-  return dwRefCount;
-}
-
-const FX_WCHAR* CXFA_LinkUserData::GetLinkURL() {
-  return m_wsURLContent.c_str();
-}
diff --git a/xfa/fxfa/app/cxfa_linkuserdata.h b/xfa/fxfa/app/cxfa_linkuserdata.h
index 621398e..852b467 100644
--- a/xfa/fxfa/app/cxfa_linkuserdata.h
+++ b/xfa/fxfa/app/cxfa_linkuserdata.h
@@ -7,23 +7,22 @@
 #ifndef XFA_FXFA_APP_CXFA_LINKUSERDATA_H_
 #define XFA_FXFA_APP_CXFA_LINKUSERDATA_H_
 
+#include "core/fxcrt/cfx_retain_ptr.h"
 #include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
 
-class CXFA_LinkUserData : public IFX_Retainable {
+class CXFA_LinkUserData : public CFX_Retainable {
  public:
+  template <typename T, typename... Args>
+  friend CFX_RetainPtr<T> pdfium::MakeRetain(Args&&... args);
+
+  const FX_WCHAR* GetLinkURL() const { return m_wsURLContent.c_str(); }
+
+ protected:
   explicit CXFA_LinkUserData(FX_WCHAR* pszText);
   ~CXFA_LinkUserData() override;
 
-  // IFX_Retainable:
-  uint32_t Retain() override;
-  uint32_t Release() override;
-
-  const FX_WCHAR* GetLinkURL();
-
- protected:
-  uint32_t m_dwRefCount;
   CFX_WideString m_wsURLContent;
 };
 
diff --git a/xfa/fxfa/app/cxfa_loadercontext.cpp b/xfa/fxfa/app/cxfa_loadercontext.cpp
index 56ac71b..0733c52 100644
--- a/xfa/fxfa/app/cxfa_loadercontext.cpp
+++ b/xfa/fxfa/app/cxfa_loadercontext.cpp
@@ -16,7 +16,6 @@
       m_iTotalLines(-1),
       m_pXMLNode(nullptr),
       m_pNode(nullptr),
-      m_pParentStyle(nullptr),
       m_dwFlags(0) {}
 
 CXFA_LoaderContext::~CXFA_LoaderContext() {}
diff --git a/xfa/fxfa/app/cxfa_loadercontext.h b/xfa/fxfa/app/cxfa_loadercontext.h
index c647f62..d8ccdbe 100644
--- a/xfa/fxfa/app/cxfa_loadercontext.h
+++ b/xfa/fxfa/app/cxfa_loadercontext.h
@@ -11,10 +11,10 @@
 
 #include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_system.h"
+#include "xfa/fde/css/cfde_csscomputedstyle.h"
 
 class CFDE_XMLNode;
 class CXFA_Node;
-class CFDE_CSSComputedStyle;
 
 class CXFA_LoaderContext {
  public:
@@ -31,7 +31,7 @@
   int32_t m_iTotalLines;
   CFDE_XMLNode* m_pXMLNode;
   CXFA_Node* m_pNode;
-  CFDE_CSSComputedStyle* m_pParentStyle;
+  CFX_RetainPtr<CFDE_CSSComputedStyle> m_pParentStyle;
   CFX_ArrayTemplate<FX_FLOAT> m_lineHeights;
   uint32_t m_dwFlags;
   std::vector<FX_FLOAT> m_BlocksHeight;
diff --git a/xfa/fxfa/app/cxfa_textlayout.cpp b/xfa/fxfa/app/cxfa_textlayout.cpp
index 788fea2..06cbfe0 100644
--- a/xfa/fxfa/app/cxfa_textlayout.cpp
+++ b/xfa/fxfa/app/cxfa_textlayout.cpp
@@ -80,7 +80,7 @@
       CFDE_XMLElement* pXMLElement = static_cast<CFDE_XMLElement*>(pXMLChild);
       CFX_WideString wsTag;
       pXMLElement->GetLocalTagName(wsTag);
-      if (wsTag == FX_WSTRC(L"body") || wsTag == FX_WSTRC(L"html")) {
+      if (wsTag == L"body" || wsTag == L"html") {
         pXMLContainer = pXMLChild;
         break;
       }
@@ -89,14 +89,12 @@
   return pXMLContainer;
 }
 
-CFX_RTFBreak* CXFA_TextLayout::CreateBreak(bool bDefault) {
+std::unique_ptr<CFX_RTFBreak> CXFA_TextLayout::CreateBreak(bool bDefault) {
   uint32_t dwStyle = FX_RTFLAYOUTSTYLE_ExpandTab;
   if (!bDefault)
     dwStyle |= FX_RTFLAYOUTSTYLE_Pagination;
 
-  CFX_RTFBreak* pBreak = new CFX_RTFBreak(0);
-  pBreak->SetLayoutStyles(dwStyle);
-  pBreak->SetLineBreakChar(L'\n');
+  auto pBreak = pdfium::MakeUnique<CFX_RTFBreak>(dwStyle);
   pBreak->SetLineBreakTolerance(1);
   pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, nullptr));
   pBreak->SetFontSize(m_textParser.GetFontSize(m_pTextProvider, nullptr));
@@ -109,26 +107,26 @@
   FX_FLOAT fStart = 0;
   FX_FLOAT fStartPos = 0;
   if (para) {
-    int32_t iAlign = FX_RTFLINEALIGNMENT_Left;
+    CFX_RTFLineAlignment iAlign = CFX_RTFLineAlignment::Left;
     switch (para.GetHorizontalAlign()) {
       case XFA_ATTRIBUTEENUM_Center:
-        iAlign = FX_RTFLINEALIGNMENT_Center;
+        iAlign = CFX_RTFLineAlignment::Center;
         break;
       case XFA_ATTRIBUTEENUM_Right:
-        iAlign = FX_RTFLINEALIGNMENT_Right;
+        iAlign = CFX_RTFLineAlignment::Right;
         break;
       case XFA_ATTRIBUTEENUM_Justify:
-        iAlign = FX_RTFLINEALIGNMENT_Justified;
+        iAlign = CFX_RTFLineAlignment::Justified;
         break;
       case XFA_ATTRIBUTEENUM_JustifyAll:
-        iAlign = FX_RTFLINEALIGNMENT_Distributed;
+        iAlign = CFX_RTFLineAlignment::Distributed;
         break;
     }
     m_pBreak->SetAlignment(iAlign);
 
     fStart = para.GetMarginLeft();
     if (m_pTextProvider->IsCheckButtonAndAutoWidth()) {
-      if (iAlign != FX_RTFLINEALIGNMENT_Left)
+      if (iAlign != CFX_RTFLineAlignment::Left)
         fLineWidth -= para.GetMarginRight();
     } else {
       fLineWidth -= para.GetMarginRight();
@@ -168,24 +166,25 @@
 
   if (eDisplay == FDE_CSSDisplay::Block ||
       eDisplay == FDE_CSSDisplay::ListItem) {
-    int32_t iAlign = FX_RTFLINEALIGNMENT_Left;
+    CFX_RTFLineAlignment iAlign = CFX_RTFLineAlignment::Left;
     switch (pStyle->GetTextAlign()) {
       case FDE_CSSTextAlign::Right:
-        iAlign = FX_RTFLINEALIGNMENT_Right;
+        iAlign = CFX_RTFLineAlignment::Right;
         break;
       case FDE_CSSTextAlign::Center:
-        iAlign = FX_RTFLINEALIGNMENT_Center;
+        iAlign = CFX_RTFLineAlignment::Center;
         break;
       case FDE_CSSTextAlign::Justify:
-        iAlign = FX_RTFLINEALIGNMENT_Justified;
+        iAlign = CFX_RTFLineAlignment::Justified;
         break;
       case FDE_CSSTextAlign::JustifyAll:
-        iAlign = FX_RTFLINEALIGNMENT_Distributed;
+        iAlign = CFX_RTFLineAlignment::Distributed;
         break;
       default:
         break;
     }
     m_pBreak->SetAlignment(iAlign);
+
     FX_FLOAT fStart = 0;
     const FDE_CSSRect* pRect = pStyle->GetMarginWidth();
     const FDE_CSSRect* pPaddingRect = pStyle->GetPaddingWidth();
@@ -261,7 +260,7 @@
     m_pLoader->m_fLastPos = 0;
     CalcSize(szMax, szMax, szDef);
     m_pLoader->m_bSaveLineHeight = false;
-    return szDef.y;
+    return szDef.height;
   }
 
   FX_FLOAT fHeight = m_pLoader->m_fHeight;
@@ -293,7 +292,7 @@
     m_pLoader->m_fLastPos = 0;
     CalcSize(szMax, szMax, szDef);
     m_pLoader->m_bSaveLineHeight = false;
-    fWidth = szDef.x;
+    fWidth = szDef.width;
   }
   return fWidth;
 }
@@ -388,11 +387,11 @@
 bool CXFA_TextLayout::CalcSize(const CFX_SizeF& minSize,
                                const CFX_SizeF& maxSize,
                                CFX_SizeF& defaultSize) {
-  defaultSize.x = maxSize.x;
-  if (defaultSize.x < 1)
-    defaultSize.x = 0xFFFF;
+  defaultSize.width = maxSize.width;
+  if (defaultSize.width < 1)
+    defaultSize.width = 0xFFFF;
 
-  m_pBreak.reset(CreateBreak(false));
+  m_pBreak = CreateBreak(false);
   FX_FLOAT fLinePos = 0;
   m_iLines = 0;
   m_fMaxWidth = 0;
@@ -406,11 +405,11 @@
 }
 
 bool CXFA_TextLayout::Layout(const CFX_SizeF& size, FX_FLOAT* fHeight) {
-  if (size.x < 1)
+  if (size.width < 1)
     return false;
 
   Unload();
-  m_pBreak.reset(CreateBreak(true));
+  m_pBreak = CreateBreak(true);
   if (m_pLoader) {
     m_pLoader->m_iTotalLines = -1;
     m_pLoader->m_iChar = 0;
@@ -419,7 +418,7 @@
   m_iLines = 0;
   FX_FLOAT fLinePos = 0;
   Loader(size, fLinePos, true);
-  UpdateAlign(size.y, fLinePos);
+  UpdateAlign(size.height, fLinePos);
   m_pTabstopContext.reset();
   if (fHeight)
     *fHeight = fLinePos;
@@ -445,7 +444,7 @@
     return true;
   if (iBlock == iBlocksHeightCount) {
     Unload();
-    m_pBreak.reset(CreateBreak(true));
+    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];
@@ -456,7 +455,7 @@
 
     Loader(szText, fLinePos, true);
     if (iCount == 0 && m_pLoader->m_fStartLineOffset < 0.1f)
-      UpdateAlign(szText.y, fLinePos);
+      UpdateAlign(szText.height, fLinePos);
   } else if (m_pTextDataNode) {
     iBlock *= 2;
     if (iBlock < iCount - 2)
@@ -476,7 +475,7 @@
       for (; pXMLNode;
            pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling)) {
         if (!LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle,
-                          true)) {
+                          true, nullptr)) {
           break;
         }
       }
@@ -495,7 +494,7 @@
         for (; pXMLNode;
              pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling)) {
           if (!LoadRichText(pXMLNode, szText, fLinePos,
-                            m_pLoader->m_pParentStyle, true)) {
+                            m_pLoader->m_pParentStyle, true, nullptr)) {
             break;
           }
         }
@@ -654,10 +653,9 @@
       if (!m_textParser.IsParsed())
         m_textParser.DoParse(pXMLContainer, m_pTextProvider);
 
-      CFDE_CSSComputedStyle* pRootStyle =
-          m_textParser.CreateRootStyle(m_pTextProvider);
-      LoadRichText(pXMLContainer, szText, fLinePos, pRootStyle, bSavePieces);
-      pRootStyle->Release();
+      auto pRootStyle = m_textParser.CreateRootStyle(m_pTextProvider);
+      LoadRichText(pXMLContainer, szText, fLinePos, pRootStyle, bSavePieces,
+                   nullptr);
     }
   } else {
     LoadText(m_pTextDataNode, szText, fLinePos, bSavePieces);
@@ -669,7 +667,7 @@
                                const CFX_SizeF& szText,
                                FX_FLOAT& fLinePos,
                                bool bSavePieces) {
-  InitBreak(szText.x);
+  InitBreak(szText.width);
 
   CXFA_Para para = m_pTextProvider->GetParaNode();
   FX_FLOAT fSpaceAbove = 0;
@@ -695,18 +693,19 @@
   if (bRet && m_pLoader)
     m_pLoader->m_pNode = pNode;
   else
-    EndBreak(FX_RTFBREAK_ParagraphBreak, fLinePos, bSavePieces);
+    EndBreak(CFX_RTFBreakType::Paragraph, fLinePos, bSavePieces);
 }
 
-bool CXFA_TextLayout::LoadRichText(CFDE_XMLNode* pXMLNode,
-                                   const CFX_SizeF& szText,
-                                   FX_FLOAT& fLinePos,
-                                   CFDE_CSSComputedStyle* pParentStyle,
-                                   bool bSavePieces,
-                                   CXFA_LinkUserData* pLinkData,
-                                   bool bEndBreak,
-                                   bool bIsOl,
-                                   int32_t iLiCount) {
+bool CXFA_TextLayout::LoadRichText(
+    CFDE_XMLNode* pXMLNode,
+    const CFX_SizeF& szText,
+    FX_FLOAT& fLinePos,
+    const CFX_RetainPtr<CFDE_CSSComputedStyle>& pParentStyle,
+    bool bSavePieces,
+    CFX_RetainPtr<CXFA_LinkUserData> pLinkData,
+    bool bEndBreak,
+    bool bIsOl,
+    int32_t iLiCount) {
   if (!pXMLNode)
     return false;
 
@@ -715,7 +714,7 @@
   FDE_CSSDisplay eDisplay = FDE_CSSDisplay::None;
   bool bContentNode = false;
   FX_FLOAT fSpaceBelow = 0;
-  CFDE_CSSComputedStyle* pStyle = nullptr;
+  CFX_RetainPtr<CFDE_CSSComputedStyle> pStyle;
   CFX_WideString wsName;
   if (bEndBreak) {
     bool bCurOl = false;
@@ -732,7 +731,7 @@
         pElement = static_cast<CFDE_XMLElement*>(pXMLNode);
         pElement->GetLocalTagName(wsName);
       }
-      if (wsName == FX_WSTRC(L"ol")) {
+      if (wsName == L"ol") {
         bIsOl = true;
         bCurOl = true;
       }
@@ -744,15 +743,14 @@
           return true;
         }
 
-        pStyle = m_textParser.ComputeStyle(pXMLNode, pParentStyle);
-        InitBreak(bContentNode ? pParentStyle : pStyle, eDisplay, szText.x,
-                  pXMLNode, pParentStyle);
+        pStyle = m_textParser.ComputeStyle(pXMLNode, pParentStyle.Get());
+        InitBreak(bContentNode ? pParentStyle.Get() : pStyle.Get(), eDisplay,
+                  szText.width, pXMLNode, pParentStyle.Get());
         if ((eDisplay == FDE_CSSDisplay::Block ||
              eDisplay == FDE_CSSDisplay::ListItem) &&
             pStyle &&
-            (wsName.IsEmpty() ||
-             (wsName != FX_WSTRC(L"body") && wsName != FX_WSTRC(L"html") &&
-              wsName != FX_WSTRC(L"ol") && wsName != FX_WSTRC(L"ul")))) {
+            (wsName.IsEmpty() || (wsName != L"body" && wsName != L"html" &&
+                                  wsName != L"ol" && wsName != L"ul"))) {
           const FDE_CSSRect* pRect = pStyle->GetMarginWidth();
           if (pRect) {
             fLinePos += pRect->top.GetValue();
@@ -760,32 +758,32 @@
           }
         }
 
-        if (wsName == FX_WSTRC(L"a")) {
+        if (wsName == L"a") {
           CFX_WideString wsLinkContent;
           ASSERT(pElement);
           pElement->GetString(L"href", wsLinkContent);
           if (!wsLinkContent.IsEmpty()) {
-            pLinkData = new CXFA_LinkUserData(
+            pLinkData = pdfium::MakeRetain<CXFA_LinkUserData>(
                 wsLinkContent.GetBuffer(wsLinkContent.GetLength()));
             wsLinkContent.ReleaseBuffer(wsLinkContent.GetLength());
           }
         }
 
-        int32_t iTabCount =
-            m_textParser.CountTabs(bContentNode ? pParentStyle : pStyle);
-        bool bSpaceRun =
-            m_textParser.IsSpaceRun(bContentNode ? pParentStyle : pStyle);
+        int32_t iTabCount = m_textParser.CountTabs(
+            bContentNode ? pParentStyle.Get() : pStyle.Get());
+        bool bSpaceRun = m_textParser.IsSpaceRun(
+            bContentNode ? pParentStyle.Get() : pStyle.Get());
         CFX_WideString wsText;
         if (bContentNode && iTabCount == 0) {
           static_cast<CFDE_XMLText*>(pXMLNode)->GetText(wsText);
-        } else if (wsName == FX_WSTRC(L"br")) {
+        } else if (wsName == L"br") {
           wsText = L'\n';
-        } else if (wsName == FX_WSTRC(L"li")) {
+        } else if (wsName == L"li") {
           bCurLi = true;
           if (bIsOl)
             wsText.Format(L"%d.  ", iLiCount);
           else
-            wsText = 0x00B7 + FX_WSTRC(L"  ");
+            wsText = 0x00B7 + CFX_WideStringC(L"  ", 1);
         } else if (!bContentNode) {
           if (iTabCount > 0) {
             while (iTabCount-- > 0)
@@ -819,10 +817,7 @@
 
         if (wsText.GetLength() > 0) {
           if (!m_pLoader || m_pLoader->m_iChar == 0) {
-            if (pLinkData)
-              pLinkData->Retain();
-
-            CXFA_TextUserData* pUserData = new CXFA_TextUserData(
+            auto pUserData = pdfium::MakeRetain<CXFA_TextUserData>(
                 bContentNode ? pParentStyle : pStyle, pLinkData);
             m_pBreak->SetUserData(pUserData);
           }
@@ -835,8 +830,6 @@
                 m_pLoader->m_pXMLNode = pXMLNode;
                 m_pLoader->m_pParentStyle = pParentStyle;
               }
-              if (pStyle)
-                pStyle->Release();
               return false;
             }
             return true;
@@ -863,7 +856,7 @@
         m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
     }
     if (bCurLi)
-      EndBreak(FX_RTFBREAK_LineBreak, fLinePos, bSavePieces);
+      EndBreak(CFX_RTFBreakType::Line, fLinePos, bSavePieces);
   } else {
     if (pContext)
       eDisplay = pContext->GetDisplay();
@@ -871,25 +864,16 @@
 
   if (m_bBlockContinue) {
     if (pContext && !bContentNode) {
-      uint32_t dwStatus = (eDisplay == FDE_CSSDisplay::Block)
-                              ? FX_RTFBREAK_ParagraphBreak
-                              : FX_RTFBREAK_PieceBreak;
+      CFX_RTFBreakType dwStatus = (eDisplay == FDE_CSSDisplay::Block)
+                                      ? CFX_RTFBreakType::Paragraph
+                                      : CFX_RTFBreakType::Piece;
       EndBreak(dwStatus, fLinePos, bSavePieces);
       if (eDisplay == FDE_CSSDisplay::Block) {
         fLinePos += fSpaceBelow;
         if (m_pTabstopContext)
           m_pTabstopContext->RemoveAll();
       }
-      if (wsName == FX_WSTRC(L"a")) {
-        if (pLinkData) {
-          pLinkData->Release();
-          pLinkData = nullptr;
-        }
-      }
       if (IsEnd(bSavePieces)) {
-        if (pStyle)
-          pStyle->Release();
-
         if (m_pLoader && m_pLoader->m_iTotalLines > -1) {
           m_pLoader->m_pXMLNode =
               pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling);
@@ -899,9 +883,6 @@
       }
     }
   }
-  if (pStyle)
-    pStyle->Release();
-
   return true;
 }
 
@@ -909,7 +890,7 @@
                                  FX_FLOAT& fLinePos,
                                  FX_FLOAT fSpaceAbove,
                                  bool bSavePieces) {
-  uint32_t dwStatus = 0;
+  CFX_RTFBreakType dwStatus = CFX_RTFBreakType::None;
   int32_t iChar = 0;
   if (m_pLoader)
     iChar = m_pLoader->m_iChar;
@@ -920,14 +901,16 @@
     if (wch == 0xA0)
       wch = 0x20;
 
-    if ((dwStatus = m_pBreak->AppendChar(wch)) > FX_RTFBREAK_PieceBreak) {
+    dwStatus = m_pBreak->AppendChar(wch);
+    if (dwStatus != CFX_RTFBreakType::None &&
+        dwStatus != CFX_RTFBreakType::Piece) {
       AppendTextLine(dwStatus, fLinePos, bSavePieces);
       if (IsEnd(bSavePieces)) {
         if (m_pLoader)
           m_pLoader->m_iChar = i;
         return true;
       }
-      if (dwStatus == FX_RTFBREAK_ParagraphBreak && m_bRichText)
+      if (dwStatus == CFX_RTFBreakType::Paragraph && m_bRichText)
         fLinePos += fSpaceAbove;
     }
   }
@@ -967,11 +950,11 @@
   wsText = wsText.Left(iTrimLeft);
 }
 
-void CXFA_TextLayout::EndBreak(uint32_t dwStatus,
+void CXFA_TextLayout::EndBreak(CFX_RTFBreakType dwStatus,
                                FX_FLOAT& fLinePos,
                                bool bSavePieces) {
   dwStatus = m_pBreak->EndBreak(dwStatus);
-  if (dwStatus > FX_RTFBREAK_PieceBreak)
+  if (dwStatus != CFX_RTFBreakType::None && dwStatus != CFX_RTFBreakType::Piece)
     AppendTextLine(dwStatus, fLinePos, bSavePieces, true);
 }
 
@@ -1016,10 +999,10 @@
       } else if (dwAlign == FX_HashCode_GetW(L"decimal", false)) {
         int32_t iChars = pPiece->iChars;
         for (int32_t i = 0; i < iChars; i++) {
-          if (pPiece->pszText[i] == L'.')
+          if (pPiece->szText[i] == L'.')
             break;
 
-          fLeft += pPiece->pWidths[i] / 20000.0f;
+          fLeft += pPiece->Widths[i] / 20000.0f;
         }
       }
       m_pTabstopContext->m_fLeft =
@@ -1031,7 +1014,7 @@
   }
 }
 
-void CXFA_TextLayout::AppendTextLine(uint32_t dwStatus,
+void CXFA_TextLayout::AppendTextLine(CFX_RTFBreakType dwStatus,
                                      FX_FLOAT& fLinePos,
                                      bool bSavePieces,
                                      bool bEndBreak) {
@@ -1039,7 +1022,7 @@
   if (iPieces < 1)
     return;
 
-  CFDE_CSSComputedStyle* pStyle = nullptr;
+  CFX_RetainPtr<CFDE_CSSComputedStyle> pStyle;
   if (bSavePieces) {
     auto pNew = pdfium::MakeUnique<CXFA_PieceLine>();
     CXFA_PieceLine* pPieceLine = pNew.get();
@@ -1051,35 +1034,35 @@
     int32_t i = 0;
     for (i = 0; i < iPieces; i++) {
       const CFX_RTFPiece* pPiece = m_pBreak->GetBreakPiece(i);
-      CXFA_TextUserData* pUserData = (CXFA_TextUserData*)pPiece->m_pUserData;
+      CXFA_TextUserData* pUserData =
+          static_cast<CXFA_TextUserData*>(pPiece->m_pUserData.Get());
       if (pUserData)
         pStyle = pUserData->m_pStyle;
       FX_FLOAT fVerScale = pPiece->m_iVerticalScale / 100.0f;
 
       auto pTP = pdfium::MakeUnique<XFA_TextPiece>();
-      pTP->pszText = FX_Alloc(FX_WCHAR, pPiece->m_iChars);
-      pTP->pWidths = FX_Alloc(int32_t, pPiece->m_iChars);
       pTP->iChars = pPiece->m_iChars;
-      pPiece->GetString(pTP->pszText);
-      pPiece->GetWidths(pTP->pWidths);
+      pTP->szText = pPiece->GetString();
+      pTP->Widths = pPiece->GetWidths();
       pTP->iBidiLevel = pPiece->m_iBidiLevel;
       pTP->iHorScale = pPiece->m_iHorizontalScale;
       pTP->iVerScale = pPiece->m_iVerticalScale;
-      m_textParser.GetUnderline(m_pTextProvider, pStyle, pTP->iUnderline,
+      m_textParser.GetUnderline(m_pTextProvider, pStyle.Get(), pTP->iUnderline,
                                 pTP->iPeriod);
-      m_textParser.GetLinethrough(m_pTextProvider, pStyle, pTP->iLineThrough);
-      pTP->dwColor = m_textParser.GetColor(m_pTextProvider, pStyle);
-      pTP->pFont = m_textParser.GetFont(m_pTextProvider, pStyle);
-      pTP->fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle);
+      m_textParser.GetLinethrough(m_pTextProvider, pStyle.Get(),
+                                  pTP->iLineThrough);
+      pTP->dwColor = m_textParser.GetColor(m_pTextProvider, pStyle.Get());
+      pTP->pFont = m_textParser.GetFont(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 = (FX_FLOAT)pPiece->m_iFontSize * fVerScale / 20.0f;
       FX_FLOAT fBaseLineTemp =
-          m_textParser.GetBaseline(m_pTextProvider, pStyle);
+          m_textParser.GetBaseline(m_pTextProvider, pStyle.Get());
       pTP->rtPiece.top = fBaseLineTemp;
 
       FX_FLOAT fLineHeight = m_textParser.GetLineHeight(
-          m_pTextProvider, pStyle, m_iLines == 0, fVerScale);
+          m_pTextProvider, pStyle.Get(), m_iLines == 0, fVerScale);
       if (fBaseLineTemp > 0) {
         FX_FLOAT fLineHeightTmp = fBaseLineTemp + pTP->rtPiece.height;
         if (fLineHeight < fLineHeightTmp)
@@ -1090,14 +1073,9 @@
         fBaseLine = -fBaseLineTemp;
       }
       fLineStep = std::max(fLineStep, fLineHeight);
-      if (pUserData && pUserData->m_pLinkData) {
-        pUserData->m_pLinkData->Retain();
-        pTP->pLinkData = pUserData->m_pLinkData;
-      } else {
-        pTP->pLinkData = nullptr;
-      }
+      pTP->pLinkData = pUserData ? pUserData->m_pLinkData : nullptr;
       pPieceLine->m_textPieces.push_back(std::move(pTP));
-      DoTabstops(pStyle, pPieceLine);
+      DoTabstops(pStyle.Get(), pPieceLine);
     }
     for (const auto& pTP : pPieceLine->m_textPieces) {
       FX_FLOAT& fTop = pTP->rtPiece.top;
@@ -1111,13 +1089,15 @@
     FX_FLOAT fLineWidth = 0;
     for (int32_t i = 0; i < iPieces; i++) {
       const CFX_RTFPiece* pPiece = m_pBreak->GetBreakPiece(i);
-      CXFA_TextUserData* pUserData = (CXFA_TextUserData*)pPiece->m_pUserData;
+      CXFA_TextUserData* pUserData =
+          static_cast<CXFA_TextUserData*>(pPiece->m_pUserData.Get());
       if (pUserData)
         pStyle = pUserData->m_pStyle;
       FX_FLOAT fVerScale = pPiece->m_iVerticalScale / 100.0f;
-      FX_FLOAT fBaseLine = m_textParser.GetBaseline(m_pTextProvider, pStyle);
+      FX_FLOAT fBaseLine =
+          m_textParser.GetBaseline(m_pTextProvider, pStyle.Get());
       FX_FLOAT fLineHeight = m_textParser.GetLineHeight(
-          m_pTextProvider, pStyle, m_iLines == 0, fVerScale);
+          m_pTextProvider, pStyle.Get(), m_iLines == 0, fVerScale);
       if (fBaseLine > 0) {
         FX_FLOAT fLineHeightTmp =
             fBaseLine + (FX_FLOAT)pPiece->m_iFontSize * fVerScale / 20.0f;
@@ -1136,11 +1116,9 @@
       m_pLoader->m_lineHeights.Add(fHeight);
     }
   }
-  if (pStyle)
-    pStyle->Retain();
 
   m_pBreak->ClearBreakPieces();
-  if (dwStatus == FX_RTFBREAK_ParagraphBreak) {
+  if (dwStatus == CFX_RTFBreakType::Paragraph) {
     m_pBreak->Reset();
     if (!pStyle && bEndBreak) {
       CXFA_Para para = m_pTextProvider->GetParaNode();
@@ -1171,7 +1149,6 @@
       fStart -= fTextIndent;
 
     m_pBreak->SetLineStartPos(fStart);
-    pStyle->Release();
   }
   m_iLines++;
 }
@@ -1209,11 +1186,11 @@
   int32_t iChars = GetDisplayPos(pPiece, pCharPos);
   if (iChars > 0) {
     CFX_PointF pt1, pt2;
-    FX_FLOAT fEndY = pCharPos[0].m_OriginY + 1.05f;
+    FX_FLOAT fEndY = pCharPos[0].m_Origin.y + 1.05f;
     if (pPiece->iPeriod == XFA_ATTRIBUTEENUM_Word) {
       for (int32_t i = 0; i < pPiece->iUnderline; i++) {
         for (int32_t j = 0; j < iChars; j++) {
-          pt1.x = pCharPos[j].m_OriginX;
+          pt1.x = pCharPos[j].m_Origin.x;
           pt2.x =
               pt1.x + pCharPos[j].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
           pt1.y = pt2.y = fEndY;
@@ -1222,9 +1199,9 @@
         fEndY += 2.0f;
       }
     } else {
-      pt1.x = pCharPos[0].m_OriginX;
+      pt1.x = pCharPos[0].m_Origin.x;
       pt2.x =
-          pCharPos[iChars - 1].m_OriginX +
+          pCharPos[iChars - 1].m_Origin.x +
           pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
       for (int32_t i = 0; i < pPiece->iUnderline; i++) {
         pt1.y = pt2.y = fEndY;
@@ -1232,9 +1209,9 @@
         fEndY += 2.0f;
       }
     }
-    fEndY = pCharPos[0].m_OriginY - pPiece->rtPiece.height * 0.25f;
-    pt1.x = pCharPos[0].m_OriginX;
-    pt2.x = pCharPos[iChars - 1].m_OriginX +
+    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;
     for (int32_t i = 0; i < pPiece->iLineThrough; i++) {
       pt1.y = pt2.y = fEndY;
@@ -1275,25 +1252,29 @@
     if (iChars < 1)
       return;
 
-    fOrgX = pCharPos[iChars - 1].m_OriginX +
+    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)
       return;
 
-    fEndX = pCharPos[0].m_OriginX;
-    CFX_PointF pt1, pt2;
-    pt1.x = fOrgX, pt2.x = fEndX;
-    FX_FLOAT fEndY = pCharPos[0].m_OriginY + 1.05f;
+    fEndX = pCharPos[0].m_Origin.x;
+    CFX_PointF pt1;
+    CFX_PointF pt2;
+    pt1.x = fOrgX;
+    pt2.x = fEndX;
+    FX_FLOAT fEndY = pCharPos[0].m_Origin.y + 1.05f;
     for (int32_t i = 0; i < pPiece->iUnderline; i++) {
-      pt1.y = pt2.y = fEndY;
+      pt1.y = fEndY;
+      pt2.y = fEndY;
       pPath->AddLine(pt1, pt2);
       fEndY += 2.0f;
     }
-    fEndY = pCharPos[0].m_OriginY - 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 = pt2.y = fEndY;
+      pt1.y = fEndY;
+      pt2.y = fEndY;
       pPath->AddLine(pt1, pt2);
       fEndY += 2.0f;
     }
@@ -1318,17 +1299,15 @@
   if (iLength < 1)
     return false;
 
-  tr->pStr = pPiece->pszText;
+  tr->pStr = pPiece->szText;
   tr->pFont = pPiece->pFont;
   tr->pRect = &pPiece->rtPiece;
-  tr->pWidths = pPiece->pWidths;
+  tr->pWidths = pPiece->Widths;
   tr->iLength = iLength;
   tr->fFontSize = pPiece->fFontSize;
   tr->iBidiLevel = pPiece->iBidiLevel;
-  tr->iCharRotation = 0;
   tr->wLineBreakChar = L'\n';
   tr->iVerticalScale = pPiece->iVerScale;
-  tr->dwLayoutStyles = FX_RTFLAYOUTSTYLE_ExpandTab;
   tr->iHorizontalScale = pPiece->iHorScale;
   return true;
 }
diff --git a/xfa/fxfa/app/cxfa_textlayout.h b/xfa/fxfa/app/cxfa_textlayout.h
index 4de53d1..d4d60cf 100644
--- a/xfa/fxfa/app/cxfa_textlayout.h
+++ b/xfa/fxfa/app/cxfa_textlayout.h
@@ -60,12 +60,12 @@
   }
 
   bool m_bHasBlock;
-  CFX_Int32Array m_Blocks;
+  CFX_ArrayTemplate<int32_t> m_Blocks;
 
  private:
   void GetTextDataNode();
   CFDE_XMLNode* GetXMLContainerNode();
-  CFX_RTFBreak* CreateBreak(bool bDefault);
+  std::unique_ptr<CFX_RTFBreak> CreateBreak(bool bDefault);
   void InitBreak(FX_FLOAT fLineWidth);
   void InitBreak(CFDE_CSSComputedStyle* pStyle,
                  FDE_CSSDisplay eDisplay,
@@ -82,9 +82,9 @@
   bool LoadRichText(CFDE_XMLNode* pXMLNode,
                     const CFX_SizeF& szText,
                     FX_FLOAT& fLinePos,
-                    CFDE_CSSComputedStyle* pParentStyle,
+                    const CFX_RetainPtr<CFDE_CSSComputedStyle>& pParentStyle,
                     bool bSavePieces,
-                    CXFA_LinkUserData* pLinkData = nullptr,
+                    CFX_RetainPtr<CXFA_LinkUserData> pLinkData,
                     bool bEndBreak = true,
                     bool bIsOl = false,
                     int32_t iLiCount = 0);
@@ -92,11 +92,11 @@
                   FX_FLOAT& fLinePos,
                   FX_FLOAT fSpaceAbove,
                   bool bSavePieces);
-  void AppendTextLine(uint32_t dwStatus,
+  void AppendTextLine(CFX_RTFBreakType dwStatus,
                       FX_FLOAT& fLinePos,
                       bool bSavePieces,
                       bool bEndBreak = false);
-  void EndBreak(uint32_t dwStatus, FX_FLOAT& fLinePos, bool bDefault);
+  void EndBreak(CFX_RTFBreakType dwStatus, FX_FLOAT& fLinePos, bool bDefault);
   bool IsEnd(bool bSavePieces);
   void ProcessText(CFX_WideString& wsText);
   void UpdateAlign(FX_FLOAT fHeight, FX_FLOAT fBottom);
diff --git a/xfa/fxfa/app/cxfa_textparsecontext.cpp b/xfa/fxfa/app/cxfa_textparsecontext.cpp
index c0c226c..851d844 100644
--- a/xfa/fxfa/app/cxfa_textparsecontext.cpp
+++ b/xfa/fxfa/app/cxfa_textparsecontext.cpp
@@ -12,23 +12,6 @@
 
 CXFA_TextParseContext::CXFA_TextParseContext()
     : m_pParentStyle(nullptr),
-      m_ppMatchedDecls(nullptr),
-      m_dwMatchedDecls(0),
       m_eDisplay(FDE_CSSDisplay::None) {}
 
-CXFA_TextParseContext::~CXFA_TextParseContext() {
-  if (m_pParentStyle)
-    m_pParentStyle->Release();
-  FX_Free(m_ppMatchedDecls);
-}
-
-void CXFA_TextParseContext::SetDecls(const CFDE_CSSDeclaration** ppDeclArray,
-                                     int32_t iDeclCount) {
-  if (iDeclCount <= 0 || !ppDeclArray)
-    return;
-
-  m_dwMatchedDecls = iDeclCount;
-  m_ppMatchedDecls = FX_Alloc(CFDE_CSSDeclaration*, iDeclCount);
-  FXSYS_memcpy(m_ppMatchedDecls, ppDeclArray,
-               iDeclCount * sizeof(CFDE_CSSDeclaration*));
-}
+CXFA_TextParseContext::~CXFA_TextParseContext() {}
diff --git a/xfa/fxfa/app/cxfa_textparsecontext.h b/xfa/fxfa/app/cxfa_textparsecontext.h
index 2faaadb..5ea68e9 100644
--- a/xfa/fxfa/app/cxfa_textparsecontext.h
+++ b/xfa/fxfa/app/cxfa_textparsecontext.h
@@ -7,9 +7,13 @@
 #ifndef XFA_FXFA_APP_CXFA_TEXTPARSECONTEXT_H_
 #define XFA_FXFA_APP_CXFA_TEXTPARSECONTEXT_H_
 
+#include <utility>
+#include <vector>
+
+#include "third_party/base/stl_util.h"
+#include "xfa/fde/css/cfde_cssdeclaration.h"
 #include "xfa/fde/css/fde_css.h"
 
-class CFDE_CSSDeclaration;
 class CFDE_CSSComputedStyle;
 
 class CXFA_TextParseContext {
@@ -20,17 +24,15 @@
   void SetDisplay(FDE_CSSDisplay eDisplay) { m_eDisplay = eDisplay; }
   FDE_CSSDisplay GetDisplay() const { return m_eDisplay; }
 
-  void SetDecls(const CFDE_CSSDeclaration** ppDeclArray, int32_t iDeclCount);
-  const CFDE_CSSDeclaration** GetDecls() {
-    return const_cast<const CFDE_CSSDeclaration**>(m_ppMatchedDecls);
+  void SetDecls(std::vector<const CFDE_CSSDeclaration*>&& decl) {
+    decls_ = std::move(decl);
   }
-  uint32_t CountDecls() const { return m_dwMatchedDecls; }
+  const std::vector<const CFDE_CSSDeclaration*>& GetDecls() { return decls_; }
 
-  CFDE_CSSComputedStyle* m_pParentStyle;
+  CFX_RetainPtr<CFDE_CSSComputedStyle> m_pParentStyle;
 
  protected:
-  CFDE_CSSDeclaration** m_ppMatchedDecls;
-  uint32_t m_dwMatchedDecls;
+  std::vector<const CFDE_CSSDeclaration*> decls_;
   FDE_CSSDisplay m_eDisplay;
 };
 
diff --git a/xfa/fxfa/app/cxfa_textparser.cpp b/xfa/fxfa/app/cxfa_textparser.cpp
index 9920f6e..9759cb2 100644
--- a/xfa/fxfa/app/cxfa_textparser.cpp
+++ b/xfa/fxfa/app/cxfa_textparser.cpp
@@ -7,9 +7,10 @@
 #include "xfa/fxfa/app/cxfa_textparser.h"
 
 #include <algorithm>
+#include <utility>
+#include <vector>
 
 #include "third_party/base/ptr_util.h"
-#include "xfa/fde/css/cfde_cssaccelerator.h"
 #include "xfa/fde/css/cfde_csscomputedstyle.h"
 #include "xfa/fde/css/cfde_cssstyleselector.h"
 #include "xfa/fde/css/cfde_cssstylesheet.h"
@@ -39,12 +40,10 @@
 
 }  // namespace
 
-CXFA_TextParser::CXFA_TextParser() : m_pUASheet(nullptr), m_bParsed(false) {}
+CXFA_TextParser::CXFA_TextParser()
+    : m_bParsed(false), m_cssInitialized(false) {}
 
 CXFA_TextParser::~CXFA_TextParser() {
-  if (m_pUASheet)
-    m_pUASheet->Release();
-
   for (auto& pair : m_mapXMLNodeToParseContext) {
     if (pair.second)
       delete pair.second;
@@ -76,37 +75,37 @@
     m_pSelector->SetDefFontSize(fFontSize);
   }
 
-  if (!m_pUASheet) {
-    m_pUASheet = LoadDefaultSheetStyle();
-    m_pSelector->SetStyleSheet(FDE_CSSStyleSheetGroup::UserAgent, m_pUASheet);
-    m_pSelector->UpdateStyleIndex(FDE_CSSMEDIATYPE_ALL);
-  }
+  if (m_cssInitialized)
+    return;
+
+  m_cssInitialized = true;
+  auto uaSheet = LoadDefaultSheetStyle();
+  m_pSelector->SetUAStyleSheet(std::move(uaSheet));
+  m_pSelector->UpdateStyleIndex();
 }
 
-CFDE_CSSStyleSheet* CXFA_TextParser::LoadDefaultSheetStyle() {
+std::unique_ptr<CFDE_CSSStyleSheet> CXFA_TextParser::LoadDefaultSheetStyle() {
   static const FX_WCHAR s_pStyle[] =
       L"html,body,ol,p,ul{display:block}"
       L"li{display:list-item}"
-      L"ol,ul{padding-left:33px}ol{list-style-type:decimal}ol,ul{margin-top:0;"
-      L"margin-bottom:0}ul,ol{margin:1.12em 0}"
-      L"a{color:#0000ff;text-decoration:underline}b{font-weight:bolder}i{font-"
-      L"style:italic}"
-      L"sup{vertical-align:+15em;font-size:.66em}sub{vertical-align:-15em;font-"
-      L"size:.66em}";
+      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}";
 
-  CFDE_CSSStyleSheet* pStyleSheet = new CFDE_CSSStyleSheet();
-  if (!pStyleSheet->LoadFromBuffer(s_pStyle, FXSYS_wcslen(s_pStyle))) {
-    pStyleSheet->Release();
-    pStyleSheet = nullptr;
-  }
-  return pStyleSheet;
+  auto sheet = pdfium::MakeUnique<CFDE_CSSStyleSheet>();
+  return sheet->LoadBuffer(s_pStyle, FXSYS_wcslen(s_pStyle)) ? std::move(sheet)
+                                                             : nullptr;
 }
 
-CFDE_CSSComputedStyle* CXFA_TextParser::CreateRootStyle(
+CFX_RetainPtr<CFDE_CSSComputedStyle> CXFA_TextParser::CreateRootStyle(
     CXFA_TextProvider* pTextProvider) {
   CXFA_Font font = pTextProvider->GetFontNode();
   CXFA_Para para = pTextProvider->GetParaNode();
-  CFDE_CSSComputedStyle* pStyle = m_pSelector->CreateComputedStyle(nullptr);
+  auto pStyle = m_pSelector->CreateComputedStyle(nullptr);
   FX_FLOAT fLineHeight = 0;
   FX_FLOAT fFontSize = 10;
 
@@ -164,10 +163,9 @@
   return pStyle;
 }
 
-CFDE_CSSComputedStyle* CXFA_TextParser::CreateStyle(
+CFX_RetainPtr<CFDE_CSSComputedStyle> CXFA_TextParser::CreateStyle(
     CFDE_CSSComputedStyle* pParentStyle) {
-  CFDE_CSSComputedStyle* pNewStyle =
-      m_pSelector->CreateComputedStyle(pParentStyle);
+  auto pNewStyle = m_pSelector->CreateComputedStyle(pParentStyle);
   ASSERT(pNewStyle);
   if (!pParentStyle)
     return pNewStyle;
@@ -186,7 +184,7 @@
   return pNewStyle;
 }
 
-CFDE_CSSComputedStyle* CXFA_TextParser::ComputeStyle(
+CFX_RetainPtr<CFDE_CSSComputedStyle> CXFA_TextParser::ComputeStyle(
     CFDE_XMLNode* pXMLNode,
     CFDE_CSSComputedStyle* pParentStyle) {
   auto it = m_mapXMLNodeToParseContext.find(pXMLNode);
@@ -197,20 +195,16 @@
   if (!pContext)
     return nullptr;
 
-  pContext->m_pParentStyle = pParentStyle;
-  pParentStyle->Retain();
+  pContext->m_pParentStyle.Reset(pParentStyle);
 
-  CXFA_CSSTagProvider tagProvider;
-  ParseTagInfo(pXMLNode, tagProvider);
-  if (tagProvider.m_bContent)
+  auto tagProvider = ParseTagInfo(pXMLNode);
+  if (tagProvider->m_bContent)
     return nullptr;
 
-  CFDE_CSSComputedStyle* pStyle = CreateStyle(pParentStyle);
-  CFDE_CSSAccelerator* pCSSAccel = m_pSelector->InitAccelerator();
-  pCSSAccel->OnEnterTag(&tagProvider);
-  m_pSelector->ComputeStyle(&tagProvider, pContext->GetDecls(),
-                            pContext->CountDecls(), pStyle);
-  pCSSAccel->OnLeaveTag(&tagProvider);
+  auto pStyle = CreateStyle(pParentStyle);
+  m_pSelector->ComputeStyle(pContext->GetDecls(),
+                            tagProvider->GetAttribute(L"style"),
+                            tagProvider->GetAttribute(L"align"), pStyle.Get());
   return pStyle;
 }
 
@@ -221,9 +215,8 @@
 
   m_bParsed = true;
   InitCSSData(pTextProvider);
-  CFDE_CSSComputedStyle* pRootStyle = CreateRootStyle(pTextProvider);
-  ParseRichText(pXMLContainer, pRootStyle);
-  pRootStyle->Release();
+  auto pRootStyle = CreateRootStyle(pTextProvider);
+  ParseRichText(pXMLContainer, pRootStyle.Get());
 }
 
 void CXFA_TextParser::ParseRichText(CFDE_XMLNode* pXMLNode,
@@ -231,30 +224,25 @@
   if (!pXMLNode)
     return;
 
-  CXFA_CSSTagProvider tagProvider;
-  ParseTagInfo(pXMLNode, tagProvider);
-  if (!tagProvider.m_bTagAvailable)
+  auto tagProvider = ParseTagInfo(pXMLNode);
+  if (!tagProvider->m_bTagAvailable)
     return;
 
-  CFDE_CSSComputedStyle* pNewStyle = nullptr;
-  if ((tagProvider.GetTagName() != FX_WSTRC(L"body")) ||
-      (tagProvider.GetTagName() != FX_WSTRC(L"html"))) {
+  CFX_RetainPtr<CFDE_CSSComputedStyle> pNewStyle;
+  if ((tagProvider->GetTagName() != L"body") ||
+      (tagProvider->GetTagName() != L"html")) {
     CXFA_TextParseContext* pTextContext = new CXFA_TextParseContext;
     FDE_CSSDisplay eDisplay = FDE_CSSDisplay::Inline;
-    if (!tagProvider.m_bContent) {
+    if (!tagProvider->m_bContent) {
+      auto declArray =
+          m_pSelector->MatchDeclarations(tagProvider->GetTagName());
       pNewStyle = CreateStyle(pParentStyle);
-      CFDE_CSSAccelerator* pCSSAccel = m_pSelector->InitAccelerator();
-      pCSSAccel->OnEnterTag(&tagProvider);
-      CFX_ArrayTemplate<CFDE_CSSDeclaration*> DeclArray;
-      int32_t iMatchedDecls =
-          m_pSelector->MatchDeclarations(&tagProvider, DeclArray);
-      const CFDE_CSSDeclaration** ppMatchDecls =
-          const_cast<const CFDE_CSSDeclaration**>(DeclArray.GetData());
-      m_pSelector->ComputeStyle(&tagProvider, ppMatchDecls, iMatchedDecls,
-                                pNewStyle);
-      pCSSAccel->OnLeaveTag(&tagProvider);
-      if (iMatchedDecls > 0)
-        pTextContext->SetDecls(ppMatchDecls, iMatchedDecls);
+      m_pSelector->ComputeStyle(declArray, tagProvider->GetAttribute(L"style"),
+                                tagProvider->GetAttribute(L"align"),
+                                pNewStyle.Get());
+
+      if (!declArray.empty())
+        pTextContext->SetDecls(std::move(declArray));
 
       eDisplay = pNewStyle->GetDisplay();
     }
@@ -266,10 +254,8 @@
            pXMLNode->GetNodeItem(CFDE_XMLNode::FirstChild);
        pXMLChild;
        pXMLChild = pXMLChild->GetNodeItem(CFDE_XMLNode::NextSibling)) {
-    ParseRichText(pXMLChild, pNewStyle);
+    ParseRichText(pXMLChild, pNewStyle.Get());
   }
-  if (pNewStyle)
-    pNewStyle->Release();
 }
 
 bool CXFA_TextParser::TagValidate(const CFX_WideString& wsName) const {
@@ -294,23 +280,26 @@
                             FX_HashCode_GetW(wsName.AsStringC(), true));
 }
 
-void CXFA_TextParser::ParseTagInfo(CFDE_XMLNode* pXMLNode,
-                                   CXFA_CSSTagProvider& tagProvider) {
+std::unique_ptr<CXFA_CSSTagProvider> CXFA_TextParser::ParseTagInfo(
+    CFDE_XMLNode* pXMLNode) {
+  auto tagProvider = pdfium::MakeUnique<CXFA_CSSTagProvider>();
+
   CFX_WideString wsName;
   if (pXMLNode->GetType() == FDE_XMLNODE_Element) {
     CFDE_XMLElement* pXMLElement = static_cast<CFDE_XMLElement*>(pXMLNode);
     pXMLElement->GetLocalTagName(wsName);
-    tagProvider.SetTagNameObj(wsName);
-    tagProvider.m_bTagAvailable = TagValidate(wsName);
+    tagProvider->SetTagName(wsName);
+    tagProvider->m_bTagAvailable = TagValidate(wsName);
 
     CFX_WideString wsValue;
     pXMLElement->GetString(L"style", wsValue);
     if (!wsValue.IsEmpty())
-      tagProvider.SetAttribute(L"style", wsValue);
+      tagProvider->SetAttribute(L"style", wsValue);
   } else if (pXMLNode->GetType() == FDE_XMLNODE_Text) {
-    tagProvider.m_bTagAvailable = true;
-    tagProvider.m_bContent = true;
+    tagProvider->m_bTagAvailable = true;
+    tagProvider->m_bContent = true;
   }
+  return tagProvider;
 }
 
 int32_t CXFA_TextParser::GetVAlign(CXFA_TextProvider* pTextProvider) const {
@@ -320,23 +309,23 @@
 
 FX_FLOAT CXFA_TextParser::GetTabInterval(CFDE_CSSComputedStyle* pStyle) const {
   CFX_WideString wsValue;
-  if (pStyle && pStyle->GetCustomStyle(FX_WSTRC(L"tab-interval"), wsValue))
+  if (pStyle && pStyle->GetCustomStyle(L"tab-interval", wsValue))
     return CXFA_Measurement(wsValue.AsStringC()).ToUnit(XFA_UNIT_Pt);
   return 36;
 }
 
 int32_t CXFA_TextParser::CountTabs(CFDE_CSSComputedStyle* pStyle) const {
   CFX_WideString wsValue;
-  if (pStyle && pStyle->GetCustomStyle(FX_WSTRC(L"xfa-tab-count"), wsValue))
+  if (pStyle && pStyle->GetCustomStyle(L"xfa-tab-count", wsValue))
     return wsValue.GetInteger();
   return 0;
 }
 
 bool CXFA_TextParser::IsSpaceRun(CFDE_CSSComputedStyle* pStyle) const {
   CFX_WideString wsValue;
-  if (pStyle && pStyle->GetCustomStyle(FX_WSTRC(L"xfa-spacerun"), wsValue)) {
+  if (pStyle && pStyle->GetCustomStyle(L"xfa-spacerun", wsValue)) {
     wsValue.MakeLower();
-    return wsValue == FX_WSTRC(L"yes");
+    return wsValue == L"yes";
   }
   return false;
 }
@@ -414,7 +403,7 @@
                                      CFDE_CSSComputedStyle* pStyle) const {
   if (pStyle) {
     CFX_WideString wsValue;
-    if (pStyle->GetCustomStyle(FX_WSTRC(L"xfa-font-vertical-scale"), wsValue))
+    if (pStyle->GetCustomStyle(L"xfa-font-vertical-scale", wsValue))
       return wsValue.GetInteger();
   }
 
@@ -445,8 +434,8 @@
     iUnderline = 1;
 
   CFX_WideString wsValue;
-  if (pStyle->GetCustomStyle(FX_WSTRC(L"underlinePeriod"), wsValue)) {
-    if (wsValue == FX_WSTRC(L"word"))
+  if (pStyle->GetCustomStyle(L"underlinePeriod", wsValue)) {
+    if (wsValue == L"word")
       iPeriod = XFA_ATTRIBUTEENUM_Word;
   } else if (CXFA_Font font = pTextProvider->GetFontNode()) {
     iPeriod = font.GetUnderlinePeriod();
@@ -535,8 +524,8 @@
     else
       ws.MakeLower();
 
-    bool bURI = (ws == FX_WSTRC(L"uri"));
-    if (!bURI && ws != FX_WSTRC(L"som"))
+    bool bURI = (ws == L"uri");
+    if (!bURI && ws != L"som")
       return false;
 
     ws.clear();
@@ -546,8 +535,8 @@
     else
       ws.MakeLower();
 
-    bool bRaw = (ws == FX_WSTRC(L"raw"));
-    if (!bRaw && ws != FX_WSTRC(L"formatted"))
+    bool bRaw = (ws == L"raw");
+    if (!bRaw && ws != L"formatted")
       return false;
 
     bRet = pTextProvider->GetEmbbedObj(bURI, bRaw, wsAttr, wsValue);
@@ -567,8 +556,8 @@
     return false;
 
   CFX_WideString wsValue;
-  if (!pStyle->GetCustomStyle(FX_WSTRC(L"xfa-tab-stops"), wsValue) &&
-      !pStyle->GetCustomStyle(FX_WSTRC(L"tab-stops"), wsValue)) {
+  if (!pStyle->GetCustomStyle(L"xfa-tab-stops", wsValue) &&
+      !pStyle->GetCustomStyle(L"tab-stops", wsValue)) {
     return false;
   }
 
diff --git a/xfa/fxfa/app/cxfa_textparser.h b/xfa/fxfa/app/cxfa_textparser.h
index a0b5ab1..86da502 100644
--- a/xfa/fxfa/app/cxfa_textparser.h
+++ b/xfa/fxfa/app/cxfa_textparser.h
@@ -33,9 +33,11 @@
   void Reset();
   void DoParse(CFDE_XMLNode* pXMLContainer, CXFA_TextProvider* pTextProvider);
 
-  CFDE_CSSComputedStyle* CreateRootStyle(CXFA_TextProvider* pTextProvider);
-  CFDE_CSSComputedStyle* ComputeStyle(CFDE_XMLNode* pXMLNode,
-                                      CFDE_CSSComputedStyle* pParentStyle);
+  CFX_RetainPtr<CFDE_CSSComputedStyle> CreateRootStyle(
+      CXFA_TextProvider* pTextProvider);
+  CFX_RetainPtr<CFDE_CSSComputedStyle> ComputeStyle(
+      CFDE_XMLNode* pXMLNode,
+      CFDE_CSSComputedStyle* pParentStyle);
 
   bool IsParsed() const { return m_bParsed; }
 
@@ -87,14 +89,15 @@
   void InitCSSData(CXFA_TextProvider* pTextProvider);
   void ParseRichText(CFDE_XMLNode* pXMLNode,
                      CFDE_CSSComputedStyle* pParentStyle);
-  void ParseTagInfo(CFDE_XMLNode* pXMLNode, CXFA_CSSTagProvider& tagProvider);
-  CFDE_CSSStyleSheet* LoadDefaultSheetStyle();
-  CFDE_CSSComputedStyle* CreateStyle(CFDE_CSSComputedStyle* pParentStyle);
+  std::unique_ptr<CXFA_CSSTagProvider> ParseTagInfo(CFDE_XMLNode* pXMLNode);
+  std::unique_ptr<CFDE_CSSStyleSheet> LoadDefaultSheetStyle();
+  CFX_RetainPtr<CFDE_CSSComputedStyle> CreateStyle(
+      CFDE_CSSComputedStyle* pParentStyle);
 
   std::unique_ptr<CFDE_CSSStyleSelector> m_pSelector;
-  CFDE_CSSStyleSheet* m_pUASheet;
   std::map<CFDE_XMLNode*, CXFA_TextParseContext*> m_mapXMLNodeToParseContext;
   bool m_bParsed;
+  bool m_cssInitialized;
 };
 
 #endif  // XFA_FXFA_APP_CXFA_TEXTPARSER_H_
diff --git a/xfa/fxfa/app/cxfa_textuserdata.cpp b/xfa/fxfa/app/cxfa_textuserdata.cpp
index 4fdabd6..e4e5493 100644
--- a/xfa/fxfa/app/cxfa_textuserdata.cpp
+++ b/xfa/fxfa/app/cxfa_textuserdata.cpp
@@ -11,33 +11,13 @@
 #include "xfa/fde/css/fde_css.h"
 #include "xfa/fxfa/app/cxfa_linkuserdata.h"
 
-CXFA_TextUserData::CXFA_TextUserData(CFDE_CSSComputedStyle* pStyle)
-    : m_pStyle(pStyle), m_pLinkData(nullptr), m_dwRefCount(0) {
-  if (m_pStyle)
-    m_pStyle->Retain();
-}
+CXFA_TextUserData::CXFA_TextUserData(
+    const CFX_RetainPtr<CFDE_CSSComputedStyle>& pStyle)
+    : m_pStyle(pStyle) {}
 
-CXFA_TextUserData::CXFA_TextUserData(CFDE_CSSComputedStyle* pStyle,
-                                     CXFA_LinkUserData* pLinkData)
-    : m_pStyle(pStyle), m_pLinkData(pLinkData), m_dwRefCount(0) {
-  if (m_pStyle)
-    m_pStyle->Retain();
-}
+CXFA_TextUserData::CXFA_TextUserData(
+    const CFX_RetainPtr<CFDE_CSSComputedStyle>& pStyle,
+    const CFX_RetainPtr<CXFA_LinkUserData>& pLinkData)
+    : m_pStyle(pStyle), m_pLinkData(pLinkData) {}
 
-CXFA_TextUserData::~CXFA_TextUserData() {
-  if (m_pStyle)
-    m_pStyle->Release();
-  if (m_pLinkData)
-    m_pLinkData->Release();
-}
-
-uint32_t CXFA_TextUserData::Retain() {
-  return ++m_dwRefCount;
-}
-
-uint32_t CXFA_TextUserData::Release() {
-  uint32_t dwRefCount = --m_dwRefCount;
-  if (dwRefCount == 0)
-    delete this;
-  return dwRefCount;
-}
+CXFA_TextUserData::~CXFA_TextUserData() {}
diff --git a/xfa/fxfa/app/cxfa_textuserdata.h b/xfa/fxfa/app/cxfa_textuserdata.h
index 83f762d..b0eff73 100644
--- a/xfa/fxfa/app/cxfa_textuserdata.h
+++ b/xfa/fxfa/app/cxfa_textuserdata.h
@@ -7,27 +7,26 @@
 #ifndef XFA_FXFA_APP_CXFA_TEXTUSERDATA_H_
 #define XFA_FXFA_APP_CXFA_TEXTUSERDATA_H_
 
+#include "core/fxcrt/cfx_retain_ptr.h"
 #include "core/fxcrt/fx_basic.h"
 
 class CFDE_CSSComputedStyle;
 class CXFA_LinkUserData;
 
-class CXFA_TextUserData : public IFX_Retainable {
+class CXFA_TextUserData : public CFX_Retainable {
  public:
-  explicit CXFA_TextUserData(CFDE_CSSComputedStyle* pStyle);
-  CXFA_TextUserData(CFDE_CSSComputedStyle* pStyle,
-                    CXFA_LinkUserData* pLinkData);
-  ~CXFA_TextUserData() override;
+  template <typename T, typename... Args>
+  friend CFX_RetainPtr<T> pdfium::MakeRetain(Args&&... args);
 
-  // IFX_Retainable:
-  uint32_t Retain() override;
-  uint32_t Release() override;
-
-  CFDE_CSSComputedStyle* m_pStyle;
-  CXFA_LinkUserData* m_pLinkData;
+  CFX_RetainPtr<CFDE_CSSComputedStyle> m_pStyle;
+  CFX_RetainPtr<CXFA_LinkUserData> m_pLinkData;
 
  protected:
-  uint32_t m_dwRefCount;
+  explicit CXFA_TextUserData(
+      const CFX_RetainPtr<CFDE_CSSComputedStyle>& pStyle);
+  CXFA_TextUserData(const CFX_RetainPtr<CFDE_CSSComputedStyle>& pStyle,
+                    const CFX_RetainPtr<CXFA_LinkUserData>& pLinkData);
+  ~CXFA_TextUserData() override;
 };
 
 #endif  // XFA_FXFA_APP_CXFA_TEXTUSERDATA_H_
diff --git a/xfa/fxfa/app/xfa_ffbarcode.cpp b/xfa/fxfa/app/xfa_ffbarcode.cpp
index 822029d..b136b8d 100644
--- a/xfa/fxfa/app/xfa_ffbarcode.cpp
+++ b/xfa/fxfa/app/xfa_ffbarcode.cpp
@@ -116,9 +116,8 @@
 
 }  // namespace.
 
-CXFA_FFBarcode::CXFA_FFBarcode(CXFA_FFPageView* pPageView,
-                               CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFTextEdit(pPageView, pDataAcc) {}
+CXFA_FFBarcode::CXFA_FFBarcode(CXFA_WidgetAcc* pDataAcc)
+    : CXFA_FFTextEdit(pDataAcc) {}
 
 CXFA_FFBarcode::~CXFA_FFBarcode() {}
 
@@ -145,21 +144,20 @@
 void CXFA_FFBarcode::RenderWidget(CFX_Graphics* pGS,
                                   CFX_Matrix* pMatrix,
                                   uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus)) {
+  if (!IsMatchVisibleStatus(dwStatus))
     return;
-  }
-  CFX_Matrix mtRotate;
-  GetRotateMatrix(mtRotate);
-  if (pMatrix) {
+
+  CFX_Matrix mtRotate = GetRotateMatrix();
+  if (pMatrix)
     mtRotate.Concat(*pMatrix);
-  }
+
   CXFA_FFWidget::RenderWidget(pGS, &mtRotate, dwStatus);
   CXFA_Border borderUI = m_pDataAcc->GetUIBorder();
   DrawBorder(pGS, borderUI, m_rtUI, &mtRotate);
   RenderCaption(pGS, &mtRotate);
   CFX_RectF rtWidget = m_pNormalWidget->GetWidgetRect();
-  CFX_Matrix mt;
-  mt.Set(1, 0, 0, 1, rtWidget.left, rtWidget.top);
+
+  CFX_Matrix mt(1, 0, 0, 1, rtWidget.left, rtWidget.top);
   mt.Concat(mtRotate);
   m_pNormalWidget->DrawWidget(pGS, &mt);
 }
@@ -223,20 +221,18 @@
   }
 }
 
-bool CXFA_FFBarcode::OnLButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
+bool CXFA_FFBarcode::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
   CFWL_Barcode* pBarCodeWidget = (CFWL_Barcode*)m_pNormalWidget;
-  if (!pBarCodeWidget || pBarCodeWidget->IsProtectedType()) {
+  if (!pBarCodeWidget || pBarCodeWidget->IsProtectedType())
     return false;
-  }
-  if (m_pDataAcc->GetAccess() != XFA_ATTRIBUTEENUM_Open) {
+  if (m_pDataAcc->GetAccess() != XFA_ATTRIBUTEENUM_Open)
     return false;
-  }
-  return CXFA_FFTextEdit::OnLButtonDown(dwFlags, fx, fy);
+  return CXFA_FFTextEdit::OnLButtonDown(dwFlags, point);
 }
-bool CXFA_FFBarcode::OnRButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
+
+bool CXFA_FFBarcode::OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
   CFWL_Barcode* pBarCodeWidget = (CFWL_Barcode*)m_pNormalWidget;
-  if (!pBarCodeWidget || pBarCodeWidget->IsProtectedType()) {
+  if (!pBarCodeWidget || pBarCodeWidget->IsProtectedType())
     return false;
-  }
-  return CXFA_FFTextEdit::OnRButtonDown(dwFlags, fx, fy);
+  return CXFA_FFTextEdit::OnRButtonDown(dwFlags, point);
 }
diff --git a/xfa/fxfa/app/xfa_ffbarcode.h b/xfa/fxfa/app/xfa_ffbarcode.h
index 4690b3d..c20feb5 100644
--- a/xfa/fxfa/app/xfa_ffbarcode.h
+++ b/xfa/fxfa/app/xfa_ffbarcode.h
@@ -13,7 +13,7 @@
 
 class CXFA_FFBarcode : public CXFA_FFTextEdit {
  public:
-  CXFA_FFBarcode(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFBarcode(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFBarcode() override;
 
   // CXFA_FFTextEdit
@@ -22,8 +22,8 @@
                     CFX_Matrix* pMatrix,
                     uint32_t dwStatus) override;
   void UpdateWidgetProperty() override;
-  bool OnLButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnRButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
+  bool OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) override;
+  bool OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) override;
 };
 
 enum XFA_BARCODETYPEENUM {
diff --git a/xfa/fxfa/app/xfa_ffcheckbutton.cpp b/xfa/fxfa/app/xfa_ffcheckbutton.cpp
index e8a422e..f088b5d 100644
--- a/xfa/fxfa/app/xfa_ffcheckbutton.cpp
+++ b/xfa/fxfa/app/xfa_ffcheckbutton.cpp
@@ -18,11 +18,8 @@
 #include "xfa/fxfa/xfa_ffpageview.h"
 #include "xfa/fxfa/xfa_ffwidget.h"
 
-CXFA_FFCheckButton::CXFA_FFCheckButton(CXFA_FFPageView* pPageView,
-                                       CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFField(pPageView, pDataAcc), m_pOldDelegate(nullptr) {
-  m_rtCheckBox.Set(0, 0, 0, 0);
-}
+CXFA_FFCheckButton::CXFA_FFCheckButton(CXFA_WidgetAcc* pDataAcc)
+    : CXFA_FFField(pDataAcc), m_pOldDelegate(nullptr) {}
 
 CXFA_FFCheckButton::~CXFA_FFCheckButton() {}
 
@@ -91,8 +88,7 @@
   CXFA_FFWidget::PerformLayout();
   FX_FLOAT fCheckSize = m_pDataAcc->GetCheckButtonSize();
   CXFA_Margin mgWidget = m_pDataAcc->GetMargin();
-  CFX_RectF rtWidget;
-  GetRectWithoutRotate(rtWidget);
+  CFX_RectF rtWidget = GetRectWithoutRotate();
   if (mgWidget) {
     XFA_RectWidthoutMargin(rtWidget, mgWidget);
   }
@@ -100,8 +96,7 @@
   FX_FLOAT fCapReserve = 0;
   CXFA_Caption caption = m_pDataAcc->GetCaption();
   if (caption && caption.GetPresence()) {
-    m_rtCaption.Set(rtWidget.left, rtWidget.top, rtWidget.width,
-                    rtWidget.height);
+    m_rtCaption = rtWidget;
     iCapPlacement = caption.GetPlacementType();
     fCapReserve = caption.GetReserve();
     if (fCapReserve <= 0) {
@@ -216,14 +211,13 @@
 void CXFA_FFCheckButton::RenderWidget(CFX_Graphics* pGS,
                                       CFX_Matrix* pMatrix,
                                       uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus)) {
+  if (!IsMatchVisibleStatus(dwStatus))
     return;
-  }
-  CFX_Matrix mtRotate;
-  GetRotateMatrix(mtRotate);
-  if (pMatrix) {
+
+  CFX_Matrix mtRotate = GetRotateMatrix();
+  if (pMatrix)
     mtRotate.Concat(*pMatrix);
-  }
+
   CXFA_FFWidget::RenderWidget(pGS, &mtRotate, dwStatus);
   CXFA_Border borderUI = m_pDataAcc->GetUIBorder();
   DrawBorder(pGS, borderUI, m_rtUI, &mtRotate,
@@ -233,14 +227,12 @@
   RenderCaption(pGS, &mtRotate);
   DrawHighlight(pGS, &mtRotate, dwStatus,
                 m_pDataAcc->GetCheckButtonShape() == XFA_ATTRIBUTEENUM_Round);
-  CFX_Matrix mt;
-  mt.Set(1, 0, 0, 1, m_rtCheckBox.left, m_rtCheckBox.top);
+  CFX_Matrix mt(1, 0, 0, 1, m_rtCheckBox.left, m_rtCheckBox.top);
   mt.Concat(mtRotate);
   GetApp()->GetWidgetMgrDelegate()->OnDrawWidget(m_pNormalWidget, pGS, &mt);
 }
 bool CXFA_FFCheckButton::OnLButtonUp(uint32_t dwFlags,
-                                     FX_FLOAT fx,
-                                     FX_FLOAT fy) {
+                                     const CFX_PointF& point) {
   if (!m_pNormalWidget || !IsButtonDown())
     return false;
 
@@ -248,9 +240,7 @@
   CFWL_MessageMouse ms(nullptr, m_pNormalWidget);
   ms.m_dwCmd = FWL_MouseCommand::LeftButtonUp;
   ms.m_dwFlags = dwFlags;
-  ms.m_fx = fx;
-  ms.m_fy = fy;
-  FWLToClient(ms.m_fx, ms.m_fy);
+  ms.m_pos = FWLToClient(point);
   TranslateFWLMessage(&ms);
   return true;
 }
diff --git a/xfa/fxfa/app/xfa_ffcheckbutton.h b/xfa/fxfa/app/xfa_ffcheckbutton.h
index dcd6893..2c0acd6 100644
--- a/xfa/fxfa/app/xfa_ffcheckbutton.h
+++ b/xfa/fxfa/app/xfa_ffcheckbutton.h
@@ -12,7 +12,7 @@
 
 class CXFA_FFCheckButton : public CXFA_FFField {
  public:
-  CXFA_FFCheckButton(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFCheckButton(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFCheckButton() override;
 
   // CXFA_FFField
@@ -24,7 +24,7 @@
   bool PerformLayout() override;
   bool UpdateFWLData() override;
   void UpdateWidgetProperty() override;
-  bool OnLButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
+  bool OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) override;
   void OnProcessMessage(CFWL_Message* pMessage) override;
   void OnProcessEvent(CFWL_Event* pEvent) override;
   void OnDrawWidget(CFX_Graphics* pGraphics,
diff --git a/xfa/fxfa/app/xfa_ffchoicelist.cpp b/xfa/fxfa/app/xfa_ffchoicelist.cpp
index 2764d72..3aabde8 100644
--- a/xfa/fxfa/app/xfa_ffchoicelist.cpp
+++ b/xfa/fxfa/app/xfa_ffchoicelist.cpp
@@ -25,9 +25,8 @@
 #include "xfa/fxfa/xfa_ffpageview.h"
 #include "xfa/fxfa/xfa_ffwidget.h"
 
-CXFA_FFListBox::CXFA_FFListBox(CXFA_FFPageView* pPageView,
-                               CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFField(pPageView, pDataAcc), m_pOldDelegate(nullptr) {}
+CXFA_FFListBox::CXFA_FFListBox(CXFA_WidgetAcc* pDataAcc)
+    : CXFA_FFField(pDataAcc), m_pOldDelegate(nullptr) {}
 
 CXFA_FFListBox::~CXFA_FFListBox() {
   if (m_pNormalWidget) {
@@ -65,7 +64,7 @@
   }
   dwExtendedStyle |= GetAlignment();
   m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
-  CFX_Int32Array iSelArray;
+  CFX_ArrayTemplate<int32_t> iSelArray;
   m_pDataAcc->GetSelectedItems(iSelArray);
   int32_t iSelCount = iSelArray.GetSize();
   for (int32_t j = 0; j < iSelCount; j++) {
@@ -86,7 +85,7 @@
 bool CXFA_FFListBox::CommitData() {
   CFWL_ListBox* pListBox = static_cast<CFWL_ListBox*>(m_pNormalWidget);
   int32_t iSels = pListBox->CountSelItems();
-  CFX_Int32Array iSelArray;
+  CFX_ArrayTemplate<int32_t> iSelArray;
   for (int32_t i = 0; i < iSels; ++i)
     iSelArray.Add(pListBox->GetSelIndex(i));
   m_pDataAcc->SetSelectedItems(iSelArray, true, false, true);
@@ -94,7 +93,7 @@
 }
 
 bool CXFA_FFListBox::IsDataChanged() {
-  CFX_Int32Array iSelArray;
+  CFX_ArrayTemplate<int32_t> iSelArray;
   m_pDataAcc->GetSelectedItems(iSelArray);
   int32_t iOldSels = iSelArray.GetSize();
   CFWL_ListBox* pListBox = (CFWL_ListBox*)m_pNormalWidget;
@@ -140,7 +139,7 @@
   }
   CFWL_ListBox* pListBox = ((CFWL_ListBox*)m_pNormalWidget);
   CFX_ArrayTemplate<CFWL_ListItem*> selItemArray;
-  CFX_Int32Array iSelArray;
+  CFX_ArrayTemplate<int32_t> iSelArray;
   m_pDataAcc->GetSelectedItems(iSelArray);
   int32_t iSelCount = iSelArray.GetSize();
   for (int32_t j = 0; j < iSelCount; j++) {
@@ -154,8 +153,9 @@
   m_pNormalWidget->Update();
   return true;
 }
-void CXFA_FFListBox::OnSelectChanged(CFWL_Widget* pWidget,
-                                     const CFX_Int32Array& arrSels) {
+void CXFA_FFListBox::OnSelectChanged(
+    CFWL_Widget* pWidget,
+    const CFX_ArrayTemplate<int32_t>& arrSels) {
   CXFA_EventParam eParam;
   eParam.m_eType = XFA_EVENT_Change;
   eParam.m_pTarget = m_pDataAcc;
@@ -201,7 +201,7 @@
   CXFA_FFField::OnProcessEvent(pEvent);
   switch (pEvent->GetType()) {
     case CFWL_Event::Type::SelectChanged: {
-      CFX_Int32Array arrSels;
+      CFX_ArrayTemplate<int32_t> arrSels;
       OnSelectChanged(m_pNormalWidget, arrSels);
       break;
     }
@@ -215,26 +215,20 @@
   m_pOldDelegate->OnDrawWidget(pGraphics, pMatrix);
 }
 
-CXFA_FFComboBox::CXFA_FFComboBox(CXFA_FFPageView* pPageView,
-                                 CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFField(pPageView, pDataAcc), m_pOldDelegate(nullptr) {}
+CXFA_FFComboBox::CXFA_FFComboBox(CXFA_WidgetAcc* pDataAcc)
+    : CXFA_FFField(pDataAcc), m_pOldDelegate(nullptr) {}
 
 CXFA_FFComboBox::~CXFA_FFComboBox() {}
 
-bool CXFA_FFComboBox::GetBBox(CFX_RectF& rtBox,
-                              uint32_t dwStatus,
-                              bool bDrawFocus) {
+CFX_RectF CXFA_FFComboBox::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
   if (bDrawFocus)
-    return false;
-  return CXFA_FFWidget::GetBBox(rtBox, dwStatus);
+    return CFX_RectF();
+  return CXFA_FFWidget::GetBBox(dwStatus);
 }
 
-bool CXFA_FFComboBox::PtInActiveRect(FX_FLOAT fx, FX_FLOAT fy) {
-  if (!m_pNormalWidget)
-    return false;
-  return static_cast<CFWL_ComboBox*>(m_pNormalWidget)
-      ->GetBBox()
-      .Contains(fx, fy);
+bool CXFA_FFComboBox::PtInActiveRect(const CFX_PointF& point) {
+  auto pComboBox = static_cast<CFWL_ComboBox*>(m_pNormalWidget);
+  return pComboBox && pComboBox->GetBBox().Contains(point);
 }
 
 bool CXFA_FFComboBox::LoadWidget() {
@@ -256,7 +250,7 @@
   for (int32_t i = 0; i < iItems; i++) {
     pComboBox->AddString(wsLabelArray[i].AsStringC());
   }
-  CFX_Int32Array iSelArray;
+  CFX_ArrayTemplate<int32_t> iSelArray;
   m_pDataAcc->GetSelectedItems(iSelArray);
   int32_t iSelCount = iSelArray.GetSize();
   if (iSelCount > 0) {
@@ -295,13 +289,15 @@
   }
   pComboBox->EditModifyStylesEx(dwEditStyles, 0xFFFFFFFF);
 }
-bool CXFA_FFComboBox::OnRButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
-  if (!CXFA_FFField::OnRButtonUp(dwFlags, fx, fy))
+
+bool CXFA_FFComboBox::OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
+  if (!CXFA_FFField::OnRButtonUp(dwFlags, point))
     return false;
 
-  GetDoc()->GetDocEnvironment()->PopupMenu(this, CFX_PointF(fx, fy));
+  GetDoc()->GetDocEnvironment()->PopupMenu(this, point);
   return true;
 }
+
 bool CXFA_FFComboBox::OnKillFocus(CXFA_FFWidget* pNewWidget) {
   bool flag = ProcessCommittedData();
   if (!flag) {
@@ -383,7 +379,7 @@
   if (!m_pNormalWidget) {
     return false;
   }
-  CFX_Int32Array iSelArray;
+  CFX_ArrayTemplate<int32_t> iSelArray;
   m_pDataAcc->GetSelectedItems(iSelArray);
   int32_t iSelCount = iSelArray.GetSize();
   if (iSelCount > 0) {
diff --git a/xfa/fxfa/app/xfa_ffchoicelist.h b/xfa/fxfa/app/xfa_ffchoicelist.h
index e9bee6f..e89366a 100644
--- a/xfa/fxfa/app/xfa_ffchoicelist.h
+++ b/xfa/fxfa/app/xfa_ffchoicelist.h
@@ -12,7 +12,7 @@
 
 class CXFA_FFListBox : public CXFA_FFField {
  public:
-  CXFA_FFListBox(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFListBox(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFListBox() override;
 
   // CXFA_FFField
@@ -23,7 +23,8 @@
   void OnDrawWidget(CFX_Graphics* pGraphics,
                     const CFX_Matrix* pMatrix = nullptr) override;
 
-  void OnSelectChanged(CFWL_Widget* pWidget, const CFX_Int32Array& arrSels);
+  void OnSelectChanged(CFWL_Widget* pWidget,
+                       const CFX_ArrayTemplate<int32_t>& arrSels);
   void SetItemState(int32_t nIndex, bool bSelected);
   void InsertItem(const CFX_WideStringC& wsLabel, int32_t nIndex = -1);
   void DeleteItem(int32_t nIndex);
@@ -40,16 +41,14 @@
 
 class CXFA_FFComboBox : public CXFA_FFField {
  public:
-  CXFA_FFComboBox(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFComboBox(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFComboBox() override;
 
   // CXFA_FFField
-  bool GetBBox(CFX_RectF& rtBox,
-               uint32_t dwStatus,
-               bool bDrawFocus = false) override;
+  CFX_RectF GetBBox(uint32_t dwStatus, bool bDrawFocus = false) override;
   bool LoadWidget() override;
   void UpdateWidgetProperty() override;
-  bool OnRButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
+  bool OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) override;
   bool OnKillFocus(CXFA_FFWidget* pNewWidget) override;
   bool CanUndo() override;
   bool CanRedo() override;
@@ -85,7 +84,7 @@
 
  protected:
   // CXFA_FFField
-  bool PtInActiveRect(FX_FLOAT fx, FX_FLOAT fy) override;
+  bool PtInActiveRect(const CFX_PointF& point) override;
   bool CommitData() override;
   bool UpdateFWLData() override;
   bool IsDataChanged() override;
diff --git a/xfa/fxfa/app/xfa_ffdoc.cpp b/xfa/fxfa/app/xfa_ffdoc.cpp
index c34213c..911bdf8 100644
--- a/xfa/fxfa/app/xfa_ffdoc.cpp
+++ b/xfa/fxfa/app/xfa_ffdoc.cpp
@@ -183,7 +183,7 @@
       CFX_WideString wsTagName;
       CFDE_XMLElement* pXMLElement = static_cast<CFDE_XMLElement*>(pXMLNode);
       pXMLElement->GetTagName(wsTagName);
-      if (wsTagName == FX_WSTRC(L"document")) {
+      if (wsTagName == L"document") {
         pDocumentElement = pXMLElement;
         break;
       }
@@ -200,7 +200,7 @@
       CFX_WideString wsTagName;
       CFDE_XMLElement* pXMLElement = static_cast<CFDE_XMLElement*>(pXMLNode);
       pXMLElement->GetTagName(wsTagName);
-      if (wsTagName == FX_WSTRC(L"chunk")) {
+      if (wsTagName == L"chunk") {
         pChunkElement = pXMLElement;
         break;
       }
@@ -265,7 +265,7 @@
     return;
   }
   CFX_WideString wsType;
-  if (pDynamicRender->TryContent(wsType) && wsType == FX_WSTRC(L"required")) {
+  if (pDynamicRender->TryContent(wsType) && wsType == L"required") {
     m_dwDocType = XFA_DOCTYPE_Dynamic;
   }
 }
diff --git a/xfa/fxfa/app/xfa_ffdocview.cpp b/xfa/fxfa/app/xfa_ffdocview.cpp
index bf91baf..8744181 100644
--- a/xfa/fxfa/app/xfa_ffdocview.cpp
+++ b/xfa/fxfa/app/xfa_ffdocview.cpp
@@ -155,7 +155,7 @@
     iCount -= iRemain;
     CFX_WideString wsMsg;
     for (int32_t i = 0; i < iCount; i++) {
-      wsMsg += m_arrNullTestMsg[i] + FX_WSTRC(L"\n");
+      wsMsg += m_arrNullTestMsg[i] + L"\n";
     }
     if (iRemain > 0) {
       CFX_WideString wsTemp;
@@ -163,7 +163,7 @@
           L"Message limit exceeded. Remaining %d "
           L"validation errors not reported.",
           iRemain);
-      wsMsg += FX_WSTRC(L"\n") + wsTemp;
+      wsMsg += L"\n" + wsTemp;
     }
     pAppProvider->MsgBox(wsMsg, pAppProvider->GetAppTitle(), XFA_MBICON_Status,
                          XFA_MB_OK);
@@ -551,10 +551,7 @@
     m_mapPageInvalidate[pPageView]->Union(rtInvalidate);
     return;
   }
-  CFX_RectF* pRect = new CFX_RectF;
-  pRect->Set(rtInvalidate.left, rtInvalidate.top, rtInvalidate.width,
-             rtInvalidate.height);
-  m_mapPageInvalidate[pPageView].reset(pRect);
+  m_mapPageInvalidate[pPageView] = pdfium::MakeUnique<CFX_RectF>(rtInvalidate);
 }
 
 void CXFA_FFDocView::RunInvalidate() {
@@ -636,11 +633,12 @@
 }
 
 void CXFA_FFDocView::AddCalculateNodeNotify(CXFA_Node* pNodeChange) {
-  CXFA_CalcData* pGlobalData =
-      (CXFA_CalcData*)pNodeChange->GetUserData(XFA_CalcData);
-  int32_t iCount = pGlobalData ? pGlobalData->m_Globals.GetSize() : 0;
-  for (int32_t i = 0; i < iCount; i++) {
-    CXFA_WidgetAcc* pResultAcc = pGlobalData->m_Globals[i];
+  auto pGlobalData =
+      static_cast<CXFA_CalcData*>(pNodeChange->GetUserData(XFA_CalcData));
+  if (!pGlobalData)
+    return;
+
+  for (const auto& pResultAcc : pGlobalData->m_Globals) {
     if (!pResultAcc->GetNode()->HasRemovedChildren())
       AddCalculateWidgetAcc(pResultAcc);
   }
@@ -754,10 +752,8 @@
     binditems.GetValueRef(wsValueRef);
     binditems.GetLabelRef(wsLabelRef);
     const bool bUseValue = wsLabelRef.IsEmpty() || wsLabelRef == wsValueRef;
-    const bool bLabelUseContent =
-        wsLabelRef.IsEmpty() || wsLabelRef == FX_WSTRC(L"$");
-    const bool bValueUseContent =
-        wsValueRef.IsEmpty() || wsValueRef == FX_WSTRC(L"$");
+    const bool bLabelUseContent = wsLabelRef.IsEmpty() || wsLabelRef == L"$";
+    const bool bValueUseContent = wsValueRef.IsEmpty() || wsValueRef == L"$";
     CFX_WideString wsValue;
     CFX_WideString wsLabel;
     uint32_t uValueHash = FX_HashCode_GetW(wsValueRef, false);
diff --git a/xfa/fxfa/app/xfa_ffdraw.cpp b/xfa/fxfa/app/xfa_ffdraw.cpp
index da1ae65..37095dd 100644
--- a/xfa/fxfa/app/xfa_ffdraw.cpp
+++ b/xfa/fxfa/app/xfa_ffdraw.cpp
@@ -11,6 +11,6 @@
 #include "xfa/fxfa/xfa_ffpageview.h"
 #include "xfa/fxfa/xfa_ffwidget.h"
 
-CXFA_FFDraw::CXFA_FFDraw(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFWidget(pPageView, pDataAcc) {}
+CXFA_FFDraw::CXFA_FFDraw(CXFA_WidgetAcc* pDataAcc) : CXFA_FFWidget(pDataAcc) {}
+
 CXFA_FFDraw::~CXFA_FFDraw() {}
diff --git a/xfa/fxfa/app/xfa_ffdraw.h b/xfa/fxfa/app/xfa_ffdraw.h
index bf9fd84..0212dcc 100644
--- a/xfa/fxfa/app/xfa_ffdraw.h
+++ b/xfa/fxfa/app/xfa_ffdraw.h
@@ -12,7 +12,7 @@
 
 class CXFA_FFDraw : public CXFA_FFWidget {
  public:
-  CXFA_FFDraw(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFDraw(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFDraw() override;
 };
 
diff --git a/xfa/fxfa/app/xfa_ffexclgroup.cpp b/xfa/fxfa/app/xfa_ffexclgroup.cpp
index a6b9447..7d63dad 100644
--- a/xfa/fxfa/app/xfa_ffexclgroup.cpp
+++ b/xfa/fxfa/app/xfa_ffexclgroup.cpp
@@ -11,20 +11,20 @@
 #include "xfa/fxfa/xfa_ffpageview.h"
 #include "xfa/fxfa/xfa_ffwidget.h"
 
-CXFA_FFExclGroup::CXFA_FFExclGroup(CXFA_FFPageView* pPageView,
-                                   CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFWidget(pPageView, pDataAcc) {}
+CXFA_FFExclGroup::CXFA_FFExclGroup(CXFA_WidgetAcc* pDataAcc)
+    : CXFA_FFWidget(pDataAcc) {}
+
 CXFA_FFExclGroup::~CXFA_FFExclGroup() {}
+
 void CXFA_FFExclGroup::RenderWidget(CFX_Graphics* pGS,
                                     CFX_Matrix* pMatrix,
                                     uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus)) {
+  if (!IsMatchVisibleStatus(dwStatus))
     return;
-  }
-  CFX_Matrix mtRotate;
-  GetRotateMatrix(mtRotate);
-  if (pMatrix) {
+
+  CFX_Matrix mtRotate = GetRotateMatrix();
+  if (pMatrix)
     mtRotate.Concat(*pMatrix);
-  }
+
   CXFA_FFWidget::RenderWidget(pGS, &mtRotate, dwStatus);
 }
diff --git a/xfa/fxfa/app/xfa_ffexclgroup.h b/xfa/fxfa/app/xfa_ffexclgroup.h
index 90e8251..12a13ae 100644
--- a/xfa/fxfa/app/xfa_ffexclgroup.h
+++ b/xfa/fxfa/app/xfa_ffexclgroup.h
@@ -12,7 +12,7 @@
 
 class CXFA_FFExclGroup : public CXFA_FFWidget {
  public:
-  CXFA_FFExclGroup(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFExclGroup(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFExclGroup() override;
 
   // CXFA_FFWidget
diff --git a/xfa/fxfa/app/xfa_fffield.cpp b/xfa/fxfa/app/xfa_fffield.cpp
index aa8abbd..630d043 100644
--- a/xfa/fxfa/app/xfa_fffield.cpp
+++ b/xfa/fxfa/app/xfa_fffield.cpp
@@ -25,45 +25,39 @@
 #include "xfa/fxgraphics/cfx_color.h"
 #include "xfa/fxgraphics/cfx_path.h"
 
-CXFA_FFField::CXFA_FFField(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFWidget(pPageView, pDataAcc), m_pNormalWidget(nullptr) {
-  m_rtUI.Set(0, 0, 0, 0);
-  m_rtCaption.Set(0, 0, 0, 0);
-}
+CXFA_FFField::CXFA_FFField(CXFA_WidgetAcc* pDataAcc)
+    : CXFA_FFWidget(pDataAcc), m_pNormalWidget(nullptr) {}
+
 CXFA_FFField::~CXFA_FFField() {
   CXFA_FFField::UnloadWidget();
 }
 
-bool CXFA_FFField::GetBBox(CFX_RectF& rtBox,
-                           uint32_t dwStatus,
-                           bool bDrawFocus) {
+CFX_RectF CXFA_FFField::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
   if (!bDrawFocus)
-    return CXFA_FFWidget::GetBBox(rtBox, dwStatus);
+    return CXFA_FFWidget::GetBBox(dwStatus);
 
   XFA_Element type = m_pDataAcc->GetUIType();
-  if (type == XFA_Element::Button || type == XFA_Element::CheckButton ||
-      type == XFA_Element::ImageEdit || type == XFA_Element::Signature ||
-      type == XFA_Element::ChoiceList) {
-    rtBox = m_rtUI;
-    CFX_Matrix mt;
-    GetRotateMatrix(mt);
-    mt.TransformRect(rtBox);
-    return true;
+  if (type != XFA_Element::Button && type != XFA_Element::CheckButton &&
+      type != XFA_Element::ImageEdit && type != XFA_Element::Signature &&
+      type != XFA_Element::ChoiceList) {
+    return CFX_RectF();
   }
-  return false;
+
+  CFX_RectF rtBox = m_rtUI;
+  GetRotateMatrix().TransformRect(rtBox);
+  return rtBox;
 }
 
 void CXFA_FFField::RenderWidget(CFX_Graphics* pGS,
                                 CFX_Matrix* pMatrix,
                                 uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus)) {
+  if (!IsMatchVisibleStatus(dwStatus))
     return;
-  }
-  CFX_Matrix mtRotate;
-  GetRotateMatrix(mtRotate);
-  if (pMatrix) {
+
+  CFX_Matrix mtRotate = GetRotateMatrix();
+  if (pMatrix)
     mtRotate.Concat(*pMatrix);
-  }
+
   CXFA_FFWidget::RenderWidget(pGS, &mtRotate, dwStatus);
   CXFA_Border borderUI = m_pDataAcc->GetUIBorder();
   DrawBorder(pGS, borderUI, m_rtUI, &mtRotate);
@@ -71,8 +65,7 @@
   DrawHighlight(pGS, &mtRotate, dwStatus, false);
 
   CFX_RectF rtWidget = m_pNormalWidget->GetWidgetRect();
-  CFX_Matrix mt;
-  mt.Set(1, 0, 0, 1, rtWidget.left, rtWidget.top);
+  CFX_Matrix mt(1, 0, 0, 1, rtWidget.left, rtWidget.top);
   mt.Concat(mtRotate);
   GetApp()->GetWidgetMgrDelegate()->OnDrawWidget(m_pNormalWidget, pGS, &mt);
 }
@@ -89,12 +82,11 @@
     CFX_Color crHighlight(pDoc->GetDocEnvironment()->GetHighlightColor(pDoc));
     pGS->SetFillColor(&crHighlight);
     CFX_Path path;
-    path.Create();
-    if (bEllipse) {
+    if (bEllipse)
       path.AddEllipse(m_rtUI);
-    } else {
+    else
       path.AddRectangle(m_rtUI.left, m_rtUI.top, m_rtUI.width, m_rtUI.height);
-    }
+
     pGS->FillPath(&path, FXFILL_WINDING, pMatrix);
   }
 }
@@ -105,8 +97,8 @@
     FX_FLOAT DashPattern[2] = {1, 1};
     pGS->SetLineDash(0.0f, DashPattern, 2);
     pGS->SetLineWidth(0, false);
+
     CFX_Path path;
-    path.Create();
     path.AddRectangle(m_rtUI.left, m_rtUI.top, m_rtUI.width, m_rtUI.height);
     pGS->StrokePath(&path, pMatrix);
   }
@@ -157,8 +149,7 @@
   return true;
 }
 void CXFA_FFField::CapPlacement() {
-  CFX_RectF rtWidget;
-  GetRectWithoutRotate(rtWidget);
+  CFX_RectF rtWidget = GetRectWithoutRotate();
   CXFA_Margin mgWidget = m_pDataAcc->GetMargin();
   if (mgWidget) {
     CXFA_LayoutItem* pItem = this;
@@ -170,38 +161,35 @@
     if (!pItem->GetPrev() && !pItem->GetNext()) {
       rtWidget.Deflate(fLeftInset, fTopInset, fRightInset, fBottomInset);
     } else {
-      if (!pItem->GetPrev()) {
+      if (!pItem->GetPrev())
         rtWidget.Deflate(fLeftInset, fTopInset, fRightInset, 0);
-      } else if (!pItem->GetNext()) {
+      else if (!pItem->GetNext())
         rtWidget.Deflate(fLeftInset, 0, fRightInset, fBottomInset);
-      } else {
+      else
         rtWidget.Deflate(fLeftInset, 0, fRightInset, 0);
-      }
     }
   }
+
   XFA_ATTRIBUTEENUM iCapPlacement = XFA_ATTRIBUTEENUM_Unknown;
   FX_FLOAT fCapReserve = 0;
   CXFA_Caption caption = m_pDataAcc->GetCaption();
   if (caption && caption.GetPresence() != XFA_ATTRIBUTEENUM_Hidden) {
     iCapPlacement = (XFA_ATTRIBUTEENUM)caption.GetPlacementType();
     if (iCapPlacement == XFA_ATTRIBUTEENUM_Top && GetPrev()) {
-      m_rtCaption.Set(0, 0, 0, 0);
+      m_rtCaption.Reset();
     } else if (iCapPlacement == XFA_ATTRIBUTEENUM_Bottom && GetNext()) {
-      m_rtCaption.Set(0, 0, 0, 0);
+      m_rtCaption.Reset();
     } else {
       fCapReserve = caption.GetReserve();
       CXFA_LayoutItem* pItem = this;
       if (!pItem->GetPrev() && !pItem->GetNext()) {
-        m_rtCaption.Set(rtWidget.left, rtWidget.top, rtWidget.width,
-                        rtWidget.height);
+        m_rtCaption = rtWidget;
       } else {
         pItem = pItem->GetFirst();
-        pItem->GetRect(m_rtCaption);
+        m_rtCaption = pItem->GetRect(false);
         pItem = pItem->GetNext();
         while (pItem) {
-          CFX_RectF rtRect;
-          pItem->GetRect(rtRect);
-          m_rtCaption.height += rtRect.Height();
+          m_rtCaption.height += pItem->GetRect(false).Height();
           pItem = pItem->GetNext();
         }
         XFA_RectWidthoutMargin(m_rtCaption, mgWidget);
@@ -214,9 +202,9 @@
         pCapTextLayout->CalcSize(minSize, maxSize, size);
         if (iCapPlacement == XFA_ATTRIBUTEENUM_Top ||
             iCapPlacement == XFA_ATTRIBUTEENUM_Bottom) {
-          fCapReserve = size.y;
+          fCapReserve = size.height;
         } else {
-          fCapReserve = size.x;
+          fCapReserve = size.width;
         }
       }
     }
@@ -361,145 +349,126 @@
   return true;
 }
 
-void CXFA_FFField::FWLToClient(FX_FLOAT& fx, FX_FLOAT& fy) {
-  if (!m_pNormalWidget)
-    return;
-
-  CFX_RectF rtWidget = m_pNormalWidget->GetWidgetRect();
-  fx -= rtWidget.left;
-  fy -= rtWidget.top;
+CFX_PointF CXFA_FFField::FWLToClient(const CFX_PointF& point) {
+  return m_pNormalWidget ? point - m_pNormalWidget->GetWidgetRect().TopLeft()
+                         : point;
 }
 
-bool CXFA_FFField::OnLButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
-  if (!m_pNormalWidget) {
+bool CXFA_FFField::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
+  if (!m_pNormalWidget)
     return false;
-  }
   if (m_pDataAcc->GetAccess() != XFA_ATTRIBUTEENUM_Open ||
       !m_pDataAcc->GetDoc()->GetXFADoc()->IsInteractive()) {
     return false;
   }
-  if (!PtInActiveRect(fx, fy)) {
+  if (!PtInActiveRect(point))
     return false;
-  }
+
   SetButtonDown(true);
   CFWL_MessageMouse ms(nullptr, m_pNormalWidget);
   ms.m_dwCmd = FWL_MouseCommand::LeftButtonDown;
   ms.m_dwFlags = dwFlags;
-  ms.m_fx = fx;
-  ms.m_fy = fy;
-  FWLToClient(ms.m_fx, ms.m_fy);
+  ms.m_pos = FWLToClient(point);
   TranslateFWLMessage(&ms);
   return true;
 }
-bool CXFA_FFField::OnLButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
-  if (!m_pNormalWidget) {
+
+bool CXFA_FFField::OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
+  if (!m_pNormalWidget)
     return false;
-  }
-  if (!IsButtonDown()) {
+  if (!IsButtonDown())
     return false;
-  }
+
   SetButtonDown(false);
   CFWL_MessageMouse ms(nullptr, m_pNormalWidget);
   ms.m_dwCmd = FWL_MouseCommand::LeftButtonUp;
   ms.m_dwFlags = dwFlags;
-  ms.m_fx = fx;
-  ms.m_fy = fy;
-  FWLToClient(ms.m_fx, ms.m_fy);
+  ms.m_pos = FWLToClient(point);
   TranslateFWLMessage(&ms);
   return true;
 }
-bool CXFA_FFField::OnLButtonDblClk(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
-  if (!m_pNormalWidget) {
+
+bool CXFA_FFField::OnLButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) {
+  if (!m_pNormalWidget)
     return false;
-  }
+
   CFWL_MessageMouse ms(nullptr, m_pNormalWidget);
   ms.m_dwCmd = FWL_MouseCommand::LeftButtonDblClk;
   ms.m_dwFlags = dwFlags;
-  ms.m_fx = fx;
-  ms.m_fy = fy;
-  FWLToClient(ms.m_fx, ms.m_fy);
+  ms.m_pos = FWLToClient(point);
   TranslateFWLMessage(&ms);
   return true;
 }
-bool CXFA_FFField::OnMouseMove(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
-  if (!m_pNormalWidget) {
+
+bool CXFA_FFField::OnMouseMove(uint32_t dwFlags, const CFX_PointF& point) {
+  if (!m_pNormalWidget)
     return false;
-  }
+
   CFWL_MessageMouse ms(nullptr, m_pNormalWidget);
   ms.m_dwCmd = FWL_MouseCommand::Move;
   ms.m_dwFlags = dwFlags;
-  ms.m_fx = fx;
-  ms.m_fy = fy;
-  FWLToClient(ms.m_fx, ms.m_fy);
+  ms.m_pos = FWLToClient(point);
   TranslateFWLMessage(&ms);
   return true;
 }
+
 bool CXFA_FFField::OnMouseWheel(uint32_t dwFlags,
                                 int16_t zDelta,
-                                FX_FLOAT fx,
-                                FX_FLOAT fy) {
-  if (!m_pNormalWidget) {
+                                const CFX_PointF& point) {
+  if (!m_pNormalWidget)
     return false;
-  }
+
   CFWL_MessageMouseWheel ms(nullptr, m_pNormalWidget);
   ms.m_dwFlags = dwFlags;
-  ms.m_fx = fx;
-  ms.m_fy = fy;
-  FWLToClient(ms.m_fx, ms.m_fy);
-  ms.m_fDeltaX = zDelta;
-  ms.m_fDeltaY = 0;
+  ms.m_pos = FWLToClient(point);
+  ms.m_delta = CFX_PointF(zDelta, 0);
   TranslateFWLMessage(&ms);
   return true;
 }
-bool CXFA_FFField::OnRButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
-  if (!m_pNormalWidget) {
+
+bool CXFA_FFField::OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
+  if (!m_pNormalWidget)
     return false;
-  }
   if (m_pDataAcc->GetAccess() != XFA_ATTRIBUTEENUM_Open ||
       !m_pDataAcc->GetDoc()->GetXFADoc()->IsInteractive()) {
     return false;
   }
-  if (!PtInActiveRect(fx, fy)) {
+  if (!PtInActiveRect(point))
     return false;
-  }
+
   SetButtonDown(true);
 
   CFWL_MessageMouse ms(nullptr, m_pNormalWidget);
   ms.m_dwCmd = FWL_MouseCommand::RightButtonDown;
   ms.m_dwFlags = dwFlags;
-  ms.m_fx = fx;
-  ms.m_fy = fy;
-  FWLToClient(ms.m_fx, ms.m_fy);
+  ms.m_pos = FWLToClient(point);
   TranslateFWLMessage(&ms);
   return true;
 }
-bool CXFA_FFField::OnRButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
-  if (!m_pNormalWidget) {
+
+bool CXFA_FFField::OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
+  if (!m_pNormalWidget)
     return false;
-  }
-  if (!IsButtonDown()) {
+  if (!IsButtonDown())
     return false;
-  }
+
   SetButtonDown(false);
   CFWL_MessageMouse ms(nullptr, m_pNormalWidget);
   ms.m_dwCmd = FWL_MouseCommand::RightButtonUp;
   ms.m_dwFlags = dwFlags;
-  ms.m_fx = fx;
-  ms.m_fy = fy;
-  FWLToClient(ms.m_fx, ms.m_fy);
+  ms.m_pos = FWLToClient(point);
   TranslateFWLMessage(&ms);
   return true;
 }
-bool CXFA_FFField::OnRButtonDblClk(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
-  if (!m_pNormalWidget) {
+
+bool CXFA_FFField::OnRButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) {
+  if (!m_pNormalWidget)
     return false;
-  }
+
   CFWL_MessageMouse ms(nullptr, m_pNormalWidget);
   ms.m_dwCmd = FWL_MouseCommand::RightButtonDblClk;
   ms.m_dwFlags = dwFlags;
-  ms.m_fx = fx;
-  ms.m_fy = fy;
-  FWLToClient(ms.m_fx, ms.m_fy);
+  ms.m_pos = FWLToClient(point);
   TranslateFWLMessage(&ms);
   return true;
 }
@@ -568,28 +537,25 @@
   TranslateFWLMessage(&ms);
   return true;
 }
-FWL_WidgetHit CXFA_FFField::OnHitTest(FX_FLOAT fx, FX_FLOAT fy) {
-  if (m_pNormalWidget) {
-    FX_FLOAT ffx = fx, ffy = fy;
-    FWLToClient(ffx, ffy);
-    if (m_pNormalWidget->HitTest(ffx, ffy) != FWL_WidgetHit::Unknown)
-      return FWL_WidgetHit::Client;
+FWL_WidgetHit CXFA_FFField::OnHitTest(const CFX_PointF& point) {
+  if (m_pNormalWidget &&
+      m_pNormalWidget->HitTest(FWLToClient(point)) != FWL_WidgetHit::Unknown) {
+    return FWL_WidgetHit::Client;
   }
-  CFX_RectF rtBox;
-  GetRectWithoutRotate(rtBox);
-  if (!rtBox.Contains(fx, fy))
+
+  if (!GetRectWithoutRotate().Contains(point))
     return FWL_WidgetHit::Unknown;
-  if (m_rtCaption.Contains(fx, fy))
+  if (m_rtCaption.Contains(point))
     return FWL_WidgetHit::Titlebar;
   return FWL_WidgetHit::Border;
 }
 
-bool CXFA_FFField::OnSetCursor(FX_FLOAT fx, FX_FLOAT fy) {
+bool CXFA_FFField::OnSetCursor(const CFX_PointF& point) {
   return true;
 }
 
-bool CXFA_FFField::PtInActiveRect(FX_FLOAT fx, FX_FLOAT fy) {
-  return m_pNormalWidget && m_pNormalWidget->GetWidgetRect().Contains(fx, fy);
+bool CXFA_FFField::PtInActiveRect(const CFX_PointF& point) {
+  return m_pNormalWidget && m_pNormalWidget->GetWidgetRect().Contains(point);
 }
 
 void CXFA_FFField::LayoutCaption() {
@@ -603,47 +569,45 @@
   if (m_rtCaption.height < fHeight)
     m_rtCaption.height = fHeight;
 }
+
 void CXFA_FFField::RenderCaption(CFX_Graphics* pGS, CFX_Matrix* pMatrix) {
   CXFA_TextLayout* pCapTextLayout = m_pDataAcc->GetCaptionTextLayout();
-  if (!pCapTextLayout) {
+  if (!pCapTextLayout)
     return;
-  }
+
   CXFA_Caption caption = m_pDataAcc->GetCaption();
-  if (caption && caption.GetPresence() == XFA_ATTRIBUTEENUM_Visible) {
-    if (!pCapTextLayout->IsLoaded()) {
-      pCapTextLayout->Layout(CFX_SizeF(m_rtCaption.width, m_rtCaption.height));
-    }
-    CFX_RectF rtWidget;
-    GetRectWithoutRotate(rtWidget);
-    CFX_RectF rtClip = m_rtCaption;
-    rtClip.Intersect(rtWidget);
-    CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
-    CFX_Matrix mt;
-    mt.Set(1, 0, 0, 1, m_rtCaption.left, m_rtCaption.top);
-    if (pMatrix) {
-      pMatrix->TransformRect(rtClip);
-      mt.Concat(*pMatrix);
-    }
-    pCapTextLayout->DrawString(pRenderDevice, mt, rtClip);
+  if (!caption || caption.GetPresence() != XFA_ATTRIBUTEENUM_Visible)
+    return;
+
+  if (!pCapTextLayout->IsLoaded())
+    pCapTextLayout->Layout(CFX_SizeF(m_rtCaption.width, m_rtCaption.height));
+
+  CFX_RectF rtClip = m_rtCaption;
+  rtClip.Intersect(GetRectWithoutRotate());
+  CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
+  CFX_Matrix mt(1, 0, 0, 1, m_rtCaption.left, m_rtCaption.top);
+  if (pMatrix) {
+    pMatrix->TransformRect(rtClip);
+    mt.Concat(*pMatrix);
   }
+  pCapTextLayout->DrawString(pRenderDevice, mt, rtClip);
 }
+
 bool CXFA_FFField::ProcessCommittedData() {
-  if (m_pDataAcc->GetAccess() != XFA_ATTRIBUTEENUM_Open) {
+  if (m_pDataAcc->GetAccess() != XFA_ATTRIBUTEENUM_Open)
     return false;
-  }
-  if (!IsDataChanged()) {
+  if (!IsDataChanged())
     return false;
-  }
-  if (CalculateOverride() != 1) {
+  if (CalculateOverride() != 1)
     return false;
-  }
-  if (!CommitData()) {
+  if (!CommitData())
     return false;
-  }
+
   m_pDocView->SetChangeMark();
   m_pDocView->AddValidateWidget(m_pDataAcc);
   return true;
 }
+
 int32_t CXFA_FFField::CalculateOverride() {
   CXFA_WidgetAcc* pAcc = m_pDataAcc->GetExclGroup();
   if (!pAcc) {
diff --git a/xfa/fxfa/app/xfa_fffield.h b/xfa/fxfa/app/xfa_fffield.h
index 6b4c92a..f10ce61 100644
--- a/xfa/fxfa/app/xfa_fffield.h
+++ b/xfa/fxfa/app/xfa_fffield.h
@@ -17,13 +17,11 @@
 
 class CXFA_FFField : public CXFA_FFWidget, public IFWL_WidgetDelegate {
  public:
-  CXFA_FFField(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFField(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFField() override;
 
   // CXFA_FFWidget
-  bool GetBBox(CFX_RectF& rtBox,
-               uint32_t dwStatus,
-               bool bDrawFocus = false) override;
+  CFX_RectF GetBBox(uint32_t dwStatus, bool bDrawFocus = false) override;
   void RenderWidget(CFX_Graphics* pGS,
                     CFX_Matrix* pMatrix,
                     uint32_t dwStatus) override;
@@ -33,25 +31,24 @@
   bool PerformLayout() override;
   bool OnMouseEnter() override;
   bool OnMouseExit() override;
-  bool OnLButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnLButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnLButtonDblClk(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnMouseMove(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
+  bool OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) override;
+  bool OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) override;
+  bool OnLButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) override;
+  bool OnMouseMove(uint32_t dwFlags, const CFX_PointF& point) override;
   bool OnMouseWheel(uint32_t dwFlags,
                     int16_t zDelta,
-                    FX_FLOAT fx,
-                    FX_FLOAT fy) override;
-  bool OnRButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnRButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnRButtonDblClk(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
+                    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 OnRButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) override;
 
   bool OnSetFocus(CXFA_FFWidget* pOldWidget) override;
   bool OnKillFocus(CXFA_FFWidget* pNewWidget) 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(FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnSetCursor(FX_FLOAT fx, FX_FLOAT fy) override;
+  FWL_WidgetHit OnHitTest(const CFX_PointF& point) override;
+  bool OnSetCursor(const CFX_PointF& point) override;
 
   // IFWL_WidgetDelegate
   void OnProcessMessage(CFWL_Message* pMessage) override;
@@ -63,12 +60,12 @@
   uint32_t UpdateUIProperty();
 
  protected:
-  bool PtInActiveRect(FX_FLOAT fx, FX_FLOAT fy) override;
+  bool PtInActiveRect(const CFX_PointF& point) override;
 
   virtual void SetFWLRect();
   void SetFWLThemeProvider();
   CFWL_Widget* GetNormalWidget() { return m_pNormalWidget; }
-  void FWLToClient(FX_FLOAT& fx, FX_FLOAT& fy);
+  CFX_PointF FWLToClient(const CFX_PointF& point);
   void LayoutCaption();
   void RenderCaption(CFX_Graphics* pGS, CFX_Matrix* pMatrix = nullptr);
 
diff --git a/xfa/fxfa/app/xfa_ffimage.cpp b/xfa/fxfa/app/xfa_ffimage.cpp
index c387cc2..a613221 100644
--- a/xfa/fxfa/app/xfa_ffimage.cpp
+++ b/xfa/fxfa/app/xfa_ffimage.cpp
@@ -12,11 +12,12 @@
 #include "xfa/fxfa/xfa_ffpageview.h"
 #include "xfa/fxfa/xfa_ffwidget.h"
 
-CXFA_FFImage::CXFA_FFImage(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFDraw(pPageView, pDataAcc) {}
+CXFA_FFImage::CXFA_FFImage(CXFA_WidgetAcc* pDataAcc) : CXFA_FFDraw(pDataAcc) {}
+
 CXFA_FFImage::~CXFA_FFImage() {
   CXFA_FFImage::UnloadWidget();
 }
+
 bool CXFA_FFImage::IsLoaded() {
   return !!GetDataAcc()->GetImageImage();
 }
@@ -33,34 +34,36 @@
 void CXFA_FFImage::RenderWidget(CFX_Graphics* pGS,
                                 CFX_Matrix* pMatrix,
                                 uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus)) {
+  if (!IsMatchVisibleStatus(dwStatus))
     return;
-  }
-  CFX_Matrix mtRotate;
-  GetRotateMatrix(mtRotate);
-  if (pMatrix) {
+
+  CFX_Matrix mtRotate = GetRotateMatrix();
+  if (pMatrix)
     mtRotate.Concat(*pMatrix);
-  }
+
   CXFA_FFWidget::RenderWidget(pGS, &mtRotate, dwStatus);
-  if (CFX_DIBitmap* pDIBitmap = GetDataAcc()->GetImageImage()) {
-    CFX_RectF rtImage;
-    GetRectWithoutRotate(rtImage);
-    if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin()) {
-      XFA_RectWidthoutMargin(rtImage, mgWidget);
-    }
-    int32_t iHorzAlign = XFA_ATTRIBUTEENUM_Left;
-    int32_t iVertAlign = XFA_ATTRIBUTEENUM_Top;
-    if (CXFA_Para para = m_pDataAcc->GetPara()) {
-      iHorzAlign = para.GetHorizontalAlign();
-      iVertAlign = para.GetVerticalAlign();
-    }
-    CXFA_Value value = m_pDataAcc->GetFormValue();
-    CXFA_Image imageObj = value.GetImage();
-    int32_t iAspect = imageObj.GetAspect();
-    int32_t iImageXDpi = 0;
-    int32_t iImageYDpi = 0;
-    m_pDataAcc->GetImageDpi(iImageXDpi, iImageYDpi);
-    XFA_DrawImage(pGS, rtImage, &mtRotate, pDIBitmap, iAspect, iImageXDpi,
-                  iImageYDpi, iHorzAlign, iVertAlign);
+
+  CFX_DIBitmap* pDIBitmap = GetDataAcc()->GetImageImage();
+  if (!pDIBitmap)
+    return;
+
+  CFX_RectF rtImage = GetRectWithoutRotate();
+  if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin())
+    XFA_RectWidthoutMargin(rtImage, mgWidget);
+
+  int32_t iHorzAlign = XFA_ATTRIBUTEENUM_Left;
+  int32_t iVertAlign = XFA_ATTRIBUTEENUM_Top;
+  if (CXFA_Para para = m_pDataAcc->GetPara()) {
+    iHorzAlign = para.GetHorizontalAlign();
+    iVertAlign = para.GetVerticalAlign();
   }
+
+  CXFA_Value value = m_pDataAcc->GetFormValue();
+  CXFA_Image imageObj = value.GetImage();
+  int32_t iAspect = imageObj.GetAspect();
+  int32_t iImageXDpi = 0;
+  int32_t iImageYDpi = 0;
+  m_pDataAcc->GetImageDpi(iImageXDpi, iImageYDpi);
+  XFA_DrawImage(pGS, rtImage, &mtRotate, pDIBitmap, iAspect, iImageXDpi,
+                iImageYDpi, iHorzAlign, iVertAlign);
 }
diff --git a/xfa/fxfa/app/xfa_ffimage.h b/xfa/fxfa/app/xfa_ffimage.h
index cc5320e..2c42791 100644
--- a/xfa/fxfa/app/xfa_ffimage.h
+++ b/xfa/fxfa/app/xfa_ffimage.h
@@ -11,7 +11,7 @@
 
 class CXFA_FFImage : public CXFA_FFDraw {
  public:
-  CXFA_FFImage(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFImage(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFImage() override;
 
   // CXFA_FFWidget
diff --git a/xfa/fxfa/app/xfa_ffimageedit.cpp b/xfa/fxfa/app/xfa_ffimageedit.cpp
index 3b063d6..01d29ee 100644
--- a/xfa/fxfa/app/xfa_ffimageedit.cpp
+++ b/xfa/fxfa/app/xfa_ffimageedit.cpp
@@ -16,12 +16,13 @@
 #include "xfa/fxfa/xfa_ffpageview.h"
 #include "xfa/fxfa/xfa_ffwidget.h"
 
-CXFA_FFImageEdit::CXFA_FFImageEdit(CXFA_FFPageView* pPageView,
-                                   CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFField(pPageView, pDataAcc), m_pOldDelegate(nullptr) {}
+CXFA_FFImageEdit::CXFA_FFImageEdit(CXFA_WidgetAcc* pDataAcc)
+    : CXFA_FFField(pDataAcc), m_pOldDelegate(nullptr) {}
+
 CXFA_FFImageEdit::~CXFA_FFImageEdit() {
   CXFA_FFImageEdit::UnloadWidget();
 }
+
 bool CXFA_FFImageEdit::LoadWidget() {
   CFWL_PictureBox* pPictureBox = new CFWL_PictureBox(GetFWLApp());
   m_pNormalWidget = pPictureBox;
@@ -48,47 +49,47 @@
 void CXFA_FFImageEdit::RenderWidget(CFX_Graphics* pGS,
                                     CFX_Matrix* pMatrix,
                                     uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus)) {
+  if (!IsMatchVisibleStatus(dwStatus))
     return;
-  }
-  CFX_Matrix mtRotate;
-  GetRotateMatrix(mtRotate);
-  if (pMatrix) {
+
+  CFX_Matrix mtRotate = GetRotateMatrix();
+  if (pMatrix)
     mtRotate.Concat(*pMatrix);
-  }
+
   CXFA_FFWidget::RenderWidget(pGS, &mtRotate, dwStatus);
   CXFA_Border borderUI = m_pDataAcc->GetUIBorder();
   DrawBorder(pGS, borderUI, m_rtUI, &mtRotate);
   RenderCaption(pGS, &mtRotate);
-  if (CFX_DIBitmap* pDIBitmap = m_pDataAcc->GetImageEditImage()) {
-    CFX_RectF rtImage = m_pNormalWidget->GetWidgetRect();
-    int32_t iHorzAlign = XFA_ATTRIBUTEENUM_Left;
-    int32_t iVertAlign = XFA_ATTRIBUTEENUM_Top;
-    if (CXFA_Para para = m_pDataAcc->GetPara()) {
-      iHorzAlign = para.GetHorizontalAlign();
-      iVertAlign = para.GetVerticalAlign();
-    }
-    int32_t iAspect = XFA_ATTRIBUTEENUM_Fit;
-    if (CXFA_Value value = m_pDataAcc->GetFormValue()) {
-      if (CXFA_Image imageObj = value.GetImage()) {
-        iAspect = imageObj.GetAspect();
-      }
-    }
-    int32_t iImageXDpi = 0;
-    int32_t iImageYDpi = 0;
-    m_pDataAcc->GetImageEditDpi(iImageXDpi, iImageYDpi);
-    XFA_DrawImage(pGS, rtImage, &mtRotate, pDIBitmap, iAspect, iImageXDpi,
-                  iImageYDpi, iHorzAlign, iVertAlign);
+  CFX_DIBitmap* pDIBitmap = m_pDataAcc->GetImageEditImage();
+  if (!pDIBitmap)
+    return;
+
+  CFX_RectF rtImage = m_pNormalWidget->GetWidgetRect();
+  int32_t iHorzAlign = XFA_ATTRIBUTEENUM_Left;
+  int32_t iVertAlign = XFA_ATTRIBUTEENUM_Top;
+  if (CXFA_Para para = m_pDataAcc->GetPara()) {
+    iHorzAlign = para.GetHorizontalAlign();
+    iVertAlign = para.GetVerticalAlign();
   }
+
+  int32_t iAspect = XFA_ATTRIBUTEENUM_Fit;
+  if (CXFA_Value value = m_pDataAcc->GetFormValue()) {
+    if (CXFA_Image imageObj = value.GetImage())
+      iAspect = imageObj.GetAspect();
+  }
+
+  int32_t iImageXDpi = 0;
+  int32_t iImageYDpi = 0;
+  m_pDataAcc->GetImageEditDpi(iImageXDpi, iImageYDpi);
+  XFA_DrawImage(pGS, rtImage, &mtRotate, pDIBitmap, iAspect, iImageXDpi,
+                iImageYDpi, iHorzAlign, iVertAlign);
 }
 
 bool CXFA_FFImageEdit::OnLButtonDown(uint32_t dwFlags,
-                                     FX_FLOAT fx,
-                                     FX_FLOAT fy) {
+                                     const CFX_PointF& point) {
   if (m_pDataAcc->GetAccess() != XFA_ATTRIBUTEENUM_Open)
     return false;
-
-  if (!PtInActiveRect(fx, fy))
+  if (!PtInActiveRect(point))
     return false;
 
   SetButtonDown(true);
@@ -96,9 +97,7 @@
   CFWL_MessageMouse ms(nullptr, m_pNormalWidget);
   ms.m_dwCmd = FWL_MouseCommand::LeftButtonDown;
   ms.m_dwFlags = dwFlags;
-  ms.m_fx = fx;
-  ms.m_fy = fy;
-  FWLToClient(ms.m_fx, ms.m_fy);
+  ms.m_pos = FWLToClient(point);
   TranslateFWLMessage(&ms);
   return true;
 }
diff --git a/xfa/fxfa/app/xfa_ffimageedit.h b/xfa/fxfa/app/xfa_ffimageedit.h
index b6f6ae1..73032b9 100644
--- a/xfa/fxfa/app/xfa_ffimageedit.h
+++ b/xfa/fxfa/app/xfa_ffimageedit.h
@@ -11,7 +11,7 @@
 
 class CXFA_FFImageEdit : public CXFA_FFField {
  public:
-  CXFA_FFImageEdit(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFImageEdit(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFImageEdit() override;
 
   // CXFA_FFField
@@ -20,7 +20,7 @@
                     uint32_t dwStatus) override;
   bool LoadWidget() override;
   void UnloadWidget() override;
-  bool OnLButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
+  bool OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) override;
   void OnProcessMessage(CFWL_Message* pMessage) override;
   void OnProcessEvent(CFWL_Event* pEvent) override;
   void OnDrawWidget(CFX_Graphics* pGraphics,
diff --git a/xfa/fxfa/app/xfa_ffnotify.cpp b/xfa/fxfa/app/xfa_ffnotify.cpp
index 3aef5fc..951b4fd 100644
--- a/xfa/fxfa/app/xfa_ffnotify.cpp
+++ b/xfa/fxfa/app/xfa_ffnotify.cpp
@@ -102,62 +102,62 @@
   CXFA_FFWidget* pWidget;
   switch (pAcc->GetUIType()) {
     case XFA_Element::Barcode:
-      pWidget = new CXFA_FFBarcode(nullptr, pAcc);
+      pWidget = new CXFA_FFBarcode(pAcc);
       break;
     case XFA_Element::Button:
-      pWidget = new CXFA_FFPushButton(nullptr, pAcc);
+      pWidget = new CXFA_FFPushButton(pAcc);
       break;
     case XFA_Element::CheckButton:
-      pWidget = new CXFA_FFCheckButton(nullptr, pAcc);
+      pWidget = new CXFA_FFCheckButton(pAcc);
       break;
     case XFA_Element::ChoiceList: {
       if (pAcc->IsListBox()) {
-        pWidget = new CXFA_FFListBox(nullptr, pAcc);
+        pWidget = new CXFA_FFListBox(pAcc);
       } else {
-        pWidget = new CXFA_FFComboBox(nullptr, pAcc);
+        pWidget = new CXFA_FFComboBox(pAcc);
       }
     } break;
     case XFA_Element::DateTimeEdit:
-      pWidget = new CXFA_FFDateTimeEdit(nullptr, pAcc);
+      pWidget = new CXFA_FFDateTimeEdit(pAcc);
       break;
     case XFA_Element::ImageEdit:
-      pWidget = new CXFA_FFImageEdit(nullptr, pAcc);
+      pWidget = new CXFA_FFImageEdit(pAcc);
       break;
     case XFA_Element::NumericEdit:
-      pWidget = new CXFA_FFNumericEdit(nullptr, pAcc);
+      pWidget = new CXFA_FFNumericEdit(pAcc);
       break;
     case XFA_Element::PasswordEdit:
-      pWidget = new CXFA_FFPasswordEdit(nullptr, pAcc);
+      pWidget = new CXFA_FFPasswordEdit(pAcc);
       break;
     case XFA_Element::Signature:
-      pWidget = new CXFA_FFSignature(nullptr, pAcc);
+      pWidget = new CXFA_FFSignature(pAcc);
       break;
     case XFA_Element::TextEdit:
-      pWidget = new CXFA_FFTextEdit(nullptr, pAcc);
+      pWidget = new CXFA_FFTextEdit(pAcc);
       break;
     case XFA_Element::Arc:
-      pWidget = new CXFA_FFArc(nullptr, pAcc);
+      pWidget = new CXFA_FFArc(pAcc);
       break;
     case XFA_Element::Line:
-      pWidget = new CXFA_FFLine(nullptr, pAcc);
+      pWidget = new CXFA_FFLine(pAcc);
       break;
     case XFA_Element::Rectangle:
-      pWidget = new CXFA_FFRectangle(nullptr, pAcc);
+      pWidget = new CXFA_FFRectangle(pAcc);
       break;
     case XFA_Element::Text:
-      pWidget = new CXFA_FFText(nullptr, pAcc);
+      pWidget = new CXFA_FFText(pAcc);
       break;
     case XFA_Element::Image:
-      pWidget = new CXFA_FFImage(nullptr, pAcc);
+      pWidget = new CXFA_FFImage(pAcc);
       break;
     case XFA_Element::Draw:
-      pWidget = new CXFA_FFDraw(nullptr, pAcc);
+      pWidget = new CXFA_FFDraw(pAcc);
       break;
     case XFA_Element::Subform:
-      pWidget = new CXFA_FFSubForm(nullptr, pAcc);
+      pWidget = new CXFA_FFSubForm(pAcc);
       break;
     case XFA_Element::ExclGroup:
-      pWidget = new CXFA_FFExclGroup(nullptr, pAcc);
+      pWidget = new CXFA_FFExclGroup(pAcc);
       break;
     case XFA_Element::DefaultUi:
     default:
@@ -487,9 +487,7 @@
     return;
   }
   if (pWidget->IsLoaded()) {
-    CFX_RectF rtOld;
-    pWidget->GetWidgetRect(rtOld);
-    if (rtOld != pWidget->ReCacheWidgetRect())
+    if (pWidget->GetWidgetRect() != pWidget->RecacheWidgetRect())
       pWidget->PerformLayout();
   } else {
     pWidget->LoadWidget();
diff --git a/xfa/fxfa/app/xfa_ffpageview.cpp b/xfa/fxfa/app/xfa_ffpageview.cpp
index 5ef1086..7ae5493 100644
--- a/xfa/fxfa/app/xfa_ffpageview.cpp
+++ b/xfa/fxfa/app/xfa_ffpageview.cpp
@@ -6,6 +6,11 @@
 
 #include "xfa/fxfa/xfa_ffpageview.h"
 
+#include <memory>
+#include <vector>
+
+#include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
 #include "xfa/fde/fde_render.h"
 #include "xfa/fxfa/app/xfa_ffcheckbutton.h"
 #include "xfa/fxfa/app/xfa_ffchoicelist.h"
@@ -20,16 +25,15 @@
 
 namespace {
 
-void GetPageMatrix(CFX_Matrix& pageMatrix,
-                   const CFX_RectF& docPageRect,
-                   const CFX_Rect& devicePageRect,
-                   int32_t iRotate,
-                   uint32_t dwCoordinatesType) {
+CFX_Matrix GetPageMatrix(const CFX_RectF& docPageRect,
+                         const CFX_Rect& devicePageRect,
+                         int32_t iRotate,
+                         uint32_t dwCoordinatesType) {
   ASSERT(iRotate >= 0 && iRotate <= 3);
+
   bool bFlipX = (dwCoordinatesType & 0x01) != 0;
   bool bFlipY = (dwCoordinatesType & 0x02) != 0;
-  CFX_Matrix m;
-  m.Set((bFlipX ? -1.0f : 1.0f), 0, 0, (bFlipY ? -1.0f : 1.0f), 0, 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 *= (FX_FLOAT)devicePageRect.width / docPageRect.width;
     m.d *= (FX_FLOAT)devicePageRect.height / docPageRect.height;
@@ -66,7 +70,7 @@
     default:
       break;
   }
-  pageMatrix = m;
+  return m;
 }
 
 bool PageWidgetFilter(CXFA_FFWidget* pWidget,
@@ -120,17 +124,13 @@
   return m_pDocView;
 }
 
-void CXFA_FFPageView::GetPageViewRect(CFX_RectF& rtPage) const {
-  rtPage.Set(0, 0, GetPageSize());
+CFX_RectF CXFA_FFPageView::GetPageViewRect() const {
+  return CFX_RectF(0, 0, GetPageSize());
 }
 
-void CXFA_FFPageView::GetDisplayMatrix(CFX_Matrix& mt,
-                                       const CFX_Rect& rtDisp,
-                                       int32_t iRotate) const {
-  CFX_SizeF sz = GetPageSize();
-  CFX_RectF fdePage;
-  fdePage.Set(0, 0, sz.x, sz.y);
-  GetPageMatrix(mt, fdePage, rtDisp, iRotate, 0);
+CFX_Matrix CXFA_FFPageView::GetDisplayMatrix(const CFX_Rect& rtDisp,
+                                             int32_t iRotate) const {
+  return GetPageMatrix(CFX_RectF(0, 0, GetPageSize()), rtDisp, iRotate, 0);
 }
 
 IXFA_WidgetIterator* CXFA_FFPageView::CreateWidgetIterator(
@@ -228,32 +228,34 @@
   CreateTabOrderWidgetArray();
   m_iCurWidget = -1;
 }
+
 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToFirst() {
-  if (m_TabOrderWidgetArray.GetSize() > 0) {
-    for (int32_t i = 0; i < m_TabOrderWidgetArray.GetSize(); i++) {
-      if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true,
-                           m_bIgnorerelevant)) {
-        m_iCurWidget = i;
-        return m_TabOrderWidgetArray[m_iCurWidget];
-      }
+  for (int32_t i = 0;
+       i < pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray); i++) {
+    if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true,
+                         m_bIgnorerelevant)) {
+      m_iCurWidget = i;
+      return m_TabOrderWidgetArray[m_iCurWidget];
     }
   }
   return nullptr;
 }
+
 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToLast() {
-  if (m_TabOrderWidgetArray.GetSize() > 0) {
-    for (int32_t i = m_TabOrderWidgetArray.GetSize() - 1; i >= 0; i--) {
-      if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true,
-                           m_bIgnorerelevant)) {
-        m_iCurWidget = i;
-        return m_TabOrderWidgetArray[m_iCurWidget];
-      }
+  for (int32_t i = pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray) - 1;
+       i >= 0; i--) {
+    if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true,
+                         m_bIgnorerelevant)) {
+      m_iCurWidget = i;
+      return m_TabOrderWidgetArray[m_iCurWidget];
     }
   }
   return nullptr;
 }
+
 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToNext() {
-  for (int32_t i = m_iCurWidget + 1; i < m_TabOrderWidgetArray.GetSize(); i++) {
+  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)) {
       m_iCurWidget = i;
@@ -263,6 +265,7 @@
   m_iCurWidget = -1;
   return nullptr;
 }
+
 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToPrevious() {
   for (int32_t i = m_iCurWidget - 1; i >= 0; i--) {
     if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true,
@@ -274,21 +277,22 @@
   m_iCurWidget = -1;
   return nullptr;
 }
+
 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetCurrentWidget() {
-  if (m_iCurWidget >= 0) {
-    return m_TabOrderWidgetArray[m_iCurWidget];
-  }
-  return nullptr;
+  return m_iCurWidget >= 0 ? m_TabOrderWidgetArray[m_iCurWidget] : nullptr;
 }
+
 bool CXFA_FFTabOrderPageWidgetIterator::SetCurrentWidget(
     CXFA_FFWidget* hWidget) {
-  int32_t iWidgetIndex = m_TabOrderWidgetArray.Find(hWidget);
-  if (iWidgetIndex >= 0) {
-    m_iCurWidget = iWidgetIndex;
-    return true;
-  }
-  return false;
+  auto it = std::find(m_TabOrderWidgetArray.begin(),
+                      m_TabOrderWidgetArray.end(), hWidget);
+  if (it == m_TabOrderWidgetArray.end())
+    return false;
+
+  m_iCurWidget = it - m_TabOrderWidgetArray.begin();
+  return true;
 }
+
 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetTraverseWidget(
     CXFA_FFWidget* pWidget) {
   CXFA_WidgetAcc* pAcc = pWidget->GetDataAcc();
@@ -309,29 +313,36 @@
     CXFA_FFWidget* pRefWidget) {
   return pRefWidget->GetDocView()->GetWidgetByName(wsWidgetName, pRefWidget);
 }
+
 void CXFA_FFTabOrderPageWidgetIterator::CreateTabOrderWidgetArray() {
-  m_TabOrderWidgetArray.RemoveAll();
-  CXFA_WidgetArray SpaceOrderWidgetArray;
-  CreateSpaceOrderWidgetArray(SpaceOrderWidgetArray);
-  int32_t nWidgetCount = SpaceOrderWidgetArray.GetSize();
-  if (nWidgetCount < 1) {
+  m_TabOrderWidgetArray.clear();
+
+  std::vector<CXFA_FFWidget*> SpaceOrderWidgetArray;
+  CreateSpaceOrderWidgetArray(&SpaceOrderWidgetArray);
+  if (SpaceOrderWidgetArray.empty())
     return;
-  }
+
+  int32_t nWidgetCount = pdfium::CollectionSize<int32_t>(SpaceOrderWidgetArray);
   CXFA_FFWidget* hWidget = SpaceOrderWidgetArray[0];
-  for (; m_TabOrderWidgetArray.GetSize() < nWidgetCount;) {
-    if (m_TabOrderWidgetArray.Find(hWidget) < 0) {
-      m_TabOrderWidgetArray.Add(hWidget);
+  while (pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray) <
+         nWidgetCount) {
+    if (!pdfium::ContainsValue(m_TabOrderWidgetArray, hWidget)) {
+      m_TabOrderWidgetArray.push_back(hWidget);
       CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc();
       if (pWidgetAcc->GetUIType() == XFA_Element::ExclGroup) {
-        int32_t iWidgetIndex = SpaceOrderWidgetArray.Find(hWidget) + 1;
+        auto it = std::find(SpaceOrderWidgetArray.begin(),
+                            SpaceOrderWidgetArray.end(), hWidget);
+        int32_t iWidgetIndex = it != SpaceOrderWidgetArray.end()
+                                   ? it - SpaceOrderWidgetArray.begin() + 1
+                                   : 0;
         while (true) {
           CXFA_FFWidget* pRadio =
-              SpaceOrderWidgetArray[(iWidgetIndex) % nWidgetCount];
+              SpaceOrderWidgetArray[iWidgetIndex % nWidgetCount];
           if (pRadio->GetDataAcc()->GetExclGroup() != pWidgetAcc) {
             break;
           }
-          if (m_TabOrderWidgetArray.Find(hWidget) < 0) {
-            m_TabOrderWidgetArray.Add(pRadio);
+          if (!pdfium::ContainsValue(m_TabOrderWidgetArray, hWidget)) {
+            m_TabOrderWidgetArray.push_back(pRadio);
           }
           iWidgetIndex++;
         }
@@ -341,23 +352,27 @@
         continue;
       }
     }
-    int32_t iWidgetIndex = SpaceOrderWidgetArray.Find(hWidget);
-    hWidget = SpaceOrderWidgetArray[(iWidgetIndex + 1) % nWidgetCount];
+    auto it = std::find(SpaceOrderWidgetArray.begin(),
+                        SpaceOrderWidgetArray.end(), hWidget);
+    int32_t iWidgetIndex = it != SpaceOrderWidgetArray.end()
+                               ? it - SpaceOrderWidgetArray.begin() + 1
+                               : 0;
+    hWidget = SpaceOrderWidgetArray[iWidgetIndex % nWidgetCount];
   }
 }
+
 static int32_t XFA_TabOrderWidgetComparator(const void* phWidget1,
                                             const void* phWidget2) {
-  CXFA_FFWidget* pWidget1 = (*(CXFA_TabParam**)phWidget1)->m_pWidget;
-  CXFA_FFWidget* pWidget2 = (*(CXFA_TabParam**)phWidget2)->m_pWidget;
-  CFX_RectF rt1, rt2;
-  pWidget1->GetWidgetRect(rt1);
-  pWidget2->GetWidgetRect(rt2);
+  auto param1 = *static_cast<CXFA_TabParam**>(const_cast<void*>(phWidget1));
+  auto param2 = *static_cast<CXFA_TabParam**>(const_cast<void*>(phWidget2));
+  CFX_RectF rt1 = param1->m_pWidget->GetWidgetRect();
+  CFX_RectF rt2 = param2->m_pWidget->GetWidgetRect();
   FX_FLOAT x1 = rt1.left, y1 = rt1.top, x2 = rt2.left, y2 = rt2.top;
-  if (y1 < y2 || (y1 - y2 < XFA_FLOAT_PERCISION && x1 < x2)) {
+  if (y1 < y2 || (y1 - y2 < XFA_FLOAT_PERCISION && x1 < x2))
     return -1;
-  }
   return 1;
 }
+
 void CXFA_FFTabOrderPageWidgetIterator::OrderContainer(
     CXFA_LayoutItemIterator* sIterator,
     CXFA_LayoutItem* pContainerItem,
@@ -407,36 +422,35 @@
                 XFA_TabOrderWidgetComparator);
   }
   for (int32_t iStart = 0; iStart < iChildren; iStart++) {
-    CXFA_TabParam* pParam = tabParams[iStart];
-    pContainer->m_Children.Add(pParam->m_pWidget);
-    if (pParam->m_Children.GetSize() > 0) {
-      pContainer->m_Children.Append(pParam->m_Children);
-    }
-    delete pParam;
+    std::unique_ptr<CXFA_TabParam> pParam(tabParams[iStart]);
+    pContainer->m_Children.push_back(pParam->m_pWidget);
+    pContainer->m_Children.insert(pContainer->m_Children.end(),
+                                  pParam->m_Children.begin(),
+                                  pParam->m_Children.end());
   }
   tabParams.RemoveAll();
 }
 void CXFA_FFTabOrderPageWidgetIterator::CreateSpaceOrderWidgetArray(
-    CXFA_WidgetArray& WidgetArray) {
+    std::vector<CXFA_FFWidget*>* WidgetArray) {
   CXFA_LayoutItemIterator sIterator;
   sIterator.Init(m_pPageView);
-  CXFA_TabParam* pParam = new CXFA_TabParam;
+  auto pParam = pdfium::MakeUnique<CXFA_TabParam>();
   bool bCurrentItem = false;
   bool bContentArea = false;
-  OrderContainer(&sIterator, nullptr, pParam, bCurrentItem, bContentArea);
-  if (pParam->m_Children.GetSize() > 0) {
-    WidgetArray.Append(pParam->m_Children);
-  }
+  OrderContainer(&sIterator, nullptr, pParam.get(), bCurrentItem, bContentArea);
+  WidgetArray->insert(WidgetArray->end(), pParam->m_Children.begin(),
+                      pParam->m_Children.end());
+
   sIterator.Reset();
   bCurrentItem = false;
   bContentArea = false;
-  pParam->m_Children.RemoveAll();
-  OrderContainer(&sIterator, nullptr, pParam, bCurrentItem, bContentArea, true);
-  if (pParam->m_Children.GetSize() > 0) {
-    WidgetArray.Append(pParam->m_Children);
-  }
-  delete pParam;
+  pParam->m_Children.clear();
+  OrderContainer(&sIterator, nullptr, pParam.get(), bCurrentItem, bContentArea,
+                 true);
+  WidgetArray->insert(WidgetArray->end(), pParam->m_Children.begin(),
+                      pParam->m_Children.end());
 }
+
 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetWidget(
     CXFA_LayoutItem* pLayoutItem) {
   if (CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pLayoutItem)) {
diff --git a/xfa/fxfa/app/xfa_ffpath.cpp b/xfa/fxfa/app/xfa_ffpath.cpp
index c5c91a4..43016fe 100644
--- a/xfa/fxfa/app/xfa_ffpath.cpp
+++ b/xfa/fxfa/app/xfa_ffpath.cpp
@@ -14,9 +14,10 @@
 #include "xfa/fxgraphics/cfx_color.h"
 #include "xfa/fxgraphics/cfx_path.h"
 
-CXFA_FFLine::CXFA_FFLine(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFDraw(pPageView, pDataAcc) {}
+CXFA_FFLine::CXFA_FFLine(CXFA_WidgetAcc* pDataAcc) : CXFA_FFDraw(pDataAcc) {}
+
 CXFA_FFLine::~CXFA_FFLine() {}
+
 void CXFA_FFLine::GetRectFromHand(CFX_RectF& rect,
                                   int32_t iHand,
                                   FX_FLOAT fLineWidth) {
@@ -49,50 +50,48 @@
     }
   }
 }
+
 void CXFA_FFLine::RenderWidget(CFX_Graphics* pGS,
                                CFX_Matrix* pMatrix,
                                uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus)) {
+  if (!IsMatchVisibleStatus(dwStatus))
     return;
-  }
+
   CXFA_Value value = m_pDataAcc->GetFormValue();
-  if (!value) {
+  if (!value)
     return;
-  }
+
   CXFA_Line lineObj = value.GetLine();
   FX_ARGB lineColor = 0xFF000000;
   int32_t iStrokeType = 0;
   FX_FLOAT fLineWidth = 1.0f;
-  bool bSlope = lineObj.GetSlop();
   int32_t iCap = 0;
   CXFA_Edge edge = lineObj.GetEdge();
   if (edge) {
-    if (edge.GetPresence() != XFA_ATTRIBUTEENUM_Visible) {
+    if (edge.GetPresence() != XFA_ATTRIBUTEENUM_Visible)
       return;
-    }
+
     lineColor = edge.GetColor();
     iStrokeType = edge.GetStrokeType();
     fLineWidth = edge.GetThickness();
     iCap = edge.GetCapType();
   }
-  CFX_Matrix mtRotate;
-  GetRotateMatrix(mtRotate);
-  if (pMatrix) {
+
+  CFX_Matrix mtRotate = GetRotateMatrix();
+  if (pMatrix)
     mtRotate.Concat(*pMatrix);
-  }
-  CFX_RectF rtLine;
-  GetRectWithoutRotate(rtLine);
-  if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin()) {
+
+  CFX_RectF rtLine = GetRectWithoutRotate();
+  if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin())
     XFA_RectWidthoutMargin(rtLine, mgWidget);
-  }
+
   GetRectFromHand(rtLine, lineObj.GetHand(), fLineWidth);
   CFX_Path linePath;
-  linePath.Create();
-  if (bSlope && rtLine.right() > 0.0f && rtLine.bottom() > 0.0f) {
-    linePath.AddLine(rtLine.right(), rtLine.top, rtLine.left, rtLine.bottom());
-  } else {
-    linePath.AddLine(rtLine.left, rtLine.top, rtLine.right(), rtLine.bottom());
-  }
+  if (lineObj.GetSlope() && rtLine.right() > 0.0f && rtLine.bottom() > 0.0f)
+    linePath.AddLine(rtLine.TopRight(), rtLine.BottomLeft());
+  else
+    linePath.AddLine(rtLine.TopLeft(), rtLine.BottomRight());
+
   CFX_Color color(lineColor);
   pGS->SaveGraphState();
   pGS->SetLineWidth(fLineWidth, true);
@@ -102,56 +101,56 @@
   pGS->StrokePath(&linePath, &mtRotate);
   pGS->RestoreGraphState();
 }
-CXFA_FFArc::CXFA_FFArc(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFDraw(pPageView, pDataAcc) {}
+
+CXFA_FFArc::CXFA_FFArc(CXFA_WidgetAcc* pDataAcc) : CXFA_FFDraw(pDataAcc) {}
+
 CXFA_FFArc::~CXFA_FFArc() {}
+
 void CXFA_FFArc::RenderWidget(CFX_Graphics* pGS,
                               CFX_Matrix* pMatrix,
                               uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus)) {
+  if (!IsMatchVisibleStatus(dwStatus))
     return;
-  }
+
   CXFA_Value value = m_pDataAcc->GetFormValue();
-  if (!value) {
+  if (!value)
     return;
-  }
+
   CXFA_Arc arcObj = value.GetArc();
-  CFX_Matrix mtRotate;
-  GetRotateMatrix(mtRotate);
-  if (pMatrix) {
+  CFX_Matrix mtRotate = GetRotateMatrix();
+  if (pMatrix)
     mtRotate.Concat(*pMatrix);
-  }
-  CFX_RectF rtArc;
-  GetRectWithoutRotate(rtArc);
-  if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin()) {
+
+  CFX_RectF rtArc = GetRectWithoutRotate();
+  if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin())
     XFA_RectWidthoutMargin(rtArc, mgWidget);
-  }
+
   DrawBorder(pGS, arcObj, rtArc, &mtRotate);
 }
-CXFA_FFRectangle::CXFA_FFRectangle(CXFA_FFPageView* pPageView,
-                                   CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFDraw(pPageView, pDataAcc) {}
+
+CXFA_FFRectangle::CXFA_FFRectangle(CXFA_WidgetAcc* pDataAcc)
+    : CXFA_FFDraw(pDataAcc) {}
+
 CXFA_FFRectangle::~CXFA_FFRectangle() {}
+
 void CXFA_FFRectangle::RenderWidget(CFX_Graphics* pGS,
                                     CFX_Matrix* pMatrix,
                                     uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus)) {
+  if (!IsMatchVisibleStatus(dwStatus))
     return;
-  }
+
   CXFA_Value value = m_pDataAcc->GetFormValue();
-  if (!value) {
+  if (!value)
     return;
-  }
+
   CXFA_Rectangle rtObj = value.GetRectangle();
-  CFX_RectF rect;
-  GetRectWithoutRotate(rect);
-  if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin()) {
+  CFX_RectF rect = GetRectWithoutRotate();
+  if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin())
     XFA_RectWidthoutMargin(rect, mgWidget);
-  }
-  CFX_Matrix mtRotate;
-  GetRotateMatrix(mtRotate);
-  if (pMatrix) {
+
+  CFX_Matrix mtRotate = GetRotateMatrix();
+  if (pMatrix)
     mtRotate.Concat(*pMatrix);
-  }
+
   DrawBorder(pGS, rtObj, rect, &mtRotate);
 }
diff --git a/xfa/fxfa/app/xfa_ffpath.h b/xfa/fxfa/app/xfa_ffpath.h
index 71c45e3..002f75d 100644
--- a/xfa/fxfa/app/xfa_ffpath.h
+++ b/xfa/fxfa/app/xfa_ffpath.h
@@ -11,7 +11,7 @@
 
 class CXFA_FFLine : public CXFA_FFDraw {
  public:
-  CXFA_FFLine(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFLine(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFLine() override;
 
   // CXFA_FFWidget
@@ -22,9 +22,10 @@
  private:
   void GetRectFromHand(CFX_RectF& rect, int32_t iHand, FX_FLOAT fLineWidth);
 };
+
 class CXFA_FFArc : public CXFA_FFDraw {
  public:
-  CXFA_FFArc(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFArc(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFArc() override;
 
   // CXFA_FFWidget
@@ -35,7 +36,7 @@
 
 class CXFA_FFRectangle : public CXFA_FFDraw {
  public:
-  CXFA_FFRectangle(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFRectangle(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFRectangle() override;
 
   // CXFA_FFWidget
diff --git a/xfa/fxfa/app/xfa_ffpushbutton.cpp b/xfa/fxfa/app/xfa_ffpushbutton.cpp
index 4d4d1aa..7b6be82 100644
--- a/xfa/fxfa/app/xfa_ffpushbutton.cpp
+++ b/xfa/fxfa/app/xfa_ffpushbutton.cpp
@@ -18,37 +18,37 @@
 #include "xfa/fxgraphics/cfx_color.h"
 #include "xfa/fxgraphics/cfx_path.h"
 
-CXFA_FFPushButton::CXFA_FFPushButton(CXFA_FFPageView* pPageView,
-                                     CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFField(pPageView, pDataAcc),
+CXFA_FFPushButton::CXFA_FFPushButton(CXFA_WidgetAcc* pDataAcc)
+    : CXFA_FFField(pDataAcc),
       m_pRolloverTextLayout(nullptr),
       m_pDownTextLayout(nullptr),
       m_pDownProvider(nullptr),
       m_pRollProvider(nullptr),
       m_pOldDelegate(nullptr) {}
+
 CXFA_FFPushButton::~CXFA_FFPushButton() {
   CXFA_FFPushButton::UnloadWidget();
 }
+
 void CXFA_FFPushButton::RenderWidget(CFX_Graphics* pGS,
                                      CFX_Matrix* pMatrix,
                                      uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus)) {
+  if (!IsMatchVisibleStatus(dwStatus))
     return;
-  }
-  CFX_Matrix mtRotate;
-  GetRotateMatrix(mtRotate);
-  if (pMatrix) {
+
+  CFX_Matrix mtRotate = GetRotateMatrix();
+  if (pMatrix)
     mtRotate.Concat(*pMatrix);
-  }
+
   CXFA_FFWidget::RenderWidget(pGS, &mtRotate, dwStatus);
   RenderHighlightCaption(pGS, &mtRotate);
-  CFX_RectF rtWidget;
-  GetRectWithoutRotate(rtWidget);
-  CFX_Matrix mt;
-  mt.Set(1, 0, 0, 1, rtWidget.left, rtWidget.top);
+
+  CFX_RectF rtWidget = GetRectWithoutRotate();
+  CFX_Matrix mt(1, 0, 0, 1, rtWidget.left, rtWidget.top);
   mt.Concat(mtRotate);
   GetApp()->GetWidgetMgrDelegate()->OnDrawWidget(m_pNormalWidget, pGS, &mt);
 }
+
 bool CXFA_FFPushButton::LoadWidget() {
   ASSERT(!m_pNormalWidget);
   CFWL_PushButton* pPushButton = new CFWL_PushButton(GetFWLApp());
@@ -99,22 +99,22 @@
 
 bool CXFA_FFPushButton::PerformLayout() {
   CXFA_FFWidget::PerformLayout();
-  CFX_RectF rtWidget;
-  GetRectWithoutRotate(rtWidget);
+  CFX_RectF rtWidget = GetRectWithoutRotate();
+
   m_rtUI = rtWidget;
-  if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin()) {
+  if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin())
     XFA_RectWidthoutMargin(rtWidget, mgWidget);
-  }
+
   CXFA_Caption caption = m_pDataAcc->GetCaption();
-  m_rtCaption.Set(rtWidget.left, rtWidget.top, rtWidget.width, rtWidget.height);
-  if (CXFA_Margin mgCap = caption.GetMargin()) {
+  m_rtCaption = rtWidget;
+  if (CXFA_Margin mgCap = caption.GetMargin())
     XFA_RectWidthoutMargin(m_rtCaption, mgCap);
-  }
+
   LayoutHighlightCaption();
   SetFWLRect();
-  if (m_pNormalWidget) {
+  if (m_pNormalWidget)
     m_pNormalWidget->Update();
-  }
+
   return true;
 }
 FX_FLOAT CXFA_FFPushButton::GetLineWidth() {
@@ -169,35 +169,30 @@
                                                CFX_Matrix* pMatrix) {
   CXFA_TextLayout* pCapTextLayout = m_pDataAcc->GetCaptionTextLayout();
   CXFA_Caption caption = m_pDataAcc->GetCaption();
-  if (caption && caption.GetPresence() == XFA_ATTRIBUTEENUM_Visible) {
-    CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
-    CFX_RectF rtWidget;
-    GetRectWithoutRotate(rtWidget);
-    CFX_RectF rtClip = m_rtCaption;
-    rtClip.Intersect(rtWidget);
-    CFX_Matrix mt;
-    mt.Set(1, 0, 0, 1, m_rtCaption.left, m_rtCaption.top);
-    if (pMatrix) {
-      pMatrix->TransformRect(rtClip);
-      mt.Concat(*pMatrix);
-    }
-    {
-      uint32_t dwState = m_pNormalWidget->GetStates();
-      if (m_pDownTextLayout && (dwState & FWL_STATE_PSB_Pressed) &&
-          (dwState & FWL_STATE_PSB_Hovered)) {
-        if (m_pDownTextLayout->DrawString(pRenderDevice, mt, rtClip)) {
-          return;
-        }
-      } else if (m_pRolloverTextLayout && (dwState & FWL_STATE_PSB_Hovered)) {
-        if (m_pRolloverTextLayout->DrawString(pRenderDevice, mt, rtClip)) {
-          return;
-        }
-      }
-    }
-    if (pCapTextLayout) {
-      pCapTextLayout->DrawString(pRenderDevice, mt, rtClip);
-    }
+  if (!caption || caption.GetPresence() != XFA_ATTRIBUTEENUM_Visible)
+    return;
+
+  CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
+  CFX_RectF rtClip = m_rtCaption;
+  rtClip.Intersect(GetRectWithoutRotate());
+  CFX_Matrix mt(1, 0, 0, 1, m_rtCaption.left, m_rtCaption.top);
+  if (pMatrix) {
+    pMatrix->TransformRect(rtClip);
+    mt.Concat(*pMatrix);
   }
+
+  uint32_t dwState = m_pNormalWidget->GetStates();
+  if (m_pDownTextLayout && (dwState & FWL_STATE_PSB_Pressed) &&
+      (dwState & FWL_STATE_PSB_Hovered)) {
+    if (m_pDownTextLayout->DrawString(pRenderDevice, mt, rtClip))
+      return;
+  } else if (m_pRolloverTextLayout && (dwState & FWL_STATE_PSB_Hovered)) {
+    if (m_pRolloverTextLayout->DrawString(pRenderDevice, mt, rtClip))
+      return;
+  }
+
+  if (pCapTextLayout)
+    pCapTextLayout->DrawString(pRenderDevice, mt, rtClip);
 }
 
 void CXFA_FFPushButton::OnProcessMessage(CFWL_Message* pMessage) {
@@ -214,14 +209,13 @@
   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 = m_pNormalWidget->GetWidgetRect();
-      rtFill.left = rtFill.top = 0;
+      CFX_RectF rtFill(0, 0, m_pNormalWidget->GetWidgetRect().Size());
       FX_FLOAT fLineWith = GetLineWidth();
       rtFill.Deflate(fLineWith, fLineWith);
       CFX_Color cr(FXARGB_MAKE(128, 128, 255, 255));
       pGraphics->SetFillColor(&cr);
+
       CFX_Path path;
-      path.Create();
       path.AddRectangle(rtFill.left, rtFill.top, rtFill.width, rtFill.height);
       pGraphics->FillPath(&path, FXFILL_WINDING, (CFX_Matrix*)pMatrix);
     }
@@ -233,9 +227,8 @@
       CFX_Color cr(FXARGB_MAKE(255, 128, 255, 255));
       pGraphics->SetStrokeColor(&cr);
       pGraphics->SetLineWidth(fLineWidth);
-      CFX_Path path;
-      path.Create();
 
+      CFX_Path path;
       CFX_RectF rect = m_pNormalWidget->GetWidgetRect();
       path.AddRectangle(0, 0, rect.width, rect.height);
       pGraphics->StrokePath(&path, (CFX_Matrix*)pMatrix);
diff --git a/xfa/fxfa/app/xfa_ffpushbutton.h b/xfa/fxfa/app/xfa_ffpushbutton.h
index d5fe0b2..eb18ccb 100644
--- a/xfa/fxfa/app/xfa_ffpushbutton.h
+++ b/xfa/fxfa/app/xfa_ffpushbutton.h
@@ -18,7 +18,7 @@
 
 class CXFA_FFPushButton : public CXFA_FFField {
  public:
-  CXFA_FFPushButton(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFPushButton(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFPushButton() override;
 
   // CXFA_FFField
diff --git a/xfa/fxfa/app/xfa_ffsignature.cpp b/xfa/fxfa/app/xfa_ffsignature.cpp
index 7b8da0c..bf2bba3 100644
--- a/xfa/fxfa/app/xfa_ffsignature.cpp
+++ b/xfa/fxfa/app/xfa_ffsignature.cpp
@@ -11,25 +11,27 @@
 #include "xfa/fxfa/xfa_ffpageview.h"
 #include "xfa/fxfa/xfa_ffwidget.h"
 
-CXFA_FFSignature::CXFA_FFSignature(CXFA_FFPageView* pPageView,
-                                   CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFField(pPageView, pDataAcc) {}
+CXFA_FFSignature::CXFA_FFSignature(CXFA_WidgetAcc* pDataAcc)
+    : CXFA_FFField(pDataAcc) {}
+
 CXFA_FFSignature::~CXFA_FFSignature() {}
+
 bool CXFA_FFSignature::LoadWidget() {
   return CXFA_FFField::LoadWidget();
 }
+
 void CXFA_FFSignature::RenderWidget(CFX_Graphics* pGS,
                                     CFX_Matrix* pMatrix,
                                     uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus)) {
+  if (!IsMatchVisibleStatus(dwStatus))
     return;
-  }
-  CFX_Matrix mtRotate;
-  GetRotateMatrix(mtRotate);
-  if (pMatrix) {
+
+  CFX_Matrix mtRotate = GetRotateMatrix();
+  if (pMatrix)
     mtRotate.Concat(*pMatrix);
-  }
+
   CXFA_FFWidget::RenderWidget(pGS, &mtRotate, dwStatus);
+
   CXFA_Border borderUI = m_pDataAcc->GetUIBorder();
   DrawBorder(pGS, borderUI, m_rtUI, &mtRotate);
   RenderCaption(pGS, &mtRotate);
@@ -39,68 +41,74 @@
 bool CXFA_FFSignature::OnMouseEnter() {
   return false;
 }
+
 bool CXFA_FFSignature::OnMouseExit() {
   return false;
 }
+
 bool CXFA_FFSignature::OnLButtonDown(uint32_t dwFlags,
-                                     FX_FLOAT fx,
-                                     FX_FLOAT fy) {
+                                     const CFX_PointF& point) {
   return false;
 }
-bool CXFA_FFSignature::OnLButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
+
+bool CXFA_FFSignature::OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
   return false;
 }
+
 bool CXFA_FFSignature::OnLButtonDblClk(uint32_t dwFlags,
-                                       FX_FLOAT fx,
-                                       FX_FLOAT fy) {
+                                       const CFX_PointF& point) {
   return false;
 }
-bool CXFA_FFSignature::OnMouseMove(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
+
+bool CXFA_FFSignature::OnMouseMove(uint32_t dwFlags, const CFX_PointF& point) {
   return false;
 }
+
 bool CXFA_FFSignature::OnMouseWheel(uint32_t dwFlags,
                                     int16_t zDelta,
-                                    FX_FLOAT fx,
-                                    FX_FLOAT fy) {
+                                    const CFX_PointF& point) {
   return false;
 }
+
 bool CXFA_FFSignature::OnRButtonDown(uint32_t dwFlags,
-                                     FX_FLOAT fx,
-                                     FX_FLOAT fy) {
+                                     const CFX_PointF& point) {
   return false;
 }
-bool CXFA_FFSignature::OnRButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
+
+bool CXFA_FFSignature::OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
   return false;
 }
+
 bool CXFA_FFSignature::OnRButtonDblClk(uint32_t dwFlags,
-                                       FX_FLOAT fx,
-                                       FX_FLOAT fy) {
+                                       const CFX_PointF& point) {
   return false;
 }
+
 bool CXFA_FFSignature::OnKeyDown(uint32_t dwKeyCode, uint32_t dwFlags) {
   return false;
 }
+
 bool CXFA_FFSignature::OnKeyUp(uint32_t dwKeyCode, uint32_t dwFlags) {
   return false;
 }
+
 bool CXFA_FFSignature::OnChar(uint32_t dwChar, uint32_t dwFlags) {
   return false;
 }
-FWL_WidgetHit CXFA_FFSignature::OnHitTest(FX_FLOAT fx, FX_FLOAT fy) {
-  if (m_pNormalWidget) {
-    FX_FLOAT ffx = fx, ffy = fy;
-    FWLToClient(ffx, ffy);
-    if (m_pNormalWidget->HitTest(ffx, ffy) != FWL_WidgetHit::Unknown)
-      return FWL_WidgetHit::Client;
+
+FWL_WidgetHit CXFA_FFSignature::OnHitTest(const CFX_PointF& point) {
+  if (m_pNormalWidget &&
+      m_pNormalWidget->HitTest(FWLToClient(point)) != FWL_WidgetHit::Unknown) {
+    return FWL_WidgetHit::Client;
   }
-  CFX_RectF rtBox;
-  GetRectWithoutRotate(rtBox);
-  if (!rtBox.Contains(fx, fy))
+
+  if (!GetRectWithoutRotate().Contains(point))
     return FWL_WidgetHit::Unknown;
-  if (m_rtCaption.Contains(fx, fy))
+  if (m_rtCaption.Contains(point))
     return FWL_WidgetHit::Titlebar;
   return FWL_WidgetHit::Client;
 }
-bool CXFA_FFSignature::OnSetCursor(FX_FLOAT fx, FX_FLOAT fy) {
+
+bool CXFA_FFSignature::OnSetCursor(const CFX_PointF& point) {
   return false;
 }
diff --git a/xfa/fxfa/app/xfa_ffsignature.h b/xfa/fxfa/app/xfa_ffsignature.h
index 28053b7..934323f 100644
--- a/xfa/fxfa/app/xfa_ffsignature.h
+++ b/xfa/fxfa/app/xfa_ffsignature.h
@@ -11,7 +11,7 @@
 
 class CXFA_FFSignature final : public CXFA_FFField {
  public:
-  CXFA_FFSignature(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFSignature(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFSignature() override;
 
   // CXFA_FFField
@@ -21,23 +21,22 @@
   bool LoadWidget() override;
   bool OnMouseEnter() override;
   bool OnMouseExit() override;
-  bool OnLButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnLButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnLButtonDblClk(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnMouseMove(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
+  bool OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) override;
+  bool OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) override;
+  bool OnLButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) override;
+  bool OnMouseMove(uint32_t dwFlags, const CFX_PointF& point) override;
   bool OnMouseWheel(uint32_t dwFlags,
                     int16_t zDelta,
-                    FX_FLOAT fx,
-                    FX_FLOAT fy) override;
-  bool OnRButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnRButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnRButtonDblClk(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
+                    const CFX_PointF& pointy) override;
+  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(FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnSetCursor(FX_FLOAT fx, FX_FLOAT fy) override;
+  FWL_WidgetHit OnHitTest(const CFX_PointF& point) override;
+  bool OnSetCursor(const CFX_PointF& point) override;
 };
 
 #endif  // XFA_FXFA_APP_XFA_FFSIGNATURE_H_
diff --git a/xfa/fxfa/app/xfa_ffsubform.cpp b/xfa/fxfa/app/xfa_ffsubform.cpp
index 38c21fb..0b479f4 100644
--- a/xfa/fxfa/app/xfa_ffsubform.cpp
+++ b/xfa/fxfa/app/xfa_ffsubform.cpp
@@ -11,7 +11,7 @@
 #include "xfa/fxfa/xfa_ffpageview.h"
 #include "xfa/fxfa/xfa_ffwidget.h"
 
-CXFA_FFSubForm::CXFA_FFSubForm(CXFA_FFPageView* pPageView,
-                               CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFWidget(pPageView, pDataAcc) {}
+CXFA_FFSubForm::CXFA_FFSubForm(CXFA_WidgetAcc* pDataAcc)
+    : CXFA_FFWidget(pDataAcc) {}
+
 CXFA_FFSubForm::~CXFA_FFSubForm() {}
diff --git a/xfa/fxfa/app/xfa_ffsubform.h b/xfa/fxfa/app/xfa_ffsubform.h
index 98ce739..e6b77a8 100644
--- a/xfa/fxfa/app/xfa_ffsubform.h
+++ b/xfa/fxfa/app/xfa_ffsubform.h
@@ -12,7 +12,7 @@
 
 class CXFA_FFSubForm : public CXFA_FFWidget {
  public:
-  CXFA_FFSubForm(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFSubForm(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFSubForm() override;
 };
 
diff --git a/xfa/fxfa/app/xfa_fftext.cpp b/xfa/fxfa/app/xfa_fftext.cpp
index 3d2c9a6..e8d7aa3 100644
--- a/xfa/fxfa/app/xfa_fftext.cpp
+++ b/xfa/fxfa/app/xfa_fftext.cpp
@@ -19,52 +19,55 @@
 #include "xfa/fxfa/xfa_ffwidget.h"
 #include "xfa/fxgraphics/cfx_graphics.h"
 
-CXFA_FFText::CXFA_FFText(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFDraw(pPageView, pDataAcc) {}
+CXFA_FFText::CXFA_FFText(CXFA_WidgetAcc* pDataAcc) : CXFA_FFDraw(pDataAcc) {}
+
 CXFA_FFText::~CXFA_FFText() {}
+
 void CXFA_FFText::RenderWidget(CFX_Graphics* pGS,
                                CFX_Matrix* pMatrix,
                                uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus)) {
+  if (!IsMatchVisibleStatus(dwStatus))
     return;
-  }
-  {
-    CFX_Matrix mtRotate;
-    GetRotateMatrix(mtRotate);
-    if (pMatrix) {
-      mtRotate.Concat(*pMatrix);
-    }
-    CXFA_FFWidget::RenderWidget(pGS, &mtRotate, dwStatus);
-    CXFA_TextLayout* pTextLayout = m_pDataAcc->GetTextLayout();
-    if (pTextLayout) {
-      CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
-      CFX_RectF rtText;
-      GetRectWithoutRotate(rtText);
-      if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin()) {
-        CXFA_LayoutItem* pItem = this;
-        if (!pItem->GetPrev() && !pItem->GetNext()) {
-          XFA_RectWidthoutMargin(rtText, mgWidget);
-        } else {
-          FX_FLOAT fLeftInset, fRightInset, fTopInset = 0, fBottomInset = 0;
-          mgWidget.GetLeftInset(fLeftInset);
-          mgWidget.GetRightInset(fRightInset);
-          if (!pItem->GetPrev()) {
-            mgWidget.GetTopInset(fTopInset);
-          } else if (!pItem->GetNext()) {
-            mgWidget.GetBottomInset(fBottomInset);
-          }
-          rtText.Deflate(fLeftInset, fTopInset, fRightInset, fBottomInset);
-        }
-      }
-      CFX_Matrix mt;
-      mt.Set(1, 0, 0, 1, rtText.left, rtText.top);
-      CFX_RectF rtClip = rtText;
-      mtRotate.TransformRect(rtClip);
-      mt.Concat(mtRotate);
-      pTextLayout->DrawString(pRenderDevice, mt, rtClip, GetIndex());
+
+  CFX_Matrix mtRotate = GetRotateMatrix();
+  if (pMatrix)
+    mtRotate.Concat(*pMatrix);
+
+  CXFA_FFWidget::RenderWidget(pGS, &mtRotate, dwStatus);
+
+  CXFA_TextLayout* pTextLayout = m_pDataAcc->GetTextLayout();
+  if (!pTextLayout)
+    return;
+
+  CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
+  CFX_RectF rtText = GetRectWithoutRotate();
+  if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin()) {
+    CXFA_LayoutItem* pItem = this;
+    if (!pItem->GetPrev() && !pItem->GetNext()) {
+      XFA_RectWidthoutMargin(rtText, mgWidget);
+    } else {
+      FX_FLOAT fLeftInset;
+      FX_FLOAT fRightInset;
+      FX_FLOAT fTopInset = 0;
+      FX_FLOAT fBottomInset = 0;
+      mgWidget.GetLeftInset(fLeftInset);
+      mgWidget.GetRightInset(fRightInset);
+      if (!pItem->GetPrev())
+        mgWidget.GetTopInset(fTopInset);
+      else if (!pItem->GetNext())
+        mgWidget.GetBottomInset(fBottomInset);
+
+      rtText.Deflate(fLeftInset, fTopInset, fRightInset, fBottomInset);
     }
   }
+
+  CFX_Matrix mt(1, 0, 0, 1, rtText.left, rtText.top);
+  CFX_RectF rtClip = rtText;
+  mtRotate.TransformRect(rtClip);
+  mt.Concat(mtRotate);
+  pTextLayout->DrawString(pRenderDevice, mt, rtClip, GetIndex());
 }
+
 bool CXFA_FFText::IsLoaded() {
   CXFA_TextLayout* pTextLayout = m_pDataAcc->GetTextLayout();
   return pTextLayout && !pTextLayout->m_bHasBlock;
@@ -85,8 +88,7 @@
   }
   pItem = pItem->GetFirst();
   while (pItem) {
-    CFX_RectF rtText;
-    pItem->GetRect(rtText);
+    CFX_RectF rtText = pItem->GetRect(false);
     if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin()) {
       if (!pItem->GetPrev()) {
         FX_FLOAT fTopInset;
@@ -104,73 +106,58 @@
   pTextLayout->m_bHasBlock = false;
   return true;
 }
-bool CXFA_FFText::OnLButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
-  CFX_RectF rtBox;
-  GetRectWithoutRotate(rtBox);
-  if (!rtBox.Contains(fx, fy)) {
+
+bool CXFA_FFText::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
+  if (!GetRectWithoutRotate().Contains(point))
     return false;
-  }
-  const FX_WCHAR* wsURLContent = GetLinkURLAtPoint(fx, fy);
-  if (!wsURLContent) {
+
+  const FX_WCHAR* wsURLContent = GetLinkURLAtPoint(point);
+  if (!wsURLContent)
     return false;
-  }
+
   SetButtonDown(true);
   return true;
 }
-bool CXFA_FFText::OnMouseMove(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
-  CFX_RectF rtBox;
-  GetRectWithoutRotate(rtBox);
-  if (!rtBox.Contains(fx, fy)) {
-    return false;
-  }
-  const FX_WCHAR* wsURLContent = GetLinkURLAtPoint(fx, fy);
-  if (!wsURLContent) {
-    return false;
-  }
-  return true;
+
+bool CXFA_FFText::OnMouseMove(uint32_t dwFlags, const CFX_PointF& point) {
+  return GetRectWithoutRotate().Contains(point) && !!GetLinkURLAtPoint(point);
 }
-bool CXFA_FFText::OnLButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
-  if (!IsButtonDown()) {
+
+bool CXFA_FFText::OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
+  if (!IsButtonDown())
     return false;
-  }
+
   SetButtonDown(false);
-  const FX_WCHAR* wsURLContent = GetLinkURLAtPoint(fx, fy);
-  if (!wsURLContent) {
+  const FX_WCHAR* wsURLContent = GetLinkURLAtPoint(point);
+  if (!wsURLContent)
     return false;
-  }
+
   CXFA_FFDoc* pDoc = GetDoc();
   pDoc->GetDocEnvironment()->GotoURL(pDoc, wsURLContent);
   return true;
 }
-FWL_WidgetHit CXFA_FFText::OnHitTest(FX_FLOAT fx, FX_FLOAT fy) {
-  CFX_RectF rtBox;
-  GetRectWithoutRotate(rtBox);
-  if (!rtBox.Contains(fx, fy))
+
+FWL_WidgetHit CXFA_FFText::OnHitTest(const CFX_PointF& point) {
+  if (!GetRectWithoutRotate().Contains(point))
     return FWL_WidgetHit::Unknown;
-  if (!GetLinkURLAtPoint(fx, fy))
+  if (!GetLinkURLAtPoint(point))
     return FWL_WidgetHit::Unknown;
   return FWL_WidgetHit::HyperLink;
 }
-const FX_WCHAR* CXFA_FFText::GetLinkURLAtPoint(FX_FLOAT fx, FX_FLOAT fy) {
+
+const FX_WCHAR* CXFA_FFText::GetLinkURLAtPoint(const CFX_PointF& point) {
   CXFA_TextLayout* pTextLayout = m_pDataAcc->GetTextLayout();
   if (!pTextLayout)
     return nullptr;
 
-  FX_FLOAT x(fx);
-  FX_FLOAT y(fy);
-  FWLToClient(x, y);
-
+  CFX_RectF rect = GetRectWithoutRotate();
   for (const auto& pPieceLine : *pTextLayout->GetPieceLines()) {
     for (const auto& pPiece : pPieceLine->m_textPieces) {
-      if (pPiece->pLinkData && pPiece->rtPiece.Contains(x, y))
+      if (pPiece->pLinkData &&
+          pPiece->rtPiece.Contains(point - rect.TopLeft())) {
         return pPiece->pLinkData->GetLinkURL();
+      }
     }
   }
   return nullptr;
 }
-void CXFA_FFText::FWLToClient(FX_FLOAT& fx, FX_FLOAT& fy) {
-  CFX_RectF rtWidget;
-  GetRectWithoutRotate(rtWidget);
-  fx -= rtWidget.left;
-  fy -= rtWidget.top;
-}
diff --git a/xfa/fxfa/app/xfa_fftext.h b/xfa/fxfa/app/xfa_fftext.h
index 71f36e2..c553821 100644
--- a/xfa/fxfa/app/xfa_fftext.h
+++ b/xfa/fxfa/app/xfa_fftext.h
@@ -11,14 +11,14 @@
 
 class CXFA_FFText : public CXFA_FFDraw {
  public:
-  CXFA_FFText(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFText(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFText() override;
 
   // CXFA_FFWidget
-  bool OnLButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnLButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnMouseMove(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
-  FWL_WidgetHit OnHitTest(FX_FLOAT fx, FX_FLOAT fy) 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;
   void RenderWidget(CFX_Graphics* pGS,
                     CFX_Matrix* pMatrix,
                     uint32_t dwStatus) override;
@@ -26,8 +26,7 @@
   bool PerformLayout() override;
 
  private:
-  const FX_WCHAR* GetLinkURLAtPoint(FX_FLOAT fx, FX_FLOAT fy);
-  void FWLToClient(FX_FLOAT& fx, FX_FLOAT& fy);
+  const FX_WCHAR* GetLinkURLAtPoint(const CFX_PointF& point);
 };
 
 #endif  // XFA_FXFA_APP_XFA_FFTEXT_H_
diff --git a/xfa/fxfa/app/xfa_fftextedit.cpp b/xfa/fxfa/app/xfa_fftextedit.cpp
index 1088afd..094839f 100644
--- a/xfa/fxfa/app/xfa_fftextedit.cpp
+++ b/xfa/fxfa/app/xfa_fftextedit.cpp
@@ -28,9 +28,8 @@
 #include "xfa/fxfa/xfa_ffpageview.h"
 #include "xfa/fxfa/xfa_ffwidget.h"
 
-CXFA_FFTextEdit::CXFA_FFTextEdit(CXFA_FFPageView* pPageView,
-                                 CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFField(pPageView, pDataAcc), m_pOldDelegate(nullptr) {}
+CXFA_FFTextEdit::CXFA_FFTextEdit(CXFA_WidgetAcc* pDataAcc)
+    : CXFA_FFField(pDataAcc), m_pOldDelegate(nullptr) {}
 
 CXFA_FFTextEdit::~CXFA_FFTextEdit() {
   if (m_pNormalWidget) {
@@ -104,58 +103,53 @@
   m_pNormalWidget->ModifyStyles(dwStyle, 0xFFFFFFFF);
   m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
 }
-bool CXFA_FFTextEdit::OnLButtonDown(uint32_t dwFlags,
-                                    FX_FLOAT fx,
-                                    FX_FLOAT fy) {
-  if (!PtInActiveRect(fx, fy)) {
+
+bool CXFA_FFTextEdit::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
+  if (!PtInActiveRect(point))
     return false;
-  }
   if (!IsFocused()) {
     m_dwStatus |= XFA_WidgetStatus_Focused;
     UpdateFWLData();
     AddInvalidateRect();
   }
+
   SetButtonDown(true);
   CFWL_MessageMouse ms(nullptr, m_pNormalWidget);
   ms.m_dwCmd = FWL_MouseCommand::LeftButtonDown;
   ms.m_dwFlags = dwFlags;
-  ms.m_fx = fx;
-  ms.m_fy = fy;
-  FWLToClient(ms.m_fx, ms.m_fy);
+  ms.m_pos = FWLToClient(point);
   TranslateFWLMessage(&ms);
   return true;
 }
-bool CXFA_FFTextEdit::OnRButtonDown(uint32_t dwFlags,
-                                    FX_FLOAT fx,
-                                    FX_FLOAT fy) {
-  if (m_pDataAcc->GetAccess() != XFA_ATTRIBUTEENUM_Open) {
+
+bool CXFA_FFTextEdit::OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
+  if (m_pDataAcc->GetAccess() != XFA_ATTRIBUTEENUM_Open)
     return false;
-  }
-  if (!PtInActiveRect(fx, fy)) {
+  if (!PtInActiveRect(point))
     return false;
-  }
   if (!IsFocused()) {
     m_dwStatus |= XFA_WidgetStatus_Focused;
     UpdateFWLData();
     AddInvalidateRect();
   }
+
   SetButtonDown(true);
   CFWL_MessageMouse ms(nullptr, nullptr);
   ms.m_dwCmd = FWL_MouseCommand::RightButtonDown;
   ms.m_dwFlags = dwFlags;
-  ms.m_fx = fx;
-  ms.m_fy = fy;
-  FWLToClient(ms.m_fx, ms.m_fy);
+  ms.m_pos = FWLToClient(point);
   TranslateFWLMessage(&ms);
   return true;
 }
-bool CXFA_FFTextEdit::OnRButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
-  if (!CXFA_FFField::OnRButtonUp(dwFlags, fx, fy))
+
+bool CXFA_FFTextEdit::OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
+  if (!CXFA_FFField::OnRButtonUp(dwFlags, point))
     return false;
 
-  GetDoc()->GetDocEnvironment()->PopupMenu(this, CFX_PointF(fx, fy));
+  GetDoc()->GetDocEnvironment()->PopupMenu(this, point);
   return true;
 }
+
 bool CXFA_FFTextEdit::OnSetFocus(CXFA_FFWidget* pOldWidget) {
   m_dwStatus &= ~XFA_WidgetStatus_TextEditValueChanged;
   if (!IsFocused()) {
@@ -360,10 +354,11 @@
   m_pOldDelegate->OnDrawWidget(pGraphics, pMatrix);
 }
 
-CXFA_FFNumericEdit::CXFA_FFNumericEdit(CXFA_FFPageView* pPageView,
-                                       CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFTextEdit(pPageView, pDataAcc) {}
+CXFA_FFNumericEdit::CXFA_FFNumericEdit(CXFA_WidgetAcc* pDataAcc)
+    : CXFA_FFTextEdit(pDataAcc) {}
+
 CXFA_FFNumericEdit::~CXFA_FFNumericEdit() {}
+
 bool CXFA_FFNumericEdit::LoadWidget() {
   CFWL_Edit* pWidget = new CFWL_Edit(
       GetFWLApp(), pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr);
@@ -437,9 +432,9 @@
   return widgetValue.ValidateNumericTemp(wsText, wsFormat,
                                          m_pDataAcc->GetLocal());
 }
-CXFA_FFPasswordEdit::CXFA_FFPasswordEdit(CXFA_FFPageView* pPageView,
-                                         CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFTextEdit(pPageView, pDataAcc) {}
+
+CXFA_FFPasswordEdit::CXFA_FFPasswordEdit(CXFA_WidgetAcc* pDataAcc)
+    : CXFA_FFTextEdit(pDataAcc) {}
 
 CXFA_FFPasswordEdit::~CXFA_FFPasswordEdit() {}
 
@@ -488,25 +483,22 @@
   dwExtendedStyle |= GetAlignment();
   m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
 }
-CXFA_FFDateTimeEdit::CXFA_FFDateTimeEdit(CXFA_FFPageView* pPageView,
-                                         CXFA_WidgetAcc* pDataAcc)
-    : CXFA_FFTextEdit(pPageView, pDataAcc) {}
+CXFA_FFDateTimeEdit::CXFA_FFDateTimeEdit(CXFA_WidgetAcc* pDataAcc)
+    : CXFA_FFTextEdit(pDataAcc) {}
 
 CXFA_FFDateTimeEdit::~CXFA_FFDateTimeEdit() {}
 
-bool CXFA_FFDateTimeEdit::GetBBox(CFX_RectF& rtBox,
-                                  uint32_t dwStatus,
-                                  bool bDrawFocus) {
+CFX_RectF CXFA_FFDateTimeEdit::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
   if (bDrawFocus)
-    return false;
-  return CXFA_FFWidget::GetBBox(rtBox, dwStatus);
+    return CFX_RectF();
+  return CXFA_FFWidget::GetBBox(dwStatus);
 }
 
-bool CXFA_FFDateTimeEdit::PtInActiveRect(FX_FLOAT fx, FX_FLOAT fy) {
+bool CXFA_FFDateTimeEdit::PtInActiveRect(const CFX_PointF& point) {
   return m_pNormalWidget &&
          static_cast<CFWL_DateTimePicker*>(m_pNormalWidget)
              ->GetBBox()
-             .Contains(fx, fy);
+             .Contains(point);
 }
 
 bool CXFA_FFDateTimeEdit::LoadWidget() {
diff --git a/xfa/fxfa/app/xfa_fftextedit.h b/xfa/fxfa/app/xfa_fftextedit.h
index 88622e3..1e0562a 100644
--- a/xfa/fxfa/app/xfa_fftextedit.h
+++ b/xfa/fxfa/app/xfa_fftextedit.h
@@ -13,15 +13,15 @@
 
 class CXFA_FFTextEdit : public CXFA_FFField {
  public:
-  CXFA_FFTextEdit(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFTextEdit(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFTextEdit() override;
 
   // CXFA_FFField
   bool LoadWidget() override;
   void UpdateWidgetProperty() override;
-  bool OnLButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnRButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) override;
-  bool OnRButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) 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;
   void OnProcessMessage(CFWL_Message* pMessage) override;
@@ -48,7 +48,7 @@
 
 class CXFA_FFNumericEdit : public CXFA_FFTextEdit {
  public:
-  CXFA_FFNumericEdit(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFNumericEdit(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFNumericEdit() override;
 
   // CXFA_FFTextEdit
@@ -62,7 +62,7 @@
 
 class CXFA_FFPasswordEdit : public CXFA_FFTextEdit {
  public:
-  CXFA_FFPasswordEdit(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFPasswordEdit(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFPasswordEdit() override;
 
   // CXFA_FFTextEdit
@@ -80,13 +80,11 @@
 
 class CXFA_FFDateTimeEdit : public CXFA_FFTextEdit {
  public:
-  CXFA_FFDateTimeEdit(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFDateTimeEdit(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFDateTimeEdit() override;
 
   // CXFA_FFTextEdit
-  bool GetBBox(CFX_RectF& rtBox,
-               uint32_t dwStatus,
-               bool bDrawFocus = false) override;
+  CFX_RectF GetBBox(uint32_t dwStatus, bool bDrawFocus = false) override;
   bool LoadWidget() override;
   void UpdateWidgetProperty() override;
   void OnProcessEvent(CFWL_Event* pEvent) override;
@@ -97,7 +95,7 @@
                        int32_t iDay);
 
  protected:
-  bool PtInActiveRect(FX_FLOAT fx, FX_FLOAT fy) override;
+  bool PtInActiveRect(const CFX_PointF& point) override;
   bool CommitData() override;
   bool UpdateFWLData() override;
   bool IsDataChanged() override;
diff --git a/xfa/fxfa/app/xfa_ffwidget.cpp b/xfa/fxfa/app/xfa_ffwidget.cpp
index 64aed4f..9995fd1 100644
--- a/xfa/fxfa/app/xfa_ffwidget.cpp
+++ b/xfa/fxfa/app/xfa_ffwidget.cpp
@@ -32,39 +32,31 @@
 #include "xfa/fxgraphics/cfx_pattern.h"
 #include "xfa/fxgraphics/cfx_shading.h"
 
-CXFA_FFWidget::CXFA_FFWidget(CXFA_FFPageView* pPageView,
-                             CXFA_WidgetAcc* pDataAcc)
+CXFA_FFWidget::CXFA_FFWidget(CXFA_WidgetAcc* pDataAcc)
     : CXFA_ContentLayoutItem(pDataAcc->GetNode()),
-      m_pPageView(pPageView),
-      m_pDataAcc(pDataAcc) {
-  m_rtWidget.Set(0, 0, 0, 0);
-}
+      m_pPageView(nullptr),
+      m_pDataAcc(pDataAcc) {}
+
 CXFA_FFWidget::~CXFA_FFWidget() {}
-CXFA_FFPageView* CXFA_FFWidget::GetPageView() {
-  return m_pPageView;
-}
-void CXFA_FFWidget::SetPageView(CXFA_FFPageView* pPageView) {
-  m_pPageView = pPageView;
-}
 
 const CFWL_App* CXFA_FFWidget::GetFWLApp() {
   return GetPageView()->GetDocView()->GetDoc()->GetApp()->GetFWLApp();
 }
 
-void CXFA_FFWidget::GetWidgetRect(CFX_RectF& rtWidget) {
-  if ((m_dwStatus & XFA_WidgetStatus_RectCached) == 0) {
-    m_dwStatus |= XFA_WidgetStatus_RectCached;
-    GetRect(m_rtWidget);
-  }
-  rtWidget = m_rtWidget;
-}
-CFX_RectF CXFA_FFWidget::ReCacheWidgetRect() {
-  m_dwStatus |= XFA_WidgetStatus_RectCached;
-  GetRect(m_rtWidget);
+CFX_RectF CXFA_FFWidget::GetWidgetRect() {
+  if ((m_dwStatus & XFA_WidgetStatus_RectCached) == 0)
+    RecacheWidgetRect();
   return m_rtWidget;
 }
-void CXFA_FFWidget::GetRectWithoutRotate(CFX_RectF& rtWidget) {
-  GetWidgetRect(rtWidget);
+
+CFX_RectF CXFA_FFWidget::RecacheWidgetRect() {
+  m_dwStatus |= XFA_WidgetStatus_RectCached;
+  m_rtWidget = GetRect(false);
+  return m_rtWidget;
+}
+
+CFX_RectF CXFA_FFWidget::GetRectWithoutRotate() {
+  CFX_RectF rtWidget = GetWidgetRect();
   FX_FLOAT fValue = 0;
   switch (m_pDataAcc->GetRotate()) {
     case 90:
@@ -84,7 +76,9 @@
       rtWidget.height = fValue;
       break;
   }
+  return rtWidget;
 }
+
 uint32_t CXFA_FFWidget::GetStatus() {
   return m_dwStatus;
 }
@@ -93,14 +87,10 @@
   m_dwStatus = (m_dwStatus & ~dwRemoved) | dwAdded;
 }
 
-bool CXFA_FFWidget::GetBBox(CFX_RectF& rtBox,
-                            uint32_t dwStatus,
-                            bool bDrawFocus) {
-  if (bDrawFocus)
-    return false;
-  if (m_pPageView)
-    m_pPageView->GetPageViewRect(rtBox);
-  return true;
+CFX_RectF CXFA_FFWidget::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
+  if (bDrawFocus || !m_pPageView)
+    return CFX_RectF();
+  return m_pPageView->GetPageViewRect();
 }
 
 CXFA_WidgetAcc* CXFA_FFWidget::GetDataAcc() {
@@ -115,24 +105,26 @@
   }
   return GetCaptionText(wsToolTip);
 }
+
 void CXFA_FFWidget::RenderWidget(CFX_Graphics* pGS,
                                  CFX_Matrix* pMatrix,
                                  uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus)) {
+  if (!IsMatchVisibleStatus(dwStatus))
     return;
-  }
+
   CXFA_Border border = m_pDataAcc->GetBorder();
-  if (border) {
-    CFX_RectF rtBorder;
-    GetRectWithoutRotate(rtBorder);
-    CXFA_Margin margin = border.GetMargin();
-    if (margin) {
-      XFA_RectWidthoutMargin(rtBorder, margin);
-    }
-    rtBorder.Normalize();
-    DrawBorder(pGS, border, rtBorder, pMatrix);
-  }
+  if (!border)
+    return;
+
+  CFX_RectF rtBorder = GetRectWithoutRotate();
+  CXFA_Margin margin = border.GetMargin();
+  if (margin)
+    XFA_RectWidthoutMargin(rtBorder, margin);
+
+  rtBorder.Normalize();
+  DrawBorder(pGS, border, rtBorder, pMatrix);
 }
+
 bool CXFA_FFWidget::IsLoaded() {
   return !!m_pPageView;
 }
@@ -142,7 +134,7 @@
 }
 void CXFA_FFWidget::UnloadWidget() {}
 bool CXFA_FFWidget::PerformLayout() {
-  ReCacheWidgetRect();
+  RecacheWidgetRect();
   return true;
 }
 bool CXFA_FFWidget::UpdateFWLData() {
@@ -156,28 +148,31 @@
                                uint32_t dwFlags) {
   XFA_DrawBox(box, pGS, rtBorder, pMatrix, dwFlags);
 }
+
 void CXFA_FFWidget::InvalidateWidget(const CFX_RectF* pRect) {
-  if (!pRect) {
-    CFX_RectF rtWidget;
-    GetBBox(rtWidget, XFA_WidgetStatus_Focused);
-    rtWidget.Inflate(2, 2);
-    GetDoc()->GetDocEnvironment()->InvalidateRect(m_pPageView, rtWidget,
-                                                  XFA_INVALIDATE_CurrentPage);
-  } else {
+  if (pRect) {
     GetDoc()->GetDocEnvironment()->InvalidateRect(m_pPageView, *pRect,
                                                   XFA_INVALIDATE_CurrentPage);
+    return;
   }
+
+  CFX_RectF rtWidget = GetBBox(XFA_WidgetStatus_Focused);
+  rtWidget.Inflate(2, 2);
+  GetDoc()->GetDocEnvironment()->InvalidateRect(m_pPageView, rtWidget,
+                                                XFA_INVALIDATE_CurrentPage);
 }
+
 void CXFA_FFWidget::AddInvalidateRect(const CFX_RectF* pRect) {
   CFX_RectF rtWidget;
   if (pRect) {
     rtWidget = *pRect;
   } else {
-    GetBBox(rtWidget, XFA_WidgetStatus_Focused);
+    rtWidget = GetBBox(XFA_WidgetStatus_Focused);
     rtWidget.Inflate(2, 2);
   }
   m_pDocView->AddInvalidateRect(m_pPageView, rtWidget);
 }
+
 bool CXFA_FFWidget::GetCaptionText(CFX_WideString& wsCap) {
   CXFA_TextLayout* pCapTextlayout = m_pDataAcc->GetCaptionTextLayout();
   if (!pCapTextlayout) {
@@ -194,38 +189,42 @@
 bool CXFA_FFWidget::OnMouseEnter() {
   return false;
 }
+
 bool CXFA_FFWidget::OnMouseExit() {
   return false;
 }
-bool CXFA_FFWidget::OnLButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
+
+bool CXFA_FFWidget::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
   return false;
 }
-bool CXFA_FFWidget::OnLButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
+
+bool CXFA_FFWidget::OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
   return false;
 }
-bool CXFA_FFWidget::OnLButtonDblClk(uint32_t dwFlags,
-                                    FX_FLOAT fx,
-                                    FX_FLOAT fy) {
+
+bool CXFA_FFWidget::OnLButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) {
   return false;
 }
-bool CXFA_FFWidget::OnMouseMove(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
+
+bool CXFA_FFWidget::OnMouseMove(uint32_t dwFlags, const CFX_PointF& point) {
   return false;
 }
+
 bool CXFA_FFWidget::OnMouseWheel(uint32_t dwFlags,
                                  int16_t zDelta,
-                                 FX_FLOAT fx,
-                                 FX_FLOAT fy) {
+                                 const CFX_PointF& point) {
   return false;
 }
-bool CXFA_FFWidget::OnRButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
+
+bool CXFA_FFWidget::OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
   return false;
 }
-bool CXFA_FFWidget::OnRButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
+
+bool CXFA_FFWidget::OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
   return false;
 }
-bool CXFA_FFWidget::OnRButtonDblClk(uint32_t dwFlags,
-                                    FX_FLOAT fx,
-                                    FX_FLOAT fy) {
+
+bool CXFA_FFWidget::OnRButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) {
   return false;
 }
 
@@ -241,6 +240,7 @@
   m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Enter, &eParam);
   return true;
 }
+
 bool CXFA_FFWidget::OnKillFocus(CXFA_FFWidget* pNewWidget) {
   m_dwStatus &= ~XFA_WidgetStatus_Focused;
   EventKillFocus();
@@ -252,57 +252,75 @@
   }
   return true;
 }
+
 bool CXFA_FFWidget::OnKeyDown(uint32_t dwKeyCode, uint32_t dwFlags) {
   return false;
 }
+
 bool CXFA_FFWidget::OnKeyUp(uint32_t dwKeyCode, uint32_t dwFlags) {
   return false;
 }
+
 bool CXFA_FFWidget::OnChar(uint32_t dwChar, uint32_t dwFlags) {
   return false;
 }
-FWL_WidgetHit CXFA_FFWidget::OnHitTest(FX_FLOAT fx, FX_FLOAT fy) {
+
+FWL_WidgetHit CXFA_FFWidget::OnHitTest(const CFX_PointF& point) {
   return FWL_WidgetHit::Unknown;
 }
-bool CXFA_FFWidget::OnSetCursor(FX_FLOAT fx, FX_FLOAT fy) {
+
+bool CXFA_FFWidget::OnSetCursor(const CFX_PointF& point) {
   return false;
 }
+
 bool CXFA_FFWidget::CanUndo() {
   return false;
 }
+
 bool CXFA_FFWidget::CanRedo() {
   return false;
 }
+
 bool CXFA_FFWidget::Undo() {
   return false;
 }
+
 bool CXFA_FFWidget::Redo() {
   return false;
 }
+
 bool CXFA_FFWidget::CanCopy() {
   return false;
 }
+
 bool CXFA_FFWidget::CanCut() {
   return false;
 }
+
 bool CXFA_FFWidget::CanPaste() {
   return false;
 }
+
 bool CXFA_FFWidget::CanSelectAll() {
   return false;
 }
+
 bool CXFA_FFWidget::CanDelete() {
   return CanCut();
 }
+
 bool CXFA_FFWidget::CanDeSelect() {
   return CanCopy();
 }
+
 bool CXFA_FFWidget::Copy(CFX_WideString& wsCopy) {
   return false;
 }
+
 bool CXFA_FFWidget::Cut(CFX_WideString& wsCut) {
   return false;
 }
+
 bool CXFA_FFWidget::Paste(const CFX_WideString& wsPaste) {
   return false;
 }
@@ -321,16 +339,17 @@
                                           const CFX_ByteStringC& bsReplace) {
   return false;
 }
-void CXFA_FFWidget::Rotate2Normal(FX_FLOAT& fx, FX_FLOAT& fy) {
-  CFX_Matrix mt;
-  GetRotateMatrix(mt);
-  if (mt.IsIdentity()) {
-    return;
-  }
+
+CFX_PointF CXFA_FFWidget::Rotate2Normal(const CFX_PointF& point) {
+  CFX_Matrix mt = GetRotateMatrix();
+  if (mt.IsIdentity())
+    return point;
+
   CFX_Matrix mtReverse;
   mtReverse.SetReverse(mt);
-  mtReverse.TransformPoint(fx, fy);
+  return mtReverse.Transform(point);
 }
+
 static void XFA_GetMatrix(CFX_Matrix& m,
                           int32_t iRotate,
                           XFA_ATTRIBUTEENUM at,
@@ -387,20 +406,22 @@
       break;
   }
 }
-void CXFA_FFWidget::GetRotateMatrix(CFX_Matrix& mt) {
-  mt.Set(1, 0, 0, 1, 0, 0);
+
+CFX_Matrix CXFA_FFWidget::GetRotateMatrix() {
+  CFX_Matrix mt;
   int32_t iRotate = m_pDataAcc->GetRotate();
-  if (!iRotate) {
-    return;
-  }
-  CFX_RectF rcWidget;
-  GetRectWithoutRotate(rcWidget);
+  if (!iRotate)
+    return mt;
+
+  CFX_RectF rcWidget = GetRectWithoutRotate();
   XFA_ATTRIBUTEENUM at = XFA_ATTRIBUTEENUM_TopLeft;
   XFA_GetMatrix(mt, iRotate, at, rcWidget);
+
+  return mt;
 }
+
 bool CXFA_FFWidget::IsLayoutRectEmpty() {
-  CFX_RectF rtLayout;
-  GetRectWithoutRotate(rtLayout);
+  CFX_RectF rtLayout = GetRectWithoutRotate();
   return rtLayout.width < 0.1f && rtLayout.height < 0.1f;
 }
 CXFA_FFWidget* CXFA_FFWidget::GetParent() {
@@ -415,63 +436,45 @@
   }
   return nullptr;
 }
+
 bool CXFA_FFWidget::IsAncestorOf(CXFA_FFWidget* pWidget) {
-  if (!pWidget) {
+  if (!pWidget)
     return false;
-  }
+
   CXFA_Node* pNode = m_pDataAcc->GetNode();
   CXFA_Node* pChildNode = pWidget->GetDataAcc()->GetNode();
   while (pChildNode) {
-    if (pChildNode == pNode) {
+    if (pChildNode == pNode)
       return true;
-    }
+
     pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_Parent);
   }
   return false;
 }
-bool CXFA_FFWidget::PtInActiveRect(FX_FLOAT fx, FX_FLOAT fy) {
-  CFX_RectF rtWidget;
-  GetWidgetRect(rtWidget);
-  if (rtWidget.Contains(fx, fy)) {
-    return true;
-  }
-  return false;
+
+bool CXFA_FFWidget::PtInActiveRect(const CFX_PointF& point) {
+  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();
 }
+
 CXFA_FFApp* CXFA_FFWidget::GetApp() {
   return GetDoc()->GetApp();
 }
+
 IXFA_AppProvider* CXFA_FFWidget::GetAppProvider() {
   return GetApp()->GetAppProvider();
 }
-void CXFA_FFWidget::GetMinMaxWidth(FX_FLOAT fMinWidth, FX_FLOAT fMaxWidth) {
-  fMinWidth = fMaxWidth = 0;
-  FX_FLOAT fWidth = 0;
-  if (m_pDataAcc->GetWidth(fWidth)) {
-    fMinWidth = fMaxWidth = fWidth;
-  } else {
-    m_pDataAcc->GetMinWidth(fMinWidth);
-    m_pDataAcc->GetMaxWidth(fMaxWidth);
-  }
-}
-void CXFA_FFWidget::GetMinMaxHeight(FX_FLOAT fMinHeight, FX_FLOAT fMaxHeight) {
-  fMinHeight = fMaxHeight = 0;
-  FX_FLOAT fHeight = 0;
-  if (m_pDataAcc->GetHeight(fHeight)) {
-    fMinHeight = fMaxHeight = fHeight;
-  } else {
-    m_pDataAcc->GetMinHeight(fMinHeight);
-    m_pDataAcc->GetMaxHeight(fMaxHeight);
-  }
-}
 
 bool CXFA_FFWidget::IsMatchVisibleStatus(uint32_t dwStatus) {
   return !!(m_dwStatus & XFA_WidgetStatus_Visible);
@@ -839,18 +842,15 @@
                    int32_t iImageYDpi,
                    int32_t iHorzAlign,
                    int32_t iVertAlign) {
-  if (rtImage.IsEmpty()) {
+  if (rtImage.IsEmpty())
     return;
-  }
-  if (!pDIBitmap || !pDIBitmap->GetBuffer()) {
+  if (!pDIBitmap || !pDIBitmap->GetBuffer())
     return;
-  }
-  FX_FLOAT fWidth =
-      XFA_UnitPx2Pt((FX_FLOAT)pDIBitmap->GetWidth(), (FX_FLOAT)iImageXDpi);
-  FX_FLOAT fHeight =
-      XFA_UnitPx2Pt((FX_FLOAT)pDIBitmap->GetHeight(), (FX_FLOAT)iImageYDpi);
-  CFX_RectF rtFit;
-  rtFit.Set(rtImage.left, rtImage.top, fWidth, fHeight);
+
+  CFX_RectF rtFit(
+      rtImage.TopLeft(),
+      XFA_UnitPx2Pt((FX_FLOAT)pDIBitmap->GetWidth(), (FX_FLOAT)iImageXDpi),
+      XFA_UnitPx2Pt((FX_FLOAT)pDIBitmap->GetHeight(), (FX_FLOAT)iImageYDpi));
   switch (iAspect) {
     case XFA_ATTRIBUTEENUM_Fit: {
       FX_FLOAT f1 = rtImage.height / rtFit.height;
@@ -888,18 +888,22 @@
   }
   CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
   pRenderDevice->SaveState();
+
   CFX_PathData path;
   path.AppendRect(rtImage.left, rtImage.bottom(), rtImage.right(), rtImage.top);
   pRenderDevice->SetClip_PathFill(&path, pMatrix, FXFILL_WINDING);
+
   CFX_Matrix mtImage(1, 0, 0, -1, 0, 1);
-  mtImage.Concat(rtFit.width, 0, 0, rtFit.height, rtFit.left, rtFit.top);
+  mtImage.Concat(
+      CFX_Matrix(rtFit.width, 0, 0, rtFit.height, rtFit.left, rtFit.top));
   mtImage.Concat(*pMatrix);
+
   CXFA_ImageRenderer imageRender;
   bool bRet = imageRender.Start(pRenderDevice, pDIBitmap, 0, 255, &mtImage,
                                 FXDIB_INTERPOL);
-  while (bRet) {
+  while (bRet)
     bRet = imageRender.Continue(nullptr);
-  }
+
   pRenderDevice->RestoreState(false);
 }
 
@@ -1020,21 +1024,16 @@
 FXCODEC_IMAGE_TYPE XFA_GetImageType(const CFX_WideString& wsType) {
   CFX_WideString wsContentType(wsType);
   wsContentType.MakeLower();
-  if (wsContentType == FX_WSTRC(L"image/jpg")) {
+  if (wsContentType == L"image/jpg")
     return FXCODEC_IMAGE_JPG;
-  }
-  if (wsContentType == FX_WSTRC(L"image/png")) {
+  if (wsContentType == L"image/png")
     return FXCODEC_IMAGE_PNG;
-  }
-  if (wsContentType == FX_WSTRC(L"image/gif")) {
+  if (wsContentType == L"image/gif")
     return FXCODEC_IMAGE_GIF;
-  }
-  if (wsContentType == FX_WSTRC(L"image/bmp")) {
+  if (wsContentType == L"image/bmp")
     return FXCODEC_IMAGE_BMP;
-  }
-  if (wsContentType == FX_WSTRC(L"image/tif")) {
+  if (wsContentType == L"image/tif")
     return FXCODEC_IMAGE_TIF;
-  }
   return FXCODEC_IMAGE_UNKNOWN;
 }
 CFX_DIBitmap* XFA_LoadImageData(CXFA_FFDoc* pDoc,
@@ -1073,8 +1072,7 @@
     }
   } else {
     CFX_WideString wsURL = wsHref;
-    if (wsURL.Left(7) != FX_WSTRC(L"http://") &&
-        wsURL.Left(6) != FX_WSTRC(L"ftp://")) {
+    if (wsURL.Left(7) != L"http://" && wsURL.Left(6) != L"ftp://") {
       CFX_DIBitmap* pBitmap =
           pDoc->GetPDFNamedImage(wsURL.AsStringC(), iImageXDpi, iImageYDpi);
       if (pBitmap) {
@@ -1130,7 +1128,7 @@
 
   CFX_DIBAttribute dibAttr;
   CFX_DIBitmap* pBitmap = nullptr;
-  CCodec_ProgressiveDecoder* pProgressiveDecoder =
+  std::unique_ptr<CCodec_ProgressiveDecoder> pProgressiveDecoder =
       pCodecMgr->CreateProgressiveDecoder();
   pProgressiveDecoder->LoadImageInfo(pImageFileRead, type, &dibAttr, false);
   switch (dibAttr.m_wDPIUnit) {
@@ -1166,9 +1164,9 @@
       pProgressiveDecoder->ContinueDecode();
     }
   }
-  delete pProgressiveDecoder;
   return pBitmap;
 }
+
 void XFA_RectWidthoutMargin(CFX_RectF& rt, const CXFA_Margin& mg, bool bUI) {
   if (!mg) {
     return;
@@ -1213,11 +1211,11 @@
   }
   startAngle = -startAngle * FX_PI / 180.0f;
   sweepAngle = -sweepAngle * FX_PI / 180.0f;
-  fillPath.AddArc(rtDraw.left, rtDraw.top, rtDraw.width, rtDraw.height,
-                  startAngle, sweepAngle);
+  fillPath.AddArc(rtDraw.TopLeft(), rtDraw.Size(), startAngle, sweepAngle);
 }
+
 static void XFA_BOX_GetPath(CXFA_Box box,
-                            const CXFA_StrokeArray& strokes,
+                            const std::vector<CXFA_Stroke>& strokes,
                             CFX_RectF rtWidget,
                             CFX_Path& path,
                             int32_t nIndex,
@@ -1338,54 +1336,55 @@
         cpStart.x = cp1.x, cpStart.y = cp1.y - fRadius1 + halfBefore,
         offsetEY = -halfAfter;
       }
-      vx = 1, vy = -1;
-      nx = 0, ny = 1;
+      vx = 1;
+      vy = -1;
+      nx = 0;
+      ny = 1;
       if (bRound) {
         sx = bInverted ? 0 : FX_PI / 2;
       } else {
-        sx = 0, sy = -1;
+        sx = 0;
+        sy = -1;
       }
       break;
   }
   if (bStart) {
-    path.MoveTo(cpStart.x, cpStart.y);
+    path.MoveTo(cpStart);
   }
   if (nIndex & 1) {
-    path.LineTo(cp2.x + fRadius2 * nx + offsetEX,
-                cp2.y + fRadius2 * ny + offsetEY);
+    path.LineTo(CFX_PointF(cp2.x + fRadius2 * nx + offsetEX,
+                           cp2.y + fRadius2 * ny + offsetEY));
     return;
   }
   if (bRound) {
-    if (fRadius1 < 0) {
+    if (fRadius1 < 0)
       sx -= FX_PI;
-    }
-    if (bInverted) {
+    if (bInverted)
       sy *= -1;
-    }
-    CFX_RectF rtRadius;
-    rtRadius.Set(cp1.x + offsetX * 2, cp1.y + offsetY * 2,
-                 fRadius1 * 2 * vx - offsetX * 2,
-                 fRadius1 * 2 * vy - offsetY * 2);
+
+    CFX_RectF rtRadius(cp1.x + offsetX * 2, cp1.y + offsetY * 2,
+                       fRadius1 * 2 * vx - offsetX * 2,
+                       fRadius1 * 2 * vy - offsetY * 2);
     rtRadius.Normalize();
-    if (bInverted) {
+    if (bInverted)
       rtRadius.Offset(-fRadius1 * vx, -fRadius1 * vy);
-    }
-    path.ArcTo(rtRadius.left, rtRadius.top, rtRadius.width, rtRadius.height, sx,
-               sy);
+
+    path.ArcTo(rtRadius.TopLeft(), rtRadius.Size(), sx, sy);
   } else {
     CFX_PointF cp;
     if (bInverted) {
-      cp.x = cp1.x + fRadius1 * vx, cp.y = cp1.y + fRadius1 * vy;
+      cp.x = cp1.x + fRadius1 * vx;
+      cp.y = cp1.y + fRadius1 * vy;
     } else {
       cp = cp1;
     }
-    path.LineTo(cp.x, cp.y);
-    path.LineTo(cp1.x + fRadius1 * sx + offsetX,
-                cp1.y + fRadius1 * sy + offsetY);
+    path.LineTo(cp);
+    path.LineTo(CFX_PointF(cp1.x + fRadius1 * sx + offsetX,
+                           cp1.y + fRadius1 * sy + offsetY));
   }
 }
 static void XFA_BOX_GetFillPath(CXFA_Box box,
-                                const CXFA_StrokeArray& strokes,
+                                const std::vector<CXFA_Stroke>& strokes,
                                 CFX_RectF rtWidget,
                                 CFX_Path& fillPath,
                                 uint16_t dwFlags) {
@@ -1501,39 +1500,38 @@
         if (bRound) {
           sx = bInverted ? 0 : FX_PI / 2;
         } else {
-          sx = 0, sy = -1;
+          sx = 0;
+          sy = -1;
         }
         break;
     }
-    if (i == 0) {
-      fillPath.MoveTo(cp1.x, cp1.y + fRadius1);
-    }
+    if (i == 0)
+      fillPath.MoveTo(CFX_PointF(cp1.x, cp1.y + fRadius1));
+
     if (bRound) {
-      if (fRadius1 < 0) {
+      if (fRadius1 < 0)
         sx -= FX_PI;
-      }
-      if (bInverted) {
+      if (bInverted)
         sy *= -1;
-      }
-      CFX_RectF rtRadius;
-      rtRadius.Set(cp1.x, cp1.y, fRadius1 * 2 * vx, fRadius1 * 2 * vy);
+
+      CFX_RectF rtRadius(cp1.x, cp1.y, fRadius1 * 2 * vx, fRadius1 * 2 * vy);
       rtRadius.Normalize();
-      if (bInverted) {
+      if (bInverted)
         rtRadius.Offset(-fRadius1 * vx, -fRadius1 * vy);
-      }
-      fillPath.ArcTo(rtRadius.left, rtRadius.top, rtRadius.width,
-                     rtRadius.height, sx, sy);
+
+      fillPath.ArcTo(rtRadius.TopLeft(), rtRadius.Size(), sx, sy);
     } else {
       CFX_PointF cp;
       if (bInverted) {
-        cp.x = cp1.x + fRadius1 * vx, cp.y = cp1.y + fRadius1 * vy;
+        cp.x = cp1.x + fRadius1 * vx;
+        cp.y = cp1.y + fRadius1 * vy;
       } else {
         cp = cp1;
       }
-      fillPath.LineTo(cp.x, cp.y);
-      fillPath.LineTo(cp1.x + fRadius1 * sx, cp1.y + fRadius1 * sy);
+      fillPath.LineTo(cp);
+      fillPath.LineTo(CFX_PointF(cp1.x + fRadius1 * sx, cp1.y + fRadius1 * sy));
     }
-    fillPath.LineTo(cp2.x + fRadius2 * nx, cp2.y + fRadius2 * ny);
+    fillPath.LineTo(CFX_PointF(cp2.x + fRadius2 * nx, cp2.y + fRadius2 * ny));
   }
 }
 static void XFA_BOX_Fill_Radial(CXFA_Box box,
@@ -1568,22 +1566,22 @@
   FX_ARGB crStart, crEnd;
   crStart = fill.GetColor();
   int32_t iType = fill.GetPattern(crEnd);
-  FX_HatchStyle iHatch = FX_HATCHSTYLE_Cross;
+  FX_HatchStyle iHatch = FX_HatchStyle::Cross;
   switch (iType) {
     case XFA_ATTRIBUTEENUM_CrossDiagonal:
-      iHatch = FX_HATCHSTYLE_DiagonalCross;
+      iHatch = FX_HatchStyle::DiagonalCross;
       break;
     case XFA_ATTRIBUTEENUM_DiagonalLeft:
-      iHatch = FX_HATCHSTYLE_ForwardDiagonal;
+      iHatch = FX_HatchStyle::ForwardDiagonal;
       break;
     case XFA_ATTRIBUTEENUM_DiagonalRight:
-      iHatch = FX_HATCHSTYLE_BackwardDiagonal;
+      iHatch = FX_HatchStyle::BackwardDiagonal;
       break;
     case XFA_ATTRIBUTEENUM_Horizontal:
-      iHatch = FX_HATCHSTYLE_Horizontal;
+      iHatch = FX_HatchStyle::Horizontal;
       break;
     case XFA_ATTRIBUTEENUM_Vertical:
-      iHatch = FX_HATCHSTYLE_Vertical;
+      iHatch = FX_HatchStyle::Vertical;
       break;
     default:
       break;
@@ -1631,18 +1629,17 @@
   pGS->FillPath(&fillPath, FXFILL_WINDING, pMatrix);
 }
 static void XFA_BOX_Fill(CXFA_Box box,
-                         const CXFA_StrokeArray& strokes,
+                         const std::vector<CXFA_Stroke>& strokes,
                          CFX_Graphics* pGS,
                          const CFX_RectF& rtWidget,
                          CFX_Matrix* pMatrix,
                          uint32_t dwFlags) {
   CXFA_Fill fill = box.GetFill();
-  if (!fill || fill.GetPresence() != XFA_ATTRIBUTEENUM_Visible) {
+  if (!fill || fill.GetPresence() != XFA_ATTRIBUTEENUM_Visible)
     return;
-  }
+
   pGS->SaveGraphState();
   CFX_Path fillPath;
-  fillPath.Create();
   XFA_BOX_GetFillPath(box, strokes, rtWidget, fillPath,
                       (dwFlags & XFA_DRAWBOX_ForceRound) != 0);
   fillPath.Close();
@@ -1731,54 +1728,61 @@
   }
   if ((dwFlags & XFA_DRAWBOX_ForceRound) == 0 ||
       (dwFlags & XFA_DRAWBOX_Lowered3D) == 0) {
-    if (fHalf < 0.001f) {
+    if (fHalf < 0.001f)
       return;
-    }
+
     CFX_Path arcPath;
-    arcPath.Create();
     XFA_BOX_GetPath_Arc(box, rtWidget, arcPath, dwFlags);
     XFA_BOX_StrokePath(edge, &arcPath, pGS, pMatrix);
     return;
   }
   pGS->SaveGraphState();
   pGS->SetLineWidth(fHalf);
+
   FX_FLOAT a, b;
   a = rtWidget.width / 2.0f;
   b = rtWidget.height / 2.0f;
   if (dwFlags & XFA_DRAWBOX_ForceRound) {
-    a = b = std::min(a, b);
+    a = std::min(a, b);
+    b = a;
   }
+
   CFX_PointF center = rtWidget.Center();
   rtWidget.left = center.x - a;
   rtWidget.top = center.y - b;
   rtWidget.width = a + a;
   rtWidget.height = b + b;
+
   FX_FLOAT startAngle = 0, sweepAngle = 360;
   startAngle = startAngle * FX_PI / 180.0f;
   sweepAngle = -sweepAngle * FX_PI / 180.0f;
+
   CFX_Path arcPath;
-  arcPath.Create();
-  arcPath.AddArc(rtWidget.left, rtWidget.top, rtWidget.width, rtWidget.height,
-                 3.0f * FX_PI / 4.0f, FX_PI);
+  arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), 3.0f * FX_PI / 4.0f,
+                 FX_PI);
+
   CFX_Color cr(0xFF808080);
   pGS->SetStrokeColor(&cr);
   pGS->StrokePath(&arcPath, pMatrix);
   arcPath.Clear();
-  arcPath.AddArc(rtWidget.left, rtWidget.top, rtWidget.width, rtWidget.height,
-                 -1.0f * FX_PI / 4.0f, FX_PI);
+  arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), -1.0f * FX_PI / 4.0f,
+                 FX_PI);
+
   cr.Set(0xFFFFFFFF);
   pGS->SetStrokeColor(&cr);
   pGS->StrokePath(&arcPath, pMatrix);
   rtWidget.Deflate(fHalf, fHalf);
   arcPath.Clear();
-  arcPath.AddArc(rtWidget.left, rtWidget.top, rtWidget.width, rtWidget.height,
-                 3.0f * FX_PI / 4.0f, FX_PI);
+  arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), 3.0f * FX_PI / 4.0f,
+                 FX_PI);
+
   cr.Set(0xFF404040);
   pGS->SetStrokeColor(&cr);
   pGS->StrokePath(&arcPath, pMatrix);
   arcPath.Clear();
-  arcPath.AddArc(rtWidget.left, rtWidget.top, rtWidget.width, rtWidget.height,
-                 -1.0f * FX_PI / 4.0f, FX_PI);
+  arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), -1.0f * FX_PI / 4.0f,
+                 FX_PI);
+
   cr.Set(0xFFC0C0C0);
   pGS->SetStrokeColor(&cr);
   pGS->StrokePath(&arcPath, pMatrix);
@@ -1795,26 +1799,26 @@
   FX_FLOAT fBottom = rt.bottom();
   FX_FLOAT fRight = rt.right();
   CFX_Path pathLT;
-  pathLT.Create();
-  pathLT.MoveTo(rt.left, fBottom);
-  pathLT.LineTo(rt.left, rt.top);
-  pathLT.LineTo(fRight, rt.top);
-  pathLT.LineTo(fRight - fLineWidth, rt.top + fLineWidth);
-  pathLT.LineTo(rt.left + fLineWidth, rt.top + fLineWidth);
-  pathLT.LineTo(rt.left + fLineWidth, fBottom - fLineWidth);
-  pathLT.LineTo(rt.left, fBottom);
+  pathLT.MoveTo(CFX_PointF(rt.left, fBottom));
+  pathLT.LineTo(CFX_PointF(rt.left, rt.top));
+  pathLT.LineTo(CFX_PointF(fRight, rt.top));
+  pathLT.LineTo(CFX_PointF(fRight - fLineWidth, rt.top + fLineWidth));
+  pathLT.LineTo(CFX_PointF(rt.left + fLineWidth, rt.top + fLineWidth));
+  pathLT.LineTo(CFX_PointF(rt.left + fLineWidth, fBottom - fLineWidth));
+  pathLT.LineTo(CFX_PointF(rt.left, fBottom));
   pGraphic->FillPath(&pathLT, FXFILL_WINDING, pMatrix);
+
   CFX_Color crRB(argbBottomRight);
   pGraphic->SetFillColor(&crRB);
+
   CFX_Path pathRB;
-  pathRB.Create();
-  pathRB.MoveTo(fRight, rt.top);
-  pathRB.LineTo(fRight, fBottom);
-  pathRB.LineTo(rt.left, fBottom);
-  pathRB.LineTo(rt.left + fLineWidth, fBottom - fLineWidth);
-  pathRB.LineTo(fRight - fLineWidth, fBottom - fLineWidth);
-  pathRB.LineTo(fRight - fLineWidth, rt.top + fLineWidth);
-  pathRB.LineTo(fRight, rt.top);
+  pathRB.MoveTo(CFX_PointF(fRight, rt.top));
+  pathRB.LineTo(CFX_PointF(fRight, fBottom));
+  pathRB.LineTo(CFX_PointF(rt.left, fBottom));
+  pathRB.LineTo(CFX_PointF(rt.left + fLineWidth, fBottom - fLineWidth));
+  pathRB.LineTo(CFX_PointF(fRight - fLineWidth, fBottom - fLineWidth));
+  pathRB.LineTo(CFX_PointF(fRight - fLineWidth, rt.top + fLineWidth));
+  pathRB.LineTo(CFX_PointF(fRight, rt.top));
   pGraphic->FillPath(&pathRB, FXFILL_WINDING, pMatrix);
 }
 static void XFA_BOX_Stroke_3DRect_Lowered(CFX_Graphics* pGS,
@@ -1827,7 +1831,6 @@
   CFX_Color cr(0xFF000000);
   pGS->SetFillColor(&cr);
   CFX_Path path;
-  path.Create();
   path.AddRectangle(rt.left, rt.top, rt.width, rt.height);
   path.AddRectangle(rtInner.left, rtInner.top, rtInner.width, rtInner.height);
   pGS->FillPath(&path, FXFILL_ALTERNATE, pMatrix);
@@ -1843,7 +1846,6 @@
   CFX_Color cr(0xFF000000);
   pGS->SetFillColor(&cr);
   CFX_Path path;
-  path.Create();
   path.AddRectangle(rt.left, rt.top, rt.width, rt.height);
   path.AddRectangle(rtInner.left, rtInner.top, rtInner.width, rtInner.height);
   pGS->FillPath(&path, FXFILL_ALTERNATE, pMatrix);
@@ -1870,7 +1872,7 @@
   XFA_Draw3DRect(pGS, rtInner, fHalfWidth, pMatrix, 0xFF000000, 0xFF808080);
 }
 static void XFA_BOX_Stroke_Rect(CXFA_Box box,
-                                const CXFA_StrokeArray& strokes,
+                                const std::vector<CXFA_Stroke>& strokes,
                                 CFX_Graphics* pGS,
                                 CFX_RectF rtWidget,
                                 CFX_Matrix* pMatrix) {
@@ -1922,17 +1924,14 @@
     }
     if (bSameStyles) {
       stroke1 = strokes[0];
-      if (stroke1.IsInverted()) {
+      if (stroke1.IsInverted())
         bSameStyles = false;
-      }
-      if (stroke1.GetJoinType() != XFA_ATTRIBUTEENUM_Square) {
+      if (stroke1.GetJoinType() != XFA_ATTRIBUTEENUM_Square)
         bSameStyles = false;
-      }
     }
   }
   bool bStart = true;
   CFX_Path path;
-  path.Create();
   for (int32_t i = 0; i < 8; i++) {
     CXFA_Stroke stroke = strokes[i];
     if ((i % 1) == 0 && stroke.GetRadius() < 0) {
@@ -1961,7 +1960,7 @@
   }
 }
 static void XFA_BOX_Stroke(CXFA_Box box,
-                           const CXFA_StrokeArray& strokes,
+                           const std::vector<CXFA_Stroke>& strokes,
                            CFX_Graphics* pGS,
                            CFX_RectF rtWidget,
                            CFX_Matrix* pMatrix,
@@ -2038,16 +2037,14 @@
       eType != XFA_Element::Rectangle) {
     return;
   }
-  CXFA_StrokeArray strokes;
-  if (!(dwFlags & XFA_DRAWBOX_ForceRound) && eType != XFA_Element::Arc) {
-    box.GetStrokes(strokes);
-  }
+  std::vector<CXFA_Stroke> strokes;
+  if (!(dwFlags & XFA_DRAWBOX_ForceRound) && eType != XFA_Element::Arc)
+    box.GetStrokes(&strokes);
+
   XFA_BOX_Fill(box, strokes, pGS, rtWidget, pMatrix, dwFlags);
   XFA_BOX_Stroke(box, strokes, pGS, rtWidget, pMatrix, dwFlags);
 }
 
 CXFA_CalcData::CXFA_CalcData() : m_iRefCount(0) {}
 
-CXFA_CalcData::~CXFA_CalcData() {
-  m_Globals.RemoveAll();
-}
+CXFA_CalcData::~CXFA_CalcData() {}
diff --git a/xfa/fxfa/app/xfa_ffwidgetacc.cpp b/xfa/fxfa/app/xfa_ffwidgetacc.cpp
index d4d9949..adc5c31 100644
--- a/xfa/fxfa/app/xfa_ffwidgetacc.cpp
+++ b/xfa/fxfa/app/xfa_ffwidgetacc.cpp
@@ -183,7 +183,7 @@
   }
   m_pNode->GetSOMExpression(wsName);
   if (iNameType == 2 && wsName.GetLength() >= 15) {
-    CFX_WideStringC wsPre = FX_WSTRC(L"xfa[0].form[0].");
+    CFX_WideStringC wsPre = L"xfa[0].form[0].";
     if (wsPre == CFX_WideStringC(wsName.c_str(), wsPre.GetLength())) {
       wsName.Delete(0, wsPre.GetLength());
     }
@@ -678,9 +678,8 @@
           pRefNode->SetUserData(XFA_CalcData, pGlobalData,
                                 &gs_XFADeleteCalcData);
         }
-        if (pGlobalData->m_Globals.Find(this) < 0) {
-          pGlobalData->m_Globals.Add(this);
-        }
+        if (!pdfium::ContainsValue(pGlobalData->m_Globals, this))
+          pGlobalData->m_Globals.push_back(this);
       }
     }
   }
@@ -728,12 +727,12 @@
           ->m_pCapTextLayout.get();
   if (pCapTextLayout) {
     if (!bVert && eUIType != XFA_Element::Button) {
-      szCap.x = fCapReserve;
+      szCap.width = fCapReserve;
     }
     CFX_SizeF minSize;
     pCapTextLayout->CalcSize(minSize, szCap, szCap);
     if (bReserveExit) {
-      bVert ? szCap.y = fCapReserve : szCap.x = fCapReserve;
+      bVert ? szCap.height = fCapReserve : szCap.width = fCapReserve;
     }
   } else {
     FX_FLOAT fFontSize = 10.0f;
@@ -743,10 +742,10 @@
       fFontSize = widgetfont.GetFontSize();
     }
     if (bVert) {
-      szCap.y = fCapReserve > 0 ? fCapReserve : fFontSize;
+      szCap.height = fCapReserve > 0 ? fCapReserve : fFontSize;
     } else {
-      szCap.x = fCapReserve > 0 ? fCapReserve : 0;
-      szCap.y = fFontSize;
+      szCap.width = fCapReserve > 0 ? fCapReserve : 0;
+      szCap.height = fFontSize;
     }
   }
   if (CXFA_Margin mgCap = caption.GetMargin()) {
@@ -756,11 +755,11 @@
     mgCap.GetRightInset(fRightInset);
     mgCap.GetBottomInset(fBottomInset);
     if (bReserveExit) {
-      bVert ? (szCap.x += fLeftInset + fRightInset)
-            : (szCap.y += fTopInset + fBottomInset);
+      bVert ? (szCap.width += fLeftInset + fRightInset)
+            : (szCap.height += fTopInset + fBottomInset);
     } else {
-      szCap.x += fLeftInset + fRightInset;
-      szCap.y += fTopInset + fBottomInset;
+      szCap.width += fLeftInset + fRightInset;
+      szCap.height += fTopInset + fBottomInset;
     }
   }
 }
@@ -768,21 +767,21 @@
   CFX_SizeF szCap;
   CalcCaptionSize(szCap);
   CFX_RectF rtUIMargin = GetUIMargin();
-  size.x += rtUIMargin.left + rtUIMargin.width;
-  size.y += rtUIMargin.top + rtUIMargin.height;
-  if (szCap.x > 0 && szCap.y > 0) {
+  size.width += rtUIMargin.left + rtUIMargin.width;
+  size.height += rtUIMargin.top + rtUIMargin.height;
+  if (szCap.width > 0 && szCap.height > 0) {
     int32_t iCapPlacement = GetCaption().GetPlacementType();
     switch (iCapPlacement) {
       case XFA_ATTRIBUTEENUM_Left:
       case XFA_ATTRIBUTEENUM_Right:
       case XFA_ATTRIBUTEENUM_Inline: {
-        size.x += szCap.x;
-        size.y = std::max(size.y, szCap.y);
+        size.width += szCap.width;
+        size.height = std::max(size.height, szCap.height);
       } break;
       case XFA_ATTRIBUTEENUM_Top:
       case XFA_ATTRIBUTEENUM_Bottom: {
-        size.y += szCap.y;
-        size.x = std::max(size.x, szCap.x);
+        size.height += szCap.height;
+        size.width = std::max(size.width, szCap.width);
       }
       default:
         break;
@@ -798,46 +797,47 @@
     mgWidget.GetTopInset(fTopInset);
     mgWidget.GetRightInset(fRightInset);
     mgWidget.GetBottomInset(fBottomInset);
-    size.x += fLeftInset + fRightInset;
-    size.y += fTopInset + fBottomInset;
+    size.width += fLeftInset + fRightInset;
+    size.height += fTopInset + fBottomInset;
   }
   CXFA_Para para = GetPara();
-  if (para) {
-    size.x += para.GetMarginLeft();
-    size.x += para.GetTextIndent();
-  }
-  FX_FLOAT fVal = 0, fMin = 0, fMax = 0;
+  if (para)
+    size.width += para.GetMarginLeft() + para.GetTextIndent();
+
+  FX_FLOAT fVal = 0;
+  FX_FLOAT fMin = 0;
+  FX_FLOAT fMax = 0;
   if (GetWidth(fVal)) {
-    size.x = fVal;
+    size.width = fVal;
   } else {
-    if (GetMinWidth(fMin)) {
-      size.x = std::max(size.x, fMin);
-    }
-    if (GetMaxWidth(fMax) && fMax > 0) {
-      size.x = std::min(size.x, fMax);
-    }
+    if (GetMinWidth(fMin))
+      size.width = std::max(size.width, fMin);
+    if (GetMaxWidth(fMax) && fMax > 0)
+      size.width = std::min(size.width, fMax);
   }
-  fVal = 0, fMin = 0, fMax = 0;
+  fVal = 0;
+  fMin = 0;
+  fMax = 0;
   if (GetHeight(fVal)) {
-    size.y = fVal;
+    size.height = fVal;
   } else {
-    if (GetMinHeight(fMin)) {
-      size.y = std::max(size.y, fMin);
-    }
-    if (GetMaxHeight(fMax) && fMax > 0) {
-      size.y = std::min(size.y, fMax);
-    }
+    if (GetMinHeight(fMin))
+      size.height = std::max(size.height, fMin);
+    if (GetMaxHeight(fMax) && fMax > 0)
+      size.height = std::min(size.height, fMax);
   }
   return true;
 }
+
 void CXFA_WidgetAcc::CalculateTextContentSize(CFX_SizeF& size) {
   FX_FLOAT fFontSize = GetFontSize();
   CFX_WideString wsText;
   GetValue(wsText, XFA_VALUEPICTURE_Display);
   if (wsText.IsEmpty()) {
-    size.y += fFontSize;
+    size.height += fFontSize;
     return;
   }
+
   FX_WCHAR wcEnter = '\n';
   FX_WCHAR wsLast = wsText.GetAt(wsText.GetLength() - 1);
   if (wsLast == wcEnter) {
@@ -863,11 +863,11 @@
                                         size);
 }
 bool CXFA_WidgetAcc::CalculateTextEditAutoSize(CFX_SizeF& size) {
-  if (size.x > 0) {
+  if (size.width > 0) {
     CFX_SizeF szOrz = size;
     CFX_SizeF szCap;
     CalcCaptionSize(szCap);
-    bool bCapExit = szCap.x > 0.01 && szCap.y > 0.01;
+    bool bCapExit = szCap.width > 0.01 && szCap.height > 0.01;
     int32_t iCapPlacement = XFA_ATTRIBUTEENUM_Unknown;
     if (bCapExit) {
       iCapPlacement = GetCaption().GetPlacementType();
@@ -875,39 +875,39 @@
         case XFA_ATTRIBUTEENUM_Left:
         case XFA_ATTRIBUTEENUM_Right:
         case XFA_ATTRIBUTEENUM_Inline: {
-          size.x -= szCap.x;
+          size.width -= szCap.width;
         }
         default:
           break;
       }
     }
     CFX_RectF rtUIMargin = GetUIMargin();
-    size.x -= rtUIMargin.left + rtUIMargin.width;
+    size.width -= rtUIMargin.left + rtUIMargin.width;
     CXFA_Margin mgWidget = GetMargin();
     if (mgWidget) {
       FX_FLOAT fLeftInset, fRightInset;
       mgWidget.GetLeftInset(fLeftInset);
       mgWidget.GetRightInset(fRightInset);
-      size.x -= fLeftInset + fRightInset;
+      size.width -= fLeftInset + fRightInset;
     }
     CalculateTextContentSize(size);
-    size.y += rtUIMargin.top + rtUIMargin.height;
+    size.height += rtUIMargin.top + rtUIMargin.height;
     if (bCapExit) {
       switch (iCapPlacement) {
         case XFA_ATTRIBUTEENUM_Left:
         case XFA_ATTRIBUTEENUM_Right:
         case XFA_ATTRIBUTEENUM_Inline: {
-          size.y = std::max(size.y, szCap.y);
+          size.height = std::max(size.height, szCap.height);
         } break;
         case XFA_ATTRIBUTEENUM_Top:
         case XFA_ATTRIBUTEENUM_Bottom: {
-          size.y += szCap.y;
+          size.height += szCap.height;
         }
         default:
           break;
       }
     }
-    size.x = szOrz.x;
+    size.width = szOrz.width;
     return CalculateWidgetAutoSize(size);
   }
   CalculateTextContentSize(size);
@@ -915,7 +915,7 @@
 }
 bool CXFA_WidgetAcc::CalculateCheckButtonAutoSize(CFX_SizeF& size) {
   FX_FLOAT fCheckSize = GetCheckButtonSize();
-  size.x = size.y = fCheckSize;
+  size = CFX_SizeF(fCheckSize, fCheckSize);
   return CalculateFieldAutoSize(size);
 }
 bool CXFA_WidgetAcc::CalculatePushButtonAutoSize(CFX_SizeF& size) {
@@ -928,16 +928,15 @@
   }
   size.clear();
   if (CFX_DIBitmap* pBitmap = GetImageImage()) {
-    CFX_RectF rtImage, rtFit;
-    rtImage.Set(0, 0, 0, 0);
-    rtFit.Set(0, 0, 0, 0);
     int32_t iImageXDpi = 0;
     int32_t iImageYDpi = 0;
     GetImageDpi(iImageXDpi, iImageYDpi);
-    rtImage.width =
-        XFA_UnitPx2Pt((FX_FLOAT)pBitmap->GetWidth(), (FX_FLOAT)iImageXDpi);
-    rtImage.height =
-        XFA_UnitPx2Pt((FX_FLOAT)pBitmap->GetHeight(), (FX_FLOAT)iImageYDpi);
+    CFX_RectF rtImage(
+        0, 0,
+        XFA_UnitPx2Pt((FX_FLOAT)pBitmap->GetWidth(), (FX_FLOAT)iImageXDpi),
+        XFA_UnitPx2Pt((FX_FLOAT)pBitmap->GetHeight(), (FX_FLOAT)iImageYDpi));
+
+    CFX_RectF rtFit;
     if (GetWidth(rtFit.width)) {
       GetWidthWithoutMargin(rtFit.width);
     } else {
@@ -948,8 +947,7 @@
     } else {
       rtFit.height = rtImage.height;
     }
-    size.x = rtFit.width;
-    size.y = rtFit.height;
+    size = rtFit.Size();
   }
   return CalculateWidgetAutoSize(size);
 }
@@ -959,16 +957,15 @@
   }
   size.clear();
   if (CFX_DIBitmap* pBitmap = GetImageEditImage()) {
-    CFX_RectF rtImage, rtFit;
-    rtImage.Set(0, 0, 0, 0);
-    rtFit.Set(0, 0, 0, 0);
     int32_t iImageXDpi = 0;
     int32_t iImageYDpi = 0;
     GetImageEditDpi(iImageXDpi, iImageYDpi);
-    rtImage.width =
-        XFA_UnitPx2Pt((FX_FLOAT)pBitmap->GetWidth(), (FX_FLOAT)iImageXDpi);
-    rtImage.height =
-        XFA_UnitPx2Pt((FX_FLOAT)pBitmap->GetHeight(), (FX_FLOAT)iImageYDpi);
+    CFX_RectF rtImage(
+        0, 0,
+        XFA_UnitPx2Pt((FX_FLOAT)pBitmap->GetWidth(), (FX_FLOAT)iImageXDpi),
+        XFA_UnitPx2Pt((FX_FLOAT)pBitmap->GetHeight(), (FX_FLOAT)iImageYDpi));
+
+    CFX_RectF rtFit;
     if (GetWidth(rtFit.width)) {
       GetWidthWithoutMargin(rtFit.width);
     } else {
@@ -979,8 +976,8 @@
     } else {
       rtFit.height = rtImage.height;
     }
-    size.x = rtFit.width;
-    size.y = rtFit.height;
+    size.width = rtFit.width;
+    size.height = rtFit.height;
   }
   return CalculateFieldAutoSize(size);
 }
@@ -1011,8 +1008,8 @@
   CXFA_TextLayout* pTextLayout =
       static_cast<CXFA_TextLayoutData*>(m_pLayoutData.get())->GetTextLayout();
   if (pTextLayout) {
-    size.x = pTextLayout->StartLayout(size.x);
-    size.y = pTextLayout->GetLayoutHeight();
+    size.width = pTextLayout->StartLayout(size.width);
+    size.height = pTextLayout->GetLayoutHeight();
   }
   return CalculateWidgetAutoSize(size);
 }
@@ -1142,9 +1139,9 @@
     default:
       break;
   }
-  fWidth = sz.x;
-  m_pLayoutData->m_fWidgetHeight = sz.y;
-  fCalcHeight = sz.y;
+  fWidth = sz.width;
+  m_pLayoutData->m_fWidgetHeight = sz.height;
+  fCalcHeight = sz.height;
 }
 bool CXFA_WidgetAcc::FindSplitPos(int32_t iBlockIndex, FX_FLOAT& fCalcHeight) {
   XFA_Element eUIType = GetUIType();
@@ -1498,7 +1495,7 @@
 }
 
 CFX_RetainPtr<CFGAS_GEFont> CXFA_WidgetAcc::GetFDEFont() {
-  CFX_WideStringC wsFontName = FX_WSTRC(L"Courier");
+  CFX_WideStringC wsFontName = L"Courier";
   uint32_t dwFontStyle = 0;
   if (CXFA_Font font = GetFont()) {
     if (font.IsBold())
@@ -1542,7 +1539,7 @@
       CFX_WideString wsContentType;
       m_pTextNode->GetAttribute(XFA_ATTRIBUTE_ContentType, wsContentType,
                                 false);
-      if (wsContentType == FX_WSTRC(L"text/html")) {
+      if (wsContentType == L"text/html") {
         bRichText = true;
       }
     }
@@ -1558,7 +1555,7 @@
     if (pChildNode && pChildNode->GetElementType() == XFA_Element::ExData) {
       CFX_WideString wsContentType;
       pChildNode->GetAttribute(XFA_ATTRIBUTE_ContentType, wsContentType, false);
-      if (wsContentType == FX_WSTRC(L"text/html")) {
+      if (wsContentType == L"text/html") {
         bRichText = true;
       }
     }
@@ -1593,7 +1590,7 @@
     if (pChildNode && pChildNode->GetElementType() == XFA_Element::ExData) {
       CFX_WideString wsContentType;
       pChildNode->GetAttribute(XFA_ATTRIBUTE_ContentType, wsContentType, false);
-      if (wsContentType == FX_WSTRC(L"text/html")) {
+      if (wsContentType == L"text/html") {
         bRichText = true;
       }
     }
@@ -1608,11 +1605,10 @@
   while (pNode) {
     CFX_WideStringC wsName;
     pNode->TryCData(XFA_ATTRIBUTE_Name, wsName);
-    if (m_eType == XFA_TEXTPROVIDERTYPE_Rollover &&
-        wsName == FX_WSTRC(L"rollover")) {
+    if (m_eType == XFA_TEXTPROVIDERTYPE_Rollover && wsName == L"rollover") {
       return pNode;
     }
-    if (m_eType == XFA_TEXTPROVIDERTYPE_Down && wsName == FX_WSTRC(L"down")) {
+    if (m_eType == XFA_TEXTPROVIDERTYPE_Down && wsName == L"down") {
       return pNode;
     }
     pNode = pNode->GetNodeItem(XFA_NODEITEM_NextSibling);
diff --git a/xfa/fxfa/app/xfa_ffwidgethandler.cpp b/xfa/fxfa/app/xfa_ffwidgethandler.cpp
index 551d8f6..2fddfb6 100644
--- a/xfa/fxfa/app/xfa_ffwidgethandler.cpp
+++ b/xfa/fxfa/app/xfa_ffwidgethandler.cpp
@@ -40,11 +40,9 @@
 
 bool CXFA_FFWidgetHandler::OnLButtonDown(CXFA_FFWidget* hWidget,
                                          uint32_t dwFlags,
-                                         FX_FLOAT fx,
-                                         FX_FLOAT fy) {
+                                         const CFX_PointF& point) {
   m_pDocView->LockUpdate();
-  hWidget->Rotate2Normal(fx, fy);
-  bool bRet = hWidget->OnLButtonDown(dwFlags, fx, fy);
+  bool bRet = hWidget->OnLButtonDown(dwFlags, hWidget->Rotate2Normal(point));
   if (bRet && m_pDocView->SetFocus(hWidget)) {
     m_pDocView->GetDoc()->GetDocEnvironment()->SetFocusWidget(
         m_pDocView->GetDoc(), hWidget);
@@ -56,12 +54,10 @@
 
 bool CXFA_FFWidgetHandler::OnLButtonUp(CXFA_FFWidget* hWidget,
                                        uint32_t dwFlags,
-                                       FX_FLOAT fx,
-                                       FX_FLOAT fy) {
+                                       const CFX_PointF& point) {
   m_pDocView->LockUpdate();
-  hWidget->Rotate2Normal(fx, fy);
   m_pDocView->m_bLayoutEvent = true;
-  bool bRet = hWidget->OnLButtonUp(dwFlags, fx, fy);
+  bool bRet = hWidget->OnLButtonUp(dwFlags, hWidget->Rotate2Normal(point));
   m_pDocView->UnlockUpdate();
   m_pDocView->UpdateDocView();
   return bRet;
@@ -69,20 +65,16 @@
 
 bool CXFA_FFWidgetHandler::OnLButtonDblClk(CXFA_FFWidget* hWidget,
                                            uint32_t dwFlags,
-                                           FX_FLOAT fx,
-                                           FX_FLOAT fy) {
-  hWidget->Rotate2Normal(fx, fy);
-  bool bRet = hWidget->OnLButtonDblClk(dwFlags, fx, fy);
+                                           const CFX_PointF& point) {
+  bool bRet = hWidget->OnLButtonDblClk(dwFlags, hWidget->Rotate2Normal(point));
   m_pDocView->RunInvalidate();
   return bRet;
 }
 
 bool CXFA_FFWidgetHandler::OnMouseMove(CXFA_FFWidget* hWidget,
                                        uint32_t dwFlags,
-                                       FX_FLOAT fx,
-                                       FX_FLOAT fy) {
-  hWidget->Rotate2Normal(fx, fy);
-  bool bRet = hWidget->OnMouseMove(dwFlags, fx, fy);
+                                       const CFX_PointF& point) {
+  bool bRet = hWidget->OnMouseMove(dwFlags, hWidget->Rotate2Normal(point));
   m_pDocView->RunInvalidate();
   return bRet;
 }
@@ -90,20 +82,17 @@
 bool CXFA_FFWidgetHandler::OnMouseWheel(CXFA_FFWidget* hWidget,
                                         uint32_t dwFlags,
                                         int16_t zDelta,
-                                        FX_FLOAT fx,
-                                        FX_FLOAT fy) {
-  hWidget->Rotate2Normal(fx, fy);
-  bool bRet = hWidget->OnMouseWheel(dwFlags, zDelta, fx, fy);
+                                        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,
-                                         FX_FLOAT fx,
-                                         FX_FLOAT fy) {
-  hWidget->Rotate2Normal(fx, fy);
-  bool bRet = hWidget->OnRButtonDown(dwFlags, fx, fy);
+                                         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);
@@ -114,20 +103,16 @@
 
 bool CXFA_FFWidgetHandler::OnRButtonUp(CXFA_FFWidget* hWidget,
                                        uint32_t dwFlags,
-                                       FX_FLOAT fx,
-                                       FX_FLOAT fy) {
-  hWidget->Rotate2Normal(fx, fy);
-  bool bRet = hWidget->OnRButtonUp(dwFlags, fx, fy);
+                                       const CFX_PointF& point) {
+  bool bRet = hWidget->OnRButtonUp(dwFlags, hWidget->Rotate2Normal(point));
   m_pDocView->RunInvalidate();
   return bRet;
 }
 
 bool CXFA_FFWidgetHandler::OnRButtonDblClk(CXFA_FFWidget* hWidget,
                                            uint32_t dwFlags,
-                                           FX_FLOAT fx,
-                                           FX_FLOAT fy) {
-  hWidget->Rotate2Normal(fx, fy);
-  bool bRet = hWidget->OnRButtonDblClk(dwFlags, fx, fy);
+                                           const CFX_PointF& point) {
+  bool bRet = hWidget->OnRButtonDblClk(dwFlags, hWidget->Rotate2Normal(point));
   m_pDocView->RunInvalidate();
   return bRet;
 }
@@ -158,20 +143,15 @@
 }
 
 FWL_WidgetHit CXFA_FFWidgetHandler::OnHitTest(CXFA_FFWidget* hWidget,
-                                              FX_FLOAT fx,
-                                              FX_FLOAT fy) {
+                                              const CFX_PointF& point) {
   if (!(hWidget->GetStatus() & XFA_WidgetStatus_Visible))
     return FWL_WidgetHit::Unknown;
-
-  hWidget->Rotate2Normal(fx, fy);
-  return hWidget->OnHitTest(fx, fy);
+  return hWidget->OnHitTest(hWidget->Rotate2Normal(point));
 }
 
 bool CXFA_FFWidgetHandler::OnSetCursor(CXFA_FFWidget* hWidget,
-                                       FX_FLOAT fx,
-                                       FX_FLOAT fy) {
-  hWidget->Rotate2Normal(fx, fy);
-  return hWidget->OnSetCursor(fx, fy);
+                                       const CFX_PointF& point) {
+  return hWidget->OnSetCursor(hWidget->Rotate2Normal(point));
 }
 
 void CXFA_FFWidgetHandler::RenderWidget(CXFA_FFWidget* hWidget,
diff --git a/xfa/fxfa/app/xfa_fwladapter.cpp b/xfa/fxfa/app/xfa_fwladapter.cpp
index 3dfa679..e1f3e20 100644
--- a/xfa/fxfa/app/xfa_fwladapter.cpp
+++ b/xfa/fxfa/app/xfa_fwladapter.cpp
@@ -30,10 +30,8 @@
                                            const CFX_RectF& rtAnchor,
                                            CFX_RectF& rtPopup) {
   CXFA_FFWidget* pFFWidget = pWidget->GetLayoutItem();
-  CFX_Matrix mt;
-  pFFWidget->GetRotateMatrix(mt);
   CFX_RectF rtRotateAnchor(rtAnchor);
-  mt.TransformRect(rtRotateAnchor);
+  pFFWidget->GetRotateMatrix().TransformRect(rtRotateAnchor);
   pFFWidget->GetDoc()->GetDocEnvironment()->GetPopupPos(
       pFFWidget, fMinHeight, fMaxHeight, rtRotateAnchor, rtPopup);
   return true;
diff --git a/xfa/fxfa/app/xfa_fwladapter.h b/xfa/fxfa/app/xfa_fwladapter.h
index 406709b..c68fb70 100644
--- a/xfa/fxfa/app/xfa_fwladapter.h
+++ b/xfa/fxfa/app/xfa_fwladapter.h
@@ -9,7 +9,6 @@
 
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_system.h"
-#include "xfa/fwl/fwl_error.h"
 
 class CFWL_Widget;
 
diff --git a/xfa/fxfa/app/xfa_fwltheme.cpp b/xfa/fxfa/app/xfa_fwltheme.cpp
index 1de302e..73abaec 100644
--- a/xfa/fxfa/app/xfa_fwltheme.cpp
+++ b/xfa/fxfa/app/xfa_fwltheme.cpp
@@ -149,8 +149,6 @@
 
 CFX_RectF CXFA_FWLTheme::GetUIMargin(CFWL_ThemePart* pThemePart) const {
   CFX_RectF rect;
-  rect.Reset();
-
   CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pThemePart->m_pWidget);
   if (!pWidget)
     return rect;
@@ -217,8 +215,8 @@
   if (CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pThemePart->m_pWidget)) {
     CXFA_WidgetAcc* pWidgetAcc = pWidget->GetDataAcc();
     if (CXFA_Para para = pWidgetAcc->GetPara()) {
-      sizeAboveBelow.x = para.GetSpaceAbove();
-      sizeAboveBelow.y = para.GetSpaceBelow();
+      sizeAboveBelow.width = para.GetSpaceAbove();
+      sizeAboveBelow.height = para.GetSpaceBelow();
     }
   }
   return sizeAboveBelow;
diff --git a/xfa/fxfa/app/xfa_rendercontext.cpp b/xfa/fxfa/app/xfa_rendercontext.cpp
index 75e7e7d..a855105 100644
--- a/xfa/fxfa/app/xfa_rendercontext.cpp
+++ b/xfa/fxfa/app/xfa_rendercontext.cpp
@@ -32,11 +32,10 @@
   m_pGS = pGS;
   m_matrix = matrix;
   m_options = options;
-  CFX_RectF rtPage;
-  pGS->GetClipRect(rtPage);
+
   CFX_Matrix mtRes;
   mtRes.SetReverse(matrix);
-  m_rtClipRect.Set(rtPage.left, rtPage.top, rtPage.width, rtPage.height);
+  m_rtClipRect = pGS->GetClipRect();
   mtRes.TransformRect(m_rtClipRect);
   m_dwStatus = m_options.m_bHighlight ? XFA_WidgetStatus_Highlight : 0;
   uint32_t dwFilterType = XFA_WidgetStatus_Visible |
@@ -52,12 +51,12 @@
   int32_t iCount = 0;
   while (m_pWidget) {
     CXFA_FFWidget* pWidget = m_pWidget;
-    CFX_RectF rtWidgetBox;
-    pWidget->GetBBox(rtWidgetBox, XFA_WidgetStatus_Visible);
+    CFX_RectF rtWidgetBox = pWidget->GetBBox(XFA_WidgetStatus_Visible);
     rtWidgetBox.width += 1;
     rtWidgetBox.height += 1;
     if (rtWidgetBox.IntersectWith(m_rtClipRect))
       pWidget->RenderWidget(m_pGS, &m_matrix, m_dwStatus);
+
     m_pWidget = m_pWidgetIterator->MoveToNext();
     iCount++;
     if (iCount > kMaxCount && pPause && pPause->NeedToPauseNow())
diff --git a/xfa/fxfa/app/xfa_textpiece.cpp b/xfa/fxfa/app/xfa_textpiece.cpp
index 933af6c..c53e45f 100644
--- a/xfa/fxfa/app/xfa_textpiece.cpp
+++ b/xfa/fxfa/app/xfa_textpiece.cpp
@@ -8,13 +8,6 @@
 
 #include "xfa/fxfa/app/cxfa_linkuserdata.h"
 
-XFA_TextPiece::XFA_TextPiece()
-    : pszText(nullptr), pWidths(nullptr), pFont(nullptr), pLinkData(nullptr) {}
+XFA_TextPiece::XFA_TextPiece() {}
 
-XFA_TextPiece::~XFA_TextPiece() {
-  if (pLinkData)
-    pLinkData->Release();
-
-  FX_Free(pszText);
-  FX_Free(pWidths);
-}
+XFA_TextPiece::~XFA_TextPiece() {}
diff --git a/xfa/fxfa/app/xfa_textpiece.h b/xfa/fxfa/app/xfa_textpiece.h
index 2b74155..6802df5 100644
--- a/xfa/fxfa/app/xfa_textpiece.h
+++ b/xfa/fxfa/app/xfa_textpiece.h
@@ -7,6 +7,8 @@
 #ifndef XFA_FXFA_APP_XFA_TEXTPIECE_H_
 #define XFA_FXFA_APP_XFA_TEXTPIECE_H_
 
+#include <vector>
+
 #include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_string.h"
@@ -20,20 +22,20 @@
   XFA_TextPiece();
   ~XFA_TextPiece();
 
-  FX_WCHAR* pszText;
+  CFX_WideString szText;
+  std::vector<int32_t> Widths;
   int32_t iChars;
-  int32_t* pWidths;
   int32_t iHorScale;
   int32_t iVerScale;
   int32_t iBidiLevel;
   int32_t iUnderline;
   int32_t iPeriod;
   int32_t iLineThrough;
-  CFX_RetainPtr<CFGAS_GEFont> pFont;
   FX_ARGB dwColor;
   FX_FLOAT fFontSize;
   CFX_RectF rtPiece;
-  CXFA_LinkUserData* pLinkData;
+  CFX_RetainPtr<CFGAS_GEFont> pFont;
+  CFX_RetainPtr<CXFA_LinkUserData> pLinkData;
 };
 
 #endif  // XFA_FXFA_APP_XFA_TEXTPIECE_H_
diff --git a/xfa/fxfa/fm2js/xfa_expression.cpp b/xfa/fxfa/fm2js/xfa_expression.cpp
index a4d1195..32db6d2 100644
--- a/xfa/fxfa/fm2js/xfa_expression.cpp
+++ b/xfa/fxfa/fm2js/xfa_expression.cpp
@@ -46,24 +46,24 @@
 
 void CXFA_FMFunctionDefinition::ToJavaScript(CFX_WideTextBuf& javascript) {
   if (m_isGlobal && m_pExpressions.empty()) {
-    javascript << FX_WSTRC(L"// comments only");
+    javascript << L"// comments only";
     return;
   }
   if (m_isGlobal) {
-    javascript << FX_WSTRC(L"(\n");
+    javascript << L"(\n";
   }
-  javascript << FX_WSTRC(L"function ");
+  javascript << L"function ";
   if (m_wsName.GetAt(0) == L'!') {
     CFX_WideString tempName = EXCLAMATION_IN_IDENTIFIER + m_wsName.Mid(1);
     javascript << tempName;
   } else {
     javascript << m_wsName;
   }
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   bool bNeedComma = false;
   for (const auto& identifier : m_pArguments) {
     if (bNeedComma)
-      javascript << FX_WSTRC(L", ");
+      javascript << L", ";
     if (identifier.GetAt(0) == L'!') {
       CFX_WideString tempIdentifier =
           EXCLAMATION_IN_IDENTIFIER + identifier.Mid(1);
@@ -73,28 +73,28 @@
     }
     bNeedComma = true;
   }
-  javascript << FX_WSTRC(L")\n{\n");
-  javascript << FX_WSTRC(L"var ");
+  javascript << L")\n{\n";
+  javascript << L"var ";
   javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << FX_WSTRC(L" = null;\n");
+  javascript << L" = null;\n";
   for (const auto& expr : m_pExpressions) {
     if (expr == m_pExpressions.back())
       expr->ToImpliedReturnJS(javascript);
     else
       expr->ToJavaScript(javascript);
   }
-  javascript << FX_WSTRC(L"return ");
+  javascript << L"return ";
   if (m_isGlobal) {
     javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-    javascript << FX_WSTRC(L"(");
+    javascript << L"(";
     javascript << RUNTIMEFUNCTIONRETURNVALUE;
-    javascript << FX_WSTRC(L")");
+    javascript << L")";
   } else {
     javascript << RUNTIMEFUNCTIONRETURNVALUE;
   }
-  javascript << FX_WSTRC(L";\n}\n");
+  javascript << L";\n}\n";
   if (m_isGlobal) {
-    javascript << FX_WSTRC(L").call(this);\n");
+    javascript << L").call(this);\n";
   }
 }
 
@@ -111,49 +111,49 @@
 CXFA_FMVarExpression::~CXFA_FMVarExpression() {}
 
 void CXFA_FMVarExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  javascript << FX_WSTRC(L"var ");
+  javascript << L"var ";
   CFX_WideString tempName(m_wsName);
   if (m_wsName.GetAt(0) == L'!') {
     tempName = EXCLAMATION_IN_IDENTIFIER + m_wsName.Mid(1);
   }
   javascript << tempName;
-  javascript << FX_WSTRC(L" = ");
+  javascript << L" = ";
   if (m_pInit) {
     m_pInit->ToJavaScript(javascript);
     javascript << tempName;
-    javascript << FX_WSTRC(L" = ");
+    javascript << L" = ";
     javascript << XFA_FM_EXPTypeToString(VARFILTER);
-    javascript << FX_WSTRC(L"(");
+    javascript << L"(";
     javascript << tempName;
-    javascript << FX_WSTRC(L");\n");
+    javascript << L");\n";
   } else {
-    javascript << FX_WSTRC(L"\"\";\n");
+    javascript << L"\"\";\n";
   }
 }
 
 void CXFA_FMVarExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
-  javascript << FX_WSTRC(L"var ");
+  javascript << L"var ";
   CFX_WideString tempName(m_wsName);
   if (m_wsName.GetAt(0) == L'!') {
     tempName = EXCLAMATION_IN_IDENTIFIER + m_wsName.Mid(1);
   }
   javascript << tempName;
-  javascript << FX_WSTRC(L" = ");
+  javascript << L" = ";
   if (m_pInit) {
     m_pInit->ToJavaScript(javascript);
     javascript << tempName;
-    javascript << FX_WSTRC(L" = ");
+    javascript << L" = ";
     javascript << XFA_FM_EXPTypeToString(VARFILTER);
-    javascript << FX_WSTRC(L"(");
+    javascript << L"(";
     javascript << tempName;
-    javascript << FX_WSTRC(L");\n");
+    javascript << L");\n";
   } else {
-    javascript << FX_WSTRC(L"\"\";\n");
+    javascript << L"\"\";\n";
   }
   javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << FX_WSTRC(L" = ");
+  javascript << L" = ";
   javascript << tempName;
-  javascript << FX_WSTRC(L";\n");
+  javascript << L";\n";
 }
 
 CXFA_FMExpExpression::CXFA_FMExpExpression(
@@ -169,7 +169,7 @@
     m_pExpression->ToJavaScript(javascript);
   } else {
     m_pExpression->ToJavaScript(javascript);
-    javascript << FX_WSTRC(L";\n");
+    javascript << L";\n";
   }
 }
 
@@ -183,16 +183,16 @@
         m_pExpression->GetOperatorToken() == TOKdotdot ||
         m_pExpression->GetOperatorToken() == TOKdot) {
       javascript << RUNTIMEFUNCTIONRETURNVALUE;
-      javascript << FX_WSTRC(L" = ");
+      javascript << L" = ";
       javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-      javascript << FX_WSTRC(L"(");
+      javascript << L"(";
       m_pExpression->ToJavaScript(javascript);
-      javascript << FX_WSTRC(L");\n");
+      javascript << L");\n";
     } else {
       javascript << RUNTIMEFUNCTIONRETURNVALUE;
-      javascript << FX_WSTRC(L" = ");
+      javascript << L" = ";
       m_pExpression->ToJavaScript(javascript);
-      javascript << FX_WSTRC(L";\n");
+      javascript << L";\n";
     }
   }
 }
@@ -206,21 +206,21 @@
 CXFA_FMBlockExpression::~CXFA_FMBlockExpression() {}
 
 void CXFA_FMBlockExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  javascript << FX_WSTRC(L"{\n");
+  javascript << L"{\n";
   for (const auto& expr : m_ExpressionList)
     expr->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L"}\n");
+  javascript << L"}\n";
 }
 
 void CXFA_FMBlockExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
-  javascript << FX_WSTRC(L"{\n");
+  javascript << L"{\n";
   for (const auto& expr : m_ExpressionList) {
     if (expr == m_ExpressionList.back())
       expr->ToImpliedReturnJS(javascript);
     else
       expr->ToJavaScript(javascript);
   }
-  javascript << FX_WSTRC(L"}\n");
+  javascript << L"}\n";
 }
 
 CXFA_FMDoExpression::CXFA_FMDoExpression(
@@ -251,25 +251,25 @@
 CXFA_FMIfExpression::~CXFA_FMIfExpression() {}
 
 void CXFA_FMIfExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  javascript << FX_WSTRC(L"if (");
+  javascript << L"if (";
   if (m_pExpression) {
     javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-    javascript << FX_WSTRC(L"(");
+    javascript << L"(";
     m_pExpression->ToJavaScript(javascript);
-    javascript << FX_WSTRC(L")");
+    javascript << L")";
   }
-  javascript << FX_WSTRC(L")\n");
+  javascript << L")\n";
   if (m_pIfExpression) {
     m_pIfExpression->ToJavaScript(javascript);
   }
   if (m_pElseExpression) {
     if (m_pElseExpression->GetExpType() == XFA_FM_EXPTYPE_IF) {
-      javascript << FX_WSTRC(L"else\n");
-      javascript << FX_WSTRC(L"{\n");
+      javascript << L"else\n";
+      javascript << L"{\n";
       m_pElseExpression->ToJavaScript(javascript);
-      javascript << FX_WSTRC(L"}\n");
+      javascript << L"}\n";
     } else {
-      javascript << FX_WSTRC(L"else\n");
+      javascript << L"else\n";
       m_pElseExpression->ToJavaScript(javascript);
     }
   }
@@ -277,26 +277,26 @@
 
 void CXFA_FMIfExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
   javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << FX_WSTRC(L" = 0;\n");
-  javascript << FX_WSTRC(L"if (");
+  javascript << L" = 0;\n";
+  javascript << L"if (";
   if (m_pExpression) {
     javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-    javascript << FX_WSTRC(L"(");
+    javascript << L"(";
     m_pExpression->ToJavaScript(javascript);
-    javascript << FX_WSTRC(L")");
+    javascript << L")";
   }
-  javascript << FX_WSTRC(L")\n");
+  javascript << L")\n";
   if (m_pIfExpression) {
     m_pIfExpression->ToImpliedReturnJS(javascript);
   }
   if (m_pElseExpression) {
     if (m_pElseExpression->GetExpType() == XFA_FM_EXPTYPE_IF) {
-      javascript << FX_WSTRC(L"else\n");
-      javascript << FX_WSTRC(L"{\n");
+      javascript << L"else\n";
+      javascript << L"{\n";
       m_pElseExpression->ToImpliedReturnJS(javascript);
-      javascript << FX_WSTRC(L"}\n");
+      javascript << L"}\n";
     } else {
-      javascript << FX_WSTRC(L"else\n");
+      javascript << L"else\n";
       m_pElseExpression->ToImpliedReturnJS(javascript);
     }
   }
@@ -319,18 +319,18 @@
 CXFA_FMWhileExpression::~CXFA_FMWhileExpression() {}
 
 void CXFA_FMWhileExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  javascript << FX_WSTRC(L"while (");
+  javascript << L"while (";
   m_pCondition->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L")\n");
+  javascript << L")\n";
   m_pExpression->ToJavaScript(javascript);
 }
 
 void CXFA_FMWhileExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
   javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << FX_WSTRC(L" = 0;\n");
-  javascript << FX_WSTRC(L"while (");
+  javascript << L" = 0;\n";
+  javascript << L"while (";
   m_pCondition->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L")\n");
+  javascript << L")\n";
   m_pExpression->ToImpliedReturnJS(javascript);
 }
 
@@ -341,14 +341,14 @@
 
 void CXFA_FMBreakExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
   javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << FX_WSTRC(L" = 0;\n");
-  javascript << FX_WSTRC(L"break;\n");
+  javascript << L" = 0;\n";
+  javascript << L"break;\n";
 }
 
 void CXFA_FMBreakExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
   javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << FX_WSTRC(L" = 0;\n");
-  javascript << FX_WSTRC(L"break;\n");
+  javascript << L" = 0;\n";
+  javascript << L"break;\n";
 }
 
 CXFA_FMContinueExpression::CXFA_FMContinueExpression(uint32_t line)
@@ -358,14 +358,14 @@
 
 void CXFA_FMContinueExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
   javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << FX_WSTRC(L" = 0;\n");
-  javascript << FX_WSTRC(L"continue;\n");
+  javascript << L" = 0;\n";
+  javascript << L"continue;\n";
 }
 
 void CXFA_FMContinueExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
   javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << FX_WSTRC(L" = 0;\n");
-  javascript << FX_WSTRC(L"continue;\n");
+  javascript << L" = 0;\n";
+  javascript << L"continue;\n";
 }
 
 CXFA_FMForExpression::CXFA_FMForExpression(
@@ -387,7 +387,7 @@
 CXFA_FMForExpression::~CXFA_FMForExpression() {}
 
 void CXFA_FMForExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  javascript << FX_WSTRC(L"{\nvar ");
+  javascript << L"{\nvar ";
   CFX_WideString tempVariant;
   if (m_wsVariant.GetAt(0) == L'!') {
     tempVariant = EXCLAMATION_IN_IDENTIFIER + m_wsVariant.Mid(1);
@@ -396,49 +396,49 @@
     tempVariant = m_wsVariant;
     javascript << m_wsVariant;
   }
-  javascript << FX_WSTRC(L" = null;\n");
-  javascript << FX_WSTRC(L"for (");
+  javascript << L" = null;\n";
+  javascript << L"for (";
   javascript << tempVariant;
-  javascript << FX_WSTRC(L" = ");
+  javascript << L" = ";
   javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   m_pAssignment->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L"); ");
+  javascript << L"); ";
   javascript << tempVariant;
   if (m_iDirection == 1) {
-    javascript << FX_WSTRC(L" <= ");
+    javascript << L" <= ";
     javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-    javascript << FX_WSTRC(L"(");
+    javascript << L"(";
     m_pAccessor->ToJavaScript(javascript);
-    javascript << FX_WSTRC(L"); ");
+    javascript << L"); ";
     javascript << tempVariant;
-    javascript << FX_WSTRC(L" += ");
+    javascript << L" += ";
   } else {
-    javascript << FX_WSTRC(L" >= ");
+    javascript << L" >= ";
     javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-    javascript << FX_WSTRC(L"(");
+    javascript << L"(";
     m_pAccessor->ToJavaScript(javascript);
-    javascript << FX_WSTRC(L"); ");
+    javascript << L"); ";
     javascript << tempVariant;
-    javascript << FX_WSTRC(L" -= ");
+    javascript << L" -= ";
   }
   if (m_pStep) {
     javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-    javascript << FX_WSTRC(L"(");
+    javascript << L"(";
     m_pStep->ToJavaScript(javascript);
-    javascript << FX_WSTRC(L")");
+    javascript << L")";
   } else {
-    javascript << FX_WSTRC(L"1");
+    javascript << L"1";
   }
-  javascript << FX_WSTRC(L")\n");
+  javascript << L")\n";
   m_pList->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L"}\n");
+  javascript << L"}\n";
 }
 
 void CXFA_FMForExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
   javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << FX_WSTRC(L" = 0;\n");
-  javascript << FX_WSTRC(L"{\nvar ");
+  javascript << L" = 0;\n";
+  javascript << L"{\nvar ";
   CFX_WideString tempVariant;
   if (m_wsVariant.GetAt(0) == L'!') {
     tempVariant = EXCLAMATION_IN_IDENTIFIER + m_wsVariant.Mid(1);
@@ -447,43 +447,43 @@
     tempVariant = m_wsVariant;
     javascript << m_wsVariant;
   }
-  javascript << FX_WSTRC(L" = null;\n");
-  javascript << FX_WSTRC(L"for (");
+  javascript << L" = null;\n";
+  javascript << L"for (";
   javascript << tempVariant;
-  javascript << FX_WSTRC(L" = ");
+  javascript << L" = ";
   javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   m_pAssignment->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L"); ");
+  javascript << L"); ";
   javascript << tempVariant;
   if (m_iDirection == 1) {
-    javascript << FX_WSTRC(L" <= ");
+    javascript << L" <= ";
     javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-    javascript << FX_WSTRC(L"(");
+    javascript << L"(";
     m_pAccessor->ToJavaScript(javascript);
-    javascript << FX_WSTRC(L"); ");
+    javascript << L"); ";
     javascript << tempVariant;
-    javascript << FX_WSTRC(L" += ");
+    javascript << L" += ";
   } else {
-    javascript << FX_WSTRC(L" >= ");
+    javascript << L" >= ";
     javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-    javascript << FX_WSTRC(L"(");
+    javascript << L"(";
     m_pAccessor->ToJavaScript(javascript);
-    javascript << FX_WSTRC(L"); ");
+    javascript << L"); ";
     javascript << tempVariant;
-    javascript << FX_WSTRC(L" -= ");
+    javascript << L" -= ";
   }
   if (m_pStep) {
     javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-    javascript << FX_WSTRC(L"(");
+    javascript << L"(";
     m_pStep->ToJavaScript(javascript);
-    javascript << FX_WSTRC(L")");
+    javascript << L")";
   } else {
-    javascript << FX_WSTRC(L"1");
+    javascript << L"1";
   }
-  javascript << FX_WSTRC(L")\n");
+  javascript << L")\n";
   m_pList->ToImpliedReturnJS(javascript);
-  javascript << FX_WSTRC(L"}\n");
+  javascript << L"}\n";
 }
 
 CXFA_FMForeachExpression::CXFA_FMForeachExpression(
@@ -499,8 +499,8 @@
 CXFA_FMForeachExpression::~CXFA_FMForeachExpression() {}
 
 void CXFA_FMForeachExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  javascript << FX_WSTRC(L"{\n");
-  javascript << FX_WSTRC(L"var ");
+  javascript << L"{\n";
+  javascript << L"var ";
   if (m_wsIdentifier.GetAt(0) == L'!') {
     CFX_WideString tempIdentifier =
         EXCLAMATION_IN_IDENTIFIER + m_wsIdentifier.Mid(1);
@@ -508,27 +508,27 @@
   } else {
     javascript << m_wsIdentifier;
   }
-  javascript << FX_WSTRC(L" = null;\n");
-  javascript << FX_WSTRC(L"var ");
+  javascript << L" = null;\n";
+  javascript << L"var ";
   javascript << RUNTIMEBLOCKTEMPARRAY;
-  javascript << FX_WSTRC(L" = ");
+  javascript << L" = ";
   javascript << XFA_FM_EXPTypeToString(CONCATFMOBJECT);
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
 
   for (const auto& expr : m_pAccessors) {
     expr->ToJavaScript(javascript);
     if (expr != m_pAccessors.back())
       javascript << L", ";
   }
-  javascript << FX_WSTRC(L");\n");
-  javascript << FX_WSTRC(L"var ");
+  javascript << L");\n";
+  javascript << L"var ";
   javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
-  javascript << FX_WSTRC(L" = 0;\n");
-  javascript << FX_WSTRC(L"while(");
+  javascript << (L" = 0;\n");
+  javascript << L"while(";
   javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
-  javascript << FX_WSTRC(L" < ");
+  javascript << L" < ";
   javascript << RUNTIMEBLOCKTEMPARRAY;
-  javascript << FX_WSTRC(L".length)\n{\n");
+  javascript << L".length)\n{\n";
   if (m_wsIdentifier.GetAt(0) == L'!') {
     CFX_WideString tempIdentifier =
         EXCLAMATION_IN_IDENTIFIER + m_wsIdentifier.Mid(1);
@@ -536,21 +536,21 @@
   } else {
     javascript << m_wsIdentifier;
   }
-  javascript << FX_WSTRC(L" = ");
+  javascript << L" = ";
   javascript << RUNTIMEBLOCKTEMPARRAY;
-  javascript << FX_WSTRC(L"[");
+  javascript << L"[";
   javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
-  javascript << FX_WSTRC(L"++];\n");
+  javascript << L"++];\n";
   m_pList->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L"}\n");
-  javascript << FX_WSTRC(L"}\n");
+  javascript << L"}\n";
+  javascript << L"}\n";
 }
 
 void CXFA_FMForeachExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
   javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << FX_WSTRC(L" = 0;\n");
-  javascript << FX_WSTRC(L"{\n");
-  javascript << FX_WSTRC(L"var ");
+  javascript << L" = 0;\n";
+  javascript << L"{\n";
+  javascript << L"var ";
   if (m_wsIdentifier.GetAt(0) == L'!') {
     CFX_WideString tempIdentifier =
         EXCLAMATION_IN_IDENTIFIER + m_wsIdentifier.Mid(1);
@@ -558,26 +558,26 @@
   } else {
     javascript << m_wsIdentifier;
   }
-  javascript << FX_WSTRC(L" = null;\n");
-  javascript << FX_WSTRC(L"var ");
+  javascript << L" = null;\n";
+  javascript << L"var ";
   javascript << RUNTIMEBLOCKTEMPARRAY;
-  javascript << FX_WSTRC(L" = ");
+  javascript << L" = ";
   javascript << XFA_FM_EXPTypeToString(CONCATFMOBJECT);
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   for (const auto& expr : m_pAccessors) {
     expr->ToJavaScript(javascript);
     if (expr != m_pAccessors.back())
       javascript << L", ";
   }
-  javascript << FX_WSTRC(L");\n");
-  javascript << FX_WSTRC(L"var ");
+  javascript << L");\n";
+  javascript << L"var ";
   javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
-  javascript << FX_WSTRC(L" = 0;\n");
-  javascript << FX_WSTRC(L"while(");
+  javascript << L" = 0;\n";
+  javascript << L"while(";
   javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
-  javascript << FX_WSTRC(L" < ");
+  javascript << L" < ";
   javascript << RUNTIMEBLOCKTEMPARRAY;
-  javascript << FX_WSTRC(L".length)\n{\n");
+  javascript << L".length)\n{\n";
   if (m_wsIdentifier.GetAt(0) == L'!') {
     CFX_WideString tempIdentifier =
         EXCLAMATION_IN_IDENTIFIER + m_wsIdentifier.Mid(1);
@@ -585,12 +585,12 @@
   } else {
     javascript << m_wsIdentifier;
   }
-  javascript << FX_WSTRC(L" = ");
+  javascript << L" = ";
   javascript << RUNTIMEBLOCKTEMPARRAY;
-  javascript << FX_WSTRC(L"[");
+  javascript << L"[";
   javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
-  javascript << FX_WSTRC(L"++];\n");
+  javascript << L"++];\n";
   m_pList->ToImpliedReturnJS(javascript);
-  javascript << FX_WSTRC(L"}\n");
-  javascript << FX_WSTRC(L"}\n");
+  javascript << L"}\n";
+  javascript << L"}\n";
 }
diff --git a/xfa/fxfa/fm2js/xfa_fm2jscontext.cpp b/xfa/fxfa/fm2js/xfa_fm2jscontext.cpp
index b307687..e8cb2d0 100644
--- a/xfa/fxfa/fm2js/xfa_fm2jscontext.cpp
+++ b/xfa/fxfa/fm2js/xfa_fm2jscontext.cpp
@@ -409,30 +409,30 @@
 bool PatternStringType(const CFX_ByteStringC& szPattern,
                        uint32_t& patternType) {
   CFX_WideString wsPattern = CFX_WideString::FromUTF8(szPattern);
-  if (FX_WSTRC(L"datetime") == wsPattern.Left(8)) {
+  if (L"datetime" == wsPattern.Left(8)) {
     patternType = XFA_VT_DATETIME;
     return true;
   }
-  if (FX_WSTRC(L"date") == wsPattern.Left(4)) {
+  if (L"date" == wsPattern.Left(4)) {
     patternType = wsPattern.Find(L"time") > 0 ? XFA_VT_DATETIME : XFA_VT_DATE;
     return true;
   }
-  if (FX_WSTRC(L"time") == wsPattern.Left(4)) {
+  if (L"time" == wsPattern.Left(4)) {
     patternType = XFA_VT_TIME;
     return true;
   }
-  if (FX_WSTRC(L"text") == wsPattern.Left(4)) {
+  if (L"text" == wsPattern.Left(4)) {
     patternType = XFA_VT_TEXT;
     return true;
   }
-  if (FX_WSTRC(L"num") == wsPattern.Left(3)) {
-    if (FX_WSTRC(L"integer") == wsPattern.Mid(4, 7)) {
+  if (L"num" == wsPattern.Left(3)) {
+    if (L"integer" == wsPattern.Mid(4, 7)) {
       patternType = XFA_VT_INTEGER;
-    } else if (FX_WSTRC(L"decimal") == wsPattern.Mid(4, 7)) {
+    } else if (L"decimal" == wsPattern.Mid(4, 7)) {
       patternType = XFA_VT_DECIMAL;
-    } else if (FX_WSTRC(L"currency") == wsPattern.Mid(4, 8)) {
+    } else if (L"currency" == wsPattern.Mid(4, 8)) {
       patternType = XFA_VT_FLOAT;
-    } else if (FX_WSTRC(L"percent") == wsPattern.Mid(4, 7)) {
+    } else if (L"percent" == wsPattern.Mid(4, 7)) {
       patternType = XFA_VT_FLOAT;
     } else {
       patternType = XFA_VT_FLOAT;
@@ -2026,7 +2026,7 @@
   CFX_WideString wsRet;
   widgetValue.FormatPatterns(wsRet, wsFormat, pLocale,
                              XFA_VALUEPICTURE_Display);
-  strLocalDate = FX_UTF8Encode(wsRet.c_str(), wsRet.GetLength());
+  strLocalDate = wsRet.UTF8Encode();
   return true;
 }
 
@@ -2065,7 +2065,7 @@
   CFX_WideString wsRet;
   widgetValue.FormatPatterns(wsRet, wsFormat, pLocale,
                              XFA_VALUEPICTURE_Display);
-  strLocalTime = FX_UTF8Encode(wsRet.c_str(), wsRet.GetLength());
+  strLocalTime = wsRet.UTF8Encode();
   return true;
 }
 
@@ -2104,7 +2104,7 @@
   CFX_WideString wsRet;
   widgetValue.FormatPatterns(wsRet, wsFormat, pLocale,
                              XFA_VALUEPICTURE_Display);
-  strGMTTime = FX_UTF8Encode(wsRet.c_str(), wsRet.GetLength());
+  strGMTTime = wsRet.UTF8Encode();
   return true;
 }
 
@@ -2213,7 +2213,7 @@
     pLocale->GetDateTimeSymbols(wsSymbols);
     AlternateDateTimeSymbols(strRet, wsSymbols, g_sAltTable_Date);
   }
-  strFormat = FX_UTF8Encode(strRet.c_str(), strRet.GetLength());
+  strFormat = strRet.UTF8Encode();
 }
 
 // static
@@ -2264,7 +2264,7 @@
     pLocale->GetDateTimeSymbols(wsSymbols);
     AlternateDateTimeSymbols(strRet, wsSymbols, g_sAltTable_Time);
   }
-  strFormat = FX_UTF8Encode(strRet.c_str(), strRet.GetLength());
+  strFormat = strRet.UTF8Encode();
 }
 
 // static
@@ -2959,10 +2959,8 @@
       CFXJSE_Context::Create(pIsolate, nullptr, nullptr));
 
   auto returnValue = pdfium::MakeUnique<CFXJSE_Value>(pIsolate);
-  CFX_WideString javaScript(wsJavaScriptBuf.AsStringC());
-  pNewContext->ExecuteScript(
-      FX_UTF8Encode(javaScript.c_str(), javaScript.GetLength()).c_str(),
-      returnValue.get());
+  pNewContext->ExecuteScript(FX_UTF8Encode(wsJavaScriptBuf.AsStringC()).c_str(),
+                             returnValue.get());
 
   args.GetReturnValue()->Assign(returnValue.get());
 }
@@ -3428,11 +3426,8 @@
     ++i;
   }
   wsResultBuf.AppendChar(0);
-
   szResultString.Clear();
-  szResultString << FX_UTF8Encode(wsResultBuf.GetBuffer(),
-                                  wsResultBuf.GetLength())
-                        .AsStringC();
+  szResultString << FX_UTF8Encode(wsResultBuf.AsStringC());
 }
 
 // static
@@ -3508,9 +3503,7 @@
   wsResultBuf.AppendChar(0);
 
   szResultString.Clear();
-  szResultString << FX_UTF8Encode(wsResultBuf.GetBuffer(),
-                                  wsResultBuf.GetLength())
-                        .AsStringC();
+  szResultString << FX_UTF8Encode(wsResultBuf.AsStringC());
 }
 
 // static
@@ -3610,10 +3603,8 @@
     iCode = 0;
   }
   wsXMLBuf.AppendChar(0);
-
   szResultString.Clear();
-  szResultString << FX_UTF8Encode(wsXMLBuf.GetBuffer(), wsXMLBuf.GetLength())
-                        .AsStringC();
+  szResultString << FX_UTF8Encode(wsXMLBuf.AsStringC());
 }
 
 // static
@@ -3685,7 +3676,7 @@
         int32_t iIndex = ch / 16;
         strEncode[1] = strCode[iIndex];
         strEncode[2] = strCode[ch - iIndex * 16];
-        wsResultBuf << FX_WSTRC(strEncode);
+        wsResultBuf << strEncode;
         break;
       }
       ++i;
@@ -3700,7 +3691,7 @@
         int32_t iIndex = ch / 16;
         strEncode[1] = strCode[iIndex];
         strEncode[2] = strCode[ch - iIndex * 16];
-        wsResultBuf << FX_WSTRC(strEncode);
+        wsResultBuf << strEncode;
         break;
       }
       ++i;
@@ -3724,7 +3715,7 @@
       int32_t iIndex = ch / 16;
       strEncode[1] = strCode[iIndex];
       strEncode[2] = strCode[ch - iIndex * 16];
-      wsResultBuf << FX_WSTRC(strEncode);
+      wsResultBuf << strEncode;
     } else if (ch >= 0x20 && ch <= 0x7e) {
       wsResultBuf.AppendChar(ch);
     } else {
@@ -3750,20 +3741,18 @@
         strEncode[2] = strTmp.GetAt(iLen - 2);
         iIndex = iLen - 3;
       }
-      wsResultBuf << FX_WSTRC(strEncode);
+      wsResultBuf << strEncode;
       while (iIndex > 0) {
         strEncode[1] = strTmp.GetAt(iIndex);
         strEncode[2] = strTmp.GetAt(iIndex - 1);
         iIndex -= 2;
-        wsResultBuf << FX_WSTRC(strEncode);
+        wsResultBuf << strEncode;
       }
     }
   }
   wsResultBuf.AppendChar(0);
   szResultBuf.Clear();
-
-  szResultBuf << FX_UTF8Encode(wsResultBuf.GetBuffer(), wsResultBuf.GetLength())
-                     .AsStringC();
+  szResultBuf << FX_UTF8Encode(wsResultBuf.AsStringC());
 }
 
 // static
@@ -3799,7 +3788,7 @@
       strEncode[4] = strCode[ch - iIndex * 16];
       strEncode[5] = ';';
       strEncode[6] = 0;
-      wsResultBuf << FX_WSTRC(strEncode);
+      wsResultBuf << strEncode;
     } else {
       int32_t iBigByte = ch / 256;
       int32_t iLittleByte = ch % 256;
@@ -3807,15 +3796,13 @@
       strEncode[4] = strCode[iBigByte % 16];
       strEncode[5] = strCode[iLittleByte / 16];
       strEncode[6] = strCode[iLittleByte % 16];
-      wsResultBuf << FX_WSTRC(strEncode);
+      wsResultBuf << strEncode;
     }
     ++i;
   }
   wsResultBuf.AppendChar(0);
   szResultBuf.Clear();
-
-  szResultBuf << FX_UTF8Encode(wsResultBuf.GetBuffer(), wsResultBuf.GetLength())
-                     .AsStringC();
+  szResultBuf << FX_UTF8Encode(wsResultBuf.AsStringC());
 }
 
 // static
@@ -3870,7 +3857,7 @@
           strEncode[4] = strCode[ch - iIndex * 16];
           strEncode[5] = ';';
           strEncode[6] = 0;
-          wsResultBuf << FX_WSTRC(strEncode);
+          wsResultBuf << strEncode;
         } else {
           int32_t iBigByte = ch / 256;
           int32_t iLittleByte = ch % 256;
@@ -3878,7 +3865,7 @@
           strEncode[4] = strCode[iBigByte % 16];
           strEncode[5] = strCode[iLittleByte / 16];
           strEncode[6] = strCode[iLittleByte % 16];
-          wsResultBuf << FX_WSTRC(strEncode);
+          wsResultBuf << strEncode;
         }
         break;
       }
@@ -3886,9 +3873,7 @@
   }
   wsResultBuf.AppendChar(0);
   szResultBuf.Clear();
-
-  szResultBuf << FX_UTF8Encode(wsResultBuf.GetBuffer(), wsResultBuf.GetLength())
-                     .AsStringC();
+  szResultBuf << FX_UTF8Encode(wsResultBuf.AsStringC());
 }
 
 // static
@@ -4009,8 +3994,7 @@
     return;
   }
 
-  args.GetReturnValue()->SetString(
-      FX_UTF8Encode(wsRet.c_str(), wsRet.GetLength()).AsStringC());
+  args.GetReturnValue()->SetString(wsRet.UTF8Encode().AsStringC());
 }
 
 // static
@@ -4091,8 +4075,7 @@
   lowStringBuf.AppendChar(0);
 
   args.GetReturnValue()->SetString(
-      FX_UTF8Encode(lowStringBuf.GetBuffer(), lowStringBuf.GetLength())
-          .AsStringC());
+      FX_UTF8Encode(lowStringBuf.AsStringC()).AsStringC());
 }
 
 // static
@@ -4156,7 +4139,7 @@
       return;
     }
     args.GetReturnValue()->SetString(
-        FX_UTF8Encode(localeValue.GetValue()).AsStringC());
+        localeValue.GetValue().UTF8Encode().AsStringC());
     return;
   }
 
@@ -4173,7 +4156,7 @@
         return;
       }
       args.GetReturnValue()->SetString(
-          FX_UTF8Encode(localeValue.GetValue()).AsStringC());
+          localeValue.GetValue().UTF8Encode().AsStringC());
       return;
     }
     case XFA_VT_DATE: {
@@ -4185,7 +4168,7 @@
         return;
       }
       args.GetReturnValue()->SetString(
-          FX_UTF8Encode(localeValue.GetValue()).AsStringC());
+          localeValue.GetValue().UTF8Encode().AsStringC());
       return;
     }
     case XFA_VT_TIME: {
@@ -4197,7 +4180,7 @@
         return;
       }
       args.GetReturnValue()->SetString(
-          FX_UTF8Encode(localeValue.GetValue()).AsStringC());
+          localeValue.GetValue().UTF8Encode().AsStringC());
       return;
     }
     case XFA_VT_TEXT: {
@@ -4209,7 +4192,7 @@
         return;
       }
       args.GetReturnValue()->SetString(
-          FX_UTF8Encode(localeValue.GetValue()).AsStringC());
+          localeValue.GetValue().UTF8Encode().AsStringC());
       return;
     }
     case XFA_VT_FLOAT: {
@@ -4241,7 +4224,7 @@
         return;
       }
       args.GetReturnValue()->SetString(
-          FX_UTF8Encode(localeValue2.GetValue()).AsStringC());
+          localeValue2.GetValue().UTF8Encode().AsStringC());
       return;
     }
   }
@@ -4640,8 +4623,7 @@
   upperStringBuf.AppendChar(0);
 
   args.GetReturnValue()->SetString(
-      FX_UTF8Encode(upperStringBuf.GetBuffer(), upperStringBuf.GetLength())
-          .AsStringC());
+      FX_UTF8Encode(upperStringBuf.AsStringC()).AsStringC());
 }
 
 // static
@@ -4931,10 +4913,7 @@
     pContext->ThrowServerDeniedException();
     return;
   }
-
-  args.GetReturnValue()->SetString(
-      FX_UTF8Encode(decodedResponse.c_str(), decodedResponse.GetLength())
-          .AsStringC());
+  args.GetReturnValue()->SetString(decodedResponse.UTF8Encode().AsStringC());
 }
 
 // static
@@ -5680,9 +5659,8 @@
     return;
   }
 
-  CFX_WideString javaScript = wsJavaScriptBuf.MakeString();
   args.GetReturnValue()->SetString(
-      FX_UTF8Encode(javaScript.c_str(), javaScript.GetLength()).AsStringC());
+      FX_UTF8Encode(wsJavaScriptBuf.AsStringC()).AsStringC());
 }
 
 // static
@@ -6149,7 +6127,7 @@
         if (CXFA_Node* pXFANode = pNode->AsNode())
           pXFANode->GetAttribute(XFA_ATTRIBUTE_Name, wsName, false);
         if (wsName.IsEmpty())
-          wsName = FX_WSTRC(L"#") + pNode->GetClassName();
+          wsName = L"#" + pNode->GetClassName();
 
         wsSomExpression = wsName + wsSomExpression;
         dFlags = XFA_RESOLVENODE_Siblings;
@@ -6439,6 +6417,5 @@
   va_start(arg_ptr, str);
   wsMessage.FormatV(str, arg_ptr);
   va_end(arg_ptr);
-  FXJSE_ThrowMessage(
-      FX_UTF8Encode(wsMessage.c_str(), wsMessage.GetLength()).AsStringC());
+  FXJSE_ThrowMessage(wsMessage.UTF8Encode().AsStringC());
 }
diff --git a/xfa/fxfa/fm2js/xfa_fmparse.cpp b/xfa/fxfa/fm2js/xfa_fmparse.cpp
index 2dfdfdb..52161e8c 100644
--- a/xfa/fxfa/fm2js/xfa_fmparse.cpp
+++ b/xfa/fxfa/fm2js/xfa_fmparse.cpp
@@ -847,7 +847,7 @@
     m_lexer->SetCurrentLine(line);
     m_pToken = new CXFA_FMToken(line);
     m_pToken->m_type = TOKidentifier;
-    m_pToken->m_wstring = FX_WSTRC(L"if");
+    m_pToken->m_wstring = L"if";
     m_lexer->SetToken(m_pToken);
     m_lexer->RestorePos(pStartPos);
     return ParseExpExpression();
diff --git a/xfa/fxfa/fm2js/xfa_simpleexpression.cpp b/xfa/fxfa/fm2js/xfa_simpleexpression.cpp
index 342fe9f..686ddaa 100644
--- a/xfa/fxfa/fm2js/xfa_simpleexpression.cpp
+++ b/xfa/fxfa/fm2js/xfa_simpleexpression.cpp
@@ -132,7 +132,7 @@
     : CXFA_FMSimpleExpression(line, TOKnull) {}
 
 void CXFA_FMNullExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  javascript << FX_WSTRC(L"null");
+  javascript << L"null";
 }
 
 CXFA_FMNumberExpression::CXFA_FMNumberExpression(uint32_t line,
@@ -161,12 +161,12 @@
       switch (oneChar) {
         case L'\"': {
           i++;
-          javascript << FX_WSTRC(L"\\\"");
+          javascript << L"\\\"";
         } break;
         case 0x0d:
           break;
         case 0x0a: {
-          javascript << FX_WSTRC(L"\\n");
+          javascript << L"\\n";
         } break;
         default: { javascript.AppendChar(oneChar); } break;
       }
@@ -187,22 +187,22 @@
 
 void CXFA_FMIdentifierExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
   CFX_WideString tempStr(m_wsIdentifier);
-  if (tempStr == FX_WSTRC(L"$")) {
-    tempStr = FX_WSTRC(L"this");
-  } else if (tempStr == FX_WSTRC(L"!")) {
-    tempStr = FX_WSTRC(L"xfa.datasets");
-  } else if (tempStr == FX_WSTRC(L"$data")) {
-    tempStr = FX_WSTRC(L"xfa.datasets.data");
-  } else if (tempStr == FX_WSTRC(L"$event")) {
-    tempStr = FX_WSTRC(L"xfa.event");
-  } else if (tempStr == FX_WSTRC(L"$form")) {
-    tempStr = FX_WSTRC(L"xfa.form");
-  } else if (tempStr == FX_WSTRC(L"$host")) {
-    tempStr = FX_WSTRC(L"xfa.host");
-  } else if (tempStr == FX_WSTRC(L"$layout")) {
-    tempStr = FX_WSTRC(L"xfa.layout");
-  } else if (tempStr == FX_WSTRC(L"$template")) {
-    tempStr = FX_WSTRC(L"xfa.template");
+  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.Mid(1);
   }
@@ -240,62 +240,62 @@
     : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {}
 
 void CXFA_FMAssignExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  javascript << FX_WSTRC(L"if (");
+  javascript << L"if (";
   javascript << gs_lpStrExpFuncName[ISFMOBJECT];
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   m_pExp1->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L"))\n{\n");
+  javascript << L"))\n{\n";
   javascript << gs_lpStrExpFuncName[ASSIGN];
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   m_pExp1->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L", ");
+  javascript << L", ";
   m_pExp2->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L");\n}\n");
+  javascript << L");\n}\n";
   CFX_WideTextBuf tempExp1;
   m_pExp1->ToJavaScript(tempExp1);
   if (m_pExp1->GetOperatorToken() == TOKidentifier &&
-      tempExp1.AsStringC() != FX_WSTRC(L"this")) {
-    javascript << FX_WSTRC(L"else\n{\n");
+      tempExp1.AsStringC() != L"this") {
+    javascript << L"else\n{\n";
     javascript << tempExp1;
-    javascript << FX_WSTRC(L" = ");
+    javascript << L" = ";
     javascript << gs_lpStrExpFuncName[ASSIGN];
-    javascript << FX_WSTRC(L"(");
+    javascript << L"(";
     m_pExp1->ToJavaScript(javascript);
-    javascript << FX_WSTRC(L", ");
+    javascript << L", ";
     m_pExp2->ToJavaScript(javascript);
-    javascript << FX_WSTRC(L");\n}\n");
+    javascript << L");\n}\n";
   }
 }
 
 void CXFA_FMAssignExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
-  javascript << FX_WSTRC(L"if (");
+  javascript << L"if (";
   javascript << gs_lpStrExpFuncName[ISFMOBJECT];
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   m_pExp1->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L"))\n{\n");
+  javascript << L"))\n{\n";
   javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << FX_WSTRC(L" = ");
+  javascript << L" = ";
   javascript << gs_lpStrExpFuncName[ASSIGN];
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   m_pExp1->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L", ");
+  javascript << L", ";
   m_pExp2->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L");\n}\n");
+  javascript << L");\n}\n";
   CFX_WideTextBuf tempExp1;
   m_pExp1->ToJavaScript(tempExp1);
   if (m_pExp1->GetOperatorToken() == TOKidentifier &&
-      tempExp1.AsStringC() != FX_WSTRC(L"this")) {
-    javascript << FX_WSTRC(L"else\n{\n");
+      tempExp1.AsStringC() != L"this") {
+    javascript << L"else\n{\n";
     javascript << RUNTIMEFUNCTIONRETURNVALUE;
-    javascript << FX_WSTRC(L" = ");
+    javascript << L" = ";
     javascript << tempExp1;
-    javascript << FX_WSTRC(L" = ");
+    javascript << L" = ";
     javascript << gs_lpStrExpFuncName[ASSIGN];
-    javascript << FX_WSTRC(L"(");
+    javascript << L"(";
     m_pExp1->ToJavaScript(javascript);
-    javascript << FX_WSTRC(L", ");
+    javascript << L", ";
     m_pExp2->ToJavaScript(javascript);
-    javascript << FX_WSTRC(L");\n}\n");
+    javascript << L");\n}\n";
   }
 }
 
@@ -308,11 +308,11 @@
 
 void CXFA_FMLogicalOrExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
   javascript << gs_lpStrExpFuncName[LOGICALOR];
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   m_pExp1->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L", ");
+  javascript << L", ";
   m_pExp2->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L")");
+  javascript << L")";
 }
 
 CXFA_FMLogicalAndExpression::CXFA_FMLogicalAndExpression(
@@ -324,11 +324,11 @@
 
 void CXFA_FMLogicalAndExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
   javascript << gs_lpStrExpFuncName[LOGICALAND];
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   m_pExp1->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L", ");
+  javascript << L", ";
   m_pExp2->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L")");
+  javascript << L")";
 }
 
 CXFA_FMEqualityExpression::CXFA_FMEqualityExpression(
@@ -352,11 +352,11 @@
       ASSERT(false);
       break;
   }
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   m_pExp1->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L", ");
+  javascript << L", ";
   m_pExp2->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L")");
+  javascript << L")";
 }
 
 CXFA_FMRelationalExpression::CXFA_FMRelationalExpression(
@@ -388,11 +388,11 @@
       ASSERT(false);
       break;
   }
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   m_pExp1->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L", ");
+  javascript << L", ";
   m_pExp2->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L")");
+  javascript << L")";
 }
 
 CXFA_FMAdditiveExpression::CXFA_FMAdditiveExpression(
@@ -414,11 +414,11 @@
       ASSERT(false);
       break;
   }
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   m_pExp1->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L", ");
+  javascript << L", ";
   m_pExp2->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L")");
+  javascript << L")";
 }
 
 CXFA_FMMultiplicativeExpression::CXFA_FMMultiplicativeExpression(
@@ -441,11 +441,11 @@
       ASSERT(false);
       break;
   }
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   m_pExp1->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L", ");
+  javascript << L", ";
   m_pExp2->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L")");
+  javascript << L")";
 }
 
 CXFA_FMPosExpression::CXFA_FMPosExpression(
@@ -455,9 +455,9 @@
 
 void CXFA_FMPosExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
   javascript << gs_lpStrExpFuncName[POSITIVE];
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   m_pExp->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L")");
+  javascript << L")";
 }
 
 CXFA_FMNegExpression::CXFA_FMNegExpression(
@@ -467,9 +467,9 @@
 
 void CXFA_FMNegExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
   javascript << gs_lpStrExpFuncName[NEGATIVE];
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   m_pExp->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L")");
+  javascript << L")";
 }
 
 CXFA_FMNotExpression::CXFA_FMNotExpression(
@@ -479,9 +479,9 @@
 
 void CXFA_FMNotExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
   javascript << gs_lpStrExpFuncName[NOT];
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   m_pExp->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L")");
+  javascript << L")";
 }
 
 CXFA_FMCallExpression::CXFA_FMCallExpression(
@@ -574,12 +574,12 @@
     bool isEvalFunc = false;
     bool isExistsFunc = false;
     if (IsBuildInFunc(&funcName)) {
-      if (funcName.AsStringC() == FX_WSTRC(L"Eval")) {
+      if (funcName.AsStringC() == L"Eval") {
         isEvalFunc = true;
-        javascript << FX_WSTRC(L"eval.call(this, ");
+        javascript << L"eval.call(this, ";
         javascript << gs_lpStrExpFuncName[CALL];
-        javascript << FX_WSTRC(L"Translate");
-      } else if (funcName.AsStringC() == FX_WSTRC(L"Exists")) {
+        javascript << L"Translate";
+      } else if (funcName.AsStringC() == L"Exists") {
         isExistsFunc = true;
         javascript << gs_lpStrExpFuncName[CALL];
         javascript << funcName;
@@ -590,19 +590,19 @@
     } else {
       javascript << funcName;
     }
-    javascript << FX_WSTRC(L"(");
+    javascript << L"(";
     if (isExistsFunc) {
-      javascript << FX_WSTRC(L"\n(\nfunction ()\n{\ntry\n{\n");
+      javascript << L"\n(\nfunction ()\n{\ntry\n{\n";
       if (!m_Arguments.empty()) {
         const auto& expr = m_Arguments[0];
-        javascript << FX_WSTRC(L"return ");
+        javascript << L"return ";
         expr->ToJavaScript(javascript);
-        javascript << FX_WSTRC(L";\n}\n");
+        javascript << L";\n}\n";
       } else {
-        javascript << FX_WSTRC(L"return 0;\n}\n");
+        javascript << L"return 0;\n}\n";
       }
-      javascript << FX_WSTRC(
-          L"catch(accessExceptions)\n{\nreturn 0;\n}\n}\n).call(this)\n");
+      javascript
+          << L"catch(accessExceptions)\n{\nreturn 0;\n}\n}\n).call(this)\n";
     } else {
       for (const auto& expr : m_Arguments) {
         expr->ToJavaScript(javascript);
@@ -633,33 +633,33 @@
 
 void CXFA_FMDotAccessorExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
   javascript << gs_lpStrExpFuncName[DOT];
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   if (m_pExp1) {
     m_pExp1->ToJavaScript(javascript);
   } else {
-    javascript << FX_WSTRC(L"null");
+    javascript << L"null";
   }
-  javascript << FX_WSTRC(L", ");
-  javascript << FX_WSTRC(L"\"");
+  javascript << L", ";
+  javascript << L"\"";
   if (m_pExp1 && m_pExp1->GetOperatorToken() == TOKidentifier) {
     m_pExp1->ToJavaScript(javascript);
   }
-  javascript << FX_WSTRC(L"\", ");
+  javascript << L"\", ";
   if (m_op == TOKdotscream) {
-    javascript << FX_WSTRC(L"\"#");
+    javascript << L"\"#";
     javascript << m_wsIdentifier;
-    javascript << FX_WSTRC(L"\", ");
+    javascript << L"\", ";
   } else if (m_op == TOKdotstar) {
-    javascript << FX_WSTRC(L"\"*\", ");
+    javascript << L"\"*\", ";
   } else if (m_op == TOKcall) {
-    javascript << FX_WSTRC(L"\"\", ");
+    javascript << L"\"\", ";
   } else {
-    javascript << FX_WSTRC(L"\"");
+    javascript << L"\"";
     javascript << m_wsIdentifier;
-    javascript << FX_WSTRC(L"\", ");
+    javascript << L"\", ";
   }
   m_pExp2->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L")");
+  javascript << L")";
 }
 
 CXFA_FMIndexExpression::CXFA_FMIndexExpression(
@@ -674,26 +674,26 @@
 void CXFA_FMIndexExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
   switch (m_accessorIndex) {
     case ACCESSOR_NO_INDEX:
-      javascript << FX_WSTRC(L"0");
+      javascript << L"0";
       break;
     case ACCESSOR_NO_RELATIVEINDEX:
-      javascript << FX_WSTRC(L"1");
+      javascript << L"1";
       break;
     case ACCESSOR_POSITIVE_INDEX:
-      javascript << FX_WSTRC(L"2");
+      javascript << L"2";
       break;
     case ACCESSOR_NEGATIVE_INDEX:
-      javascript << FX_WSTRC(L"3");
+      javascript << L"3";
       break;
     default:
-      javascript << FX_WSTRC(L"0");
+      javascript << L"0";
   }
   if (!m_bIsStarIndex) {
-    javascript << FX_WSTRC(L", ");
+    javascript << L", ";
     if (m_pExp) {
       m_pExp->ToJavaScript(javascript);
     } else {
-      javascript << FX_WSTRC(L"0");
+      javascript << L"0";
     }
   }
 }
@@ -715,19 +715,19 @@
 void CXFA_FMDotDotAccessorExpression::ToJavaScript(
     CFX_WideTextBuf& javascript) {
   javascript << gs_lpStrExpFuncName[DOTDOT];
-  javascript << FX_WSTRC(L"(");
+  javascript << L"(";
   m_pExp1->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L", ");
-  javascript << FX_WSTRC(L"\"");
+  javascript << L", ";
+  javascript << L"\"";
   if (m_pExp1 && m_pExp1->GetOperatorToken() == TOKidentifier) {
     m_pExp1->ToJavaScript(javascript);
   }
-  javascript << FX_WSTRC(L"\", ");
-  javascript << FX_WSTRC(L"\"");
+  javascript << L"\", ";
+  javascript << L"\"";
   javascript << m_wsIdentifier;
-  javascript << FX_WSTRC(L"\", ");
+  javascript << L"\", ";
   m_pExp2->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L")");
+  javascript << L")";
 }
 
 CXFA_FMMethodCallExpression::CXFA_FMMethodCallExpression(
@@ -740,22 +740,22 @@
                            std::move(pCallExp)) {}
 
 void CXFA_FMMethodCallExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  javascript << FX_WSTRC(L"(\nfunction ()\n{\n");
-  javascript << FX_WSTRC(L"var method_return_value = null;\n");
-  javascript << FX_WSTRC(L"var accessor_object = ");
+  javascript << L"(\nfunction ()\n{\n";
+  javascript << L"var method_return_value = null;\n";
+  javascript << L"var accessor_object = ";
   m_pExp1->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L";\n");
-  javascript << FX_WSTRC(L"if (");
+  javascript << L";\n";
+  javascript << L"if (";
   javascript << gs_lpStrExpFuncName[ISFMARRAY];
-  javascript << FX_WSTRC(L"(accessor_object))\n{\n");
-  javascript << FX_WSTRC(
-      L"for(var index = accessor_object.length - 1; index > 1; index--)\n{\n");
-  javascript << FX_WSTRC(L"method_return_value = accessor_object[index].");
+  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].";
   m_pExp2->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L";\n}\n}\n");
-  javascript << FX_WSTRC(L"else\n{\nmethod_return_value = accessor_object.");
+  javascript << L";\n}\n}\n";
+  javascript << L"else\n{\nmethod_return_value = accessor_object.";
   m_pExp2->ToJavaScript(javascript);
-  javascript << FX_WSTRC(L";\n}\n");
-  javascript << FX_WSTRC(L"return method_return_value;\n");
-  javascript << FX_WSTRC(L"}\n).call(this)");
+  javascript << L";\n}\n";
+  javascript << L"return method_return_value;\n";
+  javascript << L"}\n).call(this)";
 }
diff --git a/xfa/fxfa/fm2js/xfa_simpleexpression.h b/xfa/fxfa/fm2js/xfa_simpleexpression.h
index 28c37ed..af1d02e 100644
--- a/xfa/fxfa/fm2js/xfa_simpleexpression.h
+++ b/xfa/fxfa/fm2js/xfa_simpleexpression.h
@@ -14,9 +14,8 @@
 #include "xfa/fxfa/fm2js/xfa_lexer.h"
 
 #define RUNTIMEFUNCTIONRETURNVALUE \
-  (FX_WSTRC(L"foxit_xfa_formcalc_runtime_func_return_value"))
-#define EXCLAMATION_IN_IDENTIFIER \
-  (FX_WSTRC(L"foxit_xfa_formcalc__exclamation__"))
+  (L"foxit_xfa_formcalc_runtime_func_return_value")
+#define EXCLAMATION_IN_IDENTIFIER (L"foxit_xfa_formcalc__exclamation__")
 
 enum XFA_FM_SimpleExpressionType {
   ASSIGN,
diff --git a/xfa/fxfa/parser/cscript_eventpseudomodel.cpp b/xfa/fxfa/parser/cscript_eventpseudomodel.cpp
index 8a7d80b..8cfedd2 100644
--- a/xfa/fxfa/parser/cscript_eventpseudomodel.cpp
+++ b/xfa/fxfa/parser/cscript_eventpseudomodel.cpp
@@ -25,7 +25,7 @@
     wsValue = pValue->ToWideString();
     return;
   }
-  pValue->SetString(FX_UTF8Encode(wsValue).AsStringC());
+  pValue->SetString(wsValue.UTF8Encode().AsStringC());
 }
 
 void InterProperty(CFXJSE_Value* pValue, int32_t& iValue, bool bSetting) {
diff --git a/xfa/fxfa/parser/cscript_hostpseudomodel.cpp b/xfa/fxfa/parser/cscript_hostpseudomodel.cpp
index 97f16f0..a06e02f 100644
--- a/xfa/fxfa/parser/cscript_hostpseudomodel.cpp
+++ b/xfa/fxfa/parser/cscript_hostpseudomodel.cpp
@@ -89,7 +89,7 @@
     return;
   }
   pValue->SetString(
-      FX_UTF8Encode(pNotify->GetAppProvider()->GetLanguage()).AsStringC());
+      pNotify->GetAppProvider()->GetLanguage().UTF8Encode().AsStringC());
 }
 
 void CScript_HostPseudoModel::NumPages(CFXJSE_Value* pValue,
@@ -118,8 +118,9 @@
     return;
   }
   pValue->SetString(
-      FX_UTF8Encode(pNotify->GetAppProvider()->GetPlatform()).AsStringC());
+      pNotify->GetAppProvider()->GetPlatform().UTF8Encode().AsStringC());
 }
+
 void CScript_HostPseudoModel::Title(CFXJSE_Value* pValue,
                                     bool bSetting,
                                     XFA_ATTRIBUTE eAttribute) {
@@ -137,7 +138,7 @@
   }
   CFX_WideString wsTitle;
   pNotify->GetDocEnvironment()->GetTitle(hDoc, wsTitle);
-  pValue->SetString(FX_UTF8Encode(wsTitle).AsStringC());
+  pValue->SetString(wsTitle.UTF8Encode().AsStringC());
 }
 
 void CScript_HostPseudoModel::ValidationsEnabled(CFXJSE_Value* pValue,
@@ -199,7 +200,7 @@
     return;
   }
   pValue->SetString(
-      FX_UTF8Encode(pNotify->GetAppProvider()->GetAppName()).AsStringC());
+      pNotify->GetAppProvider()->GetAppName().UTF8Encode().AsStringC());
 }
 
 void CScript_HostPseudoModel::GotoURL(CFXJSE_Arguments* pArguments) {
@@ -306,7 +307,7 @@
       wsQuestion, wsTitle, wsDefaultAnswer, bMark);
   CFXJSE_Value* pValue = pArguments->GetReturnValue();
   if (pValue)
-    pValue->SetString(FX_UTF8Encode(wsAnswer).AsStringC());
+    pValue->SetString(wsAnswer.UTF8Encode().AsStringC());
 }
 
 void CScript_HostPseudoModel::DocumentInBatch(CFXJSE_Arguments* pArguments) {
@@ -519,7 +520,7 @@
     return false;
   }
   if (pValueArg->IsNull()) {
-    wsValue = FX_WSTRC(L"");
+    wsValue = L"";
   } else {
     wsValue = pValueArg->ToWideString();
   }
@@ -674,7 +675,7 @@
   CFX_WideString wsDataTime = pNotify->GetCurrentDateTime();
   CFXJSE_Value* pValue = pArguments->GetReturnValue();
   if (pValue)
-    pValue->SetString(FX_UTF8Encode(wsDataTime).AsStringC());
+    pValue->SetString(wsDataTime.UTF8Encode().AsStringC());
 }
 
 void CScript_HostPseudoModel::ThrowSetLanguageException() const {
diff --git a/xfa/fxfa/parser/cscript_layoutpseudomodel.cpp b/xfa/fxfa/parser/cscript_layoutpseudomodel.cpp
index a1d1ca5..152b568 100644
--- a/xfa/fxfa/parser/cscript_layoutpseudomodel.cpp
+++ b/xfa/fxfa/parser/cscript_layoutpseudomodel.cpp
@@ -90,7 +90,7 @@
   if (!pDocLayout) {
     return;
   }
-  CFX_RectF rtRect;
+
   CXFA_Measurement measure;
   CXFA_LayoutItem* pLayoutItem = pDocLayout->GetLayoutItem(pNode);
   if (!pLayoutItem) {
@@ -105,7 +105,8 @@
     pValue->SetFloat(0);
     return;
   }
-  pLayoutItem->GetRect(rtRect, true);
+
+  CFX_RectF rtRect = pLayoutItem->GetRect(true);
   switch (layoutModel) {
     case XFA_LAYOUTMODEL_H:
       measure.Set(rtRect.height, XFA_UNIT_Pt);
@@ -217,13 +218,13 @@
   if (!pLayoutPage) {
     return;
   }
-  if (wsType == FX_WSTRC(L"pageArea")) {
+  if (wsType == L"pageArea") {
     if (CXFA_Node* pMasterPage = pLayoutPage->m_pFormNode) {
       retArray.Add(pMasterPage);
     }
     return;
   }
-  if (wsType == FX_WSTRC(L"contentArea")) {
+  if (wsType == L"contentArea") {
     for (CXFA_LayoutItem* pItem = pLayoutPage->m_pFirstChild; pItem;
          pItem = pItem->m_pNextSibling) {
       if (pItem->m_pFormNode->GetElementType() == XFA_Element::ContentArea) {
@@ -288,13 +289,13 @@
     return;
   }
   XFA_Element eType = XFA_Element::Unknown;
-  if (wsType == FX_WSTRC(L"field")) {
+  if (wsType == L"field") {
     eType = XFA_Element::Field;
-  } else if (wsType == FX_WSTRC(L"draw")) {
+  } else if (wsType == L"draw") {
     eType = XFA_Element::Draw;
-  } else if (wsType == FX_WSTRC(L"subform")) {
+  } else if (wsType == L"subform") {
     eType = XFA_Element::Subform;
-  } else if (wsType == FX_WSTRC(L"area")) {
+  } else if (wsType == L"area") {
     eType = XFA_Element::Area;
   }
   if (eType != XFA_Element::Unknown) {
diff --git a/xfa/fxfa/parser/cxfa_box.cpp b/xfa/fxfa/parser/cxfa_box.cpp
index 9d9b4b4..552c980 100644
--- a/xfa/fxfa/parser/cxfa_box.cpp
+++ b/xfa/fxfa/parser/cxfa_box.cpp
@@ -13,53 +13,47 @@
 namespace {
 
 void GetStrokesInternal(CXFA_Node* pNode,
-                        CXFA_StrokeArray& strokes,
+                        std::vector<CXFA_Stroke>* strokes,
                         bool bNull) {
-  strokes.RemoveAll();
+  strokes->clear();
   if (!pNode)
     return;
 
-  strokes.SetSize(8);
+  strokes->resize(8);
   int32_t i, j;
   for (i = 0, j = 0; i < 4; i++) {
     CXFA_Corner corner =
         CXFA_Corner(pNode->GetProperty(i, XFA_Element::Corner, i == 0));
-    if (corner || i == 0)
-      strokes.SetAt(j, corner);
-    else if (bNull)
-      strokes.SetAt(j, CXFA_Stroke(nullptr));
-    else if (i == 1)
-      strokes.SetAt(j, strokes[0]);
-    else if (i == 2)
-      strokes.SetAt(j, strokes[0]);
-    else
-      strokes.SetAt(j, strokes[2]);
-
+    if (corner || i == 0) {
+      (*strokes)[j] = corner;
+    } else if (!bNull) {
+      if (i == 1 || i == 2)
+        (*strokes)[j] = (*strokes)[0];
+      else
+        (*strokes)[j] = (*strokes)[2];
+    }
     j++;
     CXFA_Edge edge =
         CXFA_Edge(pNode->GetProperty(i, XFA_Element::Edge, i == 0));
-    if (edge || i == 0)
-      strokes.SetAt(j, edge);
-    else if (bNull)
-      strokes.SetAt(j, CXFA_Stroke(nullptr));
-    else if (i == 1)
-      strokes.SetAt(j, strokes[1]);
-    else if (i == 2)
-      strokes.SetAt(j, strokes[1]);
-    else
-      strokes.SetAt(j, strokes[3]);
-
+    if (edge || i == 0) {
+      (*strokes)[j] = edge;
+    } else if (!bNull) {
+      if (i == 1 || i == 2)
+        (*strokes)[j] = (*strokes)[1];
+      else
+        (*strokes)[j] = (*strokes)[3];
+    }
     j++;
   }
 }
 
-static int32_t Style3D(const CXFA_StrokeArray& strokes, CXFA_Stroke& stroke) {
-  int32_t iCount = strokes.GetSize();
-  if (iCount < 1)
+static int32_t Style3D(const std::vector<CXFA_Stroke>& strokes,
+                       CXFA_Stroke& stroke) {
+  if (strokes.empty())
     return 0;
 
   stroke = strokes[0];
-  for (int32_t i = 1; i < iCount; i++) {
+  for (size_t i = 1; i < strokes.size(); i++) {
     CXFA_Stroke find = strokes[i];
     if (!find)
       continue;
@@ -105,7 +99,7 @@
               : nullptr);
 }
 
-void CXFA_Box::GetStrokes(CXFA_StrokeArray& strokes) const {
+void CXFA_Box::GetStrokes(std::vector<CXFA_Stroke>* strokes) const {
   GetStrokesInternal(m_pNode, strokes, false);
 }
 
@@ -158,8 +152,8 @@
   if (IsArc())
     return 0;
 
-  CXFA_StrokeArray strokes;
-  GetStrokesInternal(m_pNode, strokes, true);
+  std::vector<CXFA_Stroke> strokes;
+  GetStrokesInternal(m_pNode, &strokes, true);
   CXFA_Stroke stroke(nullptr);
   int32_t iType = Style3D(strokes, stroke);
   if (iType) {
diff --git a/xfa/fxfa/parser/cxfa_box.h b/xfa/fxfa/parser/cxfa_box.h
index 014155c..a0af2f4 100644
--- a/xfa/fxfa/parser/cxfa_box.h
+++ b/xfa/fxfa/parser/cxfa_box.h
@@ -7,6 +7,8 @@
 #ifndef XFA_FXFA_PARSER_CXFA_BOX_H_
 #define XFA_FXFA_PARSER_CXFA_BOX_H_
 
+#include <vector>
+
 #include "core/fxcrt/fx_system.h"
 #include "xfa/fxfa/parser/cxfa_data.h"
 #include "xfa/fxfa/parser/cxfa_edge.h"
@@ -28,7 +30,7 @@
   int32_t GetPresence() const;
   int32_t CountEdges() const;
   CXFA_Edge GetEdge(int32_t nIndex = 0) const;
-  void GetStrokes(CXFA_StrokeArray& strokes) const;
+  void GetStrokes(std::vector<CXFA_Stroke>* strokes) const;
   bool IsCircular() const;
   bool GetStartAngle(FX_FLOAT& fStartAngle) const;
   FX_FLOAT GetStartAngle() const {
diff --git a/xfa/fxfa/parser/cxfa_containerlayoutitem.cpp b/xfa/fxfa/parser/cxfa_containerlayoutitem.cpp
index dd759b6..5ef29f1 100644
--- a/xfa/fxfa/parser/cxfa_containerlayoutitem.cpp
+++ b/xfa/fxfa/parser/cxfa_containerlayoutitem.cpp
@@ -34,7 +34,7 @@
                    pMedium->GetMeasure(XFA_ATTRIBUTE_Long).ToUnit(XFA_UNIT_Pt));
   if (pMedium->GetEnum(XFA_ATTRIBUTE_Orientation) ==
       XFA_ATTRIBUTEENUM_Landscape) {
-    size = CFX_SizeF(size.y, size.x);
+    size = CFX_SizeF(size.height, size.width);
   }
   return size;
 }
diff --git a/xfa/fxfa/parser/cxfa_dataexporter.cpp b/xfa/fxfa/parser/cxfa_dataexporter.cpp
index 72d1fa7..fe99475 100644
--- a/xfa/fxfa/parser/cxfa_dataexporter.cpp
+++ b/xfa/fxfa/parser/cxfa_dataexporter.cpp
@@ -24,19 +24,19 @@
   for (int32_t i = 0; i < iLen; i++) {
     switch (str[i]) {
       case '&':
-        textBuf << FX_WSTRC(L"&amp;");
+        textBuf << L"&amp;";
         break;
       case '<':
-        textBuf << FX_WSTRC(L"&lt;");
+        textBuf << L"&lt;";
         break;
       case '>':
-        textBuf << FX_WSTRC(L"&gt;");
+        textBuf << L"&gt;";
         break;
       case '\'':
-        textBuf << FX_WSTRC(L"&apos;");
+        textBuf << L"&apos;";
         break;
       case '\"':
-        textBuf << FX_WSTRC(L"&quot;");
+        textBuf << L"&quot;";
         break;
       default:
         textBuf.AppendChar(str[i]);
@@ -54,20 +54,20 @@
       continue;
 
     if (ch == '&') {
-      textBuf << FX_WSTRC(L"&amp;");
+      textBuf << L"&amp;";
     } else if (ch == '<') {
-      textBuf << FX_WSTRC(L"&lt;");
+      textBuf << L"&lt;";
     } else if (ch == '>') {
-      textBuf << FX_WSTRC(L"&gt;");
+      textBuf << L"&gt;";
     } else if (ch == '\'') {
-      textBuf << FX_WSTRC(L"&apos;");
+      textBuf << L"&apos;";
     } else if (ch == '\"') {
-      textBuf << FX_WSTRC(L"&quot;");
+      textBuf << L"&quot;";
     } else if (ch == ' ') {
       if (i && str.GetAt(i - 1) != ' ') {
         textBuf.AppendChar(' ');
       } else {
-        textBuf << FX_WSTRC(L"&#x20;");
+        textBuf << L"&#x20;";
       }
     } else {
       textBuf.AppendChar(str.GetAt(i));
@@ -87,11 +87,11 @@
     return;
   }
   wsValue = ExportEncodeAttribute(wsValue);
-  wsOutput += FX_WSTRC(L" ");
+  wsOutput += L" ";
   wsOutput += wsName;
-  wsOutput += FX_WSTRC(L"=\"");
+  wsOutput += L"=\"";
   wsOutput += wsValue;
-  wsOutput += FX_WSTRC(L"\"");
+  wsOutput += L"\"";
 }
 
 bool AttributeSaveInDataModel(CXFA_Node* pNode, XFA_ATTRIBUTE eAttribute) {
@@ -190,7 +190,7 @@
       CFX_WideString wsContentType;
       pNode->GetAttribute(XFA_ATTRIBUTE_ContentType, wsContentType, false);
       if (pRawValueNode->GetElementType() == XFA_Element::SharpxHTML &&
-          wsContentType == FX_WSTRC(L"text/html")) {
+          wsContentType == L"text/html") {
         CFDE_XMLNode* pExDataXML = pNode->GetXMLMappingNode();
         if (!pExDataXML)
           break;
@@ -214,7 +214,7 @@
         wsChildren += CFX_WideString::FromUTF8(
             CFX_ByteStringC(pMemStream->GetBuffer(), pMemStream->GetSize()));
       } else if (pRawValueNode->GetElementType() == XFA_Element::Sharpxml &&
-                 wsContentType == FX_WSTRC(L"text/xml")) {
+                 wsContentType == L"text/xml") {
         CFX_WideString wsRawValue;
         pRawValueNode->GetAttribute(XFA_ATTRIBUTE_Value, wsRawValue, false);
         if (wsRawValue.IsEmpty())
@@ -240,20 +240,20 @@
         CFX_WideString bodyTagName;
         bodyTagName = pGrandparentNode->GetCData(XFA_ATTRIBUTE_Name);
         if (bodyTagName.IsEmpty())
-          bodyTagName = FX_WSTRC(L"ListBox1");
+          bodyTagName = L"ListBox1";
 
-        buf << FX_WSTRC(L"<");
+        buf << L"<";
         buf << bodyTagName;
-        buf << FX_WSTRC(L" xmlns=\"\"\n>");
+        buf << L" xmlns=\"\"\n>";
         for (int32_t i = 0; i < pdfium::CollectionSize<int32_t>(wsSelTextArray);
              i++) {
-          buf << FX_WSTRC(L"<value\n>");
+          buf << L"<value\n>";
           buf << ExportEncodeContent(wsSelTextArray[i].AsStringC());
-          buf << FX_WSTRC(L"</value\n>");
+          buf << L"</value\n>";
         }
-        buf << FX_WSTRC(L"</");
+        buf << L"</";
         buf << bodyTagName;
-        buf << FX_WSTRC(L"\n>");
+        buf << L"\n>";
         wsChildren += buf.AsStringC();
         buf.Clear();
       } else {
@@ -305,19 +305,19 @@
       pNode->HasAttribute(XFA_ATTRIBUTE_Name)) {
     CFX_WideStringC wsElement = pNode->GetClassName();
     CFX_WideString wsName;
-    SaveAttribute(pNode, XFA_ATTRIBUTE_Name, FX_WSTRC(L"name"), true, wsName);
-    buf << FX_WSTRC(L"<");
+    SaveAttribute(pNode, XFA_ATTRIBUTE_Name, L"name", true, wsName);
+    buf << L"<";
     buf << wsElement;
     buf << wsName;
     buf << wsAttrs;
     if (wsChildren.IsEmpty()) {
-      buf << FX_WSTRC(L"\n/>");
+      buf << L"\n/>";
     } else {
-      buf << FX_WSTRC(L"\n>");
+      buf << L"\n>";
       buf << wsChildren;
-      buf << FX_WSTRC(L"</");
+      buf << L"</";
       buf << wsElement;
-      buf << FX_WSTRC(L"\n>");
+      buf << L"\n>";
     }
   }
 }
@@ -340,7 +340,7 @@
   pStream->WriteString(L"<", 1);
   pStream->WriteString(wsElement.c_str(), wsElement.GetLength());
   CFX_WideString wsOutput;
-  SaveAttribute(pNode, XFA_ATTRIBUTE_Name, FX_WSTRC(L"name"), true, wsOutput);
+  SaveAttribute(pNode, XFA_ATTRIBUTE_Name, L"name", true, wsOutput);
   CFX_WideString wsAttrs;
   int32_t iAttrs = 0;
   const uint8_t* pAttrs =
@@ -399,10 +399,10 @@
     RecognizeXFAVersionNumber(
         ToNode(pNode->GetDocument()->GetXFAObject(XFA_HASHCODE_Template)),
         wsVersionNumber);
-    if (wsVersionNumber.IsEmpty()) {
-      wsVersionNumber = FX_WSTRC(L"2.8");
-    }
-    wsVersionNumber += FX_WSTRC(L"/\"\n>");
+    if (wsVersionNumber.IsEmpty())
+      wsVersionNumber = L"2.8";
+
+    wsVersionNumber += L"/\"\n>";
     pStream->WriteString(wsVersionNumber.c_str(), wsVersionNumber.GetLength());
     CXFA_Node* pChildNode = pNode->GetNodeItem(XFA_NODEITEM_FirstChild);
     while (pChildNode) {
diff --git a/xfa/fxfa/parser/cxfa_document.cpp b/xfa/fxfa/parser/cxfa_document.cpp
index 374fb98..adb8eb2 100644
--- a/xfa/fxfa/parser/cxfa_document.cpp
+++ b/xfa/fxfa/parser/cxfa_document.cpp
@@ -105,6 +105,16 @@
   PurgeNodes();
 }
 
+CXFA_LayoutProcessor* CXFA_Document::GetLayoutProcessor() {
+  if (!m_pLayoutProcessor)
+    m_pLayoutProcessor = new CXFA_LayoutProcessor(this);
+  return m_pLayoutProcessor;
+}
+
+CXFA_LayoutProcessor* CXFA_Document::GetDocLayout() {
+  return GetLayoutProcessor();
+}
+
 void CXFA_Document::ClearLayoutData() {
   delete m_pLayoutProcessor;
   m_pLayoutProcessor = nullptr;
@@ -272,8 +282,7 @@
   CXFA_Node* pFormFiller = pPDF->GetChild(0, XFA_Element::Interactive);
   if (pFormFiller) {
     m_dwDocFlags |= XFA_DOCFLAG_HasInteractive;
-    if (pFormFiller->TryContent(wsInteractive) &&
-        wsInteractive == FX_WSTRC(L"1")) {
+    if (pFormFiller->TryContent(wsInteractive) && wsInteractive == L"1") {
       m_dwDocFlags |= XFA_DOCFLAG_Interactive;
       return true;
     }
@@ -381,8 +390,7 @@
         wsURI = CFX_WideStringC(wsUseVal.c_str(), uSharpPos);
         FX_STRSIZE uLen = wsUseVal.GetLength();
         if (uLen >= uSharpPos + 5 &&
-            CFX_WideStringC(wsUseVal.c_str() + uSharpPos, 5) ==
-                FX_WSTRC(L"#som(") &&
+            CFX_WideStringC(wsUseVal.c_str() + uSharpPos, 5) == L"#som(" &&
             wsUseVal[uLen - 1] == ')') {
           wsSOM = CFX_WideStringC(wsUseVal.c_str() + uSharpPos + 5,
                                   uLen - 1 - uSharpPos - 5);
@@ -399,7 +407,7 @@
         wsSOM = CFX_WideStringC(wsUseVal.c_str(), wsUseVal.GetLength());
     }
 
-    if (!wsURI.IsEmpty() && wsURI != FX_WSTRC(L"."))
+    if (!wsURI.IsEmpty() && wsURI != L".")
       continue;
 
     CXFA_Node* pProtoNode = nullptr;
diff --git a/xfa/fxfa/parser/cxfa_image.cpp b/xfa/fxfa/parser/cxfa_image.cpp
index 8061018..8cf7fc1 100644
--- a/xfa/fxfa/parser/cxfa_image.cpp
+++ b/xfa/fxfa/parser/cxfa_image.cpp
@@ -22,7 +22,7 @@
 bool CXFA_Image::GetHref(CFX_WideString& wsHref) {
   if (m_bDefValue)
     return m_pNode->TryCData(XFA_ATTRIBUTE_Href, wsHref);
-  return m_pNode->GetAttribute(FX_WSTRC(L"href"), wsHref);
+  return m_pNode->GetAttribute(L"href", wsHref);
 }
 
 int32_t CXFA_Image::GetTransferEncoding() {
diff --git a/xfa/fxfa/parser/cxfa_layoutitem.cpp b/xfa/fxfa/parser/cxfa_layoutitem.cpp
index 264fe4e..476d611 100644
--- a/xfa/fxfa/parser/cxfa_layoutitem.cpp
+++ b/xfa/fxfa/parser/cxfa_layoutitem.cpp
@@ -9,6 +9,7 @@
 #include "xfa/fxfa/app/xfa_ffnotify.h"
 #include "xfa/fxfa/parser/cxfa_containerlayoutitem.h"
 #include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
+#include "xfa/fxfa/parser/cxfa_measurement.h"
 
 void XFA_ReleaseLayoutItem(CXFA_LayoutItem* pLayoutItem) {
   CXFA_LayoutItem* pNode = pLayoutItem->m_pFirstChild;
@@ -45,7 +46,175 @@
   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_Node* pMarginNode =
+          pLayoutItem->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
+      if (pMarginNode) {
+        sPos += CFX_PointF(pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset)
+                               .ToUnit(XFA_UNIT_Pt),
+                           pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset)
+                               .ToUnit(XFA_UNIT_Pt));
+      }
+      continue;
+    }
+
+    if (pLayoutItem->m_pFormNode->GetElementType() ==
+        XFA_Element::ContentArea) {
+      sPos += CFX_PointF(pLayoutItem->m_pFormNode->GetMeasure(XFA_ATTRIBUTE_X)
+                             .ToUnit(XFA_UNIT_Pt),
+                         pLayoutItem->m_pFormNode->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
index 5991cd6..9c08860 100644
--- a/xfa/fxfa/parser/cxfa_layoutitem.h
+++ b/xfa/fxfa/parser/cxfa_layoutitem.h
@@ -25,15 +25,15 @@
   CXFA_ContentLayoutItem* AsContentLayoutItem();
 
   CXFA_ContainerLayoutItem* GetPage() const;
-  CXFA_Node* GetFormNode() const;
-  void GetRect(CFX_RectF& rtLayout, bool bRelative = false) 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;
-  const CXFA_LayoutItem* GetFirst() const;
+
+  CXFA_LayoutItem* GetParent() const { return m_pParent; }
   CXFA_LayoutItem* GetFirst();
   const CXFA_LayoutItem* GetLast() const;
-  CXFA_LayoutItem* GetLast();
   CXFA_LayoutItem* GetPrev() const;
   CXFA_LayoutItem* GetNext() const;
 
diff --git a/xfa/fxfa/parser/cxfa_layoutpagemgr.cpp b/xfa/fxfa/parser/cxfa_layoutpagemgr.cpp
index 0a057f5..f38ef0e 100644
--- a/xfa/fxfa/parser/cxfa_layoutpagemgr.cpp
+++ b/xfa/fxfa/parser/cxfa_layoutpagemgr.cpp
@@ -63,9 +63,9 @@
   uint32_t dwRelevant = XFA_WidgetStatus_Viewable | XFA_WidgetStatus_Printable;
   CFX_WideStringC wsRelevant;
   if (pFormItem->TryCData(XFA_ATTRIBUTE_Relevant, wsRelevant)) {
-    if (wsRelevant == FX_WSTRC(L"+print") || wsRelevant == FX_WSTRC(L"print"))
+    if (wsRelevant == L"+print" || wsRelevant == L"print")
       dwRelevant &= ~XFA_WidgetStatus_Viewable;
-    else if (wsRelevant == FX_WSTRC(L"-print"))
+    else if (wsRelevant == L"-print")
       dwRelevant &= ~XFA_WidgetStatus_Printable;
   }
 
@@ -140,14 +140,14 @@
   CFX_WideString wsTargetAll(wsTargetExpr);
   wsTargetAll.TrimLeft();
   wsTargetAll.TrimRight();
-  int32_t iSpliteIndex = 0;
+  int32_t iSplitIndex = 0;
   bool bTargetAllFind = true;
-  while (iSpliteIndex != -1) {
+  while (iSplitIndex != -1) {
     CFX_WideString wsExpr;
-    int32_t iSpliteNextIndex = 0;
+    int32_t iSplitNextIndex = 0;
     if (!bTargetAllFind) {
-      iSpliteNextIndex = wsTargetAll.Find(' ', iSpliteIndex);
-      wsExpr = wsTargetAll.Mid(iSpliteIndex, iSpliteNextIndex - iSpliteIndex);
+      iSplitNextIndex = wsTargetAll.Find(' ', iSplitIndex);
+      wsExpr = wsTargetAll.Mid(iSplitIndex, iSplitNextIndex - iSplitIndex);
     } else {
       wsExpr = wsTargetAll;
     }
@@ -163,8 +163,7 @@
         return pNode;
     } else if (bNewExprStyle) {
       CFX_WideString wsProcessedTarget = wsExpr;
-      if (wsExpr.Left(4) == FX_WSTRC(L"som(") &&
-          wsExpr.Right(1) == FX_WSTRC(L")")) {
+      if (wsExpr.Left(4) == L"som(" && wsExpr.Right(1) == L")") {
         wsProcessedTarget = wsExpr.Mid(4, wsExpr.GetLength() - 5);
       }
       XFA_RESOLVENODE_RS rs;
@@ -176,7 +175,7 @@
       if (iCount > 0 && rs.nodes[0]->IsNode())
         return rs.nodes[0]->AsNode();
     }
-    iSpliteIndex = iSpliteNextIndex;
+    iSplitIndex = iSplitNextIndex;
   }
   return nullptr;
 }
@@ -445,8 +444,8 @@
     m_bCreateOverFlowPage = false;
   }
 
-  if (eStatus != XFA_ItemLayoutProcessorResult_Done) {
-    if (eStatus == XFA_ItemLayoutProcessorResult_PageFullBreak &&
+  if (eStatus != XFA_ItemLayoutProcessorResult::Done) {
+    if (eStatus == XFA_ItemLayoutProcessorResult::PageFullBreak &&
         m_CurrentContainerRecordIter == GetTailPosition()) {
       AppendNewPage();
     }
@@ -467,7 +466,7 @@
     return fAvailHeight;
   if (m_CurrentContainerRecordIter == m_ProposedContainerRecords.begin())
     return 0.0f;
-  return XFA_LAYOUT_FLOAT_MAX;
+  return FLT_MAX;
 }
 
 bool XFA_LayoutPageMgr_RunBreakTestScript(CXFA_Node* pTestScript) {
@@ -665,7 +664,7 @@
                      pContentChildLayoutItem->m_pNextSibling) {
               if (CXFA_ContentLayoutItem* pContent =
                       pContentChildLayoutItem->AsContentLayoutItem()) {
-                fUsedHeight += pContent->m_sSize.y;
+                fUsedHeight += pContent->m_sSize.height;
               }
             }
             rgUsedHeights.Add(fUsedHeight);
@@ -1588,11 +1587,6 @@
   m_pPageSetMap.clear();
 }
 
-CXFA_LayoutItem* CXFA_LayoutPageMgr::FindOrCreateLayoutItem(
-    CXFA_Node* pFormNode) {
-  return pFormNode->GetDocument()->GetNotify()->OnCreateLayoutItem(pFormNode);
-}
-
 void CXFA_LayoutPageMgr::SaveLayoutItem(CXFA_LayoutItem* pParentLayoutItem) {
   CXFA_LayoutItem* pNextLayoutItem;
   CXFA_LayoutItem* pCurLayoutItem = pParentLayoutItem->m_pFirstChild;
diff --git a/xfa/fxfa/parser/cxfa_layoutpagemgr.h b/xfa/fxfa/parser/cxfa_layoutpagemgr.h
index 1133e17..3c8e7f9 100644
--- a/xfa/fxfa/parser/cxfa_layoutpagemgr.h
+++ b/xfa/fxfa/parser/cxfa_layoutpagemgr.h
@@ -50,7 +50,6 @@
   bool ProcessBookendLeaderOrTrailer(CXFA_Node* pBookendNode,
                                      bool bLeader,
                                      CXFA_Node*& pBookendAppendNode);
-  CXFA_LayoutItem* FindOrCreateLayoutItem(CXFA_Node* pFormNode);
 
  protected:
   bool AppendNewPage(bool bFirstTemPage = false);
diff --git a/xfa/fxfa/parser/cxfa_layoutprocessor.cpp b/xfa/fxfa/parser/cxfa_layoutprocessor.cpp
index ea1064a..e179d38 100644
--- a/xfa/fxfa/parser/cxfa_layoutprocessor.cpp
+++ b/xfa/fxfa/parser/cxfa_layoutprocessor.cpp
@@ -17,18 +17,6 @@
 #include "xfa/fxfa/parser/xfa_object.h"
 #include "xfa/fxfa/parser/xfa_utils.h"
 
-CXFA_LayoutProcessor* CXFA_Document::GetLayoutProcessor() {
-  if (!m_pLayoutProcessor) {
-    m_pLayoutProcessor = new CXFA_LayoutProcessor(this);
-    ASSERT(m_pLayoutProcessor);
-  }
-  return m_pLayoutProcessor;
-}
-
-CXFA_LayoutProcessor* CXFA_Document::GetDocLayout() {
-  return GetLayoutProcessor();
-}
-
 CXFA_LayoutProcessor::CXFA_LayoutProcessor(CXFA_Document* pDocument)
     : m_pDocument(pDocument),
       m_nProgressCounter(0),
@@ -80,9 +68,9 @@
   FX_FLOAT fPosY = pFormNode->GetMeasure(XFA_ATTRIBUTE_Y).ToUnit(XFA_UNIT_Pt);
   do {
     FX_FLOAT fAvailHeight = m_pLayoutPageMgr->GetAvailHeight();
-    eStatus =
-        m_pRootItemLayoutProcessor->DoLayout(true, fAvailHeight, fAvailHeight);
-    if (eStatus != XFA_ItemLayoutProcessorResult_Done)
+    eStatus = m_pRootItemLayoutProcessor->DoLayout(true, fAvailHeight,
+                                                   fAvailHeight, nullptr);
+    if (eStatus != XFA_ItemLayoutProcessorResult::Done)
       m_nProgressCounter++;
 
     CXFA_ContentLayoutItem* pLayoutItem =
@@ -91,16 +79,16 @@
       pLayoutItem->m_sPos = CFX_PointF(fPosX, fPosY);
 
     m_pLayoutPageMgr->SubmitContentItem(pLayoutItem, eStatus);
-  } while (eStatus != XFA_ItemLayoutProcessorResult_Done &&
+  } while (eStatus != XFA_ItemLayoutProcessorResult::Done &&
            (!pPause || !pPause->NeedToPauseNow()));
 
-  if (eStatus == XFA_ItemLayoutProcessorResult_Done) {
+  if (eStatus == XFA_ItemLayoutProcessorResult::Done) {
     m_pLayoutPageMgr->FinishPaginatedPageSets();
     m_pLayoutPageMgr->SyncLayoutData();
     m_bNeeLayout = false;
     m_rgChangedContainers.RemoveAll();
   }
-  return 100 * (eStatus == XFA_ItemLayoutProcessorResult_Done
+  return 100 * (eStatus == XFA_ItemLayoutProcessorResult::Done
                     ? m_nProgressCounter
                     : m_nProgressCounter - 1) /
          m_nProgressCounter;
diff --git a/xfa/fxfa/parser/cxfa_line.cpp b/xfa/fxfa/parser/cxfa_line.cpp
index f0d9a0b..38de0d8 100644
--- a/xfa/fxfa/parser/cxfa_line.cpp
+++ b/xfa/fxfa/parser/cxfa_line.cpp
@@ -12,9 +12,8 @@
   return m_pNode->GetEnum(XFA_ATTRIBUTE_Hand);
 }
 
-bool CXFA_Line::GetSlop() {
-  XFA_ATTRIBUTEENUM eSlop = m_pNode->GetEnum(XFA_ATTRIBUTE_Slope);
-  return eSlop == XFA_ATTRIBUTEENUM_Slash;
+bool CXFA_Line::GetSlope() {
+  return m_pNode->GetEnum(XFA_ATTRIBUTE_Slope) == XFA_ATTRIBUTEENUM_Slash;
 }
 
 CXFA_Edge CXFA_Line::GetEdge() {
diff --git a/xfa/fxfa/parser/cxfa_line.h b/xfa/fxfa/parser/cxfa_line.h
index bf18029..f014cc0 100644
--- a/xfa/fxfa/parser/cxfa_line.h
+++ b/xfa/fxfa/parser/cxfa_line.h
@@ -18,7 +18,7 @@
   explicit CXFA_Line(CXFA_Node* pNode) : CXFA_Data(pNode) {}
 
   int32_t GetHand();
-  bool GetSlop();
+  bool GetSlope();
   CXFA_Edge GetEdge();
 };
 
diff --git a/xfa/fxfa/parser/cxfa_measurement.cpp b/xfa/fxfa/parser/cxfa_measurement.cpp
index b1843a8..ebf7b7b 100644
--- a/xfa/fxfa/parser/cxfa_measurement.cpp
+++ b/xfa/fxfa/parser/cxfa_measurement.cpp
@@ -119,21 +119,21 @@
 }
 
 XFA_UNIT CXFA_Measurement::GetUnit(const CFX_WideStringC& wsUnit) {
-  if (wsUnit == FX_WSTRC(L"mm"))
+  if (wsUnit == L"mm")
     return XFA_UNIT_Mm;
-  if (wsUnit == FX_WSTRC(L"pt"))
+  if (wsUnit == L"pt")
     return XFA_UNIT_Pt;
-  if (wsUnit == FX_WSTRC(L"in"))
+  if (wsUnit == L"in")
     return XFA_UNIT_In;
-  if (wsUnit == FX_WSTRC(L"cm"))
+  if (wsUnit == L"cm")
     return XFA_UNIT_Cm;
-  if (wsUnit == FX_WSTRC(L"pc"))
+  if (wsUnit == L"pc")
     return XFA_UNIT_Pc;
-  if (wsUnit == FX_WSTRC(L"mp"))
+  if (wsUnit == L"mp")
     return XFA_UNIT_Mp;
-  if (wsUnit == FX_WSTRC(L"em"))
+  if (wsUnit == L"em")
     return XFA_UNIT_Em;
-  if (wsUnit == FX_WSTRC(L"%"))
+  if (wsUnit == L"%")
     return XFA_UNIT_Percent;
   return XFA_UNIT_Unknown;
 }
diff --git a/xfa/fxfa/parser/cxfa_node.cpp b/xfa/fxfa/parser/cxfa_node.cpp
index bc2a10c..1e50896 100644
--- a/xfa/fxfa/parser/cxfa_node.cpp
+++ b/xfa/fxfa/parser/cxfa_node.cpp
@@ -511,7 +511,7 @@
     pNode = pNext;
   }
   if (m_pXMLNode && IsOwnXMLNode())
-    m_pXMLNode->Release();
+    delete m_pXMLNode;
 }
 
 CXFA_Node* CXFA_Node::Clone(bool bRecursive) {
@@ -1097,7 +1097,7 @@
   uint32_t dwFlag = XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_ALL;
   CFX_WideString wsName;
   GetAttribute(XFA_ATTRIBUTE_Name, wsName);
-  CFX_WideString wsExpression = wsName + FX_WSTRC(L"[*]");
+  CFX_WideString wsExpression = wsName + L"[*]";
   Script_Som_ResolveNodeList(pValue, wsExpression, dwFlag);
 }
 
@@ -1109,8 +1109,7 @@
     return;
   if (bSetting) {
     CFX_WideString wsMessage = L"Unable to set ";
-    FXJSE_ThrowMessage(
-        FX_UTF8Encode(wsMessage.c_str(), wsMessage.GetLength()).AsStringC());
+    FXJSE_ThrowMessage(wsMessage.UTF8Encode().AsStringC());
   } else {
     CXFA_AttachNodeList* pNodeList = new CXFA_AttachNodeList(m_pDocument, this);
     pValue->SetObject(pNodeList, pScriptContext->GetJseNormalClass());
@@ -1124,10 +1123,8 @@
     ThrowInvalidPropertyException();
     return;
   }
-
   uint32_t dwFlag = XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_ALL;
-  CFX_WideString wsExpression =
-      FX_WSTRC(L"#") + GetClassName() + FX_WSTRC(L"[*]");
+  CFX_WideString wsExpression = L"#" + GetClassName() + L"[*]";
   Script_Som_ResolveNodeList(pValue, wsExpression, dwFlag);
 }
 
@@ -1175,7 +1172,7 @@
   }
   CFX_WideString wsSOMExpression;
   GetSOMExpression(wsSOMExpression);
-  pValue->SetString(FX_UTF8Encode(wsSOMExpression).AsStringC());
+  pValue->SetString(wsSOMExpression.UTF8Encode().AsStringC());
 }
 
 void CXFA_Node::Script_NodeClass_ApplyXSL(CFXJSE_Arguments* pArguments) {
@@ -1239,7 +1236,7 @@
   GetAttribute(wsExpression.AsStringC(), wsValue);
   CFXJSE_Value* pValue = pArguments->GetReturnValue();
   if (pValue)
-    pValue->SetString(FX_UTF8Encode(wsValue).AsStringC());
+    pValue->SetString(wsValue.UTF8Encode().AsStringC());
 }
 
 void CXFA_Node::Script_NodeClass_GetElement(CFXJSE_Arguments* pArguments) {
@@ -1406,10 +1403,8 @@
     }
     pFakeRoot->SetFlag(XFA_NodeFlag_HasRemovedChildren, false);
   } else {
-    if (pFakeXMLRoot) {
-      pFakeXMLRoot->Release();
-      pFakeXMLRoot = nullptr;
-    }
+    delete pFakeXMLRoot;
+    pFakeXMLRoot = nullptr;
   }
 }
 
@@ -1511,7 +1506,7 @@
 
   CFX_WideString wsNameSpace;
   TryNamespace(wsNameSpace);
-  pValue->SetString(FX_UTF8Encode(wsNameSpace).AsStringC());
+  pValue->SetString(wsNameSpace.UTF8Encode().AsStringC());
 }
 
 void CXFA_Node::Script_NodeClass_Model(CFXJSE_Value* pValue,
@@ -1861,8 +1856,7 @@
   } else {
     CFX_WideString wsValue;
     GetAttribute(eAttribute, wsValue);
-    pValue->SetString(
-        FX_UTF8Encode(wsValue.c_str(), wsValue.GetLength()).AsStringC());
+    pValue->SetString(wsValue.UTF8Encode().AsStringC());
   }
 }
 
@@ -1876,8 +1870,7 @@
 
   CFX_WideString wsValue;
   GetAttribute(eAttribute, wsValue);
-  pValue->SetString(
-      FX_UTF8Encode(wsValue.c_str(), wsValue.GetLength()).AsStringC());
+  pValue->SetString(wsValue.UTF8Encode().AsStringC());
 }
 
 void CXFA_Node::Script_WsdlConnection_Execute(CFXJSE_Arguments* pArguments) {
@@ -1955,7 +1948,7 @@
       default:
         break;
     }
-    pValue->SetString(FX_UTF8Encode(wsMessage).AsStringC());
+    pValue->SetString(wsMessage.UTF8Encode().AsStringC());
   }
 }
 
@@ -2041,8 +2034,7 @@
       CFX_Decimal decimal(content.AsStringC());
       pValue->SetFloat((FX_FLOAT)(double)decimal);
     } else {
-      pValue->SetString(
-          FX_UTF8Encode(content.c_str(), content.GetLength()).AsStringC());
+      pValue->SetString(content.UTF8Encode().AsStringC());
     }
   }
 }
@@ -2060,8 +2052,7 @@
     pValue->SetNull();
     return;
   }
-  pValue->SetString(
-      FX_UTF8Encode(content.c_str(), content.GetLength()).AsStringC());
+  pValue->SetString(content.UTF8Encode().AsStringC());
 }
 
 void CXFA_Node::Script_Boolean_Value(CFXJSE_Value* pValue,
@@ -2082,7 +2073,7 @@
     SetScriptContent(wsNewValue, wsFormatValue, true, true);
   } else {
     CFX_WideString wsValue = GetScriptContent(true);
-    pValue->SetBoolean(wsValue == FX_WSTRC(L"1"));
+    pValue->SetBoolean(wsValue == L"1");
   }
 }
 
@@ -2112,7 +2103,7 @@
     ArgbDecode(color, a, r, g, b);
     CFX_WideString strColor;
     strColor.Format(L"%d,%d,%d", r, g, b);
-    pValue->SetString(FX_UTF8Encode(strColor).AsStringC());
+    pValue->SetString(strColor.UTF8Encode().AsStringC());
   }
 }
 
@@ -2137,7 +2128,7 @@
     CXFA_Edge edge = border.GetEdge(0);
     CXFA_Measurement thickness = edge.GetMSThickness();
     thickness.ToString(wsThickness);
-    pValue->SetString(FX_UTF8Encode(wsThickness).AsStringC());
+    pValue->SetString(wsThickness.UTF8Encode().AsStringC());
   }
 }
 
@@ -2170,7 +2161,7 @@
     ArgbDecode(color, a, r, g, b);
     CFX_WideString wsColor;
     wsColor.Format(L"%d,%d,%d", r, g, b);
-    pValue->SetString(FX_UTF8Encode(wsColor).AsStringC());
+    pValue->SetString(wsColor.UTF8Encode().AsStringC());
   }
 }
 
@@ -2207,12 +2198,10 @@
     }
   } else {
     CFX_WideString content = GetScriptContent(true);
-    if (content.IsEmpty()) {
+    if (content.IsEmpty())
       pValue->SetNull();
-    } else {
-      pValue->SetString(
-          FX_UTF8Encode(content.c_str(), content.GetLength()).AsStringC());
-    }
+    else
+      pValue->SetString(content.UTF8Encode().AsStringC());
   }
 }
 
@@ -2261,8 +2250,7 @@
       if (pNode && pNode->GetElementType() == XFA_Element::Decimal) {
         if (pUIChild->GetElementType() == XFA_Element::NumericEdit &&
             (pNode->GetInteger(XFA_ATTRIBUTE_FracDigits) == -1)) {
-          pValue->SetString(
-              FX_UTF8Encode(content.c_str(), content.GetLength()).AsStringC());
+          pValue->SetString(content.UTF8Encode().AsStringC());
         } else {
           CFX_Decimal decimal(content.AsStringC());
           pValue->SetFloat((FX_FLOAT)(double)decimal);
@@ -2275,8 +2263,7 @@
         CFX_Decimal decimal(content.AsStringC());
         pValue->SetFloat((FX_FLOAT)(double)decimal);
       } else {
-        pValue->SetString(
-            FX_UTF8Encode(content.c_str(), content.GetLength()).AsStringC());
+        pValue->SetString(content.UTF8Encode().AsStringC());
       }
     }
   }
@@ -2294,7 +2281,7 @@
   } else {
     CFX_WideString wsValue;
     pWidgetData->GetValue(wsValue, XFA_VALUEPICTURE_Edit);
-    pValue->SetString(FX_UTF8Encode(wsValue).AsStringC());
+    pValue->SetString(wsValue.UTF8Encode().AsStringC());
   }
 }
 
@@ -2326,7 +2313,7 @@
     ArgbDecode(color, a, r, g, b);
     CFX_WideString wsColor;
     wsColor.Format(L"%d,%d,%d", r, g, b);
-    pValue->SetString(FX_UTF8Encode(wsColor).AsStringC());
+    pValue->SetString(wsColor.UTF8Encode().AsStringC());
   }
 }
 
@@ -2348,7 +2335,7 @@
   } else {
     CFX_WideString wsValue;
     pWidgetData->GetValue(wsValue, XFA_VALUEPICTURE_Display);
-    pValue->SetString(FX_UTF8Encode(wsValue).AsStringC());
+    pValue->SetString(wsValue.UTF8Encode().AsStringC());
   }
 }
 
@@ -2369,7 +2356,7 @@
     CFX_WideString wsValue;
     if (pInfo)
       wsValue = pInfo->pName;
-    pValue->SetString(FX_UTF8Encode(wsValue).AsStringC());
+    pValue->SetString(wsValue.UTF8Encode().AsStringC());
   }
 }
 
@@ -2480,13 +2467,11 @@
     return;
   }
   CFX_WideString wsValue;
-  bool bHasItem = pWidgetData->GetChoiceListItem(wsValue, iIndex, true);
-  if (bHasItem) {
-    pArguments->GetReturnValue()->SetString(
-        FX_UTF8Encode(wsValue.c_str(), wsValue.GetLength()).AsStringC());
-  } else {
+  if (!pWidgetData->GetChoiceListItem(wsValue, iIndex, true)) {
     pArguments->GetReturnValue()->SetNull();
+    return;
   }
+  pArguments->GetReturnValue()->SetString(wsValue.UTF8Encode().AsStringC());
 }
 
 void CXFA_Node::Script_Field_BoundItem(CFXJSE_Arguments* pArguments) {
@@ -2505,7 +2490,7 @@
   pWidgetData->GetItemValue(wsValue.AsStringC(), wsBoundValue);
   CFXJSE_Value* pValue = pArguments->GetReturnValue();
   if (pValue)
-    pValue->SetString(FX_UTF8Encode(wsBoundValue).AsStringC());
+    pValue->SetString(wsBoundValue.UTF8Encode().AsStringC());
 }
 
 void CXFA_Node::Script_Field_GetItemState(CFXJSE_Arguments* pArguments) {
@@ -2557,13 +2542,11 @@
     return;
   }
   CFX_WideString wsValue;
-  bool bHasItem = pWidgetData->GetChoiceListItem(wsValue, iIndex, false);
-  if (bHasItem) {
-    pArguments->GetReturnValue()->SetString(
-        FX_UTF8Encode(wsValue.c_str(), wsValue.GetLength()).AsStringC());
-  } else {
+  if (!pWidgetData->GetChoiceListItem(wsValue, iIndex, false)) {
     pArguments->GetReturnValue()->SetNull();
+    return;
   }
+  pArguments->GetReturnValue()->SetString(wsValue.UTF8Encode().AsStringC());
 }
 
 void CXFA_Node::Script_Field_SetItemState(CFXJSE_Arguments* pArguments) {
@@ -2649,7 +2632,7 @@
     if (wsValue.IsEmpty() && curVersion >= XFA_VERSION_300) {
       pValue->SetNull();
     } else {
-      pValue->SetString(FX_UTF8Encode(wsValue).AsStringC());
+      pValue->SetString(wsValue.UTF8Encode().AsStringC());
     }
   }
 }
@@ -2817,9 +2800,7 @@
   } else {
     CFX_WideString wsLocaleName;
     GetLocaleName(wsLocaleName);
-    pValue->SetString(
-        FX_UTF8Encode(wsLocaleName.c_str(), wsLocaleName.GetLength())
-            .AsStringC());
+    pValue->SetString(wsLocaleName.UTF8Encode().AsStringC());
   }
 }
 
@@ -3418,11 +3399,9 @@
     SetAttribute(XFA_ATTRIBUTE_Checksum, pValue->ToWideString().AsStringC());
     return;
   }
-
   CFX_WideString wsChecksum;
   GetAttribute(XFA_ATTRIBUTE_Checksum, wsChecksum, false);
-  pValue->SetString(
-      FX_UTF8Encode(wsChecksum.c_str(), wsChecksum.GetLength()).AsStringC());
+  pValue->SetString(wsChecksum.UTF8Encode().AsStringC());
 }
 
 void CXFA_Node::Script_Packet_GetAttribute(CFXJSE_Arguments* pArguments) {
@@ -3430,7 +3409,6 @@
     ThrowParamCountMismatchException(L"getAttribute");
     return;
   }
-
   CFX_ByteString bsAttributeName = pArguments->GetUTF8String(0);
   CFX_WideString wsAttributeValue;
   CFDE_XMLNode* pXMLNode = GetXMLMappingNode();
@@ -3440,8 +3418,7 @@
         wsAttributeValue);
   }
   pArguments->GetReturnValue()->SetString(
-      FX_UTF8Encode(wsAttributeValue.c_str(), wsAttributeValue.GetLength())
-          .AsStringC());
+      wsAttributeValue.UTF8Encode().AsStringC());
 }
 
 void CXFA_Node::Script_Packet_SetAttribute(CFXJSE_Arguments* pArguments) {
@@ -3449,7 +3426,6 @@
     ThrowParamCountMismatchException(L"setAttribute");
     return;
   }
-
   CFX_ByteString bsValue = pArguments->GetUTF8String(0);
   CFX_ByteString bsName = pArguments->GetUTF8String(1);
   CFDE_XMLNode* pXMLNode = GetXMLMappingNode();
@@ -3495,8 +3471,7 @@
       CFDE_XMLElement* pXMLElement = static_cast<CFDE_XMLElement*>(pXMLNode);
       pXMLElement->GetTextData(wsTextData);
     }
-    pValue->SetString(
-        FX_UTF8Encode(wsTextData.c_str(), wsTextData.GetLength()).AsStringC());
+    pValue->SetString(wsTextData.UTF8Encode().AsStringC());
   }
 }
 
@@ -3618,7 +3593,7 @@
     ThrowInvalidPropertyException();
     return;
   }
-  pValue->SetString(FX_UTF8Encode(FX_WSTRC(L"0")).AsStringC());
+  pValue->SetString(FX_UTF8Encode(CFX_WideStringC(L"0", 1)).AsStringC());
 }
 
 void CXFA_Node::Script_Encrypt_Format(CFXJSE_Value* pValue,
@@ -3654,7 +3629,7 @@
     case XFA_ATTRIBUTETYPE_Cdata:
       return SetCData(pAttr->eName, CFX_WideString(wsValue), bNotify);
     case XFA_ATTRIBUTETYPE_Boolean:
-      return SetBoolean(pAttr->eName, wsValue != FX_WSTRC(L"0"), bNotify);
+      return SetBoolean(pAttr->eName, wsValue != L"0", bNotify);
     case XFA_ATTRIBUTETYPE_Integer:
       return SetInteger(pAttr->eName,
                         FXSYS_round(FXSYS_wcstof(wsValue.c_str(),
@@ -3703,7 +3678,7 @@
       if (!TryBoolean(pAttr->eName, bValue, bUseDefault)) {
         return false;
       }
-      wsValue = bValue ? FX_WSTRC(L"1") : FX_WSTRC(L"0");
+      wsValue = bValue ? L"1" : L"0";
       return true;
     } break;
     case XFA_ATTRIBUTETYPE_Integer: {
@@ -3894,7 +3869,7 @@
     ASSERT(m_pXMLNode->GetType() == FDE_XMLNODE_Element);
     CFX_WideString wsAttrName = pInfo->pName;
     if (pInfo->eName == XFA_ATTRIBUTE_ContentType) {
-      wsAttrName = FX_WSTRC(L"xfa:") + wsAttrName;
+      wsAttrName = L"xfa:" + wsAttrName;
     }
     static_cast<CFDE_XMLElement*>(m_pXMLNode)->SetString(wsAttrName, wsValue);
   }
@@ -4200,16 +4175,16 @@
       CFX_WideString wsContentType;
       if (GetElementType() == XFA_Element::ExData) {
         GetAttribute(XFA_ATTRIBUTE_ContentType, wsContentType, false);
-        if (wsContentType == FX_WSTRC(L"text/html")) {
-          wsContentType = FX_WSTRC(L"");
+        if (wsContentType == L"text/html") {
+          wsContentType = L"";
           SetAttribute(XFA_ATTRIBUTE_ContentType, wsContentType.AsStringC());
         }
       }
       CXFA_Node* pContentRawDataNode = GetNodeItem(XFA_NODEITEM_FirstChild);
       if (!pContentRawDataNode) {
         pContentRawDataNode = CreateSamePacketNode(
-            (wsContentType == FX_WSTRC(L"text/xml")) ? XFA_Element::Sharpxml
-                                                     : XFA_Element::Sharptext);
+            (wsContentType == L"text/xml") ? XFA_Element::Sharpxml
+                                           : XFA_Element::Sharptext);
         InsertChild(pContentRawDataNode);
       }
       return pContentRawDataNode->SetScriptContent(
@@ -4293,8 +4268,7 @@
         }
         CXFA_Node* pChildValue = pValue->GetNodeItem(XFA_NODEITEM_FirstChild);
         if (pChildValue && XFA_FieldIsMultiListBox(this)) {
-          pChildValue->SetAttribute(XFA_ATTRIBUTE_ContentType,
-                                    FX_WSTRC(L"text/xml"));
+          pChildValue->SetAttribute(XFA_ATTRIBUTE_ContentType, L"text/xml");
         }
         return pChildValue
                    ? pChildValue->TryContent(wsContent, bScriptModify, bProto)
@@ -4308,9 +4282,9 @@
         if (GetElementType() == XFA_Element::ExData) {
           CFX_WideString wsContentType;
           GetAttribute(XFA_ATTRIBUTE_ContentType, wsContentType, false);
-          if (wsContentType == FX_WSTRC(L"text/html")) {
+          if (wsContentType == L"text/html") {
             element = XFA_Element::SharpxHTML;
-          } else if (wsContentType == FX_WSTRC(L"text/xml")) {
+          } else if (wsContentType == L"text/xml") {
             element = XFA_Element::Sharpxml;
           }
         }
diff --git a/xfa/fxfa/parser/cxfa_nodehelper.cpp b/xfa/fxfa/parser/cxfa_nodehelper.cpp
index 18a9594..2290892 100644
--- a/xfa/fxfa/parser/cxfa_nodehelper.cpp
+++ b/xfa/fxfa/parser/cxfa_nodehelper.cpp
@@ -330,7 +330,7 @@
       }
     }
     if (bAll) {
-      wsIndex = FX_WSTRC(L"1");
+      wsIndex = L"1";
       m_iCreateFlag = XFA_RESOLVENODE_RSTYPE_CreateNodeAll;
     } else {
       m_iCreateFlag = XFA_RESOLVENODE_RSTYPE_CreateNodeOne;
diff --git a/xfa/fxfa/parser/cxfa_object.cpp b/xfa/fxfa/parser/cxfa_object.cpp
index 45e3442..c8cd354 100644
--- a/xfa/fxfa/parser/cxfa_object.cpp
+++ b/xfa/fxfa/parser/cxfa_object.cpp
@@ -42,9 +42,7 @@
     ThrowInvalidPropertyException();
     return;
   }
-  CFX_WideStringC className = GetClassName();
-  pValue->SetString(
-      FX_UTF8Encode(className.c_str(), className.GetLength()).AsStringC());
+  pValue->SetString(FX_UTF8Encode(GetClassName()).AsStringC());
 }
 
 void CXFA_Object::ThrowInvalidPropertyException() const {
@@ -71,6 +69,5 @@
   va_start(arg_ptr, str);
   wsMessage.FormatV(str, arg_ptr);
   va_end(arg_ptr);
-  FXJSE_ThrowMessage(
-      FX_UTF8Encode(wsMessage.c_str(), wsMessage.GetLength()).AsStringC());
+  FXJSE_ThrowMessage(wsMessage.UTF8Encode().AsStringC());
 }
diff --git a/xfa/fxfa/parser/cxfa_resolveprocessor.cpp b/xfa/fxfa/parser/cxfa_resolveprocessor.cpp
index 271e14b..3ef4e97 100644
--- a/xfa/fxfa/parser/cxfa_resolveprocessor.cpp
+++ b/xfa/fxfa/parser/cxfa_resolveprocessor.cpp
@@ -497,7 +497,8 @@
   nodes.Append((CXFA_ObjArray&)array);
   return nodes.GetSize();
 }
-int32_t CXFA_ResolveProcessor::ResolvePopStack(CFX_Int32Array& stack) {
+int32_t CXFA_ResolveProcessor::ResolvePopStack(
+    CFX_ArrayTemplate<int32_t>& stack) {
   int32_t nType = -1;
   int32_t iSize = stack.GetSize() - 1;
   if (iSize > -1) {
@@ -520,7 +521,7 @@
   FX_WCHAR* pConditionBuf = wsCondition.GetBuffer(iLength - nStart);
   int32_t nNameCount = 0;
   int32_t nConditionCount = 0;
-  CFX_Int32Array stack;
+  CFX_ArrayTemplate<int32_t> stack;
   int32_t nType = -1;
   const FX_WCHAR* pSrc = wsExpression.c_str();
   FX_WCHAR wPrev = 0, wCur;
@@ -680,11 +681,9 @@
   ASSERT(iFoundCount == findNodes.GetSize());
   CFX_WideString wsExpression;
   XFA_SCRIPTLANGTYPE eLangType = XFA_SCRIPTLANGTYPE_Unkown;
-  if (wsCondition.Left(2) == FX_WSTRC(L".[") &&
-      wsCondition.Right(1) == FX_WSTRC(L"]")) {
+  if (wsCondition.Left(2) == L".[" && wsCondition.Right(1) == L"]") {
     eLangType = XFA_SCRIPTLANGTYPE_Formcalc;
-  } else if (wsCondition.Left(2) == FX_WSTRC(L".(") &&
-             wsCondition.Right(1) == FX_WSTRC(L")")) {
+  } else if (wsCondition.Left(2) == L".(" && wsCondition.Right(1) == L")") {
     eLangType = XFA_SCRIPTLANGTYPE_Javascript;
   } else {
     return;
diff --git a/xfa/fxfa/parser/cxfa_resolveprocessor.h b/xfa/fxfa/parser/cxfa_resolveprocessor.h
index 2590021..d806d57 100644
--- a/xfa/fxfa/parser/cxfa_resolveprocessor.h
+++ b/xfa/fxfa/parser/cxfa_resolveprocessor.h
@@ -60,7 +60,7 @@
   int32_t ResolveNumberSign(CXFA_ResolveNodesData& rnd);
   int32_t ResolveAsterisk(CXFA_ResolveNodesData& rnd);
   int32_t ResolveNormal(CXFA_ResolveNodesData& rnd);
-  int32_t ResolvePopStack(CFX_Int32Array& stack);
+  int32_t ResolvePopStack(CFX_ArrayTemplate<int32_t>& stack);
   void SetStylesForChild(uint32_t dwParentStyles, CXFA_ResolveNodesData& rnd);
 
   void ConditionArray(int32_t iCurIndex,
diff --git a/xfa/fxfa/parser/cxfa_script.cpp b/xfa/fxfa/parser/cxfa_script.cpp
index 42911e0..16f65f9 100644
--- a/xfa/fxfa/parser/cxfa_script.cpp
+++ b/xfa/fxfa/parser/cxfa_script.cpp
@@ -13,9 +13,9 @@
 XFA_SCRIPTTYPE CXFA_Script::GetContentType() {
   CFX_WideStringC cData;
   if (m_pNode->TryCData(XFA_ATTRIBUTE_ContentType, cData, false)) {
-    if (cData == FX_WSTRC(L"application/x-javascript"))
+    if (cData == L"application/x-javascript")
       return XFA_SCRIPTTYPE_Javascript;
-    if (cData == FX_WSTRC(L"application/x-formcalc"))
+    if (cData == L"application/x-formcalc")
       return XFA_SCRIPTTYPE_Formcalc;
     return XFA_SCRIPTTYPE_Unkown;
   }
diff --git a/xfa/fxfa/parser/cxfa_scriptcontext.cpp b/xfa/fxfa/parser/cxfa_scriptcontext.cpp
index 44ae9a4..584cd76 100644
--- a/xfa/fxfa/parser/cxfa_scriptcontext.cpp
+++ b/xfa/fxfa/parser/cxfa_scriptcontext.cpp
@@ -161,10 +161,9 @@
       hRetValue->SetUndefined();
       return false;
     }
-    btScript =
-        FX_UTF8Encode(wsJavaScript.GetBuffer(), wsJavaScript.GetLength());
+    btScript = FX_UTF8Encode(wsJavaScript.AsStringC());
   } else {
-    btScript = FX_UTF8Encode(wsScript.c_str(), wsScript.GetLength());
+    btScript = FX_UTF8Encode(wsScript);
   }
   CXFA_Object* pOriginalObject = m_pThisObject;
   m_pThisObject = pThisObject;
@@ -293,7 +292,7 @@
   CXFA_ScriptContext* lpScriptContext =
       pOriginalObject->GetDocument()->GetScriptContext();
   CXFA_Object* pObject = lpScriptContext->GetVariablesThis(pOriginalObject);
-  if (wsPropName == FX_WSTRC(L"xfa")) {
+  if (wsPropName == L"xfa") {
     CFXJSE_Value* pValue = lpScriptContext->GetJSValueFromMap(
         lpScriptContext->GetDocument()->GetRoot());
     pReturnValue->Assign(pValue);
@@ -491,8 +490,7 @@
   if (!pTextNode->TryCData(XFA_ATTRIBUTE_Value, wsScript))
     return false;
 
-  CFX_ByteString btScript =
-      FX_UTF8Encode(wsScript.c_str(), wsScript.GetLength());
+  CFX_ByteString btScript = FX_UTF8Encode(wsScript);
   std::unique_ptr<CFXJSE_Value> hRetValue(new CFXJSE_Value(m_pIsolate));
   CXFA_Node* pThisObject = pParent->GetNodeItem(XFA_NODEITEM_Parent);
   CFXJSE_Context* pVariablesContext =
diff --git a/xfa/fxfa/parser/cxfa_simple_parser.cpp b/xfa/fxfa/parser/cxfa_simple_parser.cpp
index 9f6fef9..4a6956d 100644
--- a/xfa/fxfa/parser/cxfa_simple_parser.cpp
+++ b/xfa/fxfa/parser/cxfa_simple_parser.cpp
@@ -102,8 +102,8 @@
     wsNSPrefix = wsAttrName.Left(wsAttributeName.GetLength() -
                                  wsLocalAttrName.GetLength() - 1);
   }
-  if (wsLocalAttrName == FX_WSTRC(L"xmlns") ||
-      wsNSPrefix == FX_WSTRC(L"xmlns") || wsNSPrefix == FX_WSTRC(L"xml")) {
+  if (wsLocalAttrName == L"xmlns" || wsNSPrefix == L"xmlns" ||
+      wsNSPrefix == L"xml") {
     return false;
   }
   if (!XFA_FDEExtension_ResolveNamespaceQualifier(
@@ -202,7 +202,7 @@
       case FDE_XMLNODE_Element: {
         CFX_WideString wsTextData;
         static_cast<CFDE_XMLElement*>(pXMLChild)->GetTextData(wsTextData);
-        wsTextData += FX_WSTRC(L"\n");
+        wsTextData += L"\n";
         wsOutput += wsTextData;
         break;
       }
@@ -257,7 +257,7 @@
   if (pRichTextXMLNode) {
     CFX_WideString wsNamespaceURI;
     GetElementTagNamespaceURI(pRichTextXMLNode, wsNamespaceURI);
-    if (wsNamespaceURI == FX_WSTRC(L"http://www.w3.org/1999/xhtml"))
+    if (wsNamespaceURI == L"http://www.w3.org/1999/xhtml")
       return true;
   }
   return false;
@@ -415,10 +415,10 @@
   CFX_WideString wsNSAttribute;
   bool bRet = false;
   if (wsQualifier.IsEmpty()) {
-    wsNSAttribute = FX_WSTRC(L"xmlns");
+    wsNSAttribute = L"xmlns";
     bRet = true;
   } else {
-    wsNSAttribute = FX_WSTRC(L"xmlns:") + wsQualifier;
+    wsNSAttribute = L"xmlns:" + wsQualifier;
   }
   for (; pNode != pFakeRoot; pNode = static_cast<CFDE_XMLElement*>(
                                  pNode->GetNodeItem(CFDE_XMLNode::Parent))) {
@@ -482,9 +482,9 @@
     for (int32_t i = 0; i < iAttributeCount; i++) {
       CFX_WideString wsAttriName, wsAttriValue;
       pElement->GetAttribute(i, wsAttriName, wsAttriValue);
-      if (wsAttriName == FX_WSTRC(L"uuid"))
+      if (wsAttriName == L"uuid")
         pXFARootNode->SetCData(XFA_ATTRIBUTE_Uuid, wsAttriValue);
-      else if (wsAttriName == FX_WSTRC(L"timeStamp"))
+      else if (wsAttriName == L"timeStamp")
         pXFARootNode->SetCData(XFA_ATTRIBUTE_TimeStamp, wsAttriValue);
     }
   }
@@ -720,7 +720,7 @@
   }
 
   CFDE_XMLNode* pDataXMLNode = nullptr;
-  if (MatchNodeName(pXMLDocumentNode, FX_WSTRC(L"data"),
+  if (MatchNodeName(pXMLDocumentNode, L"data",
                     XFA_GetPacketByIndex(XFA_PACKET_Datasets)->pURI,
                     XFA_GetPacketByIndex(XFA_PACKET_Datasets)->eFlags)) {
     static_cast<CFDE_XMLElement*>(pXMLDocumentNode)
@@ -747,7 +747,7 @@
         m_pFactory->CreateNode(XFA_XDPPACKET_Datasets, XFA_Element::DataGroup);
     if (!pNode) {
       if (pDataXMLNode != pXMLDocumentNode)
-        pDataXMLNode->Release();
+        delete pDataXMLNode;
       return nullptr;
     }
     CFX_WideString wsLocalName;
@@ -910,8 +910,7 @@
           CFX_WideString wsAttrValue;
           pXMLElement->GetAttribute(i, wsAttrQualifiedName, wsAttrValue);
           GetAttributeLocalName(wsAttrQualifiedName.AsStringC(), wsAttrName);
-          if (wsAttrName == FX_WSTRC(L"nil") &&
-              wsAttrValue == FX_WSTRC(L"true")) {
+          if (wsAttrName == L"nil" && wsAttrValue == L"true") {
             IsNeedValue = false;
           }
           const XFA_ATTRIBUTEINFO* lpAttrInfo =
@@ -965,9 +964,9 @@
   if (pXFANode->GetElementType() == XFA_Element::ExData) {
     CFX_WideStringC wsContentType =
         pXFANode->GetCData(XFA_ATTRIBUTE_ContentType);
-    if (wsContentType == FX_WSTRC(L"text/html"))
+    if (wsContentType == L"text/html")
       element = XFA_Element::SharpxHTML;
-    else if (wsContentType == FX_WSTRC(L"text/xml"))
+    else if (wsContentType == L"text/xml")
       element = XFA_Element::Sharpxml;
   }
   if (element == XFA_Element::SharpxHTML)
@@ -1030,12 +1029,9 @@
         {
           CFX_WideString wsNamespaceURI;
           GetElementTagNamespaceURI(pXMLElement, wsNamespaceURI);
-          if (wsNamespaceURI ==
-                  FX_WSTRC(L"http://www.xfa.com/schema/xfa-package/") ||
-              wsNamespaceURI ==
-                  FX_WSTRC(L"http://www.xfa.org/schema/xfa-package/") ||
-              wsNamespaceURI ==
-                  FX_WSTRC(L"http://www.w3.org/2001/XMLSchema-instance")) {
+          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;
           }
         }
@@ -1043,22 +1039,20 @@
         XFA_Element eNodeType = XFA_Element::DataModel;
         if (eNodeType == XFA_Element::DataModel) {
           CFX_WideString wsDataNodeAttr;
-          if (FindAttributeWithNS(
-                  pXMLElement, FX_WSTRC(L"dataNode"),
-                  FX_WSTRC(L"http://www.xfa.org/schema/xfa-data/1.0/"),
-                  wsDataNodeAttr)) {
-            if (wsDataNodeAttr == FX_WSTRC(L"dataGroup"))
+          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 == FX_WSTRC(L"dataValue"))
+            else if (wsDataNodeAttr == L"dataValue")
               eNodeType = XFA_Element::DataValue;
           }
         }
         CFX_WideString wsContentType;
         if (eNodeType == XFA_Element::DataModel) {
-          if (FindAttributeWithNS(
-                  pXMLElement, FX_WSTRC(L"contentType"),
-                  FX_WSTRC(L"http://www.xfa.org/schema/xfa-data/1.0/"),
-                  wsContentType)) {
+          if (FindAttributeWithNS(pXMLElement, L"contentType",
+                                  L"http://www.xfa.org/schema/xfa-data/1.0/",
+                                  wsContentType)) {
             if (!wsContentType.IsEmpty())
               eNodeType = XFA_Element::DataValue;
           }
@@ -1099,14 +1093,14 @@
                                 wsName, wsNS)) {
             continue;
           }
-          if (wsName == FX_WSTRC(L"nil") && wsValue == FX_WSTRC(L"true")) {
+          if (wsName == L"nil" && wsValue == L"true") {
             bNeedValue = false;
             continue;
           }
-          if (wsNS == FX_WSTRC(L"http://www.xfa.com/schema/xfa-package/") ||
-              wsNS == FX_WSTRC(L"http://www.xfa.org/schema/xfa-package/") ||
-              wsNS == FX_WSTRC(L"http://www.w3.org/2001/XMLSchema-instance") ||
-              wsNS == FX_WSTRC(L"http://www.xfa.org/schema/xfa-data/1.0/")) {
+          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(
@@ -1285,23 +1279,21 @@
 
   CFX_WideString wsTargetName;
   pXMLInstruction->GetTargetName(wsTargetName);
-  if (wsTargetName == FX_WSTRC(L"originalXFAVersion")) {
+  if (wsTargetName == L"originalXFAVersion") {
     CFX_WideString wsData;
     if (pXMLInstruction->GetData(0, wsData) &&
         (pXFANode->GetDocument()->RecognizeXFAVersionNumber(wsData) !=
          XFA_VERSION_UNKNOWN)) {
       wsData.clear();
       if (pXMLInstruction->GetData(1, wsData) &&
-          wsData == FX_WSTRC(L"v2.7-scripting:1")) {
+          wsData == L"v2.7-scripting:1") {
         pXFANode->GetDocument()->SetFlag(XFA_DOCFLAG_Scripting, true);
       }
     }
-  } else if (wsTargetName == FX_WSTRC(L"acrobat")) {
+  } else if (wsTargetName == L"acrobat") {
     CFX_WideString wsData;
-    if (pXMLInstruction->GetData(0, wsData) &&
-        wsData == FX_WSTRC(L"JavaScript")) {
-      if (pXMLInstruction->GetData(1, wsData) &&
-          wsData == FX_WSTRC(L"strictScoping")) {
+    if (pXMLInstruction->GetData(0, wsData) && wsData == L"JavaScript") {
+      if (pXMLInstruction->GetData(1, wsData) && wsData == L"strictScoping") {
         pXFANode->GetDocument()->SetFlag(XFA_DOCFLAG_StrictScoping, true);
       }
     }
diff --git a/xfa/fxfa/parser/cxfa_stroke.h b/xfa/fxfa/parser/cxfa_stroke.h
index a3287d2..cf941c8 100644
--- a/xfa/fxfa/parser/cxfa_stroke.h
+++ b/xfa/fxfa/parser/cxfa_stroke.h
@@ -21,6 +21,7 @@
 
 class CXFA_Stroke : public CXFA_Data {
  public:
+  CXFA_Stroke() : CXFA_Stroke(nullptr) {}
   explicit CXFA_Stroke(CXFA_Node* pNode) : CXFA_Data(pNode) {}
 
   bool IsCorner() const { return GetElementType() == XFA_Element::Corner; }
@@ -40,6 +41,4 @@
   bool SameStyles(CXFA_Stroke stroke, uint32_t dwFlags = 0) const;
 };
 
-typedef CFX_ArrayTemplate<CXFA_Stroke> CXFA_StrokeArray;
-
 #endif  // XFA_FXFA_PARSER_CXFA_STROKE_H_
diff --git a/xfa/fxfa/parser/cxfa_widgetdata.cpp b/xfa/fxfa/parser/cxfa_widgetdata.cpp
index 80c50b7..d3533c2 100644
--- a/xfa/fxfa/parser/cxfa_widgetdata.cpp
+++ b/xfa/fxfa/parser/cxfa_widgetdata.cpp
@@ -18,7 +18,7 @@
 
 namespace {
 
-FX_FLOAT GetEdgeThickness(const CXFA_StrokeArray& strokes,
+FX_FLOAT GetEdgeThickness(const std::vector<CXFA_Stroke>& strokes,
                           bool b3DStyle,
                           int32_t nIndex) {
   FX_FLOAT fThickness = 0;
@@ -407,19 +407,17 @@
 }
 
 CFX_RectF CXFA_WidgetData::GetUIMargin() {
-  CFX_RectF rtUIMargin;
-  rtUIMargin.Reset();
-
   CXFA_Node* pUIChild = GetUIChild();
   CXFA_Margin mgUI = CXFA_Margin(
       pUIChild ? pUIChild->GetProperty(0, XFA_Element::Margin, false)
                : nullptr);
+
   if (!mgUI)
-    return rtUIMargin;
+    return CFX_RectF();
 
   CXFA_Border border = GetUIBorder();
   if (border && border.GetPresence() != XFA_ATTRIBUTEENUM_Visible)
-    return rtUIMargin;
+    return CFX_RectF();
 
   FX_FLOAT fLeftInset, fTopInset, fRightInset, fBottomInset;
   bool bLeft = mgUI.GetLeftInset(fLeftInset);
@@ -431,8 +429,8 @@
     FX_FLOAT fThickness = 0;
     border.Get3DStyle(bVisible, fThickness);
     if (!bLeft || !bTop || !bRight || !bBottom) {
-      CXFA_StrokeArray strokes;
-      border.GetStrokes(strokes);
+      std::vector<CXFA_Stroke> strokes;
+      border.GetStrokes(&strokes);
       if (!bTop)
         fTopInset = GetEdgeThickness(strokes, bVisible, 0);
       if (!bRight)
@@ -443,8 +441,7 @@
         fLeftInset = GetEdgeThickness(strokes, bVisible, 3);
     }
   }
-  rtUIMargin.Set(fLeftInset, fTopInset, fRightInset, fBottomInset);
-  return rtUIMargin;
+  return CFX_RectF(fLeftInset, fTopInset, fRightInset, fBottomInset);
 }
 
 int32_t CXFA_WidgetData::GetButtonHighlight() {
@@ -462,7 +459,7 @@
     while (pText) {
       CFX_WideStringC wsName;
       pText->TryCData(XFA_ATTRIBUTE_Name, wsName);
-      if (wsName == FX_WSTRC(L"rollover")) {
+      if (wsName == L"rollover") {
         pText->TryContent(wsRollover);
         bRichText = pText->GetElementType() == XFA_Element::ExData;
         return !wsRollover.IsEmpty();
@@ -479,7 +476,7 @@
     while (pText) {
       CFX_WideStringC wsName;
       pText->TryCData(XFA_ATTRIBUTE_Name, wsName);
-      if (wsName == FX_WSTRC(L"down")) {
+      if (wsName == L"down") {
         pText->TryContent(wsDown);
         bRichText = pText->GetElementType() == XFA_Element::ExData;
         return !wsDown.IsEmpty();
@@ -874,7 +871,7 @@
   return -1;
 }
 
-void CXFA_WidgetData::GetSelectedItems(CFX_Int32Array& iSelArray) {
+void CXFA_WidgetData::GetSelectedItems(CFX_ArrayTemplate<int32_t>& iSelArray) {
   std::vector<CFX_WideString> wsValueArray;
   GetSelectedItemsValue(wsValueArray);
   int32_t iValues = pdfium::CollectionSize<int32_t>(wsValueArray);
@@ -973,7 +970,7 @@
                             bSyncData);
       }
     } else if (iSel >= 0) {
-      CFX_Int32Array iSelArray;
+      CFX_ArrayTemplate<int32_t> iSelArray;
       GetSelectedItems(iSelArray);
       for (int32_t i = 0; i < iSelArray.GetSize(); i++) {
         if (iSelArray[i] == nIndex) {
@@ -999,7 +996,7 @@
   }
 }
 
-void CXFA_WidgetData::SetSelectedItems(CFX_Int32Array& iSelArray,
+void CXFA_WidgetData::SetSelectedItems(CFX_ArrayTemplate<int32_t>& iSelArray,
                                        bool bNotify,
                                        bool bScriptModify,
                                        bool bSyncData) {
@@ -1010,9 +1007,8 @@
     GetChoiceListItems(wsSaveTextArray, true);
     CFX_WideString wsItemValue;
     for (int32_t i = 0; i < iSize; i++) {
-      wsItemValue = (iSize == 1)
-                        ? wsSaveTextArray[iSelArray[i]]
-                        : wsSaveTextArray[iSelArray[i]] + FX_WSTRC(L"\n");
+      wsItemValue = (iSize == 1) ? wsSaveTextArray[iSelArray[i]]
+                                 : wsSaveTextArray[iSelArray[i]] + L"\n";
       wsValue += wsItemValue;
     }
   }
@@ -1522,7 +1518,7 @@
     }
   } else {
     if (eType == XFA_Element::NumericEdit) {
-      if (wsNewText != FX_WSTRC(L"0")) {
+      if (wsNewText != L"0") {
         int32_t iLeadDigits = 0;
         int32_t iFracDigits = 0;
         GetLeadDigits(iLeadDigits);
@@ -1572,7 +1568,7 @@
                                   wsDataPicture);
           pLocale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Medium,
                                   wsTimePicture);
-          wsPicture = wsDataPicture + FX_WSTRC(L"T") + wsTimePicture;
+          wsPicture = wsDataPicture + L"T" + wsTimePicture;
           break;
         case XFA_VT_DECIMAL:
         case XFA_VT_FLOAT:
@@ -1640,7 +1636,7 @@
   CFX_WideString wsLocaleName;
   if (!m_pNode->GetLocaleName(wsLocaleName))
     return nullptr;
-  if (wsLocaleName == FX_WSTRC(L"ambient"))
+  if (wsLocaleName == L"ambient")
     return m_pNode->GetDocument()->GetLocalMgr()->GetDefLocale();
   return m_pNode->GetDocument()->GetLocalMgr()->GetLocaleByName(wsLocaleName);
 }
diff --git a/xfa/fxfa/parser/cxfa_widgetdata.h b/xfa/fxfa/parser/cxfa_widgetdata.h
index 7986fa9..4f5db3b 100644
--- a/xfa/fxfa/parser/cxfa_widgetdata.h
+++ b/xfa/fxfa/parser/cxfa_widgetdata.h
@@ -102,7 +102,7 @@
                           bool bSaveValue = false);
   int32_t CountSelectedItems();
   int32_t GetSelectedItem(int32_t nIndex = 0);
-  void GetSelectedItems(CFX_Int32Array& iSelArray);
+  void GetSelectedItems(CFX_ArrayTemplate<int32_t>& iSelArray);
   void GetSelectedItemsValue(std::vector<CFX_WideString>& wsSelTextArray);
   bool GetItemState(int32_t nIndex);
   void SetItemState(int32_t nIndex,
@@ -110,7 +110,7 @@
                     bool bNotify,
                     bool bScriptModify,
                     bool bSyncData);
-  void SetSelectedItems(CFX_Int32Array& iSelArray,
+  void SetSelectedItems(CFX_ArrayTemplate<int32_t>& iSelArray,
                         bool bNotify,
                         bool bScriptModify,
                         bool bSyncData);
diff --git a/xfa/fxfa/parser/cxfa_xml_parser.cpp b/xfa/fxfa/parser/cxfa_xml_parser.cpp
index 95920d9..b202022 100644
--- a/xfa/fxfa/parser/cxfa_xml_parser.cpp
+++ b/xfa/fxfa/parser/cxfa_xml_parser.cpp
@@ -85,8 +85,7 @@
         break;
       case FDE_XmlSyntaxResult::TargetName:
         m_pParser->GetTargetName(m_ws1);
-        if (m_ws1 == FX_WSTRC(L"originalXFAVersion") ||
-            m_ws1 == FX_WSTRC(L"acrobat")) {
+        if (m_ws1 == L"originalXFAVersion" || m_ws1 == L"acrobat") {
           m_pChild = new CFDE_XMLInstruction(m_ws1);
           m_pParent->InsertChildNode(m_pChild);
         } else {
@@ -104,12 +103,12 @@
         if (m_dwCheckStatus != 0x03 && m_NodeStack.GetSize() == 3) {
           CFX_WideString wsTag;
           static_cast<CFDE_XMLElement*>(m_pChild)->GetLocalTagName(wsTag);
-          if (wsTag == FX_WSTRC(L"template")) {
+          if (wsTag == L"template") {
             m_dwCheckStatus |= 0x01;
             m_dwCurrentCheckStatus = 0x01;
             m_nStart[0] = m_pParser->GetCurrentBinaryPos() -
                           (m_pParser->GetCurrentPos() - m_nElementStart);
-          } else if (wsTag == FX_WSTRC(L"datasets")) {
+          } else if (wsTag == L"datasets") {
             m_dwCheckStatus |= 0x02;
             m_dwCurrentCheckStatus = 0x02;
             m_nStart[1] = m_pParser->GetCurrentBinaryPos() -
diff --git a/xfa/fxfa/parser/cxfa_xml_parser.h b/xfa/fxfa/parser/cxfa_xml_parser.h
index e49a9dd..9393b7e 100644
--- a/xfa/fxfa/parser/cxfa_xml_parser.h
+++ b/xfa/fxfa/parser/cxfa_xml_parser.h
@@ -32,8 +32,7 @@
  protected:
   CFDE_XMLNode* m_pRoot;
   CFX_RetainPtr<IFGAS_Stream> m_pStream;
-  std::unique_ptr<CFDE_XMLSyntaxParser, ReleaseDeleter<CFDE_XMLSyntaxParser>>
-      m_pParser;
+  std::unique_ptr<CFDE_XMLSyntaxParser> m_pParser;
   CFDE_XMLNode* m_pParent;
   CFDE_XMLNode* m_pChild;
   CFX_StackTemplate<CFDE_XMLNode*> m_NodeStack;
diff --git a/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp b/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp
index f1b6088..03ab81e 100644
--- a/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp
+++ b/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp
@@ -89,9 +89,9 @@
           CFX_WideString wsContentType;
           pChildNode->GetAttribute(XFA_ATTRIBUTE_ContentType, wsContentType,
                                    false);
-          if (wsContentType == FX_WSTRC(L"text/html"))
+          if (wsContentType == L"text/html")
             element = XFA_Element::SharpxHTML;
-          else if (wsContentType == FX_WSTRC(L"text/xml"))
+          else if (wsContentType == L"text/xml")
             element = XFA_Element::Sharpxml;
         }
         pContentRawDataNode = pChildNode->CreateSamePacketNode(element);
@@ -305,7 +305,7 @@
           CFX_WideString wsItem;
           for (int32_t i = 0; i < iCounts; i++) {
             items[i]->TryContent(wsItem);
-            wsItem = (iCounts == 1) ? wsItem : wsItem + FX_WSTRC(L"\n");
+            wsItem = (iCounts == 1) ? wsItem : wsItem + L"\n";
             wsNormalizeValue += wsItem;
           }
           CXFA_ExData exData = defValue.GetExData();
@@ -456,7 +456,7 @@
                                bool bForceBind,
                                bool bUpLevel) {
   uint32_t dFlags = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_BindNew;
-  if (bUpLevel || wsRef != FX_WSTRC(L"name"))
+  if (bUpLevel || wsRef != L"name")
     dFlags |= (XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings);
 
   XFA_RESOLVENODE_RS rs;
@@ -494,7 +494,7 @@
                                        CXFA_Node* pTemplateNode,
                                        CXFA_NodeArray& subforms) {
   CFX_WideStringC wsSubformName = pTemplateNode->GetCData(XFA_ATTRIBUTE_Name);
-  CFX_WideString wsInstMgrNodeName = FX_WSTRC(L"_") + wsSubformName;
+  CFX_WideString wsInstMgrNodeName = L"_" + wsSubformName;
   uint32_t dwInstNameHash =
       FX_HashCode_GetW(wsInstMgrNodeName.AsStringC(), false);
   CXFA_Node* pExistingNode = XFA_DataMerge_FindFormDOMInstance(
@@ -530,8 +530,7 @@
 
   CXFA_Node* pNewNode =
       pDocument->CreateNode(XFA_XDPPACKET_Form, XFA_Element::InstanceManager);
-  wsInstMgrNodeName =
-      FX_WSTRC(L"_") + pTemplateNode->GetCData(XFA_ATTRIBUTE_Name);
+  wsInstMgrNodeName = L"_" + pTemplateNode->GetCData(XFA_ATTRIBUTE_Name);
   pNewNode->SetCData(XFA_ATTRIBUTE_Name, wsInstMgrNodeName);
   pFormParent->InsertChild(pNewNode, nullptr);
   pNewNode->SetTemplateNode(pTemplateNode);
@@ -1040,7 +1039,7 @@
 
       CFX_WideString wsNamespace;
       if (!pDDGroupNode->TryNamespace(wsNamespace) ||
-          wsNamespace != FX_WSTRC(L"http://ns.adobe.com/data-description/")) {
+          wsNamespace != L"http://ns.adobe.com/data-description/") {
         continue;
       }
     }
@@ -1214,7 +1213,7 @@
 
         CFX_WideString wsNamespace;
         if (!pDDGroupNode->TryNamespace(wsNamespace) ||
-            wsNamespace != FX_WSTRC(L"http://ns.adobe.com/data-description/")) {
+            wsNamespace != L"http://ns.adobe.com/data-description/") {
           continue;
         }
       }
@@ -1390,7 +1389,7 @@
     if (!pDDRoot && pChildNode->GetNameHash() == XFA_HASHCODE_DataDescription) {
       if (!pChildNode->TryNamespace(wsNamespaceURI))
         continue;
-      if (wsNamespaceURI == FX_WSTRC(L"http://ns.adobe.com/data-description/"))
+      if (wsNamespaceURI == L"http://ns.adobe.com/data-description/")
         pDDRoot = pChildNode;
     } else if (!pDataRoot && pChildNode->GetNameHash() == XFA_HASHCODE_Data) {
       if (!pChildNode->TryNamespace(wsNamespaceURI))
diff --git a/xfa/fxfa/parser/xfa_layout_itemlayout.cpp b/xfa/fxfa/parser/xfa_layout_itemlayout.cpp
index 45dc327..dd38c96 100644
--- a/xfa/fxfa/parser/xfa_layout_itemlayout.cpp
+++ b/xfa/fxfa/parser/xfa_layout_itemlayout.cpp
@@ -8,8 +8,10 @@
 
 #include <algorithm>
 #include <memory>
+#include <utility>
 #include <vector>
 
+#include "third_party/base/ptr_util.h"
 #include "third_party/base/stl_util.h"
 #include "xfa/fxfa/app/xfa_ffnotify.h"
 #include "xfa/fxfa/parser/cxfa_containerlayoutitem.h"
@@ -24,12 +26,12 @@
 
 namespace {
 
-int32_t SeparateStringW(const FX_WCHAR* pStr,
-                        int32_t iStrLen,
-                        FX_WCHAR delimiter,
-                        std::vector<CFX_WideString>& pieces) {
+std::vector<CFX_WideString> SeparateStringW(const FX_WCHAR* pStr,
+                                            int32_t iStrLen,
+                                            FX_WCHAR delimiter) {
+  std::vector<CFX_WideString> ret;
   if (!pStr)
-    return 0;
+    return ret;
   if (iStrLen < 0)
     iStrLen = FXSYS_wcslen(pStr);
 
@@ -37,191 +39,461 @@
   const FX_WCHAR* pEnd = pStr + iStrLen;
   while (true) {
     if (pStr >= pEnd || delimiter == *pStr) {
-      pieces.push_back(CFX_WideString(pToken, pStr - pToken));
+      ret.push_back(CFX_WideString(pToken, pStr - pToken));
       pToken = pStr + 1;
       if (pStr >= pEnd)
         break;
     }
     pStr++;
   }
-  return pdfium::CollectionSize<int32_t>(pieces);
+  return ret;
 }
 
-}  // namespace
-
-CXFA_ItemLayoutProcessor::CXFA_ItemLayoutProcessor(CXFA_Node* pNode,
-                                                   CXFA_LayoutPageMgr* pPageMgr)
-    : m_bKeepBreakFinish(false),
-      m_bIsProcessKeep(false),
-      m_pKeepHeadNode(nullptr),
-      m_pKeepTailNode(nullptr),
-      m_pFormNode(pNode),
-      m_pLayoutItem(nullptr),
-      m_pOldLayoutItem(nullptr),
-      m_pCurChildNode(XFA_LAYOUT_INVALIDNODE),
-      m_pCurChildPreprocessor(nullptr),
-      m_nCurChildNodeStage(XFA_ItemLayoutProcessorStages_None),
-      m_fUsedSize(0),
-      m_pPageMgr(pPageMgr),
-      m_bBreakPending(true),
-      m_fLastRowWidth(0),
-      m_fLastRowY(0),
-      m_fWidthLimite(0),
-      m_bUseInheriated(false),
-      m_ePreProcessRs(XFA_ItemLayoutProcessorResult_Done),
-      m_bHasAvailHeight(true) {
-  ASSERT(m_pFormNode && (m_pFormNode->IsContainerNode() ||
-                         m_pFormNode->GetElementType() == XFA_Element::Form));
-  m_pOldLayoutItem =
-      (CXFA_ContentLayoutItem*)m_pFormNode->GetUserData(XFA_LAYOUTITEMKEY);
-}
-
-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 = (CXFA_ContentLayoutItem*)pFormNode->GetDocument()
-                    ->GetNotify()
-                    ->OnCreateLayoutItem(pFormNode);
-  CXFA_ContentLayoutItem* pPrevLayoutItem =
-      (CXFA_ContentLayoutItem*)pFormNode->GetUserData(XFA_LAYOUTITEMKEY);
-  if (pPrevLayoutItem) {
-    while (pPrevLayoutItem->m_pNext) {
-      pPrevLayoutItem = pPrevLayoutItem->m_pNext;
+void UpdateWidgetSize(CXFA_ContentLayoutItem* pLayoutItem,
+                      FX_FLOAT* fWidth,
+                      FX_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;
     }
-    pPrevLayoutItem->m_pNext = pLayoutItem;
-    pLayoutItem->m_pPrev = pPrevLayoutItem;
-  } else {
-    pFormNode->SetUserData(XFA_LAYOUTITEMKEY, pLayoutItem);
+    case XFA_Element::Draw:
+    case XFA_Element::Field: {
+      pNode->GetDocument()->GetNotify()->StartFieldDrawLayout(pNode, *fWidth,
+                                                              *fHeight);
+      break;
+    }
+    default:
+      ASSERT(false);
   }
-  return pLayoutItem;
 }
-bool CXFA_ItemLayoutProcessor::FindLayoutItemSplitPos(
-    CXFA_ContentLayoutItem* pLayoutItem,
-    FX_FLOAT fCurVerticalOffset,
-    FX_FLOAT& fProposedSplitPos,
-    bool& bAppChange,
-    bool bCalculateMargin) {
-  CXFA_Node* pFormNode = pLayoutItem->m_pFormNode;
-  if (fProposedSplitPos > fCurVerticalOffset + XFA_LAYOUT_FLOAT_PERCISION &&
-      fProposedSplitPos <= fCurVerticalOffset + pLayoutItem->m_sSize.y -
-                               XFA_LAYOUT_FLOAT_PERCISION) {
-    switch (pFormNode->GetIntact()) {
-      case XFA_ATTRIBUTEENUM_None: {
-        bool bAnyChanged = false;
-        CXFA_Document* pDocument = pFormNode->GetDocument();
-        CXFA_FFNotify* pNotify = pDocument->GetNotify();
-        FX_FLOAT fCurTopMargin = 0, fCurBottomMargin = 0;
-        CXFA_Node* pMarginNode =
-            pFormNode->GetFirstChildByClass(XFA_Element::Margin);
-        if (pMarginNode && bCalculateMargin) {
-          fCurTopMargin = pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset)
-                              .ToUnit(XFA_UNIT_Pt);
-          fCurBottomMargin = pMarginNode->GetMeasure(XFA_ATTRIBUTE_BottomInset)
-                                 .ToUnit(XFA_UNIT_Pt);
-        }
-        bool bChanged = true;
-        while (bChanged) {
-          bChanged = false;
-          {
-            FX_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;
-              }
-            }
-          }
-          FX_FLOAT fRelSplitPos = fProposedSplitPos - fCurBottomMargin;
-          for (CXFA_ContentLayoutItem* pChildItem =
-                   (CXFA_ContentLayoutItem*)pLayoutItem->m_pFirstChild;
-               pChildItem;
-               pChildItem =
-                   (CXFA_ContentLayoutItem*)pChildItem->m_pNextSibling) {
-            FX_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;
-      } break;
-      case XFA_ATTRIBUTEENUM_ContentArea:
-      case XFA_ATTRIBUTEENUM_PageArea: {
-        fProposedSplitPos = fCurVerticalOffset;
-        return true;
+
+CFX_SizeF CalculateContainerSpecifiedSize(CXFA_Node* pFormNode,
+                                          bool* bContainerWidthAutoSize,
+                                          bool* bContainerHeightAutoSize) {
+  *bContainerWidthAutoSize = true;
+  *bContainerHeightAutoSize = true;
+
+  XFA_Element eType = pFormNode->GetElementType();
+  CXFA_Measurement mTmpValue;
+  CFX_SizeF containerSize;
+  if ((eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup) &&
+      pFormNode->TryMeasure(XFA_ATTRIBUTE_W, mTmpValue, false) &&
+      mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
+    containerSize.width = mTmpValue.ToUnit(XFA_UNIT_Pt);
+    *bContainerWidthAutoSize = false;
+  }
+  if ((eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup) &&
+      pFormNode->TryMeasure(XFA_ATTRIBUTE_H, mTmpValue, false) &&
+      mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
+    containerSize.height = mTmpValue.ToUnit(XFA_UNIT_Pt);
+    *bContainerHeightAutoSize = false;
+  }
+  if (*bContainerWidthAutoSize && eType == XFA_Element::Subform &&
+      pFormNode->TryMeasure(XFA_ATTRIBUTE_MaxW, mTmpValue, false) &&
+      mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
+    containerSize.width = mTmpValue.ToUnit(XFA_UNIT_Pt);
+    *bContainerWidthAutoSize = false;
+  }
+  if (*bContainerHeightAutoSize && eType == XFA_Element::Subform &&
+      pFormNode->TryMeasure(XFA_ATTRIBUTE_MaxH, mTmpValue, false) &&
+      mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
+    containerSize.height = mTmpValue.ToUnit(XFA_UNIT_Pt);
+    *bContainerHeightAutoSize = false;
+  }
+  return containerSize;
+}
+
+CFX_SizeF CalculateContainerComponentSizeFromContentSize(
+    CXFA_Node* pFormNode,
+    bool bContainerWidthAutoSize,
+    FX_FLOAT fContentCalculatedWidth,
+    bool bContainerHeightAutoSize,
+    FX_FLOAT fContentCalculatedHeight,
+    const CFX_SizeF& currentContainerSize) {
+  CFX_SizeF componentSize = currentContainerSize;
+  CXFA_Node* pMarginNode = pFormNode->GetFirstChildByClass(XFA_Element::Margin);
+  CXFA_Measurement mTmpValue;
+  if (bContainerWidthAutoSize) {
+    componentSize.width = fContentCalculatedWidth;
+    if (pMarginNode) {
+      if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_LeftInset, mTmpValue, false))
+        componentSize.width += mTmpValue.ToUnit(XFA_UNIT_Pt);
+      if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_RightInset, mTmpValue, false))
+        componentSize.width += mTmpValue.ToUnit(XFA_UNIT_Pt);
+    }
+  }
+
+  if (bContainerHeightAutoSize) {
+    componentSize.height = fContentCalculatedHeight;
+    if (pMarginNode) {
+      if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_TopInset, mTmpValue, false))
+        componentSize.height += mTmpValue.ToUnit(XFA_UNIT_Pt);
+      if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_BottomInset, mTmpValue,
+                                  false)) {
+        componentSize.height += mTmpValue.ToUnit(XFA_UNIT_Pt);
       }
-      default:
-        return false;
     }
   }
-  return false;
+  return componentSize;
 }
-static XFA_ATTRIBUTEENUM XFA_ItemLayoutProcessor_GetLayout(CXFA_Node* pFormNode,
-                                                           bool& bRootForceTb) {
-  bRootForceTb = false;
-  XFA_ATTRIBUTEENUM eLayoutMode;
-  if (pFormNode->TryEnum(XFA_ATTRIBUTE_Layout, eLayoutMode, false)) {
-    return eLayoutMode;
+
+void RelocateTableRowCells(
+    CXFA_ContentLayoutItem* pLayoutRow,
+    const CFX_ArrayTemplate<FX_FLOAT>& rgSpecifiedColumnWidths,
+    XFA_ATTRIBUTEENUM eLayout) {
+  bool bContainerWidthAutoSize = true;
+  bool bContainerHeightAutoSize = true;
+  CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
+      pLayoutRow->m_pFormNode, &bContainerWidthAutoSize,
+      &bContainerHeightAutoSize);
+  CXFA_Node* pMarginNode =
+      pLayoutRow->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
+  FX_FLOAT fLeftInset = 0;
+  FX_FLOAT fTopInset = 0;
+  FX_FLOAT fRightInset = 0;
+  FX_FLOAT fBottomInset = 0;
+  if (pMarginNode) {
+    fLeftInset =
+        pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
+    fTopInset =
+        pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset).ToUnit(XFA_UNIT_Pt);
+    fRightInset =
+        pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
+    fBottomInset =
+        pMarginNode->GetMeasure(XFA_ATTRIBUTE_BottomInset).ToUnit(XFA_UNIT_Pt);
   }
+
+  FX_FLOAT fContentWidthLimit =
+      bContainerWidthAutoSize ? FLT_MAX
+                              : containerSize.width - fLeftInset - fRightInset;
+  FX_FLOAT fContentCurrentHeight =
+      pLayoutRow->m_sSize.height - fTopInset - fBottomInset;
+  FX_FLOAT fContentCalculatedWidth = 0;
+  FX_FLOAT fContentCalculatedHeight = 0;
+  FX_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->GetInteger(XFA_ATTRIBUTE_ColSpan);
+    int32_t nColSpan = nOriginalColSpan;
+    FX_FLOAT fColSpanWidth = 0;
+    if (nColSpan == -1 ||
+        nCurrentColIdx + nColSpan > rgSpecifiedColumnWidths.GetSize()) {
+      nColSpan = rgSpecifiedColumnWidths.GetSize() - 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;
+    FX_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);
+      FX_FLOAT fOldChildHeight = pLayoutChild->m_sSize.height;
+      pLayoutChild->m_sSize.height = fContentCalculatedHeight;
+      CXFA_Node* pParaNode =
+          pLayoutChild->m_pFormNode->GetFirstChildByClass(XFA_Element::Para);
+      if (pParaNode && pLayoutChild->m_pFirstChild) {
+        FX_FLOAT fOffHeight = fContentCalculatedHeight - fOldChildHeight;
+        XFA_ATTRIBUTEENUM eVType = pParaNode->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) {
+    FX_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->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->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,
+                           FX_FLOAT fSplitPos,
+                           CXFA_ContentLayoutItem* pTrailerLayoutItem,
+                           bool bUseInherited) {
+  if (!pTrailerLayoutItem)
+    return;
+
+  FX_FLOAT fHeight = pTrailerLayoutItem->m_sSize.height;
+  if (bUseInherited) {
+    FX_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_Node* pMarginNode =
+      pProcessor->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
+  FX_FLOAT fLeftInset = 0;
+  FX_FLOAT fTopInset = 0;
+  FX_FLOAT fRightInset = 0;
+  FX_FLOAT fBottomInset = 0;
+  if (pMarginNode) {
+    fLeftInset =
+        pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
+    fTopInset =
+        pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset).ToUnit(XFA_UNIT_Pt);
+    fRightInset =
+        pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
+    fBottomInset =
+        pMarginNode->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;
+  }
+
+  FX_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->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_Node* pMarginNode =
+      pProcessor->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
+  FX_FLOAT fLeftInset = 0;
+  FX_FLOAT fRightInset = 0;
+  if (pMarginNode) {
+    fLeftInset =
+        pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
+    fRightInset =
+        pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
+  }
+
+  FX_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->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;
+}
+
+FX_FLOAT InsertPendingItems(CXFA_ItemLayoutProcessor* pProcessor,
+                            CXFA_Node* pCurChildNode) {
+  FX_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;
+  XFA_ATTRIBUTEENUM eLayoutMode;
+  if (pFormNode->TryEnum(XFA_ATTRIBUTE_Layout, eLayoutMode, false))
+    return eLayoutMode;
+
   CXFA_Node* pParentNode = pFormNode->GetNodeItem(XFA_NODEITEM_Parent);
   if (pParentNode && pParentNode->GetElementType() == XFA_Element::Form) {
-    bRootForceTb = true;
+    *bRootForceTb = true;
     return XFA_ATTRIBUTEENUM_Tb;
   }
   return XFA_ATTRIBUTEENUM_Position;
 }
-static bool XFA_ExistContainerKeep(CXFA_Node* pCurNode, bool bPreFind) {
-  if (!pCurNode || !XFA_ItemLayoutProcessor_IsTakingSpace(pCurNode)) {
+
+bool ExistContainerKeep(CXFA_Node* pCurNode, bool bPreFind) {
+  if (!pCurNode || !XFA_ItemLayoutProcessor_IsTakingSpace(pCurNode))
     return false;
-  }
+
   XFA_NODEITEM eItemType = XFA_NODEITEM_PrevSibling;
-  if (!bPreFind) {
+  if (!bPreFind)
     eItemType = XFA_NODEITEM_NextSibling;
-  }
+
   CXFA_Node* pPreContainer =
       pCurNode->GetNodeItem(eItemType, XFA_ObjectType::ContainerNode);
-  if (!pPreContainer) {
+  if (!pPreContainer)
     return false;
-  }
+
   CXFA_Node* pKeep = pCurNode->GetFirstChildByClass(XFA_Element::Keep);
   if (pKeep) {
     XFA_ATTRIBUTEENUM ePrevious;
     XFA_ATTRIBUTE eKeepType = XFA_ATTRIBUTE_Previous;
-    if (!bPreFind) {
+    if (!bPreFind)
       eKeepType = XFA_ATTRIBUTE_Next;
-    }
+
     if (pKeep->TryEnum(eKeepType, ePrevious, false)) {
       if (ePrevious == XFA_ATTRIBUTEENUM_ContentArea ||
           ePrevious == XFA_ATTRIBUTEENUM_PageArea) {
@@ -229,420 +501,73 @@
       }
     }
   }
+
   pKeep = pPreContainer->GetFirstChildByClass(XFA_Element::Keep);
-  if (!pKeep) {
+  if (!pKeep)
     return false;
-  }
-  XFA_ATTRIBUTEENUM eNext;
+
   XFA_ATTRIBUTE eKeepType = XFA_ATTRIBUTE_Next;
-  if (!bPreFind) {
+  if (!bPreFind)
     eKeepType = XFA_ATTRIBUTE_Previous;
-  }
-  if (!pKeep->TryEnum(eKeepType, eNext, false)) {
+
+  XFA_ATTRIBUTEENUM eNext;
+  if (!pKeep->TryEnum(eKeepType, eNext, false))
     return false;
-  }
   if (eNext == XFA_ATTRIBUTEENUM_ContentArea ||
       eNext == XFA_ATTRIBUTEENUM_PageArea) {
     return true;
   }
   return false;
 }
-FX_FLOAT CXFA_ItemLayoutProcessor::FindSplitPos(FX_FLOAT fProposedSplitPos) {
-  ASSERT(m_pLayoutItem);
-  XFA_ATTRIBUTEENUM eLayout = m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
-  bool bCalculateMargin = true;
-  if (eLayout == XFA_ATTRIBUTEENUM_Position) {
-    bCalculateMargin = false;
-  }
-  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,
-    FX_FLOAT fSplitPos) {
-  FX_FLOAT fCurTopMargin = 0, fCurBottomMargin = 0;
-  XFA_ATTRIBUTEENUM eLayout = m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
-  bool bCalculateMargin = true;
-  if (eLayout == XFA_ATTRIBUTEENUM_Position) {
-    bCalculateMargin = false;
-  }
-  CXFA_Node* pMarginNode =
-      pLayoutItem->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
-  if (pMarginNode && bCalculateMargin) {
-    fCurTopMargin =
-        pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset).ToUnit(XFA_UNIT_Pt);
-    fCurBottomMargin =
-        pMarginNode->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.x = pLayoutItem->m_sSize.x;
-  pSecondLayoutItem->m_sPos.y = 0;
-  pSecondLayoutItem->m_sSize.y = pLayoutItem->m_sSize.y - fSplitPos;
-  pLayoutItem->m_sSize.y -= pSecondLayoutItem->m_sSize.y;
-  if (pLayoutItem->m_pFirstChild) {
-    pSecondLayoutItem->m_sSize.y += fCurTopMargin;
-  }
-  if (pSecondParent) {
-    pSecondParent->AddChild(pSecondLayoutItem);
-    if (fCurTopMargin > 0 && pLayoutItem->m_pFirstChild) {
-      pSecondParent->m_sSize.y += fCurTopMargin;
-      CXFA_ContentLayoutItem* pParentItem =
-          (CXFA_ContentLayoutItem*)pSecondParent->m_pParent;
-      while (pParentItem) {
-        pParentItem->m_sSize.y += 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;
-  FX_FLOAT lHeightForKeep = 0;
-  CFX_ArrayTemplate<CXFA_ContentLayoutItem*> keepLayoutItems;
-  FX_FLOAT fAddMarginHeight = 0;
-  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 (!XFA_ExistContainerKeep(pChildItem->m_pFormNode, true)) {
-        pChildItem->m_sPos.y -= fSplitPos - fCurBottomMargin;
-        pChildItem->m_sPos.y += lHeightForKeep;
-        pChildItem->m_sPos.y += fAddMarginHeight;
-        pSecondLayoutItem->AddChild(pChildItem);
-      } else {
-        if (lHeightForKeep < XFA_LAYOUT_FLOAT_PERCISION) {
-          for (int32_t iIndex = 0; iIndex < keepLayoutItems.GetSize();
-               iIndex++) {
-            CXFA_ContentLayoutItem* pPreItem = keepLayoutItems[iIndex];
-            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.y > lHeightForKeep) {
-              pPreItem->m_sPos.y = lHeightForKeep;
-              lHeightForKeep += pPreItem->m_sSize.y;
-              pSecondLayoutItem->m_sSize.y += pPreItem->m_sSize.y;
-              if (pSecondParent) {
-                pSecondParent->m_sSize.y += pPreItem->m_sSize.y;
-              }
-            }
-            pSecondLayoutItem->AddChild(pPreItem);
-          }
-        }
-        pChildItem->m_sPos.y -= fSplitPos;
-        pChildItem->m_sPos.y += lHeightForKeep;
-        pChildItem->m_sPos.y += fAddMarginHeight;
-        pSecondLayoutItem->AddChild(pChildItem);
-      }
-    } else if (fSplitPos + XFA_LAYOUT_FLOAT_PERCISION >=
-               fCurTopMargin + fCurBottomMargin + pChildItem->m_sPos.y +
-                   pChildItem->m_sSize.y) {
-      pLayoutItem->AddChild(pChildItem);
-      if (XFA_ExistContainerKeep(pChildItem->m_pFormNode, false)) {
-        keepLayoutItems.Add(pChildItem);
-      } else {
-        keepLayoutItems.RemoveAll();
-      }
-    } else {
-      FX_FLOAT fOldHeight = pSecondLayoutItem->m_sSize.y;
-      SplitLayoutItem(
-          pChildItem, pSecondLayoutItem,
-          fSplitPos - fCurTopMargin - fCurBottomMargin - pChildItem->m_sPos.y);
-      fAddMarginHeight = pSecondLayoutItem->m_sSize.y - fOldHeight;
-      pLayoutItem->AddChild(pChildItem);
-    }
-  }
-}
-void CXFA_ItemLayoutProcessor::SplitLayoutItem(FX_FLOAT fSplitPos) {
-  ASSERT(m_pLayoutItem);
-  SplitLayoutItem(m_pLayoutItem, nullptr, fSplitPos);
-}
 
-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;
-}
-
-CXFA_Node* CXFA_LayoutItem::GetFormNode() const {
-  return m_pFormNode;
-}
-
-void CXFA_LayoutItem::GetRect(CFX_RectF& rtLayout, bool bRelative) const {
-  ASSERT(m_bIsContentLayoutItem);
-  const CXFA_ContentLayoutItem* pThis =
-      static_cast<const CXFA_ContentLayoutItem*>(this);
-  CFX_PointF sPos = pThis->m_sPos;
-  CFX_SizeF sSize = pThis->m_sSize;
-  if (!bRelative) {
-    for (CXFA_LayoutItem* pLayoutItem = pThis->m_pParent; pLayoutItem;
-         pLayoutItem = pLayoutItem->m_pParent) {
-      if (CXFA_ContentLayoutItem* pContent =
-              pLayoutItem->AsContentLayoutItem()) {
-        sPos += pContent->m_sPos;
-        if (CXFA_Node* pMarginNode =
-                pLayoutItem->m_pFormNode->GetFirstChildByClass(
-                    XFA_Element::Margin)) {
-          sPos += CFX_PointF(pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset)
-                                 .ToUnit(XFA_UNIT_Pt),
-                             pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset)
-                                 .ToUnit(XFA_UNIT_Pt));
-        }
-      } else {
-        if (pLayoutItem->m_pFormNode->GetElementType() ==
-            XFA_Element::ContentArea) {
-          sPos +=
-              CFX_PointF(pLayoutItem->m_pFormNode->GetMeasure(XFA_ATTRIBUTE_X)
-                             .ToUnit(XFA_UNIT_Pt),
-                         pLayoutItem->m_pFormNode->GetMeasure(XFA_ATTRIBUTE_Y)
-                             .ToUnit(XFA_UNIT_Pt));
-          break;
-        } else if (pLayoutItem->m_pFormNode->GetElementType() ==
-                   XFA_Element::PageArea) {
-          break;
-        }
-      }
-    }
-  }
-  rtLayout.Set(sPos.x, sPos.y, sSize.x, sSize.y);
-}
-
-CXFA_LayoutItem* CXFA_LayoutItem::GetParent() const {
-  return m_pParent;
-}
-
-const CXFA_LayoutItem* CXFA_LayoutItem::GetFirst() const {
-  ASSERT(m_bIsContentLayoutItem);
-  const CXFA_ContentLayoutItem* pCurNode =
-      static_cast<const CXFA_ContentLayoutItem*>(this);
-  while (pCurNode->m_pPrev) {
-    pCurNode = pCurNode->m_pPrev;
-  }
-  return pCurNode;
-}
-
-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;
-}
-
-CXFA_LayoutItem* CXFA_LayoutItem::GetLast() {
-  ASSERT(m_bIsContentLayoutItem);
-  CXFA_ContentLayoutItem* pCurNode = static_cast<CXFA_ContentLayoutItem*>(this);
-  while (pCurNode->m_pNext) {
-    pCurNode = pCurNode->m_pNext;
-  }
-  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;
-  } else {
-    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;
-  } else {
-    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;
-}
-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;
-}
-static bool XFA_ItemLayoutProcessor_FindBreakNode(
-    CXFA_Node* pContainerNode,
-    CXFA_Node*& pCurActionNode,
-    XFA_ItemLayoutProcessorStages& nCurStage,
-    bool bBreakBefore) {
+bool FindBreakNode(CXFA_Node* pContainerNode,
+                   CXFA_Node*& pCurActionNode,
+                   XFA_ItemLayoutProcessorStages* nCurStage,
+                   bool bBreakBefore) {
   bool bFindRs = false;
   for (CXFA_Node* pBreakNode = pContainerNode; pBreakNode;
        pBreakNode = pBreakNode->GetNodeItem(XFA_NODEITEM_NextSibling)) {
     XFA_ATTRIBUTE eAttributeType = XFA_ATTRIBUTE_Before;
-    if (!bBreakBefore) {
+    if (!bBreakBefore)
       eAttributeType = XFA_ATTRIBUTE_After;
-    }
+
     switch (pBreakNode->GetElementType()) {
       case XFA_Element::BreakBefore: {
         if (bBreakBefore) {
           pCurActionNode = pBreakNode;
-          nCurStage = XFA_ItemLayoutProcessorStages_BreakBefore;
+          *nCurStage = XFA_ItemLayoutProcessorStages::BreakBefore;
           bFindRs = true;
         }
-      } break;
+        break;
+      }
       case XFA_Element::BreakAfter: {
         if (!bBreakBefore) {
           pCurActionNode = pBreakNode;
-          nCurStage = XFA_ItemLayoutProcessorStages_BreakAfter;
+          *nCurStage = XFA_ItemLayoutProcessorStages::BreakAfter;
           bFindRs = true;
         }
-      } break;
+        break;
+      }
       case XFA_Element::Break:
         if (pBreakNode->GetEnum(eAttributeType) != XFA_ATTRIBUTEENUM_Auto) {
           pCurActionNode = pBreakNode;
-          nCurStage = XFA_ItemLayoutProcessorStages_BreakBefore;
-          if (!bBreakBefore) {
-            nCurStage = XFA_ItemLayoutProcessorStages_BreakAfter;
-          }
+          *nCurStage = XFA_ItemLayoutProcessorStages::BreakBefore;
+          if (!bBreakBefore)
+            *nCurStage = XFA_ItemLayoutProcessorStages::BreakAfter;
+
           bFindRs = true;
-          break;
         }
+        break;
       default:
         break;
     }
-    if (bFindRs) {
+    if (bFindRs)
       break;
-    }
   }
   return bFindRs;
 }
-static void XFA_DeleteLayoutGeneratedNode(CXFA_Node* pGenerateNode) {
+
+void DeleteLayoutGeneratedNode(CXFA_Node* pGenerateNode) {
   CXFA_FFNotify* pNotify = pGenerateNode->GetDocument()->GetNotify();
   CXFA_LayoutProcessor* pDocLayout =
       pGenerateNode->GetDocument()->GetDocLayout();
@@ -662,310 +587,442 @@
   }
   pGenerateNode->GetNodeItem(XFA_NODEITEM_Parent)->RemoveChild(pGenerateNode);
 }
-void CXFA_ItemLayoutProcessor::XFA_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->GetNodeItem(XFA_NODEITEM_Parent);
-    } break;
-    case XFA_ItemLayoutProcessorStages_Keep:
-    case XFA_ItemLayoutProcessorStages_Container:
-      pChildContainer = pCurActionNode;
-      break;
+
+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:
-      pChildContainer = XFA_LAYOUT_INVALIDNODE;
-      break;
-  }
-  switch (nCurStage) {
-    case XFA_ItemLayoutProcessorStages_Keep: {
-      CXFA_Node* pBreakAfterNode =
-          pChildContainer->GetNodeItem(XFA_NODEITEM_FirstChild);
-      if (!m_bKeepBreakFinish &&
-          XFA_ItemLayoutProcessor_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->GetNodeItem(XFA_NODEITEM_FirstChild)
-                     : pCurActionNode->GetNodeItem(XFA_NODEITEM_NextSibling);
-             pBookendNode; pBookendNode = pBookendNode->GetNodeItem(
-                               XFA_NODEITEM_NextSibling)) {
-          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->GetNodeItem(XFA_NODEITEM_NextSibling);
-            if (!m_bKeepBreakFinish &&
-                XFA_ItemLayoutProcessor_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->GetNodeItem(XFA_NODEITEM_FirstChild);
-          if (!m_bKeepBreakFinish &&
-              XFA_ItemLayoutProcessor_FindBreakNode(
-                  pBreakAfterNode, pCurActionNode, nCurStage, false)) {
-            return;
-          }
-        } else {
-          CXFA_Node* pBreakAfterNode =
-              pCurActionNode->GetNodeItem(XFA_NODEITEM_NextSibling);
-          if (XFA_ItemLayoutProcessor_FindBreakNode(
-                  pBreakAfterNode, pCurActionNode, nCurStage, false)) {
-            return;
-          }
-        }
-        goto CheckNextChildContainer;
-      }
-    }
-    CheckNextChildContainer : {
-      CXFA_Node* pNextChildContainer =
-          pChildContainer == XFA_LAYOUT_INVALIDNODE
-              ? pEntireContainer->GetNodeItem(XFA_NODEITEM_FirstChild,
-                                              XFA_ObjectType::ContainerNode)
-              : pChildContainer->GetNodeItem(XFA_NODEITEM_NextSibling,
-                                             XFA_ObjectType::ContainerNode);
-      while (pNextChildContainer &&
-             pNextChildContainer->IsLayoutGeneratedNode()) {
-        CXFA_Node* pSaveNode = pNextChildContainer;
-        pNextChildContainer = pNextChildContainer->GetNodeItem(
-            XFA_NODEITEM_NextSibling, XFA_ObjectType::ContainerNode);
-        if (pSaveNode->IsUnusedNode())
-          XFA_DeleteLayoutGeneratedNode(pSaveNode);
-      }
-      if (!pNextChildContainer) {
-        goto NoMoreChildContainer;
-      }
-      bool bLastKeep = false;
-      if (ProcessKeepNodesForCheckNext(pCurActionNode, nCurStage,
-                                       pNextChildContainer, bLastKeep)) {
-        return;
-      }
-      if (!m_bKeepBreakFinish && !bLastKeep &&
-          XFA_ItemLayoutProcessor_FindBreakNode(
-              pNextChildContainer->GetNodeItem(XFA_NODEITEM_FirstChild),
-              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->GetNodeItem(XFA_NODEITEM_FirstChild)
-                     : pCurActionNode->GetNodeItem(XFA_NODEITEM_NextSibling);
-             pBookendNode; pBookendNode = pBookendNode->GetNodeItem(
-                               XFA_NODEITEM_NextSibling)) {
-          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;
+      return 0;
   }
 }
-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 (XFA_ExistContainerKeep(pNextContainer, false)) {
-    bNextKeep = true;
-  }
-  if (bNextKeep && !bCanSplit) {
-    if (!m_bIsProcessKeep && !m_bKeepBreakFinish) {
-      m_pKeepHeadNode = pNextContainer;
-      m_bIsProcessKeep = true;
-    }
-  } else {
-    if (m_bIsProcessKeep && m_pKeepHeadNode) {
-      m_pKeepTailNode = pNextContainer;
-      if (!m_bKeepBreakFinish &&
-          XFA_ItemLayoutProcessor_FindBreakNode(
-              pNextContainer->GetNodeItem(XFA_NODEITEM_FirstChild),
-              pCurActionNode, nCurStage, true)) {
-        return true;
-      } else {
-        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->GetNodeItem(XFA_NODEITEM_FirstChild);
-  if (XFA_ItemLayoutProcessor_FindBreakNode(pBreakAfterNode, pCurActionNode,
-                                            nCurStage, false)) {
-    return true;
-  }
-  return false;
-}
-bool XFA_ItemLayoutProcessor_IsTakingSpace(CXFA_Node* pNode) {
-  XFA_ATTRIBUTEENUM ePresence = pNode->GetEnum(XFA_ATTRIBUTE_Presence);
-  return ePresence == XFA_ATTRIBUTEENUM_Visible ||
-         ePresence == XFA_ATTRIBUTEENUM_Invisible;
-}
-static inline void XFA_ItemLayoutProcessor_CalculateContainerSpecfiedSize(
-    CXFA_Node* pFormNode,
-    FX_FLOAT& fContainerWidth,
-    FX_FLOAT& fContainerHeight,
-    bool& bContainerWidthAutoSize,
-    bool& bContainerHeightAutoSize) {
-  fContainerWidth = 0;
-  fContainerHeight = 0;
-  bContainerWidthAutoSize = true;
-  bContainerHeightAutoSize = true;
-  XFA_Element eType = pFormNode->GetElementType();
-  CXFA_Measurement mTmpValue;
-  if (bContainerWidthAutoSize &&
-      (eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup) &&
-      pFormNode->TryMeasure(XFA_ATTRIBUTE_W, mTmpValue, false) &&
-      mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
-    fContainerWidth = mTmpValue.ToUnit(XFA_UNIT_Pt);
-    bContainerWidthAutoSize = false;
-  }
-  if (bContainerHeightAutoSize &&
-      (eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup) &&
-      pFormNode->TryMeasure(XFA_ATTRIBUTE_H, mTmpValue, false) &&
-      mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
-    fContainerHeight = mTmpValue.ToUnit(XFA_UNIT_Pt);
-    bContainerHeightAutoSize = false;
-  }
-  if (bContainerWidthAutoSize && eType == XFA_Element::Subform &&
-      pFormNode->TryMeasure(XFA_ATTRIBUTE_MaxW, mTmpValue, false) &&
-      mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
-    fContainerWidth = mTmpValue.ToUnit(XFA_UNIT_Pt);
-    bContainerWidthAutoSize = false;
-  }
-  if (bContainerHeightAutoSize && eType == XFA_Element::Subform &&
-      pFormNode->TryMeasure(XFA_ATTRIBUTE_MaxH, mTmpValue, false) &&
-      mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
-    fContainerHeight = mTmpValue.ToUnit(XFA_UNIT_Pt);
-    bContainerHeightAutoSize = false;
-  }
-}
-static inline void
-XFA_ItemLayoutProcessor_CalculateContainerComponentSizeFromContentSize(
-    CXFA_Node* pFormNode,
+
+XFA_ItemLayoutProcessorResult InsertFlowedItem(
+    CXFA_ItemLayoutProcessor* pThis,
+    CXFA_ItemLayoutProcessor* pProcessor,
     bool bContainerWidthAutoSize,
-    FX_FLOAT fContentCalculatedWidth,
-    FX_FLOAT& fContainerWidth,
     bool bContainerHeightAutoSize,
-    FX_FLOAT fContentCalculatedHeight,
-    FX_FLOAT& fContainerHeight) {
-  CXFA_Node* pMarginNode = pFormNode->GetFirstChildByClass(XFA_Element::Margin);
-  CXFA_Measurement mTmpValue;
-  if (bContainerWidthAutoSize) {
-    fContainerWidth = fContentCalculatedWidth;
-    if (pMarginNode) {
-      if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_LeftInset, mTmpValue, false)) {
-        fContainerWidth += mTmpValue.ToUnit(XFA_UNIT_Pt);
-      }
-      if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_RightInset, mTmpValue, false)) {
-        fContainerWidth += mTmpValue.ToUnit(XFA_UNIT_Pt);
+    FX_FLOAT fContainerHeight,
+    XFA_ATTRIBUTEENUM eFlowStrategy,
+    uint8_t* uCurHAlignState,
+    CFX_ArrayTemplate<CXFA_ContentLayoutItem*> (&rgCurLineLayoutItems)[3],
+    bool bUseBreakControl,
+    FX_FLOAT fAvailHeight,
+    FX_FLOAT fRealHeight,
+    FX_FLOAT fContentWidthLimit,
+    FX_FLOAT* fContentCurRowY,
+    FX_FLOAT* fContentCurRowAvailWidth,
+    FX_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->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->GetNodeItem(XFA_NODEITEM_Parent)->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 (bContainerHeightAutoSize) {
-    fContainerHeight = fContentCalculatedHeight;
-    if (pMarginNode) {
-      if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_TopInset, mTmpValue, false)) {
-        fContainerHeight += mTmpValue.ToUnit(XFA_UNIT_Pt);
+
+  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);
       }
-      if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_BottomInset, mTmpValue,
-                                  false)) {
-        fContainerHeight += mTmpValue.ToUnit(XFA_UNIT_Pt);
+
+      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].Add(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].Add(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;
+  FX_FLOAT fSplitPos =
+      pProcessor->FindSplitPos(fAvailHeight - *fContentCurRowY);
+  if (fSplitPos > XFA_LAYOUT_FLOAT_PERCISION) {
+    XFA_ATTRIBUTEENUM eLayout =
+        pProcessor->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
+    if (eLayout == XFA_ATTRIBUTEENUM_Tb &&
+        eRetValue == XFA_ItemLayoutProcessorResult::Done) {
+      pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
+                                       pOverflowTrailerNode, pTrailerLayoutItem,
+                                       pFormNode);
+      rgCurLineLayoutItems[uHAlign].Add(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].Add(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].Add(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->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,
+                            FX_FLOAT fCurVerticalOffset,
+                            FX_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();
+      FX_FLOAT fCurTopMargin = 0, fCurBottomMargin = 0;
+      CXFA_Node* pMarginNode =
+          pFormNode->GetFirstChildByClass(XFA_Element::Margin);
+      if (pMarginNode && bCalculateMargin) {
+        fCurTopMargin =
+            pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset).ToUnit(XFA_UNIT_Pt);
+        fCurBottomMargin = pMarginNode->GetMeasure(XFA_ATTRIBUTE_BottomInset)
+                               .ToUnit(XFA_UNIT_Pt);
+      }
+      bool bChanged = true;
+      while (bChanged) {
+        bChanged = false;
+        {
+          FX_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;
+            }
+          }
+        }
+        FX_FLOAT fRelSplitPos = *fProposedSplitPos - fCurBottomMargin;
+        for (CXFA_ContentLayoutItem* pChildItem =
+                 (CXFA_ContentLayoutItem*)pLayoutItem->m_pFirstChild;
+             pChildItem;
+             pChildItem = (CXFA_ContentLayoutItem*)pChildItem->m_pNextSibling) {
+          FX_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;
   }
 }
-void CXFA_ItemLayoutProcessor::CalculatePositionedContainerPos(
-    CXFA_Node* pNode,
-    FX_FLOAT fWidth,
-    FX_FLOAT fHeight,
-    FX_FLOAT& fAbsoluteX,
-    FX_FLOAT& fAbsoluteY) {
+
+CFX_PointF CalculatePositionedContainerPos(CXFA_Node* pNode,
+                                           const CFX_SizeF& size) {
   XFA_ATTRIBUTEENUM eAnchorType = pNode->GetEnum(XFA_ATTRIBUTE_AnchorType);
   int32_t nAnchorType = 0;
   switch (eAnchorType) {
@@ -1004,80 +1061,533 @@
                                          {8, 7, 6, 5, 4, 3, 2, 1, 0},
                                          {2, 5, 8, 1, 4, 7, 0, 3, 6}};
 
-  FX_FLOAT fAnchorX = pNode->GetMeasure(XFA_ATTRIBUTE_X).ToUnit(XFA_UNIT_Pt);
-  FX_FLOAT fAnchorY = pNode->GetMeasure(XFA_ATTRIBUTE_Y).ToUnit(XFA_UNIT_Pt);
+  CFX_PointF pos(pNode->GetMeasure(XFA_ATTRIBUTE_X).ToUnit(XFA_UNIT_Pt),
+                 pNode->GetMeasure(XFA_ATTRIBUTE_Y).ToUnit(XFA_UNIT_Pt));
   int32_t nRotate =
       FXSYS_round(pNode->GetMeasure(XFA_ATTRIBUTE_Rotate).GetValue());
   nRotate = XFA_MapRotation(nRotate) / 90;
   int32_t nAbsoluteAnchorType = nNextPos[nRotate][nAnchorType];
-  fAbsoluteX = fAnchorX;
-  fAbsoluteY = fAnchorY;
   switch (nAbsoluteAnchorType / 3) {
     case 1:
-      fAbsoluteY -= fHeight / 2;
+      pos.y -= size.height / 2;
       break;
     case 2:
-      fAbsoluteY -= fHeight;
+      pos.y -= size.height;
       break;
     default:
       break;
   }
   switch (nAbsoluteAnchorType % 3) {
     case 1:
-      fAbsoluteX -= fWidth / 2;
+      pos.x -= size.width / 2;
       break;
     case 2:
-      fAbsoluteX -= fWidth;
+      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 =
+      (CXFA_ContentLayoutItem*)m_pFormNode->GetUserData(XFA_LAYOUTITEMKEY);
+}
+
+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 = (CXFA_ContentLayoutItem*)pFormNode->GetDocument()
+                    ->GetNotify()
+                    ->OnCreateLayoutItem(pFormNode);
+  CXFA_ContentLayoutItem* pPrevLayoutItem =
+      (CXFA_ContentLayoutItem*)pFormNode->GetUserData(XFA_LAYOUTITEMKEY);
+  if (pPrevLayoutItem) {
+    while (pPrevLayoutItem->m_pNext)
+      pPrevLayoutItem = pPrevLayoutItem->m_pNext;
+
+    pPrevLayoutItem->m_pNext = pLayoutItem;
+    pLayoutItem->m_pPrev = pPrevLayoutItem;
+  } else {
+    pFormNode->SetUserData(XFA_LAYOUTITEMKEY, pLayoutItem);
+  }
+  return pLayoutItem;
+}
+
+FX_FLOAT CXFA_ItemLayoutProcessor::FindSplitPos(FX_FLOAT fProposedSplitPos) {
+  ASSERT(m_pLayoutItem);
+  XFA_ATTRIBUTEENUM eLayout = m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
+  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,
+    FX_FLOAT fSplitPos) {
+  FX_FLOAT fCurTopMargin = 0, fCurBottomMargin = 0;
+  XFA_ATTRIBUTEENUM eLayout = m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
+  bool bCalculateMargin = true;
+  if (eLayout == XFA_ATTRIBUTEENUM_Position)
+    bCalculateMargin = false;
+
+  CXFA_Node* pMarginNode =
+      pLayoutItem->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
+  if (pMarginNode && bCalculateMargin) {
+    fCurTopMargin =
+        pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset).ToUnit(XFA_UNIT_Pt);
+    fCurBottomMargin =
+        pMarginNode->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;
+  FX_FLOAT lHeightForKeep = 0;
+  CFX_ArrayTemplate<CXFA_ContentLayoutItem*> keepLayoutItems;
+  FX_FLOAT fAddMarginHeight = 0;
+  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 (int32_t iIndex = 0; iIndex < keepLayoutItems.GetSize(); iIndex++) {
+          CXFA_ContentLayoutItem* pPreItem = keepLayoutItems[iIndex];
+          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.Add(pChildItem);
+      else
+        keepLayoutItems.RemoveAll();
+
+      continue;
+    }
+
+    FX_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(FX_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->GetNodeItem(XFA_NODEITEM_Parent);
+      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->GetNodeItem(XFA_NODEITEM_FirstChild);
+      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->GetNodeItem(XFA_NODEITEM_FirstChild)
+                     : pCurActionNode->GetNodeItem(XFA_NODEITEM_NextSibling);
+             pBookendNode; pBookendNode = pBookendNode->GetNodeItem(
+                               XFA_NODEITEM_NextSibling)) {
+          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->GetNodeItem(XFA_NODEITEM_NextSibling);
+            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->GetNodeItem(XFA_NODEITEM_FirstChild);
+          if (!m_bKeepBreakFinish &&
+              FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage,
+                            false)) {
+            return;
+          }
+        } else {
+          CXFA_Node* pBreakAfterNode =
+              pCurActionNode->GetNodeItem(XFA_NODEITEM_NextSibling);
+          if (FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage,
+                            false)) {
+            return;
+          }
+        }
+        goto CheckNextChildContainer;
+      }
+    }
+
+    CheckNextChildContainer : {
+      CXFA_Node* pNextChildContainer =
+          pChildContainer == XFA_LAYOUT_INVALIDNODE
+              ? pEntireContainer->GetNodeItem(XFA_NODEITEM_FirstChild,
+                                              XFA_ObjectType::ContainerNode)
+              : pChildContainer->GetNodeItem(XFA_NODEITEM_NextSibling,
+                                             XFA_ObjectType::ContainerNode);
+      while (pNextChildContainer &&
+             pNextChildContainer->IsLayoutGeneratedNode()) {
+        CXFA_Node* pSaveNode = pNextChildContainer;
+        pNextChildContainer = pNextChildContainer->GetNodeItem(
+            XFA_NODEITEM_NextSibling, XFA_ObjectType::ContainerNode);
+        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->GetNodeItem(XFA_NODEITEM_FirstChild),
+              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->GetNodeItem(XFA_NODEITEM_FirstChild)
+                     : pCurActionNode->GetNodeItem(XFA_NODEITEM_NextSibling);
+             pBookendNode; pBookendNode = pBookendNode->GetNodeItem(
+                               XFA_NODEITEM_NextSibling)) {
+          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->GetNodeItem(XFA_NODEITEM_FirstChild),
+                      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->GetNodeItem(XFA_NODEITEM_FirstChild);
+  return FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage, false);
+}
+
+bool XFA_ItemLayoutProcessor_IsTakingSpace(CXFA_Node* pNode) {
+  XFA_ATTRIBUTEENUM ePresence = pNode->GetEnum(XFA_ATTRIBUTE_Presence);
+  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;
+      XFA_ItemLayoutProcessorStages::None;
   CXFA_LayoutItem* pBeforeItem = nullptr;
-  for (XFA_ItemLayoutProcessor_GotoNextContainerNode(
-           pCurChildNode, nCurChildNodeStage, pFormNode, false);
-       pCurChildNode; XFA_ItemLayoutProcessor_GotoNextContainerNode(
-           pCurChildNode, nCurChildNodeStage, pFormNode, false)) {
-    if (nCurChildNodeStage != XFA_ItemLayoutProcessorStages_Container) {
+  for (GotoNextContainerNode(pCurChildNode, nCurChildNodeStage, pFormNode,
+                             false);
+       pCurChildNode; GotoNextContainerNode(pCurChildNode, nCurChildNodeStage,
+                                            pFormNode, false)) {
+    if (nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Container)
       continue;
-    }
-    if (pCurChildNode->GetElementType() == XFA_Element::Variables) {
+    if (pCurChildNode->GetElementType() == XFA_Element::Variables)
       continue;
-    }
-    CXFA_ItemLayoutProcessor* pProcessor =
-        new CXFA_ItemLayoutProcessor(pCurChildNode, nullptr);
-    pProcessor->DoLayout(false, XFA_LAYOUT_FLOAT_MAX);
-    if (!pProcessor->HasLayoutItem()) {
-      delete pProcessor;
+
+    auto pProcessor =
+        pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pCurChildNode, nullptr);
+    pProcessor->DoLayout(false, FLT_MAX, FLT_MAX, nullptr);
+    if (!pProcessor->HasLayoutItem())
       continue;
-    }
-    FX_FLOAT fWidth, fHeight;
-    pProcessor->GetCurrentComponentSize(fWidth, fHeight);
-    FX_FLOAT fAbsoluteX = 0, fAbsoluteY = 0;
-    CalculatePositionedContainerPos(pCurChildNode, fWidth, fHeight, fAbsoluteX,
-                                    fAbsoluteY);
-    pProcessor->SetCurrentComponentPos(fAbsoluteX, fAbsoluteY);
+
+    pProcessor->SetCurrentComponentPos(CalculatePositionedContainerPos(
+        pCurChildNode, pProcessor->GetCurrentComponentSize()));
     CXFA_LayoutItem* pProcessItem = pProcessor->ExtractLayoutItem();
-    if (!pBeforeItem) {
+    if (!pBeforeItem)
       pPageAreaLayoutItem->AddHeadChild(pProcessItem);
-    } else {
+    else
       pPageAreaLayoutItem->InsertChild(pBeforeItem, pProcessItem);
-    }
+
     pBeforeItem = pProcessItem;
-    delete pProcessor;
   }
+
   pBeforeItem = nullptr;
   CXFA_LayoutItem* pLayoutItem = pPageAreaLayoutItem->m_pFirstChild;
   while (pLayoutItem) {
@@ -1086,19 +1596,21 @@
       pLayoutItem = pLayoutItem->m_pNextSibling;
       continue;
     }
-    if (pLayoutItem->m_pFormNode->GetElementType() == XFA_Element::Draw) {
-      CXFA_LayoutItem* pNextLayoutItem = pLayoutItem->m_pNextSibling;
-      pPageAreaLayoutItem->RemoveChild(pLayoutItem);
-      if (!pBeforeItem) {
-        pPageAreaLayoutItem->AddHeadChild(pLayoutItem);
-      } else {
-        pPageAreaLayoutItem->InsertChild(pBeforeItem, pLayoutItem);
-      }
-      pBeforeItem = pLayoutItem;
-      pLayoutItem = pNextLayoutItem;
-    }
+    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)
@@ -1107,29 +1619,30 @@
   m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
   bool bIgnoreXY = (m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout) !=
                     XFA_ATTRIBUTEENUM_Position);
-  FX_FLOAT fContainerWidth = 0, fContainerHeight = 0;
-  bool bContainerWidthAutoSize = true, bContainerHeightAutoSize = true;
-  XFA_ItemLayoutProcessor_CalculateContainerSpecfiedSize(
-      m_pFormNode, fContainerWidth, fContainerHeight, bContainerWidthAutoSize,
-      bContainerHeightAutoSize);
-  FX_FLOAT fContentCalculatedWidth = 0, fContentCalculatedHeight = 0;
-  FX_FLOAT fHiddenContentCalculatedWidth = 0,
-           fHiddenContentCalculatedHeight = 0;
+  bool bContainerWidthAutoSize = true;
+  bool bContainerHeightAutoSize = true;
+  CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
+      m_pFormNode, &bContainerWidthAutoSize, &bContainerHeightAutoSize);
+
+  FX_FLOAT fContentCalculatedWidth = 0;
+  FX_FLOAT fContentCalculatedHeight = 0;
+  FX_FLOAT fHiddenContentCalculatedWidth = 0;
+  FX_FLOAT fHiddenContentCalculatedHeight = 0;
   if (m_pCurChildNode == XFA_LAYOUT_INVALIDNODE) {
-    XFA_ItemLayoutProcessor_GotoNextContainerNode(
-        m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, false);
+    GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode,
+                          false);
   }
+
   int32_t iColIndex = 0;
-  for (; m_pCurChildNode; XFA_ItemLayoutProcessor_GotoNextContainerNode(
+  for (; m_pCurChildNode; GotoNextContainerNode(
            m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, false)) {
-    if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages_Container) {
+    if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Container)
       continue;
-    }
-    if (m_pCurChildNode->GetElementType() == XFA_Element::Variables) {
+    if (m_pCurChildNode->GetElementType() == XFA_Element::Variables)
       continue;
-    }
-    CXFA_ItemLayoutProcessor* pProcessor =
-        new CXFA_ItemLayoutProcessor(m_pCurChildNode, m_pPageMgr);
+
+    auto pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
+        m_pCurChildNode, m_pPageMgr);
     if (pContext && pContext->m_prgSpecifiedColumnWidths) {
       int32_t iColSpan = m_pCurChildNode->GetInteger(XFA_ATTRIBUTE_ColSpan);
       if (iColSpan <=
@@ -1138,39 +1651,37 @@
         pContext->m_bCurColumnWidthAvaiable = true;
         if (iColSpan == -1)
           iColSpan = pContext->m_prgSpecifiedColumnWidths->GetSize();
+
         for (int32_t i = 0; iColIndex + i < iColSpan; ++i) {
           pContext->m_fCurColumnWidth +=
               pContext->m_prgSpecifiedColumnWidths->GetAt(iColIndex + i);
         }
         if (pContext->m_fCurColumnWidth == 0)
           pContext->m_bCurColumnWidthAvaiable = false;
+
         iColIndex += iColSpan >= 0 ? iColSpan : 0;
       }
     }
-    pProcessor->DoLayout(false, XFA_LAYOUT_FLOAT_MAX, XFA_LAYOUT_FLOAT_MAX,
-                         pContext);
-    if (!pProcessor->HasLayoutItem()) {
-      delete pProcessor;
+
+    pProcessor->DoLayout(false, FLT_MAX, FLT_MAX, pContext);
+    if (!pProcessor->HasLayoutItem())
       continue;
-    }
-    FX_FLOAT fWidth, fHeight;
-    pProcessor->GetCurrentComponentSize(fWidth, fHeight);
+
+    CFX_SizeF size = pProcessor->GetCurrentComponentSize();
     bool bChangeParentSize = false;
-    if (XFA_ItemLayoutProcessor_IsTakingSpace(m_pCurChildNode)) {
+    if (XFA_ItemLayoutProcessor_IsTakingSpace(m_pCurChildNode))
       bChangeParentSize = true;
-    }
-    FX_FLOAT fAbsoluteX = 0, fAbsoluteY = 0;
-    if (!bIgnoreXY) {
-      CalculatePositionedContainerPos(m_pCurChildNode, fWidth, fHeight,
-                                      fAbsoluteX, fAbsoluteY);
-    }
-    pProcessor->SetCurrentComponentPos(fAbsoluteX, fAbsoluteY);
+
+    CFX_PointF absolutePos;
+    if (!bIgnoreXY)
+      absolutePos = CalculatePositionedContainerPos(m_pCurChildNode, size);
+
+    pProcessor->SetCurrentComponentPos(absolutePos);
     if (bContainerWidthAutoSize) {
-      FX_FLOAT fChildSuppliedWidth = fAbsoluteX + fWidth;
+      FX_FLOAT fChildSuppliedWidth = absolutePos.x + size.width;
       if (bChangeParentSize) {
-        if (fContentCalculatedWidth < fChildSuppliedWidth) {
-          fContentCalculatedWidth = fChildSuppliedWidth;
-        }
+        fContentCalculatedWidth =
+            std::max(fContentCalculatedWidth, fChildSuppliedWidth);
       } else {
         if (fHiddenContentCalculatedWidth < fChildSuppliedWidth &&
             m_pCurChildNode->GetElementType() != XFA_Element::Subform) {
@@ -1178,12 +1689,12 @@
         }
       }
     }
+
     if (bContainerHeightAutoSize) {
-      FX_FLOAT fChildSuppliedHeight = fAbsoluteY + fHeight;
+      FX_FLOAT fChildSuppliedHeight = absolutePos.y + size.height;
       if (bChangeParentSize) {
-        if (fContentCalculatedHeight < fChildSuppliedHeight) {
-          fContentCalculatedHeight = fChildSuppliedHeight;
-        }
+        fContentCalculatedHeight =
+            std::max(fContentCalculatedHeight, fChildSuppliedHeight);
       } else {
         if (fHiddenContentCalculatedHeight < fChildSuppliedHeight &&
             m_pCurChildNode->GetElementType() != XFA_Element::Subform) {
@@ -1192,201 +1703,35 @@
       }
     }
     m_pLayoutItem->AddChild(pProcessor->ExtractLayoutItem());
-    delete pProcessor;
   }
+
   XFA_VERSION eVersion = m_pFormNode->GetDocument()->GetCurVersionMode();
-  if (fContentCalculatedWidth == 0 && eVersion < XFA_VERSION_207) {
+  if (fContentCalculatedWidth == 0 && eVersion < XFA_VERSION_207)
     fContentCalculatedWidth = fHiddenContentCalculatedWidth;
-  }
-  if (fContentCalculatedHeight == 0 && eVersion < XFA_VERSION_207) {
+  if (fContentCalculatedHeight == 0 && eVersion < XFA_VERSION_207)
     fContentCalculatedHeight = fHiddenContentCalculatedHeight;
-  }
-  XFA_ItemLayoutProcessor_CalculateContainerComponentSizeFromContentSize(
+
+  containerSize = CalculateContainerComponentSizeFromContentSize(
       m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
-      fContainerWidth, bContainerHeightAutoSize, fContentCalculatedHeight,
-      fContainerHeight);
-  SetCurrentComponentSize(fContainerWidth, fContainerHeight);
+      bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
+  SetCurrentComponentSize(containerSize);
 }
-static inline void XFA_ItemLayoutProcessor_UpdateWidgetSize(
-    CXFA_ContentLayoutItem* pLayoutItem,
-    FX_FLOAT& fWidth,
-    FX_FLOAT& fHeight) {
-  CXFA_Node* pNode = pLayoutItem->m_pFormNode;
-  ASSERT(pNode);
-  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.x;
-      }
-      if (fHeight < -XFA_LAYOUT_FLOAT_PERCISION) {
-        fHeight = pLayoutItem->m_sSize.y;
-      }
-      break;
-    }
-    case XFA_Element::Draw:
-    case XFA_Element::Field: {
-      pNode->GetDocument()->GetNotify()->StartFieldDrawLayout(pNode, fWidth,
-                                                              fHeight);
-      break;
-    }
-    default:
-      ASSERT(false);
-  }
-}
-static inline void XFA_ItemLayoutProcessor_RelocateTableRowCells(
-    CXFA_ContentLayoutItem* pLayoutRow,
-    const CFX_ArrayTemplate<FX_FLOAT>& rgSpecifiedColumnWidths,
-    XFA_ATTRIBUTEENUM eLayout) {
-  FX_FLOAT fContainerWidth = 0, fContainerHeight = 0;
-  bool bContainerWidthAutoSize = true, bContainerHeightAutoSize = true;
-  XFA_ItemLayoutProcessor_CalculateContainerSpecfiedSize(
-      pLayoutRow->m_pFormNode, fContainerWidth, fContainerHeight,
-      bContainerWidthAutoSize, bContainerHeightAutoSize);
-  CXFA_Node* pMarginNode =
-      pLayoutRow->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
-  FX_FLOAT fLeftInset = 0, fTopInset = 0, fRightInset = 0, fBottomInset = 0;
-  if (pMarginNode) {
-    fLeftInset =
-        pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
-    fTopInset =
-        pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset).ToUnit(XFA_UNIT_Pt);
-    fRightInset =
-        pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
-    fBottomInset =
-        pMarginNode->GetMeasure(XFA_ATTRIBUTE_BottomInset).ToUnit(XFA_UNIT_Pt);
-  }
-  FX_FLOAT fContentWidthLimit =
-      bContainerWidthAutoSize ? XFA_LAYOUT_FLOAT_MAX
-                              : fContainerWidth - fLeftInset - fRightInset;
-  FX_FLOAT fContentCurrentHeight =
-      pLayoutRow->m_sSize.y - fTopInset - fBottomInset;
-  FX_FLOAT fContentCalculatedWidth = 0, fContentCalculatedHeight = 0;
-  FX_FLOAT fCurrentColX = 0;
-  int32_t nCurrentColIdx = 0;
-  bool bMetWholeRowCell = false;
-  for (CXFA_ContentLayoutItem* pLayoutChild =
-           (CXFA_ContentLayoutItem*)pLayoutRow->m_pFirstChild;
-       pLayoutChild;
-       pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
-    int32_t nOriginalColSpan =
-        pLayoutChild->m_pFormNode->GetInteger(XFA_ATTRIBUTE_ColSpan);
-    int32_t nColSpan = nOriginalColSpan;
-    FX_FLOAT fColSpanWidth = 0;
-    if (nColSpan == -1 ||
-        nCurrentColIdx + nColSpan > rgSpecifiedColumnWidths.GetSize()) {
-      nColSpan = rgSpecifiedColumnWidths.GetSize() - 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.y);
-    }
-    if (nOriginalColSpan == -1) {
-      bMetWholeRowCell = true;
-    }
-    pLayoutChild->m_sPos = CFX_PointF(fCurrentColX, 0);
-    pLayoutChild->m_sSize.x = fColSpanWidth;
-    if (XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode)) {
-      fCurrentColX += fColSpanWidth;
-      nCurrentColIdx += nColSpan;
-      FX_FLOAT fNewHeight =
-          bContainerHeightAutoSize ? -1 : fContentCurrentHeight;
-      XFA_ItemLayoutProcessor_UpdateWidgetSize(pLayoutChild, fColSpanWidth,
-                                               fNewHeight);
-      pLayoutChild->m_sSize.y = fNewHeight;
-      if (bContainerHeightAutoSize) {
-        FX_FLOAT fChildSuppliedHeight = pLayoutChild->m_sSize.y;
-        if (fContentCalculatedHeight < fChildSuppliedHeight) {
-          fContentCalculatedHeight = fChildSuppliedHeight;
-        }
-      }
-    }
-  }
-  if (bContainerHeightAutoSize) {
-    for (CXFA_ContentLayoutItem* pLayoutChild =
-             (CXFA_ContentLayoutItem*)pLayoutRow->m_pFirstChild;
-         pLayoutChild;
-         pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
-      XFA_ItemLayoutProcessor_UpdateWidgetSize(
-          pLayoutChild, pLayoutChild->m_sSize.x, fContentCalculatedHeight);
-      FX_FLOAT fOldChildHeight = pLayoutChild->m_sSize.y;
-      pLayoutChild->m_sSize.y = fContentCalculatedHeight;
-      CXFA_Node* pParaNode =
-          pLayoutChild->m_pFormNode->GetFirstChildByClass(XFA_Element::Para);
-      if (pParaNode && pLayoutChild->m_pFirstChild) {
-        FX_FLOAT fOffHeight = fContentCalculatedHeight - fOldChildHeight;
-        XFA_ATTRIBUTEENUM eVType = pParaNode->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) {
-    FX_FLOAT fChildSuppliedWidth = fCurrentColX;
-    if (fContentWidthLimit < XFA_LAYOUT_FLOAT_MAX &&
-        fContentWidthLimit > fChildSuppliedWidth) {
-      fChildSuppliedWidth = fContentWidthLimit;
-    }
-    if (fContentCalculatedWidth < fChildSuppliedWidth) {
-      fContentCalculatedWidth = fChildSuppliedWidth;
-    }
-  } else {
-    fContentCalculatedWidth = fContainerWidth - fLeftInset - fRightInset;
-  }
-  if (pLayoutRow->m_pFormNode->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.x;
-    }
-  }
-  XFA_ItemLayoutProcessor_CalculateContainerComponentSizeFromContentSize(
-      pLayoutRow->m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
-      fContainerWidth, bContainerHeightAutoSize, fContentCalculatedHeight,
-      fContainerHeight);
-  pLayoutRow->m_sSize = CFX_SizeF(fContainerWidth, fContainerHeight);
-}
+
 void CXFA_ItemLayoutProcessor::DoLayoutTableContainer(CXFA_Node* pLayoutNode) {
   if (m_pLayoutItem)
     return;
-
-  if (!pLayoutNode) {
+  if (!pLayoutNode)
     pLayoutNode = m_pFormNode;
-  }
+
   ASSERT(m_pCurChildNode == XFA_LAYOUT_INVALIDNODE);
+
   m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
-  FX_FLOAT fContainerWidth = 0, fContainerHeight = 0;
-  bool bContainerWidthAutoSize = true, bContainerHeightAutoSize = true;
-  XFA_ItemLayoutProcessor_CalculateContainerSpecfiedSize(
-      m_pFormNode, fContainerWidth, fContainerHeight, bContainerWidthAutoSize,
-      bContainerHeightAutoSize);
-  FX_FLOAT fContentCalculatedWidth = 0, fContentCalculatedHeight = 0;
+  bool bContainerWidthAutoSize = true;
+  bool bContainerHeightAutoSize = true;
+  CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
+      m_pFormNode, &bContainerWidthAutoSize, &bContainerHeightAutoSize);
+  FX_FLOAT fContentCalculatedWidth = 0;
+  FX_FLOAT fContentCalculatedHeight = 0;
   CXFA_Node* pMarginNode =
       m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
   FX_FLOAT fLeftInset = 0;
@@ -1397,54 +1742,52 @@
     fRightInset =
         pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
   }
+
   FX_FLOAT fContentWidthLimit =
-      bContainerWidthAutoSize ? XFA_LAYOUT_FLOAT_MAX
-                              : fContainerWidth - fLeftInset - fRightInset;
+      bContainerWidthAutoSize ? FLT_MAX
+                              : containerSize.width - fLeftInset - fRightInset;
   CFX_WideStringC wsColumnWidths;
   if (pLayoutNode->TryCData(XFA_ATTRIBUTE_ColumnWidths, wsColumnWidths)) {
-    std::vector<CFX_WideString> widths;
-    if (SeparateStringW(wsColumnWidths.c_str(), wsColumnWidths.GetLength(),
-                        L' ', widths) > 0) {
-      int32_t iCols = pdfium::CollectionSize<int32_t>(widths);
-      CFX_WideString wsWidth;
-      for (int32_t i = 0; i < iCols; i++) {
-        wsWidth = widths[i];
-        wsWidth.TrimLeft(L' ');
-        if (!wsWidth.IsEmpty()) {
-          CXFA_Measurement measure(wsWidth.AsStringC());
-          m_rgSpecifiedColumnWidths.Add(measure.ToUnit(XFA_UNIT_Pt));
-        }
-      }
+    auto widths = SeparateStringW(wsColumnWidths.c_str(),
+                                  wsColumnWidths.GetLength(), L' ');
+    for (auto& width : widths) {
+      width.TrimLeft(L' ');
+      if (width.IsEmpty())
+        continue;
+
+      CXFA_Measurement measure(width.AsStringC());
+      m_rgSpecifiedColumnWidths.Add(measure.ToUnit(XFA_UNIT_Pt));
     }
   }
+
   int32_t iSpecifiedColumnCount = m_rgSpecifiedColumnWidths.GetSize();
   CXFA_LayoutContext layoutContext;
   layoutContext.m_prgSpecifiedColumnWidths = &m_rgSpecifiedColumnWidths;
   CXFA_LayoutContext* pLayoutContext =
       iSpecifiedColumnCount > 0 ? &layoutContext : nullptr;
   if (m_pCurChildNode == XFA_LAYOUT_INVALIDNODE) {
-    XFA_ItemLayoutProcessor_GotoNextContainerNode(
-        m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, false);
+    GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode,
+                          false);
   }
-  for (; m_pCurChildNode; XFA_ItemLayoutProcessor_GotoNextContainerNode(
+
+  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) {
+    if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Container)
       continue;
-    }
-    CXFA_ItemLayoutProcessor* pProcessor =
-        new CXFA_ItemLayoutProcessor(m_pCurChildNode, m_pPageMgr);
-    pProcessor->DoLayout(false, XFA_LAYOUT_FLOAT_MAX, XFA_LAYOUT_FLOAT_MAX,
-                         pLayoutContext);
-    if (!pProcessor->HasLayoutItem()) {
-      delete pProcessor;
+
+    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());
-    delete pProcessor;
   }
-  int32_t iRowCount = 0, iColCount = 0;
+
+  int32_t iRowCount = 0;
+  int32_t iColCount = 0;
   {
     CFX_ArrayTemplate<CXFA_ContentLayoutItem*> rgRowItems;
     CFX_ArrayTemplate<int32_t> rgRowItemsSpan;
@@ -1453,12 +1796,11 @@
              (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
          pLayoutChild;
          pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
-      if (pLayoutChild->m_pFormNode->GetElementType() != XFA_Element::Subform) {
+      if (pLayoutChild->m_pFormNode->GetElementType() != XFA_Element::Subform)
         continue;
-      }
-      if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode)) {
+      if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode))
         continue;
-      }
+
       XFA_ATTRIBUTEENUM eLayout =
           pLayoutChild->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
       if (eLayout != XFA_ATTRIBUTEENUM_Row &&
@@ -1471,9 +1813,10 @@
         int32_t iColSpan =
             pRowLayoutCell->m_pFormNode->GetInteger(XFA_ATTRIBUTE_ColSpan);
         rgRowItemsSpan.Add(iColSpan);
-        rgRowItemsWidth.Add(pRowLayoutCell->m_sSize.x);
+        rgRowItemsWidth.Add(pRowLayoutCell->m_sSize.width);
       }
     }
+
     iRowCount = rgRowItems.GetSize();
     iColCount = 0;
     bool bMoreColumns = true;
@@ -1495,390 +1838,212 @@
               pNewCell
                   ? pNewCell->m_pFormNode->GetInteger(XFA_ATTRIBUTE_ColSpan)
                   : 0;
-          rgRowItemsWidth[i] = pNewCell ? pNewCell->m_sSize.x : 0;
+          rgRowItemsWidth[i] = pNewCell ? pNewCell->m_sSize.width : 0;
         }
         CXFA_ContentLayoutItem* pCell = rgRowItems[i];
-        if (!pCell) {
+        if (!pCell)
           continue;
-        }
+
         bMoreColumns = true;
-        if (rgRowItemsSpan[i] == 1) {
-          if (iColCount >= iSpecifiedColumnCount) {
-            for (int32_t j = 0, c = iColCount + 1 -
-                                    m_rgSpecifiedColumnWidths.GetSize();
-                 j < c; j++) {
-              m_rgSpecifiedColumnWidths.Add(0);
-            }
-          }
-          if (m_rgSpecifiedColumnWidths[iColCount] <
-              XFA_LAYOUT_FLOAT_PERCISION) {
-            bAutoCol = true;
-          }
-          if (bAutoCol &&
-              m_rgSpecifiedColumnWidths[iColCount] < rgRowItemsWidth[i]) {
-            m_rgSpecifiedColumnWidths[iColCount] = rgRowItemsWidth[i];
-          }
+        if (rgRowItemsSpan[i] != 1)
+          continue;
+
+        if (iColCount >= iSpecifiedColumnCount) {
+          int32_t c = iColCount + 1 - m_rgSpecifiedColumnWidths.GetSize();
+          for (int32_t j = 0; j < c; j++)
+            m_rgSpecifiedColumnWidths.Add(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) {
-        FX_FLOAT fFinalColumnWidth = 0.0f;
-        if (iColCount < m_rgSpecifiedColumnWidths.GetSize())
-          fFinalColumnWidth = m_rgSpecifiedColumnWidths[iColCount];
-        for (int32_t i = 0; i < iRowCount; ++i) {
-          if (!rgRowItems[i])
-            continue;
-          --rgRowItemsSpan[i];
-          rgRowItemsWidth[i] -= fFinalColumnWidth;
-        }
-        ++iColCount;
+
+      if (!bMoreColumns)
+        continue;
+
+      FX_FLOAT fFinalColumnWidth = 0.0f;
+      if (iColCount < m_rgSpecifiedColumnWidths.GetSize())
+        fFinalColumnWidth = m_rgSpecifiedColumnWidths[iColCount];
+      for (int32_t i = 0; i < iRowCount; ++i) {
+        if (!rgRowItems[i])
+          continue;
+        --rgRowItemsSpan[i];
+        rgRowItemsWidth[i] -= fFinalColumnWidth;
       }
+      ++iColCount;
     }
   }
+
   FX_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)) {
+    if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode))
       continue;
-    }
+
     if (pLayoutChild->m_pFormNode->GetElementType() == XFA_Element::Subform) {
       XFA_ATTRIBUTEENUM eSubformLayout =
           pLayoutChild->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
       if (eSubformLayout == XFA_ATTRIBUTEENUM_Row ||
           eSubformLayout == XFA_ATTRIBUTEENUM_Rl_row) {
-        XFA_ItemLayoutProcessor_RelocateTableRowCells(
-            pLayoutChild, m_rgSpecifiedColumnWidths, eSubformLayout);
+        RelocateTableRowCells(pLayoutChild, m_rgSpecifiedColumnWidths,
+                              eSubformLayout);
       }
     }
+
     pLayoutChild->m_sPos.y = fCurrentRowY;
     if (bContainerWidthAutoSize) {
       pLayoutChild->m_sPos.x = 0;
     } else {
       switch (pLayoutChild->m_pFormNode->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;
-        case XFA_ATTRIBUTEENUM_Center:
-          pLayoutChild->m_sPos.x =
-              (fContentWidthLimit - pLayoutChild->m_sSize.x) / 2;
-          break;
-        case XFA_ATTRIBUTEENUM_Right:
-          pLayoutChild->m_sPos.x = fContentWidthLimit - pLayoutChild->m_sSize.x;
-          break;
       }
     }
+
     if (bContainerWidthAutoSize) {
       FX_FLOAT fChildSuppliedWidth =
-          pLayoutChild->m_sPos.x + pLayoutChild->m_sSize.x;
-      if (fContentWidthLimit < XFA_LAYOUT_FLOAT_MAX &&
+          pLayoutChild->m_sPos.x + pLayoutChild->m_sSize.width;
+      if (fContentWidthLimit < FLT_MAX &&
           fContentWidthLimit > fChildSuppliedWidth) {
         fChildSuppliedWidth = fContentWidthLimit;
       }
-      if (fContentCalculatedWidth < fChildSuppliedWidth) {
-        fContentCalculatedWidth = fChildSuppliedWidth;
-      }
+      fContentCalculatedWidth =
+          std::max(fContentCalculatedWidth, fChildSuppliedWidth);
     }
-    fCurrentRowY += pLayoutChild->m_sSize.y;
+    fCurrentRowY += pLayoutChild->m_sSize.height;
   }
-  if (bContainerHeightAutoSize) {
-    FX_FLOAT fChildSuppliedHeight = fCurrentRowY;
-    if (fContentCalculatedHeight < fChildSuppliedHeight) {
-      fContentCalculatedHeight = fChildSuppliedHeight;
-    }
-  }
-  XFA_ItemLayoutProcessor_CalculateContainerComponentSizeFromContentSize(
+
+  if (bContainerHeightAutoSize)
+    fContentCalculatedHeight = std::max(fContentCalculatedHeight, fCurrentRowY);
+
+  containerSize = CalculateContainerComponentSizeFromContentSize(
       m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
-      fContainerWidth, bContainerHeightAutoSize, fContentCalculatedHeight,
-      fContainerHeight);
-  SetCurrentComponentSize(fContainerWidth, fContainerHeight);
+      bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
+  SetCurrentComponentSize(containerSize);
 }
-static uint8_t XFA_ItemLayoutProcessor_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;
-  }
-}
-static void XFA_ItemLayoutProcessor_UpdatePendedItemLayout(
-    CXFA_ItemLayoutProcessor* pProcessor,
-    CXFA_ContentLayoutItem* pLayoutItem) {
-  XFA_ATTRIBUTEENUM eLayout =
-      pLayoutItem->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
-  switch (eLayout) {
-    case XFA_ATTRIBUTEENUM_Row:
-    case XFA_ATTRIBUTEENUM_Rl_row:
-      XFA_ItemLayoutProcessor_RelocateTableRowCells(
-          pLayoutItem, pProcessor->m_rgSpecifiedColumnWidths, eLayout);
-      break;
-    default:
-      break;
-  }
-}
+
 bool CXFA_ItemLayoutProcessor::IsAddNewRowForTrailer(
     CXFA_ContentLayoutItem* pTrailerItem) {
-  if (!pTrailerItem) {
+  if (!pTrailerItem)
     return false;
-  }
-  FX_FLOAT fWidth = pTrailerItem->m_sSize.x;
+
+  FX_FLOAT fWidth = pTrailerItem->m_sSize.width;
   XFA_ATTRIBUTEENUM eLayout = m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
-  if (eLayout != XFA_ATTRIBUTEENUM_Tb && m_fWidthLimite > fWidth) {
-    return false;
-  }
-  return true;
+  return eLayout == XFA_ATTRIBUTEENUM_Tb || m_fWidthLimite <= fWidth;
 }
-static void XFA_ItemLayoutProcessor_AddTrailerBeforeSplit(
-    CXFA_ItemLayoutProcessor* pProcessor,
-    FX_FLOAT fSplitPos,
-    CXFA_ContentLayoutItem* pTrailerLayoutItem,
-    bool bUseInherited = false) {
-  if (!pTrailerLayoutItem) {
-    return;
-  }
-  FX_FLOAT fHeight = pTrailerLayoutItem->m_sSize.y;
-  if (bUseInherited) {
-    FX_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;
-  }
-  XFA_ItemLayoutProcessor_UpdatePendedItemLayout(pProcessor,
-                                                 pTrailerLayoutItem);
-  CXFA_Node* pMarginNode =
-      pProcessor->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
-  FX_FLOAT fLeftInset = 0, fTopInset = 0, fRightInset = 0, fBottomInset = 0;
-  if (pMarginNode) {
-    fLeftInset =
-        pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
-    fTopInset =
-        pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset).ToUnit(XFA_UNIT_Pt);
-    fRightInset =
-        pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
-    fBottomInset =
-        pMarginNode->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.x += pTrailerLayoutItem->m_sSize.x;
-    pProcessor->m_pLayoutItem->AddChild(pTrailerLayoutItem);
-    return;
-  }
-  FX_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->GetEnum(XFA_ATTRIBUTE_HAlign)) {
-    case XFA_ATTRIBUTEENUM_Left:
-    default:
-      pTrailerLayoutItem->m_sPos.x = fLeftInset;
-      break;
-    case XFA_ATTRIBUTEENUM_Right:
-      pTrailerLayoutItem->m_sPos.x = pProcessor->m_pLayoutItem->m_sSize.x -
-                                     fRightInset -
-                                     pTrailerLayoutItem->m_sSize.x;
-      break;
-    case XFA_ATTRIBUTEENUM_Center:
-      pTrailerLayoutItem->m_sPos.x =
-          (pProcessor->m_pLayoutItem->m_sSize.x - fLeftInset - fRightInset -
-           pTrailerLayoutItem->m_sSize.x) /
-          2;
-      break;
-  }
-  pProcessor->m_pLayoutItem->m_sSize.y += fHeight;
-  pProcessor->m_pLayoutItem->AddChild(pTrailerLayoutItem);
-}
-static void XFA_ItemLayoutProcessor_AddLeaderAfterSplit(
-    CXFA_ItemLayoutProcessor* pProcessor,
-    CXFA_ContentLayoutItem* pLeaderLayoutItem) {
-  XFA_ItemLayoutProcessor_UpdatePendedItemLayout(pProcessor, pLeaderLayoutItem);
-  CXFA_Node* pMarginNode =
-      pProcessor->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
-  FX_FLOAT fLeftInset = 0;
-  FX_FLOAT fRightInset = 0;
-  if (pMarginNode) {
-    fLeftInset =
-        pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
-    fRightInset =
-        pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
-  }
-  FX_FLOAT fHeight = pLeaderLayoutItem->m_sSize.y;
-  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->GetEnum(XFA_ATTRIBUTE_HAlign)) {
-    case XFA_ATTRIBUTEENUM_Left:
-    default:
-      pLeaderLayoutItem->m_sPos.x = fLeftInset;
-      break;
-    case XFA_ATTRIBUTEENUM_Right:
-      pLeaderLayoutItem->m_sPos.x = pProcessor->m_pLayoutItem->m_sSize.x -
-                                    fRightInset - pLeaderLayoutItem->m_sSize.x;
-      break;
-    case XFA_ATTRIBUTEENUM_Center:
-      pLeaderLayoutItem->m_sPos.x =
-          (pProcessor->m_pLayoutItem->m_sSize.x - fLeftInset - fRightInset -
-           pLeaderLayoutItem->m_sSize.x) /
-          2;
-      break;
-  }
-  pProcessor->m_pLayoutItem->m_sSize.y += fHeight;
-  pProcessor->m_pLayoutItem->AddChild(pLeaderLayoutItem);
-}
-static void XFA_ItemLayoutProcessor_AddPendingNode(
-    CXFA_ItemLayoutProcessor* pProcessor,
-    CXFA_Node* pPendingNode,
-    bool bBreakPending) {
-  pProcessor->m_PendingNodes.push_back(pPendingNode);
-  pProcessor->m_bBreakPending = bBreakPending;
-}
-static FX_FLOAT XFA_ItemLayoutProcessor_InsertPendingItems(
-    CXFA_ItemLayoutProcessor* pProcessor,
-    CXFA_Node* pCurChildNode) {
-  FX_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()) {
-    std::unique_ptr<CXFA_ItemLayoutProcessor> pPendingProcessor(
-        new CXFA_ItemLayoutProcessor(pProcessor->m_PendingNodes.front(),
-                                     nullptr));
-    pProcessor->m_PendingNodes.pop_front();
-    pPendingProcessor->DoLayout(false, XFA_LAYOUT_FLOAT_MAX);
-    CXFA_ContentLayoutItem* pPendingLayoutItem =
-        pPendingProcessor->HasLayoutItem()
-            ? pPendingProcessor->ExtractLayoutItem()
-            : nullptr;
-    if (pPendingLayoutItem) {
-      XFA_ItemLayoutProcessor_AddLeaderAfterSplit(pProcessor,
-                                                  pPendingLayoutItem);
-      if (pProcessor->m_bBreakPending) {
-        fTotalHeight += pPendingLayoutItem->m_sSize.y;
-      }
-    }
-  }
-  return fTotalHeight;
-}
+
 FX_FLOAT CXFA_ItemLayoutProcessor::InsertKeepLayoutItems() {
-  FX_FLOAT fTotalHeight = 0;
-  if (m_arrayKeepItems.GetSize()) {
-    if (!m_pLayoutItem) {
-      m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
-      m_pLayoutItem->m_sSize.clear();
-    }
-    for (int32_t iIndex = m_arrayKeepItems.GetSize() - 1; iIndex >= 0;
-         iIndex--) {
-      XFA_ItemLayoutProcessor_AddLeaderAfterSplit(this,
-                                                  m_arrayKeepItems[iIndex]);
-      fTotalHeight += m_arrayKeepItems[iIndex]->m_sSize.y;
-    }
-    m_arrayKeepItems.RemoveAll();
+  if (m_arrayKeepItems.empty())
+    return 0;
+
+  if (!m_pLayoutItem) {
+    m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
+    m_pLayoutItem->m_sSize.clear();
   }
+
+  FX_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::ProcessKeepForSplite(
+
+bool CXFA_ItemLayoutProcessor::ProcessKeepForSplit(
     CXFA_ItemLayoutProcessor* pParentProcessor,
     CXFA_ItemLayoutProcessor* pChildProcessor,
     XFA_ItemLayoutProcessorResult eRetValue,
-    CFX_ArrayTemplate<CXFA_ContentLayoutItem*>& rgCurLineLayoutItem,
-    FX_FLOAT& fContentCurRowAvailWidth,
-    FX_FLOAT& fContentCurRowHeight,
-    FX_FLOAT& fContentCurRowY,
-    bool& bAddedItemInRow,
-    bool& bForceEndPage,
-    XFA_ItemLayoutProcessorResult& result) {
-  if (!pParentProcessor || !pChildProcessor) {
+    CFX_ArrayTemplate<CXFA_ContentLayoutItem*>* rgCurLineLayoutItem,
+    FX_FLOAT* fContentCurRowAvailWidth,
+    FX_FLOAT* fContentCurRowHeight,
+    FX_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) {
-    if (XFA_ExistContainerKeep(pParentProcessor->m_pCurChildNode, true)) {
-      FX_FLOAT fChildWidth, fChildHeight;
-      pChildProcessor->GetCurrentComponentSize(fChildWidth, fChildHeight);
-      CFX_ArrayTemplate<CXFA_ContentLayoutItem*> keepLayoutItems;
-      if (pParentProcessor->JudgePutNextPage(pParentProcessor->m_pLayoutItem,
-                                             fChildHeight, keepLayoutItems)) {
-        m_arrayKeepItems.RemoveAll();
-        for (int32_t iIndex = 0; iIndex < keepLayoutItems.GetSize(); iIndex++) {
-          CXFA_ContentLayoutItem* pItem = keepLayoutItems.GetAt(iIndex);
-          pParentProcessor->m_pLayoutItem->RemoveChild(pItem);
-          fContentCurRowY -= pItem->m_sSize.y;
-          m_arrayKeepItems.Add(pItem);
-        }
-        bAddedItemInRow = true;
-        bForceEndPage = true;
-        result = XFA_ItemLayoutProcessorResult_PageFullBreak;
-        return true;
-      }
-      rgCurLineLayoutItem.Add(pChildProcessor->ExtractLayoutItem());
-      bAddedItemInRow = true;
-      fContentCurRowAvailWidth -= fChildWidth;
-      if (fContentCurRowHeight < fChildHeight) {
-        fContentCurRowHeight = fChildHeight;
-      }
-      result = eRetValue;
-      return true;
+
+  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;
   }
-  return false;
+
+  rgCurLineLayoutItem->Add(pChildProcessor->ExtractLayoutItem());
+  *bAddedItemInRow = true;
+  *fContentCurRowAvailWidth -= childSize.width;
+  *fContentCurRowHeight = std::max(*fContentCurRowHeight, childSize.height);
+  *result = eRetValue;
+
+  return true;
 }
+
 bool CXFA_ItemLayoutProcessor::JudgePutNextPage(
     CXFA_ContentLayoutItem* pParentLayoutItem,
     FX_FLOAT fChildHeight,
-    CFX_ArrayTemplate<CXFA_ContentLayoutItem*>& pKeepItems) {
-  if (!pParentLayoutItem) {
+    std::vector<CXFA_ContentLayoutItem*>* pKeepItems) {
+  if (!pParentLayoutItem)
     return false;
-  }
+
   FX_FLOAT fItemsHeight = 0;
   for (CXFA_ContentLayoutItem* pChildLayoutItem =
            (CXFA_ContentLayoutItem*)pParentLayoutItem->m_pFirstChild;
        pChildLayoutItem;
        pChildLayoutItem =
            (CXFA_ContentLayoutItem*)pChildLayoutItem->m_pNextSibling) {
-    if (XFA_ExistContainerKeep(pChildLayoutItem->m_pFormNode, false)) {
-      pKeepItems.Add(pChildLayoutItem);
-      fItemsHeight += pChildLayoutItem->m_sSize.y;
+    if (ExistContainerKeep(pChildLayoutItem->m_pFormNode, false)) {
+      pKeepItems->push_back(pChildLayoutItem);
+      fItemsHeight += pChildLayoutItem->m_sSize.height;
     } else {
-      pKeepItems.RemoveAll();
+      pKeepItems->clear();
       fItemsHeight = 0;
     }
   }
   fItemsHeight += fChildHeight;
-  if (m_pPageMgr->GetNextAvailContentHeight(fItemsHeight)) {
-    return true;
-  }
-  return false;
+  return m_pPageMgr->GetNextAvailContentHeight(fItemsHeight);
 }
+
 void CXFA_ItemLayoutProcessor::ProcessUnUseBinds(CXFA_Node* pFormNode) {
-  if (!pFormNode) {
+  if (!pFormNode)
     return;
-  }
+
   CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> sIterator(
       pFormNode);
   for (CXFA_Node* pNode = sIterator.MoveToNext(); pNode;
@@ -1893,6 +2058,7 @@
     pNode->SetFlag(XFA_NodeFlag_UnusedNode, true);
   }
 }
+
 void CXFA_ItemLayoutProcessor::ProcessUnUseOverFlow(
     CXFA_Node* pLeaderNode,
     CXFA_Node* pTrailerNode,
@@ -1900,370 +2066,19 @@
     CXFA_Node* pFormNode) {
   ProcessUnUseBinds(pLeaderNode);
   ProcessUnUseBinds(pTrailerNode);
-  if (!pFormNode) {
+  if (!pFormNode)
     return;
-  }
+
   if (pFormNode->GetElementType() == XFA_Element::Overflow ||
       pFormNode->GetElementType() == XFA_Element::Break) {
     pFormNode = pFormNode->GetNodeItem(XFA_NODEITEM_Parent);
   }
-  if (pLeaderNode && pFormNode) {
+  if (pLeaderNode && pFormNode)
     pFormNode->RemoveChild(pLeaderNode);
-  }
-  if (pTrailerNode && pFormNode) {
+  if (pTrailerNode && pFormNode)
     pFormNode->RemoveChild(pTrailerNode);
-  }
-  if (pTrailerItem) {
+  if (pTrailerItem)
     XFA_ReleaseLayoutItem(pTrailerItem);
-  }
-}
-static XFA_ItemLayoutProcessorResult XFA_ItemLayoutProcessor_InsertFlowedItem(
-    CXFA_ItemLayoutProcessor* pThis,
-    CXFA_ItemLayoutProcessor* pProcessor,
-    bool bContainerWidthAutoSize,
-    bool bContainerHeightAutoSize,
-    FX_FLOAT fContainerHeight,
-    XFA_ATTRIBUTEENUM eFlowStrategy,
-    uint8_t& uCurHAlignState,
-    CFX_ArrayTemplate<CXFA_ContentLayoutItem*> (&rgCurLineLayoutItems)[3],
-    bool bUseBreakControl,
-    FX_FLOAT fAvailHeight,
-    FX_FLOAT fRealHeight,
-    FX_FLOAT& fContentCurRowY,
-    FX_FLOAT& fContentWidthLimit,
-    FX_FLOAT& fContentCurRowAvailWidth,
-    FX_FLOAT& fContentCurRowHeight,
-    bool& bAddedItemInRow,
-    bool& bForceEndPage,
-    CXFA_LayoutContext* pLayoutContext = nullptr,
-    bool bNewRow = false) {
-  bool bTakeSpace =
-      XFA_ItemLayoutProcessor_IsTakingSpace(pProcessor->m_pFormNode);
-  uint8_t uHAlign = XFA_ItemLayoutProcessor_HAlignEnumToInt(
-      pThis->m_pCurChildNode->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 bIsOwnSplite =
-      pProcessor->m_pFormNode->GetIntact() == XFA_ATTRIBUTEENUM_None;
-  bool bUseRealHeight =
-      bTakeSpace && bContainerHeightAutoSize && bIsOwnSplite &&
-      pProcessor->m_pFormNode->GetNodeItem(XFA_NODEITEM_Parent)->GetIntact() ==
-          XFA_ATTRIBUTEENUM_None;
-  bool bIsTransHeight = bTakeSpace;
-  if (bIsTransHeight && !bIsOwnSplite) {
-    bool bRootForceTb = false;
-    XFA_ATTRIBUTEENUM eLayoutStrategy = XFA_ItemLayoutProcessor_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 : XFA_LAYOUT_FLOAT_MAX,
-        bIsTransHeight ? fRealHeight - fContentCurRowY : XFA_LAYOUT_FLOAT_MAX,
-        pLayoutContext);
-    pProcessor->m_ePreProcessRs = eRetValue;
-  } else {
-    eRetValue = pProcessor->m_ePreProcessRs;
-    pProcessor->m_ePreProcessRs = XFA_ItemLayoutProcessorResult_Done;
-  }
-  if (pProcessor->HasLayoutItem() == false) {
-    return eRetValue;
-  }
-  FX_FLOAT fChildWidth, fChildHeight;
-  pProcessor->GetCurrentComponentSize(fChildWidth, fChildHeight);
-  if (bUseRealHeight && fRealHeight < XFA_LAYOUT_FLOAT_PERCISION) {
-    fRealHeight = XFA_LAYOUT_FLOAT_MAX;
-    fAvailHeight = XFA_LAYOUT_FLOAT_MAX;
-  }
-  if (!bTakeSpace ||
-      (fChildWidth <= fContentCurRowAvailWidth + XFA_LAYOUT_FLOAT_PERCISION) ||
-      (fContentWidthLimit - fContentCurRowAvailWidth <=
-       XFA_LAYOUT_FLOAT_PERCISION)) {
-    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) {
-            CXFA_ItemLayoutProcessor* pOverflowLeaderProcessor =
-                new CXFA_ItemLayoutProcessor(pOverflowTrailerNode, nullptr);
-            pOverflowLeaderProcessor->DoLayout(false, XFA_LAYOUT_FLOAT_MAX);
-            pTrailerLayoutItem =
-                pOverflowLeaderProcessor->HasLayoutItem()
-                    ? pOverflowLeaderProcessor->ExtractLayoutItem()
-                    : nullptr;
-            delete pOverflowLeaderProcessor;
-          }
-          if (bUseInherited) {
-            bIsAddTrailerHeight =
-                pThis->IsAddNewRowForTrailer(pTrailerLayoutItem);
-          } else {
-            bIsAddTrailerHeight =
-                pProcessor->IsAddNewRowForTrailer(pTrailerLayoutItem);
-          }
-          if (bIsAddTrailerHeight) {
-            FX_FLOAT fTrailerHeight = pTrailerLayoutItem->m_sSize.y;
-            fChildHeight += fTrailerHeight;
-            bIsAddTrailerHeight = true;
-          }
-        }
-      }
-    }
-    if (!bTakeSpace ||
-        fContentCurRowY + fChildHeight <=
-            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) {
-            XFA_ItemLayoutProcessor_AddTrailerBeforeSplit(
-                pProcessor, fChildHeight, pTrailerLayoutItem);
-          }
-          if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode)) {
-            XFA_ItemLayoutProcessor_AddPendingNode(pProcessor,
-                                                   pOverflowLeaderNode, false);
-          }
-          pProcessor->m_bUseInheriated = false;
-        } else {
-          if (bIsAddTrailerHeight) {
-            fChildHeight -= pTrailerLayoutItem->m_sSize.y;
-          }
-          pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
-                                           pOverflowTrailerNode,
-                                           pTrailerLayoutItem, pFormNode);
-        }
-        CXFA_ContentLayoutItem* pChildLayoutItem =
-            pProcessor->ExtractLayoutItem();
-        if (XFA_ExistContainerKeep(pProcessor->m_pFormNode, false) &&
-            pProcessor->m_pFormNode->GetIntact() == XFA_ATTRIBUTEENUM_None) {
-          pThis->m_arrayKeepItems.Add(pChildLayoutItem);
-        } else {
-          pThis->m_arrayKeepItems.RemoveAll();
-        }
-        rgCurLineLayoutItems[uHAlign].Add(pChildLayoutItem);
-        bAddedItemInRow = true;
-        if (bTakeSpace) {
-          fContentCurRowAvailWidth -= fChildWidth;
-          if (fContentCurRowHeight < fChildHeight) {
-            fContentCurRowHeight = fChildHeight;
-          }
-        }
-        return XFA_ItemLayoutProcessorResult_Done;
-      } else {
-        if (eRetValue == XFA_ItemLayoutProcessorResult_PageFullBreak) {
-          if (pProcessor->m_bUseInheriated) {
-            if (pTrailerLayoutItem) {
-              XFA_ItemLayoutProcessor_AddTrailerBeforeSplit(
-                  pProcessor, fChildHeight, pTrailerLayoutItem);
-            }
-            if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode)) {
-              XFA_ItemLayoutProcessor_AddPendingNode(
-                  pProcessor, pOverflowLeaderNode, false);
-            }
-            pProcessor->m_bUseInheriated = false;
-          } else {
-            if (bIsAddTrailerHeight) {
-              fChildHeight -= pTrailerLayoutItem->m_sSize.y;
-            }
-            pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
-                                             pOverflowTrailerNode,
-                                             pTrailerLayoutItem, pFormNode);
-          }
-        }
-        rgCurLineLayoutItems[uHAlign].Add(pProcessor->ExtractLayoutItem());
-        bAddedItemInRow = true;
-        fContentCurRowAvailWidth -= fChildWidth;
-        if (fContentCurRowHeight < fChildHeight) {
-          fContentCurRowHeight = fChildHeight;
-        }
-        return eRetValue;
-      }
-    } else {
-      XFA_ItemLayoutProcessorResult eResult;
-      if (pThis->ProcessKeepForSplite(
-              pThis, pProcessor, eRetValue, rgCurLineLayoutItems[uHAlign],
-              fContentCurRowAvailWidth, fContentCurRowHeight, fContentCurRowY,
-              bAddedItemInRow, bForceEndPage, eResult)) {
-        return eResult;
-      }
-      bForceEndPage = true;
-      FX_FLOAT fSplitPos =
-          pProcessor->FindSplitPos(fAvailHeight - fContentCurRowY);
-      if (fSplitPos > XFA_LAYOUT_FLOAT_PERCISION) {
-        XFA_ATTRIBUTEENUM eLayout =
-            pProcessor->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
-        if (eLayout == XFA_ATTRIBUTEENUM_Tb &&
-            eRetValue == XFA_ItemLayoutProcessorResult_Done) {
-          pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
-                                           pOverflowTrailerNode,
-                                           pTrailerLayoutItem, pFormNode);
-          rgCurLineLayoutItems[uHAlign].Add(pProcessor->ExtractLayoutItem());
-          bAddedItemInRow = true;
-          if (bTakeSpace) {
-            fContentCurRowAvailWidth -= fChildWidth;
-            if (fContentCurRowHeight < fChildHeight) {
-              fContentCurRowHeight = fChildHeight;
-            }
-          }
-          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) {
-          XFA_ItemLayoutProcessor_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)) {
-              XFA_ItemLayoutProcessor_AddPendingNode(
-                  pProcessor, pOverflowLeaderNode, false);
-            }
-          }
-        }
-        if (pProcessor->m_pLayoutItem->m_pNextSibling) {
-          pProcessor->GetCurrentComponentSize(fChildWidth, fChildHeight);
-          rgCurLineLayoutItems[uHAlign].Add(pProcessor->ExtractLayoutItem());
-          bAddedItemInRow = true;
-          if (bTakeSpace) {
-            fContentCurRowAvailWidth -= fChildWidth;
-            if (fContentCurRowHeight < fChildHeight) {
-              fContentCurRowHeight = fChildHeight;
-            }
-          }
-        }
-        return XFA_ItemLayoutProcessorResult_PageFullBreak;
-      } else if (fContentCurRowY <= XFA_LAYOUT_FLOAT_PERCISION) {
-        pProcessor->GetCurrentComponentSize(fChildWidth, fChildHeight);
-        if (pProcessor->m_pPageMgr->GetNextAvailContentHeight(fChildHeight)) {
-          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].Add(pProcessor->ExtractLayoutItem());
-        bAddedItemInRow = true;
-        if (bTakeSpace) {
-          fContentCurRowAvailWidth -= fChildWidth;
-          if (fContentCurRowHeight < fChildHeight) {
-            fContentCurRowHeight = fChildHeight;
-          }
-        }
-        if (eRetValue == XFA_ItemLayoutProcessorResult_Done) {
-          bForceEndPage = false;
-        }
-        return eRetValue;
-      } else {
-        XFA_ATTRIBUTEENUM eLayout =
-            pProcessor->m_pFormNode->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) {
-            XFA_ItemLayoutProcessor_AddTrailerBeforeSplit(pProcessor, fSplitPos,
-                                                          pTrailerLayoutItem);
-          }
-          if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode)) {
-            XFA_ItemLayoutProcessor_AddPendingNode(pProcessor,
-                                                   pOverflowLeaderNode, false);
-          }
-        } else {
-          if (eRetValue == XFA_ItemLayoutProcessorResult_Done) {
-            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;
-      }
-    }
-  } else {
-    return XFA_ItemLayoutProcessorResult_RowFullBreak;
-  }
-  return XFA_ItemLayoutProcessorResult_Done;
 }
 
 XFA_ItemLayoutProcessorResult CXFA_ItemLayoutProcessor::DoLayoutFlowedContainer(
@@ -2274,44 +2089,47 @@
     CXFA_LayoutContext* pContext,
     bool bRootForceTb) {
   m_bHasAvailHeight = true;
-  FX_FLOAT fContainerWidth = 0, fContainerHeight = 0;
   bool bBreakDone = false;
-  bool bContainerWidthAutoSize = true, bContainerHeightAutoSize = true;
+  bool bContainerWidthAutoSize = true;
+  bool bContainerHeightAutoSize = true;
   bool bForceEndPage = false;
   bool bIsManualBreak = false;
   if (m_pCurChildPreprocessor) {
     m_pCurChildPreprocessor->m_ePreProcessRs =
-        XFA_ItemLayoutProcessorResult_Done;
+        XFA_ItemLayoutProcessorResult::Done;
   }
-  XFA_ItemLayoutProcessor_CalculateContainerSpecfiedSize(
-      m_pFormNode, fContainerWidth, fContainerHeight, bContainerWidthAutoSize,
-      bContainerHeightAutoSize);
+
+  CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
+      m_pFormNode, &bContainerWidthAutoSize, &bContainerHeightAutoSize);
   if (pContext && pContext->m_bCurColumnWidthAvaiable) {
     bContainerWidthAutoSize = false;
-    fContainerWidth = pContext->m_fCurColumnWidth;
+    containerSize.width = pContext->m_fCurColumnWidth;
   }
-  if (!bContainerHeightAutoSize) {
-    fContainerHeight -= m_fUsedSize;
-  }
+  if (!bContainerHeightAutoSize)
+    containerSize.height -= m_fUsedSize;
+
   if (!bContainerHeightAutoSize) {
     CXFA_Node* pParentNode = m_pFormNode->GetNodeItem(XFA_NODEITEM_Parent);
     bool bFocrTb = false;
     if (pParentNode &&
-        XFA_ItemLayoutProcessor_GetLayout(pParentNode, bFocrTb) ==
-            XFA_ATTRIBUTEENUM_Row) {
+        GetLayout(pParentNode, &bFocrTb) == XFA_ATTRIBUTEENUM_Row) {
       CXFA_Node* pChildContainer = m_pFormNode->GetNodeItem(
           XFA_NODEITEM_FirstChild, XFA_ObjectType::ContainerNode);
       if (pChildContainer &&
           pChildContainer->GetNodeItem(XFA_NODEITEM_NextSibling,
                                        XFA_ObjectType::ContainerNode)) {
-        fContainerHeight = 0;
+        containerSize.height = 0;
         bContainerHeightAutoSize = true;
       }
     }
   }
+
   CXFA_Node* pMarginNode =
       m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
-  FX_FLOAT fLeftInset = 0, fTopInset = 0, fRightInset = 0, fBottomInset = 0;
+  FX_FLOAT fLeftInset = 0;
+  FX_FLOAT fTopInset = 0;
+  FX_FLOAT fRightInset = 0;
+  FX_FLOAT fBottomInset = 0;
   if (pMarginNode) {
     fLeftInset =
         pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
@@ -2323,68 +2141,67 @@
         pMarginNode->GetMeasure(XFA_ATTRIBUTE_BottomInset).ToUnit(XFA_UNIT_Pt);
   }
   FX_FLOAT fContentWidthLimit =
-      bContainerWidthAutoSize ? XFA_LAYOUT_FLOAT_MAX
-                              : fContainerWidth - fLeftInset - fRightInset;
-  FX_FLOAT fContentCalculatedWidth = 0, fContentCalculatedHeight = 0;
+      bContainerWidthAutoSize ? FLT_MAX
+                              : containerSize.width - fLeftInset - fRightInset;
+  FX_FLOAT fContentCalculatedWidth = 0;
+  FX_FLOAT fContentCalculatedHeight = 0;
   FX_FLOAT fAvailHeight = fHeightLimit - fTopInset - fBottomInset;
-  if (fAvailHeight < 0) {
+  if (fAvailHeight < 0)
     m_bHasAvailHeight = false;
-  }
+
   fRealHeight = fRealHeight - fTopInset - fBottomInset;
   FX_FLOAT fContentCurRowY = 0;
   CXFA_ContentLayoutItem* pLayoutChild = nullptr;
   if (m_pLayoutItem) {
-    if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages_Done &&
+    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) {
+        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)) {
-        FX_FLOAT fChildContentWidth =
-            pLayoutTempChild->m_sPos.x + pLayoutTempChild->m_sSize.x;
-        FX_FLOAT fChildContentHeight =
-            pLayoutTempChild->m_sPos.y + pLayoutTempChild->m_sSize.y;
-        if (fContentCalculatedWidth < fChildContentWidth) {
-          fContentCalculatedWidth = fChildContentWidth;
-        }
-        if (fContentCalculatedHeight < fChildContentHeight) {
-          fContentCalculatedHeight = fChildContentHeight;
-        }
-      }
+      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) {
+
+    if (pLayoutChild)
       fContentCurRowY = pLayoutChild->m_sPos.y;
-    } else {
+    else
       fContentCurRowY = fContentCalculatedHeight;
-    }
   }
+
   fContentCurRowY += InsertKeepLayoutItems();
-  if (m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages_None) {
-    XFA_ItemLayoutProcessor_GotoNextContainerNode(
-        m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, true);
+  if (m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::None) {
+    GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode,
+                          true);
   }
-  fContentCurRowY +=
-      XFA_ItemLayoutProcessor_InsertPendingItems(this, m_pFormNode);
+
+  fContentCurRowY += InsertPendingItems(this, m_pFormNode);
   if (m_pCurChildPreprocessor &&
-      m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages_Container) {
-    if (XFA_ExistContainerKeep(m_pCurChildPreprocessor->GetFormNode(), false)) {
+      m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::Container) {
+    if (ExistContainerKeep(m_pCurChildPreprocessor->GetFormNode(), false)) {
       m_pKeepHeadNode = m_pCurChildNode;
       m_bIsProcessKeep = true;
-      m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages_Keep;
+      m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages::Keep;
     }
   }
-  while (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages_Done) {
+
+  while (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Done) {
     FX_FLOAT fContentCurRowHeight = 0;
     FX_FLOAT fContentCurRowAvailWidth = fContentWidthLimit;
     m_fWidthLimite = fContentCurRowAvailWidth;
@@ -2400,23 +2217,22 @@
           m_pCurChildPreprocessor->m_pLayoutItem = pLayoutNext;
           break;
         }
-        uint8_t uHAlign = XFA_ItemLayoutProcessor_HAlignEnumToInt(
+        uint8_t uHAlign = HAlignEnumToInt(
             pLayoutNext->m_pFormNode->GetEnum(XFA_ATTRIBUTE_HAlign));
         rgCurLineLayoutItems[uHAlign].Add(pLayoutNext);
         if (eFlowStrategy == XFA_ATTRIBUTEENUM_Lr_tb) {
-          if (uHAlign > uCurHAlignState) {
+          if (uHAlign > uCurHAlignState)
             uCurHAlignState = uHAlign;
-          }
         } else if (uHAlign < uCurHAlignState) {
           uCurHAlignState = uHAlign;
         }
         if (XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutNext->m_pFormNode)) {
-          if (pLayoutNext->m_sSize.y > fContentCurRowHeight) {
-            fContentCurRowHeight = pLayoutNext->m_sSize.y;
-          }
-          fContentCurRowAvailWidth -= pLayoutNext->m_sSize.x;
+          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;
@@ -2433,6 +2249,7 @@
           }
         }
       }
+
       CXFA_ContentLayoutItem* pLayoutNextTemp =
           (CXFA_ContentLayoutItem*)pLayoutChild;
       while (pLayoutNextTemp) {
@@ -2444,272 +2261,273 @@
       }
       pLayoutChild = nullptr;
     }
+
     while (m_pCurChildNode) {
-      CXFA_ItemLayoutProcessor* pProcessor = nullptr;
+      std::unique_ptr<CXFA_ItemLayoutProcessor> pProcessor;
       bool bAddedItemInRow = false;
-      fContentCurRowY +=
-          XFA_ItemLayoutProcessor_InsertPendingItems(this, m_pFormNode);
+      fContentCurRowY += InsertPendingItems(this, m_pFormNode);
       switch (m_nCurChildNodeStage) {
-        case XFA_ItemLayoutProcessorStages_Keep:
-        case XFA_ItemLayoutProcessorStages_None:
+        case XFA_ItemLayoutProcessorStages::Keep:
+        case XFA_ItemLayoutProcessorStages::None:
           break;
-        case XFA_ItemLayoutProcessorStages_BreakBefore: {
-          for (int32_t iIndex = 0; iIndex < m_arrayKeepItems.GetSize();
-               iIndex++) {
-            CXFA_ContentLayoutItem* pItem = m_arrayKeepItems.GetAt(iIndex);
-            m_pLayoutItem->RemoveChild(pItem);
-            fContentCalculatedHeight -= pItem->m_sSize.y;
+        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) {
+          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->GetNodeItem(XFA_NODEITEM_Parent)
+                        ->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)) {
-              XFA_ItemLayoutProcessor_AddPendingNode(this, pLeaderNode, true);
+              CalculateRowChildPosition(
+                  rgCurLineLayoutItems, eFlowStrategy, bContainerHeightAutoSize,
+                  bContainerWidthAutoSize, &fContentCalculatedWidth,
+                  &fContentCalculatedHeight, &fContentCurRowY,
+                  fContentCurRowHeight, fContentWidthLimit, false);
+              rgCurLineLayoutItems->RemoveAll();
+              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);
             }
-            if (JudgeLeaderOrTrailerForOccur(pTrailerNode)) {
-              if (m_pFormNode->GetNodeItem(XFA_NODEITEM_Parent)
-                          ->GetElementType() == XFA_Element::Form &&
-                  !m_pLayoutItem) {
-                XFA_ItemLayoutProcessor_AddPendingNode(this, pTrailerNode,
-                                                       true);
-              } else {
-                std::unique_ptr<CXFA_ItemLayoutProcessor> pTempProcessor(
-                    new CXFA_ItemLayoutProcessor(pTrailerNode, nullptr));
-                XFA_ItemLayoutProcessor_InsertFlowedItem(
-                    this, pTempProcessor.get(), bContainerWidthAutoSize,
-                    bContainerHeightAutoSize, fContainerHeight, eFlowStrategy,
-                    uCurHAlignState, rgCurLineLayoutItems, false,
-                    XFA_LAYOUT_FLOAT_MAX, XFA_LAYOUT_FLOAT_MAX, fContentCurRowY,
-                    fContentWidthLimit, fContentCurRowAvailWidth,
-                    fContentCurRowHeight, bAddedItemInRow, bForceEndPage,
-                    pContext);
-              }
-            }
-            XFA_ItemLayoutProcessor_GotoNextContainerNode(
-                m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, true);
+          } else {
+            if (JudgeLeaderOrTrailerForOccur(pLeaderNode))
+              AddPendingNode(this, pLeaderNode, true);
+          }
+
+          GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage,
+                                m_pFormNode, true);
+          if (bCreatePage) {
             bForceEndPage = true;
             bIsManualBreak = true;
-            goto SuspendAndCreateNewRow;
+            if (m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::Done)
+              bBreakDone = true;
           }
-        } break;
-        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) {
-            if (JudgeLeaderOrTrailerForOccur(pTrailerNode)) {
-              std::unique_ptr<CXFA_ItemLayoutProcessor> pTempProcessor(
-                  new CXFA_ItemLayoutProcessor(pTrailerNode, nullptr));
-              XFA_ItemLayoutProcessor_InsertFlowedItem(
-                  this, pTempProcessor.get(), bContainerWidthAutoSize,
-                  bContainerHeightAutoSize, fContainerHeight, eFlowStrategy,
-                  uCurHAlignState, rgCurLineLayoutItems, false,
-                  XFA_LAYOUT_FLOAT_MAX, XFA_LAYOUT_FLOAT_MAX, fContentCurRowY,
-                  fContentWidthLimit, fContentCurRowAvailWidth,
-                  fContentCurRowHeight, bAddedItemInRow, bForceEndPage,
-                  pContext);
-            }
-            if (!bCreatePage) {
-              if (JudgeLeaderOrTrailerForOccur(pLeaderNode)) {
-                CalculateRowChildPosition(
-                    rgCurLineLayoutItems, eFlowStrategy,
-                    bContainerHeightAutoSize, bContainerWidthAutoSize,
-                    fContentCalculatedWidth, fContentCalculatedHeight,
-                    fContentCurRowY, fContentCurRowHeight, fContentWidthLimit);
-                rgCurLineLayoutItems->RemoveAll();
-                std::unique_ptr<CXFA_ItemLayoutProcessor> pTempProcessor(
-                    new CXFA_ItemLayoutProcessor(pLeaderNode, nullptr));
-                XFA_ItemLayoutProcessor_InsertFlowedItem(
-                    this, pTempProcessor.get(), bContainerWidthAutoSize,
-                    bContainerHeightAutoSize, fContainerHeight, eFlowStrategy,
-                    uCurHAlignState, rgCurLineLayoutItems, false,
-                    XFA_LAYOUT_FLOAT_MAX, XFA_LAYOUT_FLOAT_MAX, fContentCurRowY,
-                    fContentWidthLimit, fContentCurRowAvailWidth,
-                    fContentCurRowHeight, bAddedItemInRow, bForceEndPage,
-                    pContext);
-              }
-            } else {
-              if (JudgeLeaderOrTrailerForOccur(pLeaderNode)) {
-                XFA_ItemLayoutProcessor_AddPendingNode(this, pLeaderNode, true);
-              }
-            }
-            XFA_ItemLayoutProcessor_GotoNextContainerNode(
-                m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, true);
-            if (bCreatePage) {
-              bForceEndPage = true;
-              bIsManualBreak = true;
-              if (m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages_Done) {
-                bBreakDone = true;
-              }
-            }
-            goto SuspendAndCreateNewRow;
-          }
-        } break;
-        case XFA_ItemLayoutProcessorStages_BookendLeader: {
+          goto SuspendAndCreateNewRow;
+        }
+        case XFA_ItemLayoutProcessorStages::BookendLeader: {
           CXFA_Node* pLeaderNode = nullptr;
           if (m_pCurChildPreprocessor) {
-            pProcessor = m_pCurChildPreprocessor;
+            pProcessor.reset(m_pCurChildPreprocessor);
             m_pCurChildPreprocessor = nullptr;
           } else if (m_pPageMgr &&
                      m_pPageMgr->ProcessBookendLeaderOrTrailer(
                          m_pCurChildNode, true, pLeaderNode)) {
-            pProcessor = new CXFA_ItemLayoutProcessor(pLeaderNode, m_pPageMgr);
+            pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
+                pLeaderNode, m_pPageMgr);
           }
+
           if (pProcessor) {
-            if (XFA_ItemLayoutProcessor_InsertFlowedItem(
-                    this, pProcessor, bContainerWidthAutoSize,
-                    bContainerHeightAutoSize, fContainerHeight, eFlowStrategy,
-                    uCurHAlignState, rgCurLineLayoutItems, bUseBreakControl,
-                    fAvailHeight, fRealHeight, fContentCurRowY,
-                    fContentWidthLimit, fContentCurRowAvailWidth,
-                    fContentCurRowHeight, bAddedItemInRow, bForceEndPage,
-                    pContext) != XFA_ItemLayoutProcessorResult_Done) {
+            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 {
-              delete pProcessor;
-              pProcessor = nullptr;
+              pProcessor.reset();
             }
           }
-        } break;
-        case XFA_ItemLayoutProcessorStages_BookendTrailer: {
+          break;
+        }
+        case XFA_ItemLayoutProcessorStages::BookendTrailer: {
           CXFA_Node* pTrailerNode = nullptr;
           if (m_pCurChildPreprocessor) {
-            pProcessor = m_pCurChildPreprocessor;
+            pProcessor.reset(m_pCurChildPreprocessor);
             m_pCurChildPreprocessor = nullptr;
           } else if (m_pPageMgr &&
                      m_pPageMgr->ProcessBookendLeaderOrTrailer(
                          m_pCurChildNode, false, pTrailerNode)) {
-            pProcessor = new CXFA_ItemLayoutProcessor(pTrailerNode, m_pPageMgr);
+            pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
+                pTrailerNode, m_pPageMgr);
           }
           if (pProcessor) {
-            if (XFA_ItemLayoutProcessor_InsertFlowedItem(
-                    this, pProcessor, bContainerWidthAutoSize,
-                    bContainerHeightAutoSize, fContainerHeight, eFlowStrategy,
-                    uCurHAlignState, rgCurLineLayoutItems, bUseBreakControl,
-                    fAvailHeight, fRealHeight, fContentCurRowY,
-                    fContentWidthLimit, fContentCurRowAvailWidth,
-                    fContentCurRowHeight, bAddedItemInRow, bForceEndPage,
-                    pContext) != XFA_ItemLayoutProcessorResult_Done) {
+            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 {
-              delete pProcessor;
-              pProcessor = nullptr;
+              pProcessor.reset();
             }
           }
-        } break;
-        case XFA_ItemLayoutProcessorStages_Container:
+          break;
+        }
+        case XFA_ItemLayoutProcessorStages::Container: {
           ASSERT(m_pCurChildNode->IsContainerNode());
-          if (m_pCurChildNode->GetElementType() == XFA_Element::Variables) {
+          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()) {
-            bool bNewRow = false;
-            if (m_pCurChildPreprocessor) {
-              pProcessor = m_pCurChildPreprocessor;
-              m_pCurChildPreprocessor = nullptr;
-              bNewRow = true;
-            } else {
-              pProcessor =
-                  new CXFA_ItemLayoutProcessor(m_pCurChildNode, m_pPageMgr);
-            }
-            XFA_ItemLayoutProcessor_InsertPendingItems(pProcessor,
-                                                       m_pCurChildNode);
-            XFA_ItemLayoutProcessorResult rs =
-                XFA_ItemLayoutProcessor_InsertFlowedItem(
-                    this, pProcessor, bContainerWidthAutoSize,
-                    bContainerHeightAutoSize, fContainerHeight, eFlowStrategy,
-                    uCurHAlignState, rgCurLineLayoutItems, bUseBreakControl,
-                    fAvailHeight, fRealHeight, fContentCurRowY,
-                    fContentWidthLimit, 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 += XFA_ItemLayoutProcessor_InsertPendingItems(
-                    pProcessor, m_pCurChildNode);
-                delete pProcessor;
-                pProcessor = nullptr;
-            }
+          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:
+        }
+        case XFA_ItemLayoutProcessorStages::Done:
           break;
         default:
           break;
       }
-      XFA_ItemLayoutProcessor_GotoNextContainerNode(
-          m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, true);
-      if (bAddedItemInRow && eFlowStrategy == XFA_ATTRIBUTEENUM_Tb) {
+      GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode,
+                            true);
+      if (bAddedItemInRow && eFlowStrategy == XFA_ATTRIBUTEENUM_Tb)
         break;
-      } else {
+      else
         continue;
-      }
     SuspendAndCreateNewRow:
-      if (pProcessor) {
-        m_pCurChildPreprocessor = pProcessor;
-      }
+      if (pProcessor)
+        m_pCurChildPreprocessor = pProcessor.release();
       break;
     }
-    CalculateRowChildPosition(rgCurLineLayoutItems, eFlowStrategy,
-                              bContainerHeightAutoSize, bContainerWidthAutoSize,
-                              fContentCalculatedWidth, fContentCalculatedHeight,
-                              fContentCurRowY, fContentCurRowHeight,
-                              fContentWidthLimit, bRootForceTb);
+
+    CalculateRowChildPosition(
+        rgCurLineLayoutItems, eFlowStrategy, bContainerHeightAutoSize,
+        bContainerWidthAutoSize, &fContentCalculatedWidth,
+        &fContentCalculatedHeight, &fContentCurRowY, fContentCurRowHeight,
+        fContentWidthLimit, bRootForceTb);
     m_fWidthLimite = fContentCurRowAvailWidth;
-    if (bForceEndPage) {
+    if (bForceEndPage)
       break;
-    }
   }
-  bool bRetValue = m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages_Done &&
-                   m_PendingNodes.empty();
-  if (bBreakDone) {
+
+  bool bRetValue =
+      m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::Done &&
+      m_PendingNodes.empty();
+  if (bBreakDone)
     bRetValue = false;
-  }
-  XFA_ItemLayoutProcessor_CalculateContainerComponentSizeFromContentSize(
+
+  containerSize = CalculateContainerComponentSizeFromContentSize(
       m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
-      fContainerWidth, bContainerHeightAutoSize, fContentCalculatedHeight,
-      fContainerHeight);
-  if (fContainerHeight >= XFA_LAYOUT_FLOAT_PERCISION || m_pLayoutItem ||
+      bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
+
+  if (containerSize.height >= XFA_LAYOUT_FLOAT_PERCISION || m_pLayoutItem ||
       bRetValue) {
-    if (!m_pLayoutItem) {
+    if (!m_pLayoutItem)
       m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
-    }
-    if (fContainerHeight < 0) {
-      fContainerHeight = 0;
-    }
-    SetCurrentComponentSize(fContainerWidth, fContainerHeight);
-    if (bForceEndPage) {
+    containerSize.height = std::max(containerSize.height, 0.f);
+
+    SetCurrentComponentSize(containerSize);
+    if (bForceEndPage)
       m_fUsedSize = 0;
-    } else {
-      m_fUsedSize += m_pLayoutItem->m_sSize.y;
-    }
+    else
+      m_fUsedSize += m_pLayoutItem->m_sSize.height;
   }
+
   return bRetValue
-             ? XFA_ItemLayoutProcessorResult_Done
-             : (bIsManualBreak ? XFA_ItemLayoutProcessorResult_ManualBreak
-                               : XFA_ItemLayoutProcessorResult_PageFullBreak);
+             ? XFA_ItemLayoutProcessorResult::Done
+             : (bIsManualBreak ? XFA_ItemLayoutProcessorResult::ManualBreak
+                               : XFA_ItemLayoutProcessorResult::PageFullBreak);
 }
 
 bool CXFA_ItemLayoutProcessor::CalculateRowChildPosition(
@@ -2717,9 +2535,9 @@
     XFA_ATTRIBUTEENUM eFlowStrategy,
     bool bContainerHeightAutoSize,
     bool bContainerWidthAutoSize,
-    FX_FLOAT& fContentCalculatedWidth,
-    FX_FLOAT& fContentCalculatedHeight,
-    FX_FLOAT& fContentCurRowY,
+    FX_FLOAT* fContentCalculatedWidth,
+    FX_FLOAT* fContentCalculatedHeight,
+    FX_FLOAT* fContentCurRowY,
     FX_FLOAT fContentCurRowHeight,
     FX_FLOAT fContentWidthLimit,
     bool bRootForceTb) {
@@ -2732,39 +2550,36 @@
       nTotalLength++;
       if (XFA_ItemLayoutProcessor_IsTakingSpace(
               rgCurLineLayoutItems[i][j]->m_pFormNode)) {
-        fGroupWidths[i] += rgCurLineLayoutItems[i][j]->m_sSize.x;
+        fGroupWidths[i] += rgCurLineLayoutItems[i][j]->m_sSize.width;
       }
     }
   }
+
   if (!nTotalLength) {
     if (bContainerHeightAutoSize) {
-      FX_FLOAT fNewHeight = fContentCurRowY;
-      if (fContentCalculatedHeight > fNewHeight) {
-        fContentCalculatedHeight = fNewHeight;
-      }
+      *fContentCalculatedHeight =
+          std::min(*fContentCalculatedHeight, *fContentCurRowY);
     }
     return false;
   }
-  if (!m_pLayoutItem) {
+
+  if (!m_pLayoutItem)
     m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
-  }
+
   if (eFlowStrategy != XFA_ATTRIBUTEENUM_Rl_tb) {
     FX_FLOAT fCurPos;
     fCurPos = 0;
     for (int32_t c = nGroupLengths[0], j = 0; j < c; j++) {
       if (bRootForceTb) {
-        FX_FLOAT fAbsoluteX, fAbsoluteY;
-        CalculatePositionedContainerPos(rgCurLineLayoutItems[0][j]->m_pFormNode,
-                                        rgCurLineLayoutItems[0][j]->m_sSize.x,
-                                        rgCurLineLayoutItems[0][j]->m_sSize.y,
-                                        fAbsoluteX, fAbsoluteY);
-        rgCurLineLayoutItems[0][j]->m_sPos = CFX_PointF(fAbsoluteX, fAbsoluteY);
+        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);
+            CFX_PointF(fCurPos, *fContentCurRowY);
         if (XFA_ItemLayoutProcessor_IsTakingSpace(
                 rgCurLineLayoutItems[0][j]->m_pFormNode)) {
-          fCurPos += rgCurLineLayoutItems[0][j]->m_sSize.x;
+          fCurPos += rgCurLineLayoutItems[0][j]->m_sSize.width;
         }
       }
       m_pLayoutItem->AddChild(rgCurLineLayoutItems[0][j]);
@@ -2775,18 +2590,15 @@
               2;
     for (int32_t c = nGroupLengths[1], j = 0; j < c; j++) {
       if (bRootForceTb) {
-        FX_FLOAT fAbsoluteX, fAbsoluteY;
-        CalculatePositionedContainerPos(rgCurLineLayoutItems[1][j]->m_pFormNode,
-                                        rgCurLineLayoutItems[1][j]->m_sSize.x,
-                                        rgCurLineLayoutItems[1][j]->m_sSize.y,
-                                        fAbsoluteX, fAbsoluteY);
-        rgCurLineLayoutItems[1][j]->m_sPos = CFX_PointF(fAbsoluteX, fAbsoluteY);
+        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);
+            CFX_PointF(fCurPos, *fContentCurRowY);
         if (XFA_ItemLayoutProcessor_IsTakingSpace(
                 rgCurLineLayoutItems[1][j]->m_pFormNode)) {
-          fCurPos += rgCurLineLayoutItems[1][j]->m_sSize.x;
+          fCurPos += rgCurLineLayoutItems[1][j]->m_sSize.width;
         }
       }
       m_pLayoutItem->AddChild(rgCurLineLayoutItems[1][j]);
@@ -2795,18 +2607,15 @@
     fCurPos = fContentWidthLimit - fGroupWidths[2];
     for (int32_t c = nGroupLengths[2], j = 0; j < c; j++) {
       if (bRootForceTb) {
-        FX_FLOAT fAbsoluteX, fAbsoluteY;
-        CalculatePositionedContainerPos(rgCurLineLayoutItems[2][j]->m_pFormNode,
-                                        rgCurLineLayoutItems[2][j]->m_sSize.x,
-                                        rgCurLineLayoutItems[2][j]->m_sSize.y,
-                                        fAbsoluteX, fAbsoluteY);
-        rgCurLineLayoutItems[2][j]->m_sPos = CFX_PointF(fAbsoluteX, fAbsoluteY);
+        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);
+            CFX_PointF(fCurPos, *fContentCurRowY);
         if (XFA_ItemLayoutProcessor_IsTakingSpace(
                 rgCurLineLayoutItems[2][j]->m_pFormNode)) {
-          fCurPos += rgCurLineLayoutItems[2][j]->m_sSize.x;
+          fCurPos += rgCurLineLayoutItems[2][j]->m_sSize.width;
         }
       }
       m_pLayoutItem->AddChild(rgCurLineLayoutItems[2][j]);
@@ -2818,9 +2627,10 @@
     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.x;
+        fCurPos -= rgCurLineLayoutItems[0][j]->m_sSize.width;
       }
-      rgCurLineLayoutItems[0][j]->m_sPos = CFX_PointF(fCurPos, fContentCurRowY);
+      rgCurLineLayoutItems[0][j]->m_sPos =
+          CFX_PointF(fCurPos, *fContentCurRowY);
       m_pLayoutItem->AddChild(rgCurLineLayoutItems[0][j]);
       m_fLastRowWidth = fCurPos;
     }
@@ -2830,9 +2640,10 @@
     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.x;
+        fCurPos -= rgCurLineLayoutItems[1][j]->m_sSize.width;
       }
-      rgCurLineLayoutItems[1][j]->m_sPos = CFX_PointF(fCurPos, fContentCurRowY);
+      rgCurLineLayoutItems[1][j]->m_sPos =
+          CFX_PointF(fCurPos, *fContentCurRowY);
       m_pLayoutItem->AddChild(rgCurLineLayoutItems[1][j]);
       m_fLastRowWidth = fCurPos;
     }
@@ -2840,70 +2651,68 @@
     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.x;
+        fCurPos -= rgCurLineLayoutItems[2][j]->m_sSize.width;
       }
-      rgCurLineLayoutItems[2][j]->m_sPos = CFX_PointF(fCurPos, fContentCurRowY);
+      rgCurLineLayoutItems[2][j]->m_sPos =
+          CFX_PointF(fCurPos, *fContentCurRowY);
       m_pLayoutItem->AddChild(rgCurLineLayoutItems[2][j]);
       m_fLastRowWidth = fCurPos;
     }
   }
-  m_fLastRowY = fContentCurRowY;
-  fContentCurRowY += fContentCurRowHeight;
+  m_fLastRowY = *fContentCurRowY;
+  *fContentCurRowY += fContentCurRowHeight;
   if (bContainerWidthAutoSize) {
     FX_FLOAT fChildSuppliedWidth = fGroupWidths[0];
-    if (fContentWidthLimit < XFA_LAYOUT_FLOAT_MAX &&
+    if (fContentWidthLimit < FLT_MAX &&
         fContentWidthLimit > fChildSuppliedWidth) {
       fChildSuppliedWidth = fContentWidthLimit;
     }
-    if (fContentCalculatedWidth < fChildSuppliedWidth) {
-      fContentCalculatedWidth = fChildSuppliedWidth;
-    }
+    *fContentCalculatedWidth =
+        std::max(*fContentCalculatedWidth, fChildSuppliedWidth);
   }
   if (bContainerHeightAutoSize) {
-    FX_FLOAT fChildSuppliedHeight = fContentCurRowY;
-    if (fContentCalculatedHeight < fChildSuppliedHeight) {
-      fContentCalculatedHeight = fChildSuppliedHeight;
-    }
+    *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->GetNodeItem(XFA_NODEITEM_Parent);
     while (pParent) {
-      if (pParent->GetElementType() != XFA_Element::SubformSet) {
+      if (pParent->GetElementType() != XFA_Element::SubformSet)
         return pParent;
-      }
       pParent = pParent->GetNodeItem(XFA_NODEITEM_Parent);
     }
   }
   return pSubformSet;
 }
+
 void CXFA_ItemLayoutProcessor::DoLayoutField() {
   if (m_pLayoutItem)
     return;
 
   ASSERT(m_pCurChildNode == XFA_LAYOUT_INVALIDNODE);
   m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
-  if (!m_pLayoutItem) {
+  if (!m_pLayoutItem)
     return;
-  }
+
   CXFA_Document* pDocument = m_pFormNode->GetDocument();
   CXFA_FFNotify* pNotify = pDocument->GetNotify();
-  FX_FLOAT fHeight = -1;
-  FX_FLOAT fWidth = -1;
-  pNotify->StartFieldDrawLayout(m_pFormNode, fWidth, fHeight);
+  CFX_SizeF size(-1, -1);
+  pNotify->StartFieldDrawLayout(m_pFormNode, size.width, size.height);
+
   int32_t nRotate =
       FXSYS_round(m_pFormNode->GetMeasure(XFA_ATTRIBUTE_Rotate).GetValue());
   nRotate = XFA_MapRotation(nRotate);
-  if (nRotate == 90 || nRotate == 270) {
-    FX_FLOAT fTmp = fWidth;
-    fWidth = fHeight;
-    fHeight = fTmp;
-  }
-  SetCurrentComponentSize(fWidth, fHeight);
+  if (nRotate == 90 || nRotate == 270)
+    std::swap(size.width, size.height);
+
+  SetCurrentComponentSize(size);
 }
+
 XFA_ItemLayoutProcessorResult CXFA_ItemLayoutProcessor::DoLayout(
     bool bUseBreakControl,
     FX_FLOAT fHeightLimit,
@@ -2916,8 +2725,7 @@
     case XFA_Element::SubformSet: {
       bool bRootForceTb = false;
       CXFA_Node* pLayoutNode = GetSubformSetParent(m_pFormNode);
-      XFA_ATTRIBUTEENUM eLayoutStrategy =
-          XFA_ItemLayoutProcessor_GetLayout(pLayoutNode, bRootForceTb);
+      XFA_ATTRIBUTEENUM eLayoutStrategy = GetLayout(pLayoutNode, &bRootForceTb);
       switch (eLayoutStrategy) {
         case XFA_ATTRIBUTEENUM_Tb:
         case XFA_ATTRIBUTEENUM_Lr_tb:
@@ -2930,44 +2738,36 @@
         case XFA_ATTRIBUTEENUM_Rl_row:
         default:
           DoLayoutPositionedContainer(pContext);
-          m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages_Done;
-          return XFA_ItemLayoutProcessorResult_Done;
+          m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages::Done;
+          return XFA_ItemLayoutProcessorResult::Done;
         case XFA_ATTRIBUTEENUM_Table:
           DoLayoutTableContainer(pLayoutNode);
-          m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages_Done;
-          return XFA_ItemLayoutProcessorResult_Done;
+          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;
+      m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages::Done;
+      return XFA_ItemLayoutProcessorResult::Done;
     case XFA_Element::ContentArea:
-      return XFA_ItemLayoutProcessorResult_Done;
+      return XFA_ItemLayoutProcessorResult::Done;
     default:
-      return XFA_ItemLayoutProcessorResult_Done;
+      return XFA_ItemLayoutProcessorResult::Done;
   }
 }
-void CXFA_ItemLayoutProcessor::GetCurrentComponentPos(FX_FLOAT& fAbsoluteX,
-                                                      FX_FLOAT& fAbsoluteY) {
-  ASSERT(m_pLayoutItem);
-  fAbsoluteX = m_pLayoutItem->m_sPos.x;
-  fAbsoluteY = m_pLayoutItem->m_sPos.y;
+
+CFX_SizeF CXFA_ItemLayoutProcessor::GetCurrentComponentSize() {
+  return CFX_SizeF(m_pLayoutItem->m_sSize.width, m_pLayoutItem->m_sSize.height);
 }
-void CXFA_ItemLayoutProcessor::GetCurrentComponentSize(FX_FLOAT& fWidth,
-                                                       FX_FLOAT& fHeight) {
-  ASSERT(m_pLayoutItem);
-  fWidth = m_pLayoutItem->m_sSize.x;
-  fHeight = m_pLayoutItem->m_sSize.y;
+
+void CXFA_ItemLayoutProcessor::SetCurrentComponentPos(const CFX_PointF& pos) {
+  m_pLayoutItem->m_sPos = pos;
 }
-void CXFA_ItemLayoutProcessor::SetCurrentComponentPos(FX_FLOAT fAbsoluteX,
-                                                      FX_FLOAT fAbsoluteY) {
-  m_pLayoutItem->m_sPos = CFX_PointF(fAbsoluteX, fAbsoluteY);
-}
-void CXFA_ItemLayoutProcessor::SetCurrentComponentSize(FX_FLOAT fWidth,
-                                                       FX_FLOAT fHeight) {
-  m_pLayoutItem->m_sSize = CFX_SizeF(fWidth, fHeight);
+
+void CXFA_ItemLayoutProcessor::SetCurrentComponentSize(const CFX_SizeF& size) {
+  m_pLayoutItem->m_sSize = size;
 }
 
 bool CXFA_ItemLayoutProcessor::JudgeLeaderOrTrailerForOccur(
diff --git a/xfa/fxfa/parser/xfa_layout_itemlayout.h b/xfa/fxfa/parser/xfa_layout_itemlayout.h
index 0d114a4..d411bf0 100644
--- a/xfa/fxfa/parser/xfa_layout_itemlayout.h
+++ b/xfa/fxfa/parser/xfa_layout_itemlayout.h
@@ -11,13 +11,15 @@
 
 #include <list>
 #include <map>
+#include <tuple>
+#include <vector>
 
 #include "core/fxcrt/fx_basic.h"
+#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)
-#define XFA_LAYOUT_FLOAT_MAX FLT_MAX
 
 class CXFA_ContainerLayoutItem;
 class CXFA_ContentLayoutItem;
@@ -26,22 +28,22 @@
 class CXFA_LayoutProcessor;
 class CXFA_Node;
 
-enum XFA_ItemLayoutProcessorResult {
-  XFA_ItemLayoutProcessorResult_Done,
-  XFA_ItemLayoutProcessorResult_PageFullBreak,
-  XFA_ItemLayoutProcessorResult_RowFullBreak,
-  XFA_ItemLayoutProcessorResult_ManualBreak,
+enum class XFA_ItemLayoutProcessorResult {
+  Done,
+  PageFullBreak,
+  RowFullBreak,
+  ManualBreak,
 };
 
-enum XFA_ItemLayoutProcessorStages {
-  XFA_ItemLayoutProcessorStages_None,
-  XFA_ItemLayoutProcessorStages_BookendLeader,
-  XFA_ItemLayoutProcessorStages_BreakBefore,
-  XFA_ItemLayoutProcessorStages_Keep,
-  XFA_ItemLayoutProcessorStages_Container,
-  XFA_ItemLayoutProcessorStages_BreakAfter,
-  XFA_ItemLayoutProcessorStages_BookendTrailer,
-  XFA_ItemLayoutProcessorStages_Done,
+enum class XFA_ItemLayoutProcessorStages {
+  None,
+  BookendLeader,
+  BreakBefore,
+  Keep,
+  Container,
+  BreakAfter,
+  BookendTrailer,
+  Done,
 };
 
 class CXFA_LayoutContext {
@@ -52,7 +54,8 @@
         m_bCurColumnWidthAvaiable(false),
         m_pOverflowProcessor(nullptr),
         m_pOverflowNode(nullptr) {}
-  ~CXFA_LayoutContext() { m_pOverflowProcessor = nullptr; }
+  ~CXFA_LayoutContext() {}
+
   CFX_ArrayTemplate<FX_FLOAT>* m_prgSpecifiedColumnWidths;
   FX_FLOAT m_fCurColumnWidth;
   bool m_bCurColumnWidthAvaiable;
@@ -60,99 +63,104 @@
   CXFA_Node* m_pOverflowNode;
 };
 
+bool XFA_ItemLayoutProcessor_IsTakingSpace(CXFA_Node* pNode);
+
 class CXFA_ItemLayoutProcessor {
  public:
-  CXFA_ItemLayoutProcessor(CXFA_Node* pNode, CXFA_LayoutPageMgr* pPageMgr);
-  ~CXFA_ItemLayoutProcessor();
-
-  XFA_ItemLayoutProcessorResult DoLayout(
-      bool bUseBreakControl,
-      FX_FLOAT fHeightLimit,
-      FX_FLOAT fRealHeight = XFA_LAYOUT_FLOAT_MAX,
-      CXFA_LayoutContext* pContext = nullptr);
-
-  void GetCurrentComponentPos(FX_FLOAT& fAbsoluteX, FX_FLOAT& fAbsoluteY);
-
-  void GetCurrentComponentSize(FX_FLOAT& fWidth, FX_FLOAT& fHeight);
-
-  void SetCurrentComponentPos(FX_FLOAT fAbsoluteX, FX_FLOAT fAbsoluteY);
-
-  void SetCurrentComponentSize(FX_FLOAT fWidth, FX_FLOAT fHeight);
-  CXFA_Node* GetFormNode() { return m_pFormNode; }
-  bool HasLayoutItem() { return !!m_pLayoutItem; }
-  CXFA_ContentLayoutItem* ExtractLayoutItem();
-
   static bool IncrementRelayoutNode(CXFA_LayoutProcessor* pLayoutProcessor,
                                     CXFA_Node* pNode,
                                     CXFA_Node* pParentNode);
-  static void CalculatePositionedContainerPos(CXFA_Node* pNode,
-                                              FX_FLOAT fWidth,
-                                              FX_FLOAT fHeight,
-                                              FX_FLOAT& fAbsoluteX,
-                                              FX_FLOAT& fAbsoluteY);
-  static bool FindLayoutItemSplitPos(CXFA_ContentLayoutItem* pLayoutItem,
-                                     FX_FLOAT fCurVerticalOffset,
-                                     FX_FLOAT& fProposedSplitPos,
-                                     bool& bAppChange,
-                                     bool bCalculateMargin = true);
-  FX_FLOAT FindSplitPos(FX_FLOAT fProposedSplitPos);
-  void SplitLayoutItem(CXFA_ContentLayoutItem* pLayoutItem,
-                       CXFA_ContentLayoutItem* pSecondParent,
-                       FX_FLOAT fSplitPos);
+
+  CXFA_ItemLayoutProcessor(CXFA_Node* pNode, CXFA_LayoutPageMgr* pPageMgr);
+  ~CXFA_ItemLayoutProcessor();
+
+  XFA_ItemLayoutProcessorResult DoLayout(bool bUseBreakControl,
+                                         FX_FLOAT fHeightLimit,
+                                         FX_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(FX_FLOAT fSplitPos);
-  bool JudgePutNextPage(CXFA_ContentLayoutItem* pParentLayoutItem,
-                        FX_FLOAT fChildHeight,
-                        CFX_ArrayTemplate<CXFA_ContentLayoutItem*>& pKeepItems);
-  bool ProcessKeepForSplite(
+
+  FX_FLOAT FindSplitPos(FX_FLOAT fProposedSplitPos);
+
+  bool ProcessKeepForSplit(
       CXFA_ItemLayoutProcessor* pParentProcessor,
       CXFA_ItemLayoutProcessor* pChildProcessor,
       XFA_ItemLayoutProcessorResult eRetValue,
-      CFX_ArrayTemplate<CXFA_ContentLayoutItem*>& rgCurLineLayoutItem,
-      FX_FLOAT& fContentCurRowAvailWidth,
-      FX_FLOAT& fContentCurRowHeight,
-      FX_FLOAT& fContentCurRowY,
-      bool& bAddedItemInRow,
-      bool& bForceEndPage,
-      XFA_ItemLayoutProcessorResult& result);
+      CFX_ArrayTemplate<CXFA_ContentLayoutItem*>* rgCurLineLayoutItem,
+      FX_FLOAT* fContentCurRowAvailWidth,
+      FX_FLOAT* fContentCurRowHeight,
+      FX_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;
+  FX_FLOAT m_fUsedSize;
+  CXFA_LayoutPageMgr* m_pPageMgr;
+  std::list<CXFA_Node*> m_PendingNodes;
+  bool m_bBreakPending;
+  CFX_ArrayTemplate<FX_FLOAT> m_rgSpecifiedColumnWidths;
+  std::vector<CXFA_ContentLayoutItem*> m_arrayKeepItems;
+  FX_FLOAT m_fLastRowWidth;
+  FX_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,
+                       FX_FLOAT fSplitPos);
   FX_FLOAT InsertKeepLayoutItems();
-  void DoLayoutPageArea(CXFA_ContainerLayoutItem* pPageAreaLayoutItem);
   bool CalculateRowChildPosition(
       CFX_ArrayTemplate<CXFA_ContentLayoutItem*> (&rgCurLineLayoutItems)[3],
       XFA_ATTRIBUTEENUM eFlowStrategy,
       bool bContainerHeightAutoSize,
       bool bContainerWidthAutoSize,
-      FX_FLOAT& fContentCalculatedWidth,
-      FX_FLOAT& fContentCalculatedHeight,
-      FX_FLOAT& fContentCurRowY,
+      FX_FLOAT* fContentCalculatedWidth,
+      FX_FLOAT* fContentCalculatedHeight,
+      FX_FLOAT* fContentCurRowY,
       FX_FLOAT fContentCurRowHeight,
       FX_FLOAT fContentWidthLimit,
-      bool bRootForceTb = false);
-
-  void ProcessUnUseOverFlow(CXFA_Node* pLeaderNode,
-                            CXFA_Node* pTrailerNode,
-                            CXFA_ContentLayoutItem* pTrailerItem,
-                            CXFA_Node* pFormNode);
+      bool bRootForceTb);
   void ProcessUnUseBinds(CXFA_Node* pFormNode);
-  bool IsAddNewRowForTrailer(CXFA_ContentLayoutItem* pTrailerItem);
-  bool JudgeLeaderOrTrailerForOccur(CXFA_Node* pFormNode);
-  CXFA_ContentLayoutItem* CreateContentLayoutItem(CXFA_Node* pFormNode);
+  bool JudgePutNextPage(CXFA_ContentLayoutItem* pParentLayoutItem,
+                        FX_FLOAT fChildHeight,
+                        std::vector<CXFA_ContentLayoutItem*>* pKeepItems);
 
- protected:
-  void DoLayoutPositionedContainer(CXFA_LayoutContext* pContext = nullptr);
+  void DoLayoutPositionedContainer(CXFA_LayoutContext* pContext);
   void DoLayoutTableContainer(CXFA_Node* pLayoutNode);
   XFA_ItemLayoutProcessorResult DoLayoutFlowedContainer(
       bool bUseBreakControl,
       XFA_ATTRIBUTEENUM eFlowStrategy,
       FX_FLOAT fHeightLimit,
       FX_FLOAT fRealHeight,
-      CXFA_LayoutContext* pContext = nullptr,
-      bool bRootForceTb = false);
+      CXFA_LayoutContext* pContext,
+      bool bRootForceTb);
   void DoLayoutField();
-  void XFA_ItemLayoutProcessor_GotoNextContainerNode(
-      CXFA_Node*& pCurActionNode,
-      XFA_ItemLayoutProcessorStages& nCurStage,
-      CXFA_Node* pParentContainer,
-      bool bUsePageBreak);
+
+  void GotoNextContainerNode(CXFA_Node*& pCurActionNode,
+                             XFA_ItemLayoutProcessorStages& nCurStage,
+                             CXFA_Node* pParentContainer,
+                             bool bUsePageBreak);
 
   bool ProcessKeepNodesForCheckNext(CXFA_Node*& pCurActionNode,
                                     XFA_ItemLayoutProcessorStages& nCurStage,
@@ -165,31 +173,16 @@
 
   CXFA_Node* GetSubformSetParent(CXFA_Node* pSubformSet);
 
- public:
   bool m_bKeepBreakFinish;
   bool m_bIsProcessKeep;
   CXFA_Node* m_pKeepHeadNode;
   CXFA_Node* m_pKeepTailNode;
-  CXFA_Node* m_pFormNode;
-  CXFA_ContentLayoutItem* m_pLayoutItem;
   CXFA_ContentLayoutItem* m_pOldLayoutItem;
-  CXFA_Node* m_pCurChildNode;
   CXFA_ItemLayoutProcessor* m_pCurChildPreprocessor;
   XFA_ItemLayoutProcessorStages m_nCurChildNodeStage;
-  FX_FLOAT m_fUsedSize;
-  CXFA_LayoutPageMgr* m_pPageMgr;
-  std::list<CXFA_Node*> m_PendingNodes;
-  bool m_bBreakPending;
-  CFX_ArrayTemplate<FX_FLOAT> m_rgSpecifiedColumnWidths;
-  CFX_ArrayTemplate<CXFA_ContentLayoutItem*> m_arrayKeepItems;
   std::map<CXFA_Node*, int32_t> m_PendingNodesCount;
-  FX_FLOAT m_fLastRowWidth;
-  FX_FLOAT m_fLastRowY;
   FX_FLOAT m_fWidthLimite;
-  bool m_bUseInheriated;
-  XFA_ItemLayoutProcessorResult m_ePreProcessRs;
   bool m_bHasAvailHeight;
 };
-bool XFA_ItemLayoutProcessor_IsTakingSpace(CXFA_Node* pNode);
 
 #endif  // XFA_FXFA_PARSER_XFA_LAYOUT_ITEMLAYOUT_H_
diff --git a/xfa/fxfa/parser/xfa_locale.cpp b/xfa/fxfa/parser/xfa_locale.cpp
index 5b18bcf..d835eb2 100644
--- a/xfa/fxfa/parser/xfa_locale.cpp
+++ b/xfa/fxfa/parser/xfa_locale.cpp
@@ -35,31 +35,31 @@
   switch (eType) {
     case FX_LOCALENUMSYMBOL_Decimal:
       bsSymbols = "numberSymbols";
-      wsName = FX_WSTRC(L"decimal");
+      wsName = L"decimal";
       break;
     case FX_LOCALENUMSYMBOL_Grouping:
       bsSymbols = "numberSymbols";
-      wsName = FX_WSTRC(L"grouping");
+      wsName = L"grouping";
       break;
     case FX_LOCALENUMSYMBOL_Percent:
       bsSymbols = "numberSymbols";
-      wsName = FX_WSTRC(L"percent");
+      wsName = L"percent";
       break;
     case FX_LOCALENUMSYMBOL_Minus:
       bsSymbols = "numberSymbols";
-      wsName = FX_WSTRC(L"minus");
+      wsName = L"minus";
       break;
     case FX_LOCALENUMSYMBOL_Zero:
       bsSymbols = "numberSymbols";
-      wsName = FX_WSTRC(L"zero");
+      wsName = L"zero";
       break;
     case FX_LOCALENUMSYMBOL_CurrencySymbol:
       bsSymbols = "currencySymbols";
-      wsName = FX_WSTRC(L"symbol");
+      wsName = L"symbol";
       break;
     case FX_LOCALENUMSYMBOL_CurrencyName:
       bsSymbols = "currencySymbols";
-      wsName = FX_WSTRC(L"isoname");
+      wsName = L"isoname";
       break;
     default:
       return;
@@ -238,28 +238,25 @@
                                         CFX_WideString& wsNumSymbol) const {
   switch (eType) {
     case FX_LOCALENUMSYMBOL_Decimal:
-      wsNumSymbol = GetSymbol(XFA_Element::NumberSymbols, FX_WSTRC(L"decimal"));
+      wsNumSymbol = GetSymbol(XFA_Element::NumberSymbols, L"decimal");
       break;
     case FX_LOCALENUMSYMBOL_Grouping:
-      wsNumSymbol =
-          GetSymbol(XFA_Element::NumberSymbols, FX_WSTRC(L"grouping"));
+      wsNumSymbol = GetSymbol(XFA_Element::NumberSymbols, L"grouping");
       break;
     case FX_LOCALENUMSYMBOL_Percent:
-      wsNumSymbol = GetSymbol(XFA_Element::NumberSymbols, FX_WSTRC(L"percent"));
+      wsNumSymbol = GetSymbol(XFA_Element::NumberSymbols, L"percent");
       break;
     case FX_LOCALENUMSYMBOL_Minus:
-      wsNumSymbol = GetSymbol(XFA_Element::NumberSymbols, FX_WSTRC(L"minus"));
+      wsNumSymbol = GetSymbol(XFA_Element::NumberSymbols, L"minus");
       break;
     case FX_LOCALENUMSYMBOL_Zero:
-      wsNumSymbol = GetSymbol(XFA_Element::NumberSymbols, FX_WSTRC(L"zero"));
+      wsNumSymbol = GetSymbol(XFA_Element::NumberSymbols, L"zero");
       break;
     case FX_LOCALENUMSYMBOL_CurrencySymbol:
-      wsNumSymbol =
-          GetSymbol(XFA_Element::CurrencySymbols, FX_WSTRC(L"symbol"));
+      wsNumSymbol = GetSymbol(XFA_Element::CurrencySymbols, L"symbol");
       break;
     case FX_LOCALENUMSYMBOL_CurrencyName:
-      wsNumSymbol =
-          GetSymbol(XFA_Element::CurrencySymbols, FX_WSTRC(L"isoname"));
+      wsNumSymbol = GetSymbol(XFA_Element::CurrencySymbols, L"isoname");
       break;
   }
 }
@@ -302,17 +299,17 @@
                                      CFX_WideString& wsPattern) const {
   switch (eType) {
     case FX_LOCALEDATETIMESUBCATEGORY_Short:
-      wsPattern = GetSymbol(XFA_Element::DatePatterns, FX_WSTRC(L"short"));
+      wsPattern = GetSymbol(XFA_Element::DatePatterns, L"short");
       break;
     case FX_LOCALEDATETIMESUBCATEGORY_Medium:
     case FX_LOCALEDATETIMESUBCATEGORY_Default:
-      wsPattern = GetSymbol(XFA_Element::DatePatterns, FX_WSTRC(L"med"));
+      wsPattern = GetSymbol(XFA_Element::DatePatterns, L"med");
       break;
     case FX_LOCALEDATETIMESUBCATEGORY_Full:
-      wsPattern = GetSymbol(XFA_Element::DatePatterns, FX_WSTRC(L"full"));
+      wsPattern = GetSymbol(XFA_Element::DatePatterns, L"full");
       break;
     case FX_LOCALEDATETIMESUBCATEGORY_Long:
-      wsPattern = GetSymbol(XFA_Element::DatePatterns, FX_WSTRC(L"long"));
+      wsPattern = GetSymbol(XFA_Element::DatePatterns, L"long");
       break;
   }
 }
@@ -321,17 +318,17 @@
                                      CFX_WideString& wsPattern) const {
   switch (eType) {
     case FX_LOCALEDATETIMESUBCATEGORY_Short:
-      wsPattern = GetSymbol(XFA_Element::TimePatterns, FX_WSTRC(L"short"));
+      wsPattern = GetSymbol(XFA_Element::TimePatterns, L"short");
       break;
     case FX_LOCALEDATETIMESUBCATEGORY_Medium:
     case FX_LOCALEDATETIMESUBCATEGORY_Default:
-      wsPattern = GetSymbol(XFA_Element::TimePatterns, FX_WSTRC(L"med"));
+      wsPattern = GetSymbol(XFA_Element::TimePatterns, L"med");
       break;
     case FX_LOCALEDATETIMESUBCATEGORY_Full:
-      wsPattern = GetSymbol(XFA_Element::TimePatterns, FX_WSTRC(L"full"));
+      wsPattern = GetSymbol(XFA_Element::TimePatterns, L"full");
       break;
     case FX_LOCALEDATETIMESUBCATEGORY_Long:
-      wsPattern = GetSymbol(XFA_Element::TimePatterns, FX_WSTRC(L"long"));
+      wsPattern = GetSymbol(XFA_Element::TimePatterns, L"long");
       break;
   }
 }
diff --git a/xfa/fxfa/parser/xfa_localemgr.cpp b/xfa/fxfa/parser/xfa_localemgr.cpp
index cfa5801..0cd64ea 100644
--- a/xfa/fxfa/parser/xfa_localemgr.cpp
+++ b/xfa/fxfa/parser/xfa_localemgr.cpp
@@ -1053,7 +1053,7 @@
   pCodecMgr->GetFlateModule()->FlateOrLZWDecode(false, pBuf, nBufLen, true, 0,
                                                 0, 0, 0, 0, pOut, dwSize);
   if (pOut) {
-    pLocale.reset(CXML_Element::Parse(pOut, dwSize));
+    pLocale = CXML_Element::Parse(pOut, dwSize);
     FX_Free(pOut);
   }
   return pLocale ? std::unique_ptr<IFX_Locale>(
diff --git a/xfa/fxfa/parser/xfa_localevalue.cpp b/xfa/fxfa/parser/xfa_localevalue.cpp
index 8796135..7e92535 100644
--- a/xfa/fxfa/parser/xfa_localevalue.cpp
+++ b/xfa/fxfa/parser/xfa_localevalue.cpp
@@ -128,7 +128,7 @@
       case FX_LOCALECATEGORY_Zero:
         bRet = pFormat->ParseZero(wsValue, wsFormat);
         if (!bRet) {
-          bRet = wsValue == FX_WSTRC(L"0");
+          bRet = wsValue == L"0";
         }
         break;
       case FX_LOCALECATEGORY_Num: {
@@ -498,7 +498,7 @@
       }
       break;
     case FX_LOCALECATEGORY_Zero:
-      if (m_wsValue == FX_WSTRC(L"0")) {
+      if (m_wsValue == L"0") {
         bRet = pFormat->FormatZero(wsFormat, wsResult);
       }
       break;
@@ -813,9 +813,8 @@
         break;
       case FX_LOCALECATEGORY_Zero:
         bRet = pFormat->ParseZero(wsValue, wsFormat);
-        if (bRet) {
-          m_wsValue = FX_WSTRC(L"0");
-        }
+        if (bRet)
+          m_wsValue = L"0";
         break;
       case FX_LOCALECATEGORY_Num: {
         CFX_WideString fNum;
diff --git a/xfa/fxfa/xfa_ffpageview.h b/xfa/fxfa/xfa_ffpageview.h
index c6bbe7d..4b50a23 100644
--- a/xfa/fxfa/xfa_ffpageview.h
+++ b/xfa/fxfa/xfa_ffpageview.h
@@ -1,4 +1,4 @@
-// Copyright 2014 PDFium Authors. All rights reserved.
+// Copyrig 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.
 
@@ -7,6 +7,8 @@
 #ifndef XFA_FXFA_XFA_FFPAGEVIEW_H_
 #define XFA_FXFA_XFA_FFPAGEVIEW_H_
 
+#include <vector>
+
 #include "xfa/fxfa/parser/cxfa_containerlayoutitem.h"
 #include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
 #include "xfa/fxfa/parser/cxfa_traversestrategy_layoutitem.h"
@@ -20,10 +22,8 @@
   ~CXFA_FFPageView() override;
 
   CXFA_FFDocView* GetDocView() const;
-  void GetPageViewRect(CFX_RectF& rtPage) const;
-  void GetDisplayMatrix(CFX_Matrix& mt,
-                        const CFX_Rect& rtDisp,
-                        int32_t iRotate) const;
+  CFX_RectF GetPageViewRect() const;
+  CFX_Matrix GetDisplayMatrix(const CFX_Rect& rtDisp, int32_t iRotate) const;
   IXFA_WidgetIterator* CreateWidgetIterator(
       uint32_t dwTraverseWay = XFA_TRAVERSEWAY_Form,
       uint32_t dwWidgetFilter = XFA_WidgetStatus_Visible |
@@ -59,7 +59,6 @@
   bool m_bIgnorerelevant;
   CXFA_LayoutItemIterator m_sIterator;
 };
-typedef CFX_ArrayTemplate<CXFA_FFWidget*> CXFA_WidgetArray;
 
 class CXFA_TabParam {
  public:
@@ -67,7 +66,7 @@
   ~CXFA_TabParam();
 
   CXFA_FFWidget* m_pWidget;
-  CXFA_WidgetArray m_Children;
+  std::vector<CXFA_FFWidget*> m_Children;
 };
 
 class CXFA_FFTabOrderPageWidgetIterator : public IXFA_WidgetIterator {
@@ -89,7 +88,7 @@
   CXFA_FFWidget* FindWidgetByName(const CFX_WideString& wsWidgetName,
                                   CXFA_FFWidget* pRefWidget);
   void CreateTabOrderWidgetArray();
-  void CreateSpaceOrderWidgetArray(CXFA_WidgetArray& WidgetArray);
+  void CreateSpaceOrderWidgetArray(std::vector<CXFA_FFWidget*>* WidgetArray);
   CXFA_FFWidget* GetWidget(CXFA_LayoutItem* pLayoutItem);
   void OrderContainer(CXFA_LayoutItemIterator* sIterator,
                       CXFA_LayoutItem* pContainerItem,
@@ -98,7 +97,7 @@
                       bool& bContentArea,
                       bool bMarsterPage = false);
 
-  CXFA_WidgetArray m_TabOrderWidgetArray;
+  std::vector<CXFA_FFWidget*> m_TabOrderWidgetArray;
   CXFA_FFPageView* m_pPageView;
   uint32_t m_dwFilter;
   int32_t m_iCurWidget;
diff --git a/xfa/fxfa/xfa_ffwidget.h b/xfa/fxfa/xfa_ffwidget.h
index f4ef8ce..5972b8a 100644
--- a/xfa/fxfa/xfa_ffwidget.h
+++ b/xfa/fxfa/xfa_ffwidget.h
@@ -24,7 +24,9 @@
 inline FX_FLOAT XFA_UnitPx2Pt(FX_FLOAT fPx, FX_FLOAT fDpi) {
   return fPx * 72.0f / fDpi;
 }
+
 #define XFA_FLOAT_PERCISION 0.001f
+
 enum XFA_WIDGETITEM {
   XFA_WIDGETITEM_Parent,
   XFA_WIDGETITEM_FirstChild,
@@ -37,18 +39,16 @@
   CXFA_CalcData();
   ~CXFA_CalcData();
 
-  CFX_ArrayTemplate<CXFA_WidgetAcc*> m_Globals;
+  std::vector<CXFA_WidgetAcc*> m_Globals;
   int32_t m_iRefCount;
 };
 
 class CXFA_FFWidget : public CXFA_ContentLayoutItem {
  public:
-  CXFA_FFWidget(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc);
+  explicit CXFA_FFWidget(CXFA_WidgetAcc* pDataAcc);
   ~CXFA_FFWidget() override;
 
-  virtual bool GetBBox(CFX_RectF& rtBox,
-                       uint32_t dwStatus,
-                       bool bDrawFocus = false);
+  virtual CFX_RectF GetBBox(uint32_t dwStatus, bool bDrawFocus = false);
   virtual void RenderWidget(CFX_Graphics* pGS,
                             CFX_Matrix* pMatrix,
                             uint32_t dwStatus);
@@ -60,25 +60,24 @@
   virtual void UpdateWidgetProperty();
   virtual bool OnMouseEnter();
   virtual bool OnMouseExit();
-  virtual bool OnLButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy);
-  virtual bool OnLButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy);
-  virtual bool OnLButtonDblClk(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy);
-  virtual bool OnMouseMove(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy);
+  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);
   virtual bool OnMouseWheel(uint32_t dwFlags,
                             int16_t zDelta,
-                            FX_FLOAT fx,
-                            FX_FLOAT fy);
-  virtual bool OnRButtonDown(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy);
-  virtual bool OnRButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy);
-  virtual bool OnRButtonDblClk(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy);
+                            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);
 
   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(FX_FLOAT fx, FX_FLOAT fy);
-  virtual bool OnSetCursor(FX_FLOAT fx, FX_FLOAT fy);
+  virtual FWL_WidgetHit OnHitTest(const CFX_PointF& point);
+  virtual bool OnSetCursor(const CFX_PointF& point);
   virtual bool CanUndo();
   virtual bool CanRedo();
   virtual bool Undo();
@@ -100,10 +99,10 @@
   virtual bool ReplaceSpellCheckWord(CFX_PointF pointf,
                                      const CFX_ByteStringC& bsReplace);
 
-  CXFA_FFPageView* GetPageView();
-  void SetPageView(CXFA_FFPageView* pPageView);
-  void GetWidgetRect(CFX_RectF& rtWidget);
-  CFX_RectF ReCacheWidgetRect();
+  CXFA_FFPageView* GetPageView() const { return m_pPageView; }
+  void SetPageView(CXFA_FFPageView* pPageView) { m_pPageView = pPageView; }
+  CFX_RectF GetWidgetRect();
+  CFX_RectF RecacheWidgetRect();
   uint32_t GetStatus();
   void ModifyStatus(uint32_t dwAdded, uint32_t dwRemoved);
 
@@ -119,24 +118,23 @@
   void AddInvalidateRect(const CFX_RectF* pRect = nullptr);
   bool GetCaptionText(CFX_WideString& wsCap);
   bool IsFocused();
-  void Rotate2Normal(FX_FLOAT& fx, FX_FLOAT& fy);
-  void GetRotateMatrix(CFX_Matrix& mt);
+  CFX_PointF Rotate2Normal(const CFX_PointF& point);
+  CFX_Matrix GetRotateMatrix();
   bool IsLayoutRectEmpty();
   CXFA_FFWidget* GetParent();
   bool IsAncestorOf(CXFA_FFWidget* pWidget);
   const CFWL_App* GetFWLApp();
 
  protected:
-  virtual bool PtInActiveRect(FX_FLOAT fx, FX_FLOAT fy);
+  virtual bool PtInActiveRect(const CFX_PointF& point);
 
   void DrawBorder(CFX_Graphics* pGS,
                   CXFA_Box box,
                   const CFX_RectF& rtBorder,
                   CFX_Matrix* pMatrix,
                   uint32_t dwFlags = 0);
-  void GetMinMaxWidth(FX_FLOAT fMinWidth, FX_FLOAT fMaxWidth);
-  void GetMinMaxHeight(FX_FLOAT fMinHeight, FX_FLOAT fMaxHeight);
-  void GetRectWithoutRotate(CFX_RectF& rtWidget);
+
+  CFX_RectF GetRectWithoutRotate();
   bool IsMatchVisibleStatus(uint32_t dwStatus);
   void EventKillFocus();
   bool IsButtonDown();
diff --git a/xfa/fxfa/xfa_ffwidgethandler.h b/xfa/fxfa/xfa_ffwidgethandler.h
index 7335f9d..66bda3e 100644
--- a/xfa/fxfa/xfa_ffwidgethandler.h
+++ b/xfa/fxfa/xfa_ffwidgethandler.h
@@ -29,43 +29,35 @@
   bool OnMouseExit(CXFA_FFWidget* hWidget);
   bool OnLButtonDown(CXFA_FFWidget* hWidget,
                      uint32_t dwFlags,
-                     FX_FLOAT fx,
-                     FX_FLOAT fy);
+                     const CFX_PointF& point);
   bool OnLButtonUp(CXFA_FFWidget* hWidget,
                    uint32_t dwFlags,
-                   FX_FLOAT fx,
-                   FX_FLOAT fy);
+                   const CFX_PointF& point);
   bool OnLButtonDblClk(CXFA_FFWidget* hWidget,
                        uint32_t dwFlags,
-                       FX_FLOAT fx,
-                       FX_FLOAT fy);
+                       const CFX_PointF& point);
   bool OnMouseMove(CXFA_FFWidget* hWidget,
                    uint32_t dwFlags,
-                   FX_FLOAT fx,
-                   FX_FLOAT fy);
+                   const CFX_PointF& point);
   bool OnMouseWheel(CXFA_FFWidget* hWidget,
                     uint32_t dwFlags,
                     int16_t zDelta,
-                    FX_FLOAT fx,
-                    FX_FLOAT fy);
+                    const CFX_PointF& point);
   bool OnRButtonDown(CXFA_FFWidget* hWidget,
                      uint32_t dwFlags,
-                     FX_FLOAT fx,
-                     FX_FLOAT fy);
+                     const CFX_PointF& point);
   bool OnRButtonUp(CXFA_FFWidget* hWidget,
                    uint32_t dwFlags,
-                   FX_FLOAT fx,
-                   FX_FLOAT fy);
+                   const CFX_PointF& point);
   bool OnRButtonDblClk(CXFA_FFWidget* hWidget,
                        uint32_t dwFlags,
-                       FX_FLOAT fx,
-                       FX_FLOAT fy);
+                       const CFX_PointF& point);
 
   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, FX_FLOAT fx, FX_FLOAT fy);
-  bool OnSetCursor(CXFA_FFWidget* hWidget, FX_FLOAT fx, FX_FLOAT fy);
+  FWL_WidgetHit OnHitTest(CXFA_FFWidget* hWidget, const CFX_PointF& point);
+  bool OnSetCursor(CXFA_FFWidget* hWidget, const CFX_PointF& point);
   void RenderWidget(CXFA_FFWidget* hWidget,
                     CFX_Graphics* pGS,
                     CFX_Matrix* pMatrix,
diff --git a/xfa/fxgraphics/cagg_graphics.cpp b/xfa/fxgraphics/cagg_graphics.cpp
deleted file mode 100644
index 5d1f563..0000000
--- a/xfa/fxgraphics/cagg_graphics.cpp
+++ /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
-
-#include "xfa/fxgraphics/cagg_graphics.h"
-
-CAGG_Graphics::CAGG_Graphics() : m_owner(nullptr) {}
-
-FWL_Error CAGG_Graphics::Create(CFX_Graphics* owner,
-                                int32_t width,
-                                int32_t height,
-                                FXDIB_Format format) {
-  if (owner->m_renderDevice)
-    return FWL_Error::ParameterInvalid;
-  if (m_owner)
-    return FWL_Error::PropertyInvalid;
-
-  CFX_FxgeDevice* device = new CFX_FxgeDevice;
-  device->Create(width, height, format, nullptr);
-  m_owner = owner;
-  m_owner->m_renderDevice = device;
-  m_owner->m_renderDevice->GetBitmap()->Clear(0xFFFFFFFF);
-  return FWL_Error::Succeeded;
-}
-
-CAGG_Graphics::~CAGG_Graphics() {
-  delete m_owner->m_renderDevice;
-}
diff --git a/xfa/fxgraphics/cagg_graphics.h b/xfa/fxgraphics/cagg_graphics.h
deleted file mode 100644
index 9f57a72..0000000
--- a/xfa/fxgraphics/cagg_graphics.h
+++ /dev/null
@@ -1,29 +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_FXGRAPHICS_CAGG_GRAPHICS_H_
-#define XFA_FXGRAPHICS_CAGG_GRAPHICS_H_
-
-#include "core/fxge/fx_dib.h"
-#include "xfa/fxgraphics/cfx_graphics.h"
-
-class CFX_Graphics;
-
-class CAGG_Graphics {
- public:
-  CAGG_Graphics();
-  virtual ~CAGG_Graphics();
-
-  FWL_Error Create(CFX_Graphics* owner,
-                   int32_t width,
-                   int32_t height,
-                   FXDIB_Format format);
-
- private:
-  CFX_Graphics* m_owner;
-};
-
-#endif  // XFA_FXGRAPHICS_CAGG_GRAPHICS_H_
diff --git a/xfa/fxgraphics/cfx_color.cpp b/xfa/fxgraphics/cfx_color.cpp
index 2044b76..36025a8 100644
--- a/xfa/fxgraphics/cfx_color.cpp
+++ b/xfa/fxgraphics/cfx_color.cpp
@@ -24,26 +24,23 @@
   m_type = FX_COLOR_None;
 }
 
-FWL_Error CFX_Color::Set(const FX_ARGB argb) {
+void CFX_Color::Set(const FX_ARGB argb) {
   m_type = FX_COLOR_Solid;
   m_info.argb = argb;
   m_info.pattern = nullptr;
-  return FWL_Error::Succeeded;
 }
 
-FWL_Error CFX_Color::Set(CFX_Pattern* pattern, const FX_ARGB argb) {
+void CFX_Color::Set(CFX_Pattern* pattern, const FX_ARGB argb) {
   if (!pattern)
-    return FWL_Error::ParameterInvalid;
+    return;
   m_type = FX_COLOR_Pattern;
   m_info.argb = argb;
   m_info.pattern = pattern;
-  return FWL_Error::Succeeded;
 }
 
-FWL_Error CFX_Color::Set(CFX_Shading* shading) {
+void CFX_Color::Set(CFX_Shading* shading) {
   if (!shading)
-    return FWL_Error::ParameterInvalid;
+    return;
   m_type = FX_COLOR_Shading;
   m_shading = shading;
-  return FWL_Error::Succeeded;
 }
diff --git a/xfa/fxgraphics/cfx_color.h b/xfa/fxgraphics/cfx_color.h
index f47f8c4..75f7fe2 100644
--- a/xfa/fxgraphics/cfx_color.h
+++ b/xfa/fxgraphics/cfx_color.h
@@ -23,9 +23,9 @@
   CFX_Color(CFX_Pattern* pattern, const FX_ARGB argb);
   virtual ~CFX_Color();
 
-  FWL_Error Set(const FX_ARGB argb);
-  FWL_Error Set(CFX_Pattern* pattern, const FX_ARGB argb);
-  FWL_Error Set(CFX_Shading* shading);
+  void Set(const FX_ARGB argb);
+  void Set(CFX_Pattern* pattern, const FX_ARGB argb);
+  void Set(CFX_Shading* shading);
 
  private:
   friend class CFX_Graphics;
diff --git a/xfa/fxgraphics/cfx_graphics.cpp b/xfa/fxgraphics/cfx_graphics.cpp
index 059872f..d2f2151 100644
--- a/xfa/fxgraphics/cfx_graphics.cpp
+++ b/xfa/fxgraphics/cfx_graphics.cpp
@@ -13,10 +13,8 @@
 #include "core/fxge/cfx_renderdevice.h"
 #include "core/fxge/cfx_unicodeencoding.h"
 #include "third_party/base/ptr_util.h"
-#include "xfa/fxgraphics/cagg_graphics.h"
 #include "xfa/fxgraphics/cfx_color.h"
 #include "xfa/fxgraphics/cfx_path.h"
-#include "xfa/fxgraphics/cfx_path_generator.h"
 #include "xfa/fxgraphics/cfx_pattern.h"
 #include "xfa/fxgraphics/cfx_shading.h"
 
@@ -36,668 +34,111 @@
 };
 
 const FX_HATCHDATA hatchBitmapData[FX_HATCHSTYLE_Total] = {
-    {16,
+    {16,  // Horizontal
      16,
      {
-         0xff, 0xff, 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, 0xff, 0xff, 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,
+         0xff, 0xff, 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, 0xff,
+         0xff, 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,
      }},
-    {16,
+    {16,  // Vertical
      16,
      {
-         0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00,
+         0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00,
+         0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80,
+         0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80,
+         0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
+         0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00,
+         0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
      }},
-    {16,
+    {16,  // ForwardDiagonal
      16,
      {
-         0x80, 0x80, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00,
-         0x10, 0x10, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00,
-         0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x40, 0x40, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,
-         0x08, 0x08, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00,
-         0x01, 0x01, 0x00, 0x00,
+         0x80, 0x80, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x20, 0x20, 0x00,
+         0x00, 0x10, 0x10, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x04, 0x04,
+         0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x80,
+         0x80, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00,
+         0x10, 0x10, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x04, 0x04, 0x00,
+         0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
      }},
-    {16,
+    {16,  // BackwardDiagonal
      16,
      {
-         0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00,
-         0x08, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00,
-         0x40, 0x40, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
-         0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00,
-         0x10, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00,
+         0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 0x00,
+         0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20,
+         0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x01,
+         0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00,
+         0x08, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00,
+         0x00, 0x40, 0x40, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
      }},
-    {16,
+    {16,  // Cross
      16,
      {
-         0xff, 0xff, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00,
+         0xff, 0xff, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00,
+         0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80,
+         0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0xff,
+         0xff, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
+         0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00,
+         0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
      }},
-    {16,
+    {16,  // DiagonalCross
      16,
      {
-         0x81, 0x81, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00,
-         0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00,
-         0x42, 0x42, 0x00, 0x00, 0x81, 0x81, 0x00, 0x00, 0x81, 0x81, 0x00, 0x00,
-         0x42, 0x42, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
-         0x18, 0x18, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00,
-         0x81, 0x81, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x88, 0x88, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00,
-         0x88, 0x88, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00,
-         0x88, 0x88, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x22, 0x22, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xaa, 0xaa, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
-         0x11, 0x11, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
-         0xaa, 0xaa, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
-         0x44, 0x44, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00,
-         0xaa, 0xaa, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
-         0x11, 0x11, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xaa, 0xaa, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
-         0x51, 0x51, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00,
-         0xaa, 0xaa, 0x00, 0x00, 0x15, 0x15, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
-         0x55, 0x55, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x51, 0x51, 0x00, 0x00,
-         0xaa, 0xaa, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
-         0x15, 0x15, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xaa, 0xaa, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
-         0x55, 0x55, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00,
-         0xaa, 0xaa, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
-         0x55, 0x55, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00,
-         0xaa, 0xaa, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
-         0x55, 0x55, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xee, 0xee, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0xbb, 0xbb, 0x00, 0x00,
-         0x55, 0x55, 0x00, 0x00, 0xee, 0xee, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00,
-         0xbb, 0xbb, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0xee, 0xee, 0x00, 0x00,
-         0x55, 0x55, 0x00, 0x00, 0xbb, 0xbb, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00,
-         0xee, 0xee, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0xbb, 0xbb, 0x00, 0x00,
-         0x55, 0x55, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x77, 0x77, 0x00, 0x00, 0xdd, 0xdd, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00,
-         0xdd, 0xdd, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00, 0xdd, 0xdd, 0x00, 0x00,
-         0x77, 0x77, 0x00, 0x00, 0xdd, 0xdd, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00,
-         0xdd, 0xdd, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00, 0xdd, 0xdd, 0x00, 0x00,
-         0x77, 0x77, 0x00, 0x00, 0xdd, 0xdd, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00,
-         0xdd, 0xdd, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x77, 0x77, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xdd, 0xdd, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0xdd, 0xdd, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00, 0xdd, 0xdd, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0x77, 0x77, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xdd, 0xdd, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xef, 0xef, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00, 0xef, 0xef, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0xfe, 0xfe, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xef, 0xef, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0xef, 0xef, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0xf7, 0xf7, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xf7, 0xf7, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0x7f, 0x7f, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x88, 0x88, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00,
-         0x11, 0x11, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
-         0x22, 0x22, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x44, 0x44, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00,
-         0x88, 0x88, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00,
-         0x11, 0x11, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x11, 0x11, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
-         0x88, 0x88, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00,
-         0x44, 0x44, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00,
-         0x22, 0x22, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x11, 0x11, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
-         0x88, 0x88, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xcc, 0xcc, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0x33, 0x33, 0x00, 0x00,
-         0x99, 0x99, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00,
-         0x33, 0x33, 0x00, 0x00, 0x99, 0x99, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00,
-         0x66, 0x66, 0x00, 0x00, 0x33, 0x33, 0x00, 0x00, 0x99, 0x99, 0x00, 0x00,
-         0xcc, 0xcc, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0x33, 0x33, 0x00, 0x00,
-         0x99, 0x99, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x33, 0x33, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00,
-         0x99, 0x99, 0x00, 0x00, 0x33, 0x33, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00,
-         0xcc, 0xcc, 0x00, 0x00, 0x99, 0x99, 0x00, 0x00, 0x33, 0x33, 0x00, 0x00,
-         0x66, 0x66, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00, 0x99, 0x99, 0x00, 0x00,
-         0x33, 0x33, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00,
-         0x99, 0x99, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xc1, 0xc1, 0x00, 0x00, 0xe0, 0xe0, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00,
-         0x38, 0x38, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x0e, 0x0e, 0x00, 0x00,
-         0x07, 0x07, 0x00, 0x00, 0x83, 0x83, 0x00, 0x00, 0xc1, 0xc1, 0x00, 0x00,
-         0xe0, 0xe0, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00,
-         0x1c, 0x1c, 0x00, 0x00, 0x0e, 0x0e, 0x00, 0x00, 0x07, 0x07, 0x00, 0x00,
-         0x83, 0x83, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x83, 0x83, 0x00, 0x00, 0x07, 0x07, 0x00, 0x00, 0x0e, 0x0e, 0x00, 0x00,
-         0x1c, 0x1c, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00,
-         0xe0, 0xe0, 0x00, 0x00, 0xc1, 0xc1, 0x00, 0x00, 0x83, 0x83, 0x00, 0x00,
-         0x07, 0x07, 0x00, 0x00, 0x0e, 0x0e, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00,
-         0x38, 0x38, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0xe0, 0xe0, 0x00, 0x00,
-         0xc1, 0xc1, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x88, 0x88, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x88, 0x88, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x88, 0x88, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x88, 0x88, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x88, 0x88, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x88, 0x88, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x55, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00,
-         0x55, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00,
-         0x55, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00,
-         0x55, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00,
-         0x55, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00,
-         0x55, 0x55, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xcc, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00,
-         0xcc, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00,
-         0xcc, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00,
-         0xcc, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00,
-         0xcc, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00,
-         0xcc, 0xcc, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x44, 0x44, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
-         0x22, 0x22, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00,
-         0x22, 0x22, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00,
-         0x44, 0x44, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00,
-         0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00,
-         0x08, 0x08, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x80, 0x80, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
-         0x02, 0x02, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
-         0x20, 0x20, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x08, 0x08, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00,
-         0x10, 0x10, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00,
-         0x04, 0x04, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xb1, 0xb1, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00,
-         0x1b, 0x1b, 0x00, 0x00, 0xd8, 0xd8, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00,
-         0x0c, 0x0c, 0x00, 0x00, 0x8d, 0x8d, 0x00, 0x00, 0xb1, 0xb1, 0x00, 0x00,
-         0x30, 0x30, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x1b, 0x1b, 0x00, 0x00,
-         0xd8, 0xd8, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00,
-         0x8d, 0x8d, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x81, 0x81, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00,
-         0x18, 0x18, 0x00, 0x00, 0x81, 0x81, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00,
-         0x24, 0x24, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x81, 0x81, 0x00, 0x00,
-         0x42, 0x42, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
-         0x81, 0x81, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00,
-         0x18, 0x18, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x25, 0x25, 0x00, 0x00,
-         0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
-         0x25, 0x25, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x18, 0x18, 0x00, 0x00, 0x25, 0x25, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x25, 0x25, 0x00, 0x00,
-         0xc0, 0xc0, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00,
-         0x08, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00,
-         0x42, 0x42, 0x00, 0x00, 0x81, 0x81, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
-         0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00,
-         0x18, 0x18, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00,
-         0x81, 0x81, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xff, 0xff, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00,
-         0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00,
-         0x08, 0x08, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x88, 0x88, 0x00, 0x00, 0x54, 0x54, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00,
-         0x45, 0x45, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x14, 0x14, 0x00, 0x00,
-         0x22, 0x22, 0x00, 0x00, 0x51, 0x51, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x54, 0x54, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0x45, 0x45, 0x00, 0x00,
-         0x88, 0x88, 0x00, 0x00, 0x14, 0x14, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00,
-         0x51, 0x51, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xaa, 0xaa, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
-         0x55, 0x55, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00,
-         0xf0, 0xf0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
-         0x55, 0x55, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00,
-         0xf0, 0xf0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00,
-         0xf0, 0xf0, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00,
-         0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x01, 0x01, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x10, 0x10, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-         0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x03, 0x03, 0x00, 0x00, 0x84, 0x84, 0x00, 0x00, 0x48, 0x48, 0x00, 0x00,
-         0x30, 0x30, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00,
-         0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00,
-         0x84, 0x84, 0x00, 0x00, 0x48, 0x48, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00,
-         0x0c, 0x0c, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
-         0x01, 0x01, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xff, 0xff, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0x99, 0x99, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00, 0x99, 0x99, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0x66, 0x66, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x99, 0x99, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0x99, 0x99, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x77, 0x77, 0x00, 0x00, 0x89, 0x89, 0x00, 0x00, 0x8f, 0x8f, 0x00, 0x00,
-         0x8f, 0x8f, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00, 0x98, 0x98, 0x00, 0x00,
-         0xf8, 0xf8, 0x00, 0x00, 0xf8, 0xf8, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00,
-         0x89, 0x89, 0x00, 0x00, 0x8f, 0x8f, 0x00, 0x00, 0x8f, 0x8f, 0x00, 0x00,
-         0x77, 0x77, 0x00, 0x00, 0x98, 0x98, 0x00, 0x00, 0xf8, 0xf8, 0x00, 0x00,
-         0xf8, 0xf8, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xff, 0xff, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x88, 0x88, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x88, 0x88, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-         0x88, 0x88, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0xff, 0xff, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
-         0x88, 0x88, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x99, 0x99, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00,
-         0x99, 0x99, 0x00, 0x00, 0x99, 0x99, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00,
-         0x66, 0x66, 0x00, 0x00, 0x99, 0x99, 0x00, 0x00, 0x99, 0x99, 0x00, 0x00,
-         0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0x99, 0x99, 0x00, 0x00,
-         0x99, 0x99, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00,
-         0x99, 0x99, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0xf0, 0xf0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00,
-         0xf0, 0xf0, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00,
-         0x0f, 0x0f, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00,
-         0xf0, 0xf0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00,
-         0x0f, 0x0f, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00,
-         0x0f, 0x0f, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x82, 0x82, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00, 0x28, 0x28, 0x00, 0x00,
-         0x10, 0x10, 0x00, 0x00, 0x28, 0x28, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
-         0x82, 0x82, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x82, 0x82, 0x00, 0x00,
-         0x44, 0x44, 0x00, 0x00, 0x28, 0x28, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,
-         0x28, 0x28, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00, 0x82, 0x82, 0x00, 0x00,
-         0x01, 0x01, 0x00, 0x00,
-     }},
-    {16,
-     16,
-     {
-         0x10, 0x10, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00,
-         0xfe, 0xfe, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00,
-         0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,
-         0x38, 0x38, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00,
-         0x7c, 0x7c, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,
-         0x00, 0x00, 0x00, 0x00,
+         0x81, 0x81, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x24, 0x24, 0x00,
+         0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x24, 0x24,
+         0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x81, 0x81, 0x00, 0x00, 0x81,
+         0x81, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00,
+         0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x24, 0x24, 0x00,
+         0x00, 0x42, 0x42, 0x00, 0x00, 0x81, 0x81, 0x00, 0x00,
      }},
 };
 
 }  // namespace
 
-CFX_Graphics::CFX_Graphics()
-    : m_type(FX_CONTEXT_None), m_renderDevice(nullptr) {}
-
-FWL_Error CFX_Graphics::Create(CFX_RenderDevice* renderDevice,
-                               bool isAntialiasing) {
+CFX_Graphics::CFX_Graphics(CFX_RenderDevice* renderDevice)
+    : m_type(FX_CONTEXT_None), m_renderDevice(renderDevice) {
   if (!renderDevice)
-    return FWL_Error::ParameterInvalid;
-  if (m_type != FX_CONTEXT_None)
-    return FWL_Error::PropertyInvalid;
-
+    return;
   m_type = FX_CONTEXT_Device;
-  m_info.isAntialiasing = isAntialiasing;
-  m_renderDevice = renderDevice;
-  if (m_renderDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP)
-    return FWL_Error::Succeeded;
-  return FWL_Error::Indefinite;
-}
-
-FWL_Error CFX_Graphics::Create(int32_t width,
-                               int32_t height,
-                               FXDIB_Format format,
-                               bool isNative,
-                               bool isAntialiasing) {
-  if (m_type != FX_CONTEXT_None)
-    return FWL_Error::PropertyInvalid;
-
-  m_type = FX_CONTEXT_Device;
-  m_info.isAntialiasing = isAntialiasing;
-  m_aggGraphics = pdfium::MakeUnique<CAGG_Graphics>();
-  return m_aggGraphics->Create(this, width, height, format);
 }
 
 CFX_Graphics::~CFX_Graphics() {}
 
-FWL_Error CFX_Graphics::GetDeviceCap(const int32_t capID,
-                                     FX_DeviceCap& capVal) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    capVal = m_renderDevice->GetDeviceCaps(capID);
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
+void CFX_Graphics::SaveGraphState() {
+  if (m_type != FX_CONTEXT_Device || !m_renderDevice)
+    return;
+
+  m_renderDevice->SaveState();
+  m_infoStack.push_back(pdfium::MakeUnique<TInfo>(m_info));
 }
 
-FWL_Error CFX_Graphics::IsPrinterDevice(bool& isPrinter) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    isPrinter = m_renderDevice->GetDeviceClass() == FXDC_PRINTER;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
+void CFX_Graphics::RestoreGraphState() {
+  if (m_type != FX_CONTEXT_Device || !m_renderDevice)
+    return;
+
+  m_renderDevice->RestoreState(false);
+  if (m_infoStack.empty() || !m_infoStack.back())
+    return;
+
+  m_info = *m_infoStack.back();
+  m_infoStack.pop_back();
+  return;
 }
 
-FWL_Error CFX_Graphics::EnableAntialiasing(bool isAntialiasing) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    m_info.isAntialiasing = isAntialiasing;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::SaveGraphState() {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    m_renderDevice->SaveState();
-    m_infoStack.Add(new TInfo(m_info));
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::RestoreGraphState() {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    m_renderDevice->RestoreState(false);
-    int32_t size = m_infoStack.GetSize();
-    if (size <= 0) {
-      return FWL_Error::IntermediateValueInvalid;
-    }
-    int32_t topIndex = size - 1;
-    std::unique_ptr<TInfo> info(m_infoStack.GetAt(topIndex));
-    if (!info)
-      return FWL_Error::IntermediateValueInvalid;
-    m_info = *info;
-    m_infoStack.RemoveAt(topIndex);
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::GetLineCap(CFX_GraphStateData::LineCap& lineCap) const {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    lineCap = m_info.graphState.m_LineCap;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::SetLineCap(CFX_GraphStateData::LineCap lineCap) {
+void CFX_Graphics::SetLineCap(CFX_GraphStateData::LineCap lineCap) {
   if (m_type == FX_CONTEXT_Device && m_renderDevice) {
     m_info.graphState.m_LineCap = lineCap;
-    return FWL_Error::Succeeded;
   }
-  return FWL_Error::PropertyInvalid;
 }
 
-FWL_Error CFX_Graphics::GetDashCount(int32_t& dashCount) const {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    dashCount = m_info.graphState.m_DashCount;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::GetLineDash(FX_FLOAT& dashPhase,
-                                    FX_FLOAT* dashArray) const {
-  if (!dashArray)
-    return FWL_Error::ParameterInvalid;
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    dashPhase = m_info.graphState.m_DashPhase;
-    FXSYS_memcpy(dashArray, m_info.graphState.m_DashArray,
-                 m_info.graphState.m_DashCount * sizeof(FX_FLOAT));
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::SetLineDash(FX_FLOAT dashPhase,
-                                    FX_FLOAT* dashArray,
-                                    int32_t dashCount) {
+void CFX_Graphics::SetLineDash(FX_FLOAT dashPhase,
+                               FX_FLOAT* dashArray,
+                               int32_t dashCount) {
   if (dashCount > 0 && !dashArray)
-    return FWL_Error::ParameterInvalid;
+    return;
 
   dashCount = dashCount < 0 ? 0 : dashCount;
   if (m_type == FX_CONTEXT_Device && m_renderDevice) {
@@ -710,165 +151,68 @@
     for (int32_t i = 0; i < dashCount; i++) {
       m_info.graphState.m_DashArray[i] = dashArray[i] * scale;
     }
-    return FWL_Error::Succeeded;
   }
-  return FWL_Error::PropertyInvalid;
 }
 
-FWL_Error CFX_Graphics::SetLineDash(FX_DashStyle dashStyle) {
+void CFX_Graphics::SetLineDash(FX_DashStyle dashStyle) {
   if (m_type == FX_CONTEXT_Device && m_renderDevice)
-    return RenderDeviceSetLineDash(dashStyle);
-  return FWL_Error::PropertyInvalid;
+    RenderDeviceSetLineDash(dashStyle);
 }
 
-FWL_Error CFX_Graphics::GetLineJoin(
-    CFX_GraphStateData::LineJoin& lineJoin) const {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    lineJoin = m_info.graphState.m_LineJoin;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::SetLineJoin(CFX_GraphStateData::LineJoin lineJoin) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    m_info.graphState.m_LineJoin = lineJoin;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::GetMiterLimit(FX_FLOAT& miterLimit) const {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    miterLimit = m_info.graphState.m_MiterLimit;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::SetMiterLimit(FX_FLOAT miterLimit) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    m_info.graphState.m_MiterLimit = miterLimit;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::GetLineWidth(FX_FLOAT& lineWidth) const {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    lineWidth = m_info.graphState.m_LineWidth;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::SetLineWidth(FX_FLOAT lineWidth, bool isActOnDash) {
+void CFX_Graphics::SetLineWidth(FX_FLOAT lineWidth, bool isActOnDash) {
   if (m_type == FX_CONTEXT_Device && m_renderDevice) {
     m_info.graphState.m_LineWidth = lineWidth;
     m_info.isActOnDash = isActOnDash;
-    return FWL_Error::Succeeded;
   }
-  return FWL_Error::PropertyInvalid;
 }
 
-FWL_Error CFX_Graphics::GetStrokeAlignment(
-    FX_StrokeAlignment& strokeAlignment) const {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    strokeAlignment = m_info.strokeAlignment;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::SetStrokeAlignment(FX_StrokeAlignment strokeAlignment) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    m_info.strokeAlignment = strokeAlignment;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::SetStrokeColor(CFX_Color* color) {
+void CFX_Graphics::SetStrokeColor(CFX_Color* color) {
   if (!color)
-    return FWL_Error::ParameterInvalid;
+    return;
   if (m_type == FX_CONTEXT_Device && m_renderDevice) {
     m_info.strokeColor = color;
-    return FWL_Error::Succeeded;
   }
-  return FWL_Error::PropertyInvalid;
 }
 
-FWL_Error CFX_Graphics::SetFillColor(CFX_Color* color) {
+void CFX_Graphics::SetFillColor(CFX_Color* color) {
   if (!color)
-    return FWL_Error::ParameterInvalid;
+    return;
   if (m_type == FX_CONTEXT_Device && m_renderDevice) {
     m_info.fillColor = color;
-    return FWL_Error::Succeeded;
   }
-  return FWL_Error::PropertyInvalid;
 }
 
-FWL_Error CFX_Graphics::StrokePath(CFX_Path* path, CFX_Matrix* matrix) {
+void CFX_Graphics::StrokePath(CFX_Path* path, CFX_Matrix* matrix) {
   if (!path)
-    return FWL_Error::ParameterInvalid;
+    return;
   if (m_type == FX_CONTEXT_Device && m_renderDevice)
-    return RenderDeviceStrokePath(path, matrix);
-  return FWL_Error::PropertyInvalid;
+    RenderDeviceStrokePath(path, matrix);
 }
 
-FWL_Error CFX_Graphics::FillPath(CFX_Path* path,
-                                 FX_FillMode fillMode,
-                                 CFX_Matrix* matrix) {
+void CFX_Graphics::FillPath(CFX_Path* path,
+                            FX_FillMode fillMode,
+                            CFX_Matrix* matrix) {
   if (!path)
-    return FWL_Error::ParameterInvalid;
+    return;
   if (m_type == FX_CONTEXT_Device && m_renderDevice)
-    return RenderDeviceFillPath(path, fillMode, matrix);
-  return FWL_Error::PropertyInvalid;
+    RenderDeviceFillPath(path, fillMode, matrix);
 }
 
-FWL_Error CFX_Graphics::ClipPath(CFX_Path* path,
-                                 FX_FillMode fillMode,
-                                 CFX_Matrix* matrix) {
-  if (!path)
-    return FWL_Error::ParameterInvalid;
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    bool result =
-        m_renderDevice->SetClip_PathFill(path->GetPathData(), matrix, fillMode);
-    if (!result)
-      return FWL_Error::Indefinite;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::DrawImage(CFX_DIBSource* source,
-                                  const CFX_PointF& point,
-                                  CFX_Matrix* matrix) {
+void CFX_Graphics::StretchImage(CFX_DIBSource* source,
+                                const CFX_RectF& rect,
+                                CFX_Matrix* matrix) {
   if (!source)
-    return FWL_Error::ParameterInvalid;
+    return;
   if (m_type == FX_CONTEXT_Device && m_renderDevice)
-    return RenderDeviceDrawImage(source, point, matrix);
-  return FWL_Error::PropertyInvalid;
+    RenderDeviceStretchImage(source, rect, matrix);
 }
 
-FWL_Error CFX_Graphics::StretchImage(CFX_DIBSource* source,
-                                     const CFX_RectF& rect,
-                                     CFX_Matrix* matrix) {
-  if (!source)
-    return FWL_Error::ParameterInvalid;
-  if (m_type == FX_CONTEXT_Device && m_renderDevice)
-    return RenderDeviceStretchImage(source, rect, matrix);
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::ConcatMatrix(const CFX_Matrix* matrix) {
+void CFX_Graphics::ConcatMatrix(const CFX_Matrix* matrix) {
   if (!matrix)
-    return FWL_Error::ParameterInvalid;
+    return;
   if (m_type == FX_CONTEXT_Device && m_renderDevice) {
     m_info.CTM.Concat(*matrix);
-    return FWL_Error::Succeeded;
   }
-  return FWL_Error::PropertyInvalid;
 }
 
 CFX_Matrix* CFX_Graphics::GetMatrix() {
@@ -877,445 +221,131 @@
   return nullptr;
 }
 
-FWL_Error CFX_Graphics::GetClipRect(CFX_RectF& rect) const {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    FX_RECT r = m_renderDevice->GetClipBox();
-    rect.left = (FX_FLOAT)r.left;
-    rect.top = (FX_FLOAT)r.top;
-    rect.width = (FX_FLOAT)r.Width();
-    rect.height = (FX_FLOAT)r.Height();
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::SetClipRect(const CFX_RectF& rect) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    if (!m_renderDevice->SetClip_Rect(
-            FX_RECT(FXSYS_round(rect.left), FXSYS_round(rect.top),
-                    FXSYS_round(rect.right()), FXSYS_round(rect.bottom())))) {
-      return FWL_Error::MethodNotSupported;
-    }
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::ClearClip() {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice)
-    return FWL_Error::Succeeded;
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::SetFont(CFX_Font* font) {
-  if (!font)
-    return FWL_Error::ParameterInvalid;
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    m_info.font = font;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::SetFontSize(const FX_FLOAT size) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    m_info.fontSize = size <= 0 ? 1.0f : size;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::SetFontHScale(const FX_FLOAT scale) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    m_info.fontHScale = scale <= 0 ? 1.0f : scale;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::SetCharSpacing(const FX_FLOAT spacing) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    m_info.fontSpacing = spacing < 0 ? 0 : spacing;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::SetTextDrawingMode(const int32_t mode) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice)
-    return FWL_Error::Succeeded;
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::ShowText(const CFX_PointF& point,
-                                 const CFX_WideString& text,
-                                 CFX_Matrix* matrix) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice)
-    return RenderDeviceShowText(point, text, matrix);
-  return FWL_Error::PropertyInvalid;
-}
-
-void CFX_Graphics::CalcTextRect(CFX_RectF& rect,
-                                const CFX_WideString& text,
-                                bool isMultiline,
-                                CFX_Matrix* matrix) {
+CFX_RectF CFX_Graphics::GetClipRect() const {
   if (m_type != FX_CONTEXT_Device || !m_renderDevice)
-    return;
+    return CFX_RectF();
 
-  int32_t length = text.GetLength();
-  uint32_t* charCodes = FX_Alloc(uint32_t, length);
-  FXTEXT_CHARPOS* charPos = FX_Alloc(FXTEXT_CHARPOS, length);
-  CalcTextInfo(text, charCodes, charPos, rect);
-  FX_Free(charPos);
-  FX_Free(charCodes);
+  FX_RECT r = m_renderDevice->GetClipBox();
+  return CFX_Rect(r.left, r.top, r.Width(), r.Height()).As<FX_FLOAT>();
 }
 
-FWL_Error CFX_Graphics::Transfer(CFX_Graphics* graphics,
-                                 const CFX_Matrix* matrix) {
-  if (!graphics || !graphics->m_renderDevice)
-    return FWL_Error::ParameterInvalid;
-  CFX_Matrix m;
-  m.Set(m_info.CTM.a, m_info.CTM.b, m_info.CTM.c, m_info.CTM.d, m_info.CTM.e,
-        m_info.CTM.f);
-  if (matrix) {
-    m.Concat(*matrix);
-  }
+void CFX_Graphics::SetClipRect(const CFX_RectF& rect) {
   if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    CFX_DIBitmap* bitmap = graphics->m_renderDevice->GetBitmap();
-    bool result = m_renderDevice->SetDIBits(bitmap, 0, 0);
-    if (!result)
-      return FWL_Error::MethodNotSupported;
-    return FWL_Error::Succeeded;
+    m_renderDevice->SetClip_Rect(
+        FX_RECT(FXSYS_round(rect.left), FXSYS_round(rect.top),
+                FXSYS_round(rect.right()), FXSYS_round(rect.bottom())));
   }
-  return FWL_Error::PropertyInvalid;
-}
-
-FWL_Error CFX_Graphics::Transfer(CFX_Graphics* graphics,
-                                 FX_FLOAT srcLeft,
-                                 FX_FLOAT srcTop,
-                                 const CFX_RectF& dstRect,
-                                 const CFX_Matrix* matrix) {
-  if (!graphics || !graphics->m_renderDevice)
-    return FWL_Error::ParameterInvalid;
-  CFX_Matrix m;
-  m.Set(m_info.CTM.a, m_info.CTM.b, m_info.CTM.c, m_info.CTM.d, m_info.CTM.e,
-        m_info.CTM.f);
-  if (matrix) {
-    m.Concat(*matrix);
-  }
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    CFX_DIBitmap bmp;
-    bool result =
-        bmp.Create((int32_t)dstRect.width, (int32_t)dstRect.height,
-                   graphics->m_renderDevice->GetBitmap()->GetFormat());
-    if (!result)
-      return FWL_Error::IntermediateValueInvalid;
-    result = graphics->m_renderDevice->GetDIBits(&bmp, (int32_t)srcLeft,
-                                                 (int32_t)srcTop);
-    if (!result)
-      return FWL_Error::MethodNotSupported;
-    result = m_renderDevice->SetDIBits(&bmp, (int32_t)dstRect.left,
-                                       (int32_t)dstRect.top);
-    if (!result)
-      return FWL_Error::MethodNotSupported;
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::PropertyInvalid;
 }
 
 CFX_RenderDevice* CFX_Graphics::GetRenderDevice() {
   return m_renderDevice;
 }
 
-FWL_Error CFX_Graphics::InverseRect(const CFX_RectF& rect) {
-  if (!m_renderDevice)
-    return FWL_Error::PropertyInvalid;
-  CFX_DIBitmap* bitmap = m_renderDevice->GetBitmap();
-  if (!bitmap)
-    return FWL_Error::PropertyInvalid;
-  CFX_RectF temp(rect);
-  m_info.CTM.TransformRect(temp);
-  CFX_RectF r;
-  r.Set(0, 0, (FX_FLOAT)bitmap->GetWidth(), (FX_FLOAT)bitmap->GetWidth());
-  r.Intersect(temp);
-  if (r.IsEmpty()) {
-    return FWL_Error::ParameterInvalid;
-  }
-  FX_ARGB* pBuf =
-      (FX_ARGB*)(bitmap->GetBuffer() + int32_t(r.top) * bitmap->GetPitch());
-  int32_t bottom = (int32_t)r.bottom();
-  int32_t right = (int32_t)r.right();
-  for (int32_t i = (int32_t)r.top; i < bottom; i++) {
-    FX_ARGB* pLine = pBuf + (int32_t)r.left;
-    for (int32_t j = (int32_t)r.left; j < right; j++) {
-      FX_ARGB c = *pLine;
-      *pLine++ = (c & 0xFF000000) | (0xFFFFFF - (c & 0x00FFFFFF));
-    }
-    pBuf = (FX_ARGB*)((uint8_t*)pBuf + bitmap->GetPitch());
-  }
-  return FWL_Error::Succeeded;
-}
-
-FWL_Error CFX_Graphics::XorDIBitmap(const CFX_DIBitmap* srcBitmap,
-                                    const CFX_RectF& rect) {
-  if (!m_renderDevice)
-    return FWL_Error::PropertyInvalid;
-  CFX_DIBitmap* dst = m_renderDevice->GetBitmap();
-  if (!dst)
-    return FWL_Error::PropertyInvalid;
-  CFX_RectF temp(rect);
-  m_info.CTM.TransformRect(temp);
-  CFX_RectF r;
-  r.Set(0, 0, (FX_FLOAT)dst->GetWidth(), (FX_FLOAT)dst->GetWidth());
-  r.Intersect(temp);
-  if (r.IsEmpty()) {
-    return FWL_Error::ParameterInvalid;
-  }
-  FX_ARGB* pSrcBuf = (FX_ARGB*)(srcBitmap->GetBuffer() +
-                                int32_t(r.top) * srcBitmap->GetPitch());
-  FX_ARGB* pDstBuf =
-      (FX_ARGB*)(dst->GetBuffer() + int32_t(r.top) * dst->GetPitch());
-  int32_t bottom = (int32_t)r.bottom();
-  int32_t right = (int32_t)r.right();
-  for (int32_t i = (int32_t)r.top; i < bottom; i++) {
-    FX_ARGB* pSrcLine = pSrcBuf + (int32_t)r.left;
-    FX_ARGB* pDstLine = pDstBuf + (int32_t)r.left;
-    for (int32_t j = (int32_t)r.left; j < right; j++) {
-      FX_ARGB c = *pDstLine;
-      *pDstLine++ =
-          ArgbEncode(FXARGB_A(c), (c & 0xFFFFFF) ^ (*pSrcLine & 0xFFFFFF));
-      pSrcLine++;
-    }
-    pSrcBuf = (FX_ARGB*)((uint8_t*)pSrcBuf + srcBitmap->GetPitch());
-    pDstBuf = (FX_ARGB*)((uint8_t*)pDstBuf + dst->GetPitch());
-  }
-  return FWL_Error::Succeeded;
-}
-
-FWL_Error CFX_Graphics::EqvDIBitmap(const CFX_DIBitmap* srcBitmap,
-                                    const CFX_RectF& rect) {
-  if (!m_renderDevice)
-    return FWL_Error::PropertyInvalid;
-  CFX_DIBitmap* dst = m_renderDevice->GetBitmap();
-  if (!dst)
-    return FWL_Error::PropertyInvalid;
-  CFX_RectF temp(rect);
-  m_info.CTM.TransformRect(temp);
-  CFX_RectF r;
-  r.Set(0, 0, (FX_FLOAT)dst->GetWidth(), (FX_FLOAT)dst->GetWidth());
-  r.Intersect(temp);
-  if (r.IsEmpty()) {
-    return FWL_Error::ParameterInvalid;
-  }
-  FX_ARGB* pSrcBuf = (FX_ARGB*)(srcBitmap->GetBuffer() +
-                                int32_t(r.top) * srcBitmap->GetPitch());
-  FX_ARGB* pDstBuf =
-      (FX_ARGB*)(dst->GetBuffer() + int32_t(r.top) * dst->GetPitch());
-  int32_t bottom = (int32_t)r.bottom();
-  int32_t right = (int32_t)r.right();
-  for (int32_t i = (int32_t)r.top; i < bottom; i++) {
-    FX_ARGB* pSrcLine = pSrcBuf + (int32_t)r.left;
-    FX_ARGB* pDstLine = pDstBuf + (int32_t)r.left;
-    for (int32_t j = (int32_t)r.left; j < right; j++) {
-      FX_ARGB c = *pDstLine;
-      *pDstLine++ =
-          ArgbEncode(FXARGB_A(c), ~((c & 0xFFFFFF) ^ (*pSrcLine & 0xFFFFFF)));
-      pSrcLine++;
-    }
-    pSrcBuf = (FX_ARGB*)((uint8_t*)pSrcBuf + srcBitmap->GetPitch());
-    pDstBuf = (FX_ARGB*)((uint8_t*)pDstBuf + dst->GetPitch());
-  }
-  return FWL_Error::Succeeded;
-}
-
-FWL_Error CFX_Graphics::RenderDeviceSetLineDash(FX_DashStyle dashStyle) {
+void CFX_Graphics::RenderDeviceSetLineDash(FX_DashStyle dashStyle) {
   switch (dashStyle) {
     case FX_DASHSTYLE_Solid: {
       m_info.graphState.SetDashCount(0);
-      return FWL_Error::Succeeded;
+      return;
     }
     case FX_DASHSTYLE_Dash: {
       FX_FLOAT dashArray[] = {3, 1};
       SetLineDash(0, dashArray, 2);
-      return FWL_Error::Succeeded;
+      return;
     }
     case FX_DASHSTYLE_Dot: {
       FX_FLOAT dashArray[] = {1, 1};
       SetLineDash(0, dashArray, 2);
-      return FWL_Error::Succeeded;
+      return;
     }
     case FX_DASHSTYLE_DashDot: {
       FX_FLOAT dashArray[] = {3, 1, 1, 1};
       SetLineDash(0, dashArray, 4);
-      return FWL_Error::Succeeded;
+      return;
     }
     case FX_DASHSTYLE_DashDotDot: {
       FX_FLOAT dashArray[] = {4, 1, 2, 1, 2, 1};
       SetLineDash(0, dashArray, 6);
-      return FWL_Error::Succeeded;
+      return;
     }
     default:
-      return FWL_Error::ParameterInvalid;
+      return;
   }
 }
 
-FWL_Error CFX_Graphics::RenderDeviceStrokePath(CFX_Path* path,
-                                               CFX_Matrix* matrix) {
+void CFX_Graphics::RenderDeviceStrokePath(CFX_Path* path, CFX_Matrix* matrix) {
   if (!m_info.strokeColor)
-    return FWL_Error::PropertyInvalid;
-  CFX_Matrix m;
-  m.Set(m_info.CTM.a, m_info.CTM.b, m_info.CTM.c, m_info.CTM.d, m_info.CTM.e,
-        m_info.CTM.f);
+    return;
+  CFX_Matrix m(m_info.CTM.a, m_info.CTM.b, m_info.CTM.c, m_info.CTM.d,
+               m_info.CTM.e, m_info.CTM.f);
   if (matrix) {
     m.Concat(*matrix);
   }
   switch (m_info.strokeColor->m_type) {
     case FX_COLOR_Solid: {
-      bool result =
-          m_renderDevice->DrawPath(path->GetPathData(), &m, &m_info.graphState,
-                                   0x0, m_info.strokeColor->m_info.argb, 0);
-      if (!result)
-        return FWL_Error::Indefinite;
-      return FWL_Error::Succeeded;
+      m_renderDevice->DrawPath(path->GetPathData(), &m, &m_info.graphState, 0x0,
+                               m_info.strokeColor->m_info.argb, 0);
+      return;
     }
-    case FX_COLOR_Pattern:
-      return StrokePathWithPattern(path, &m);
-    case FX_COLOR_Shading:
-      return StrokePathWithShading(path, &m);
     default:
-      return FWL_Error::PropertyInvalid;
+      return;
   }
 }
 
-FWL_Error CFX_Graphics::RenderDeviceFillPath(CFX_Path* path,
-                                             FX_FillMode fillMode,
-                                             CFX_Matrix* matrix) {
+void CFX_Graphics::RenderDeviceFillPath(CFX_Path* path,
+                                        FX_FillMode fillMode,
+                                        CFX_Matrix* matrix) {
   if (!m_info.fillColor)
-    return FWL_Error::PropertyInvalid;
-  CFX_Matrix m;
-  m.Set(m_info.CTM.a, m_info.CTM.b, m_info.CTM.c, m_info.CTM.d, m_info.CTM.e,
-        m_info.CTM.f);
+    return;
+  CFX_Matrix m(m_info.CTM.a, m_info.CTM.b, m_info.CTM.c, m_info.CTM.d,
+               m_info.CTM.e, m_info.CTM.f);
   if (matrix) {
     m.Concat(*matrix);
   }
   switch (m_info.fillColor->m_type) {
     case FX_COLOR_Solid: {
-      bool result = m_renderDevice->DrawPath(
-          path->GetPathData(), &m, &m_info.graphState,
-          m_info.fillColor->m_info.argb, 0x0, fillMode);
-      if (!result)
-        return FWL_Error::Indefinite;
-      return FWL_Error::Succeeded;
+      m_renderDevice->DrawPath(path->GetPathData(), &m, &m_info.graphState,
+                               m_info.fillColor->m_info.argb, 0x0, fillMode);
+      return;
     }
     case FX_COLOR_Pattern:
-      return FillPathWithPattern(path, fillMode, &m);
+      FillPathWithPattern(path, fillMode, &m);
+      return;
     case FX_COLOR_Shading:
-      return FillPathWithShading(path, fillMode, &m);
+      FillPathWithShading(path, fillMode, &m);
+      return;
     default:
-      return FWL_Error::PropertyInvalid;
+      return;
   }
 }
 
-FWL_Error CFX_Graphics::RenderDeviceDrawImage(CFX_DIBSource* source,
-                                              const CFX_PointF& point,
-                                              CFX_Matrix* matrix) {
-  CFX_Matrix m1;
-  m1.Set(m_info.CTM.a, m_info.CTM.b, m_info.CTM.c, m_info.CTM.d, m_info.CTM.e,
-         m_info.CTM.f);
-  if (matrix) {
-    m1.Concat(*matrix);
-  }
-  CFX_Matrix m2;
-  m2.Set((FX_FLOAT)source->GetWidth(), 0.0, 0.0, (FX_FLOAT)source->GetHeight(),
-         point.x, point.y);
-  m2.Concat(m1);
-  int32_t left, top;
-  std::unique_ptr<CFX_DIBitmap> bmp1 = source->FlipImage(false, true);
-  std::unique_ptr<CFX_DIBitmap> bmp2 = bmp1->TransformTo(&m2, left, top);
-  CFX_RectF r;
-  GetClipRect(r);
-  CFX_DIBitmap* bitmap = m_renderDevice->GetBitmap();
-  CFX_DIBitmap bmp;
-  if (bmp.Create(bitmap->GetWidth(), bitmap->GetHeight(), FXDIB_Argb) &&
-      m_renderDevice->GetDIBits(&bmp, 0, 0) &&
-      bmp.TransferBitmap(FXSYS_round(r.left), FXSYS_round(r.top),
-                         FXSYS_round(r.Width()), FXSYS_round(r.Height()),
-                         bmp2.get(), FXSYS_round(r.left - left),
-                         FXSYS_round(r.top - top)) &&
-      m_renderDevice->SetDIBits(&bmp, 0, 0)) {
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::Indefinite;
-}
-
-FWL_Error CFX_Graphics::RenderDeviceStretchImage(CFX_DIBSource* source,
-                                                 const CFX_RectF& rect,
-                                                 CFX_Matrix* matrix) {
-  CFX_Matrix m1;
-  m1.Set(m_info.CTM.a, m_info.CTM.b, m_info.CTM.c, m_info.CTM.d, m_info.CTM.e,
-         m_info.CTM.f);
+void CFX_Graphics::RenderDeviceStretchImage(CFX_DIBSource* source,
+                                            const CFX_RectF& rect,
+                                            CFX_Matrix* matrix) {
+  CFX_Matrix m1(m_info.CTM.a, m_info.CTM.b, m_info.CTM.c, m_info.CTM.d,
+                m_info.CTM.e, m_info.CTM.f);
   if (matrix) {
     m1.Concat(*matrix);
   }
   std::unique_ptr<CFX_DIBitmap> bmp1 =
       source->StretchTo((int32_t)rect.Width(), (int32_t)rect.Height());
-  CFX_Matrix m2;
-  m2.Set(rect.Width(), 0.0, 0.0, rect.Height(), rect.left, rect.top);
+  CFX_Matrix m2(rect.Width(), 0.0, 0.0, rect.Height(), rect.left, rect.top);
   m2.Concat(m1);
-  int32_t left, top;
+
+  int32_t left;
+  int32_t top;
   std::unique_ptr<CFX_DIBitmap> bmp2 = bmp1->FlipImage(false, true);
   std::unique_ptr<CFX_DIBitmap> bmp3 = bmp2->TransformTo(&m2, left, top);
-  CFX_RectF r;
-  GetClipRect(r);
+  CFX_RectF r = GetClipRect();
   CFX_DIBitmap* bitmap = m_renderDevice->GetBitmap();
-  if (bitmap->CompositeBitmap(FXSYS_round(r.left), FXSYS_round(r.top),
-                              FXSYS_round(r.Width()), FXSYS_round(r.Height()),
-                              bmp3.get(), FXSYS_round(r.left - left),
-                              FXSYS_round(r.top - top))) {
-    return FWL_Error::Succeeded;
-  }
-  return FWL_Error::Indefinite;
+  bitmap->CompositeBitmap(FXSYS_round(r.left), FXSYS_round(r.top),
+                          FXSYS_round(r.Width()), FXSYS_round(r.Height()),
+                          bmp3.get(), FXSYS_round(r.left - left),
+                          FXSYS_round(r.top - top));
 }
 
-FWL_Error CFX_Graphics::RenderDeviceShowText(const CFX_PointF& point,
-                                             const CFX_WideString& text,
-                                             CFX_Matrix* matrix) {
-  int32_t length = text.GetLength();
-  uint32_t* charCodes = FX_Alloc(uint32_t, length);
-  FXTEXT_CHARPOS* charPos = FX_Alloc(FXTEXT_CHARPOS, length);
-  CFX_RectF rect;
-  rect.Set(point.x, point.y, 0, 0);
-  CalcTextInfo(text, charCodes, charPos, rect);
-  CFX_Matrix m;
-  m.Set(m_info.CTM.a, m_info.CTM.b, m_info.CTM.c, m_info.CTM.d, m_info.CTM.e,
-        m_info.CTM.f);
-  m.Translate(0, m_info.fontSize * m_info.fontHScale);
-  if (matrix) {
-    m.Concat(*matrix);
-  }
-  bool result = m_renderDevice->DrawNormalText(
-      length, charPos, m_info.font, -m_info.fontSize * m_info.fontHScale, &m,
-      m_info.fillColor->m_info.argb, FXTEXT_CLEARTYPE);
-  if (!result)
-    return FWL_Error::Indefinite;
-  FX_Free(charPos);
-  FX_Free(charCodes);
-  return FWL_Error::Succeeded;
-}
-
-FWL_Error CFX_Graphics::StrokePathWithPattern(CFX_Path* path,
-                                              CFX_Matrix* matrix) {
-  return FWL_Error::MethodNotSupported;
-}
-
-FWL_Error CFX_Graphics::StrokePathWithShading(CFX_Path* path,
-                                              CFX_Matrix* matrix) {
-  return FWL_Error::MethodNotSupported;
-}
-
-FWL_Error CFX_Graphics::FillPathWithPattern(CFX_Path* path,
-                                            FX_FillMode fillMode,
-                                            CFX_Matrix* matrix) {
+void CFX_Graphics::FillPathWithPattern(CFX_Path* path,
+                                       FX_FillMode fillMode,
+                                       CFX_Matrix* matrix) {
   CFX_Pattern* pattern = m_info.fillColor->m_info.pattern;
   CFX_DIBitmap* bitmap = m_renderDevice->GetBitmap();
   int32_t width = bitmap->GetWidth();
@@ -1325,18 +355,15 @@
   m_renderDevice->GetDIBits(&bmp, 0, 0);
 
   FX_HatchStyle hatchStyle = m_info.fillColor->m_info.pattern->m_hatchStyle;
-  if (hatchStyle < FX_HATCHSTYLE_Horizontal ||
-      hatchStyle > FX_HATCHSTYLE_SolidDiamond) {
-    return FWL_Error::IntermediateValueInvalid;
-  }
-  const FX_HATCHDATA& data = hatchBitmapData[hatchStyle];
+  const FX_HATCHDATA& data = hatchBitmapData[static_cast<int>(hatchStyle)];
+
   CFX_DIBitmap mask;
   mask.Create(data.width, data.height, FXDIB_1bppMask);
   FXSYS_memcpy(mask.GetBuffer(), data.maskBits, mask.GetPitch() * data.height);
   CFX_FloatRect rectf = path->GetPathData()->GetBoundingBox();
-  if (matrix) {
-    rectf.Transform(matrix);
-  }
+  if (matrix)
+    matrix->TransformRect(rectf);
+
   FX_RECT rect(FXSYS_round(rectf.left), FXSYS_round(rectf.top),
                FXSYS_round(rectf.right), FXSYS_round(rectf.bottom));
   CFX_FxgeDevice device;
@@ -1353,12 +380,11 @@
   m_renderDevice->SetClip_PathFill(path->GetPathData(), matrix, fillMode);
   SetDIBitsWithMatrix(&bmp, &pattern->m_matrix);
   m_renderDevice->RestoreState(false);
-  return FWL_Error::Succeeded;
 }
 
-FWL_Error CFX_Graphics::FillPathWithShading(CFX_Path* path,
-                                            FX_FillMode fillMode,
-                                            CFX_Matrix* matrix) {
+void CFX_Graphics::FillPathWithShading(CFX_Path* path,
+                                       FX_FillMode fillMode,
+                                       CFX_Matrix* matrix) {
   CFX_DIBitmap* bitmap = m_renderDevice->GetBitmap();
   int32_t width = bitmap->GetWidth();
   int32_t height = bitmap->GetHeight();
@@ -1474,106 +500,39 @@
     SetDIBitsWithMatrix(&bmp, matrix);
     m_renderDevice->RestoreState(false);
   }
-  return result ? FWL_Error::Succeeded : FWL_Error::PropertyInvalid;
 }
 
-FWL_Error CFX_Graphics::SetDIBitsWithMatrix(CFX_DIBSource* source,
-                                            CFX_Matrix* matrix) {
+void CFX_Graphics::SetDIBitsWithMatrix(CFX_DIBSource* source,
+                                       CFX_Matrix* matrix) {
   if (matrix->IsIdentity()) {
     m_renderDevice->SetDIBits(source, 0, 0);
   } else {
-    CFX_Matrix m;
-    m.Set((FX_FLOAT)source->GetWidth(), 0, 0, (FX_FLOAT)source->GetHeight(), 0,
-          0);
+    CFX_Matrix m((FX_FLOAT)source->GetWidth(), 0, 0,
+                 (FX_FLOAT)source->GetHeight(), 0, 0);
     m.Concat(*matrix);
-    int32_t left, top;
+    int32_t left;
+    int32_t top;
     std::unique_ptr<CFX_DIBitmap> bmp1 = source->FlipImage(false, true);
     std::unique_ptr<CFX_DIBitmap> bmp2 = bmp1->TransformTo(&m, left, top);
     m_renderDevice->SetDIBits(bmp2.get(), left, top);
   }
-  return FWL_Error::Succeeded;
-}
-
-FWL_Error CFX_Graphics::CalcTextInfo(const CFX_WideString& text,
-                                     uint32_t* charCodes,
-                                     FXTEXT_CHARPOS* charPos,
-                                     CFX_RectF& rect) {
-  std::unique_ptr<CFX_UnicodeEncoding> encoding(
-      new CFX_UnicodeEncoding(m_info.font));
-  int32_t length = text.GetLength();
-  FX_FLOAT penX = (FX_FLOAT)rect.left;
-  FX_FLOAT penY = (FX_FLOAT)rect.top;
-  FX_FLOAT left = (FX_FLOAT)(0);
-  FX_FLOAT top = (FX_FLOAT)(0);
-  charCodes[0] = text.GetAt(0);
-  charPos[0].m_OriginX = penX + left;
-  charPos[0].m_OriginY = penY + top;
-  charPos[0].m_GlyphIndex = encoding->GlyphFromCharCode(charCodes[0]);
-  charPos[0].m_FontCharWidth = FXSYS_round(
-      m_info.font->GetGlyphWidth(charPos[0].m_GlyphIndex) * m_info.fontHScale);
-  charPos[0].m_bGlyphAdjust = true;
-  charPos[0].m_AdjustMatrix[0] = -1;
-  charPos[0].m_AdjustMatrix[1] = 0;
-  charPos[0].m_AdjustMatrix[2] = 0;
-  charPos[0].m_AdjustMatrix[3] = 1;
-  penX += (FX_FLOAT)(charPos[0].m_FontCharWidth) * m_info.fontSize / 1000 +
-          m_info.fontSpacing;
-  for (int32_t i = 1; i < length; i++) {
-    charCodes[i] = text.GetAt(i);
-    charPos[i].m_OriginX = penX + left;
-    charPos[i].m_OriginY = penY + top;
-    charPos[i].m_GlyphIndex = encoding->GlyphFromCharCode(charCodes[i]);
-    charPos[i].m_FontCharWidth =
-        FXSYS_round(m_info.font->GetGlyphWidth(charPos[i].m_GlyphIndex) *
-                    m_info.fontHScale);
-    charPos[i].m_bGlyphAdjust = true;
-    charPos[i].m_AdjustMatrix[0] = -1;
-    charPos[i].m_AdjustMatrix[1] = 0;
-    charPos[i].m_AdjustMatrix[2] = 0;
-    charPos[i].m_AdjustMatrix[3] = 1;
-    penX += (FX_FLOAT)(charPos[i].m_FontCharWidth) * m_info.fontSize / 1000 +
-            m_info.fontSpacing;
-  }
-  rect.width = (FX_FLOAT)penX - rect.left;
-  rect.height = rect.top + m_info.fontSize * m_info.fontHScale - rect.top;
-  return FWL_Error::Succeeded;
 }
 
 CFX_Graphics::TInfo::TInfo()
-    : isAntialiasing(true),
-      strokeAlignment(FX_STROKEALIGNMENT_Center),
-      isActOnDash(false),
-      strokeColor(nullptr),
-      fillColor(nullptr),
-      font(nullptr),
-      fontSize(40.0),
-      fontHScale(1.0),
-      fontSpacing(0.0) {}
+    : isActOnDash(false), strokeColor(nullptr), fillColor(nullptr) {}
 
 CFX_Graphics::TInfo::TInfo(const TInfo& info)
     : graphState(info.graphState),
-      isAntialiasing(info.isAntialiasing),
-      strokeAlignment(info.strokeAlignment),
       CTM(info.CTM),
       isActOnDash(info.isActOnDash),
       strokeColor(info.strokeColor),
-      fillColor(info.fillColor),
-      font(info.font),
-      fontSize(info.fontSize),
-      fontHScale(info.fontHScale),
-      fontSpacing(info.fontSpacing) {}
+      fillColor(info.fillColor) {}
 
 CFX_Graphics::TInfo& CFX_Graphics::TInfo::operator=(const TInfo& other) {
   graphState.Copy(other.graphState);
-  isAntialiasing = other.isAntialiasing;
-  strokeAlignment = other.strokeAlignment;
   CTM = other.CTM;
   isActOnDash = other.isActOnDash;
   strokeColor = other.strokeColor;
   fillColor = other.fillColor;
-  font = other.font;
-  fontSize = other.fontSize;
-  fontHScale = other.fontHScale;
-  fontSpacing = other.fontSpacing;
   return *this;
 }
diff --git a/xfa/fxgraphics/cfx_graphics.h b/xfa/fxgraphics/cfx_graphics.h
index e18564b..c18f8eb 100644
--- a/xfa/fxgraphics/cfx_graphics.h
+++ b/xfa/fxgraphics/cfx_graphics.h
@@ -8,6 +8,7 @@
 #define XFA_FXGRAPHICS_CFX_GRAPHICS_H_
 
 #include <memory>
+#include <vector>
 
 #include "core/fxcrt/fx_system.h"
 #include "core/fxge/cfx_fxgedevice.h"
@@ -15,13 +16,10 @@
 #include "core/fxge/cfx_renderdevice.h"
 #include "core/fxge/fx_dib.h"
 #include "core/fxge/fx_font.h"
-#include "xfa/fwl/fwl_error.h"
 
 class CFX_Color;
 class CFX_Path;
-class CAGG_Graphics;
 
-using FX_DeviceCap = int32_t;
 using FX_FillMode = int32_t;
 
 enum FX_DashStyle {
@@ -32,152 +30,44 @@
   FX_DASHSTYLE_DashDotDot = 4
 };
 
-enum FX_StrokeAlignment {
-  FX_STROKEALIGNMENT_Center = 0,
-  FX_STROKEALIGNMENT_Inset = 1,
-  FX_STROKEALIGNMENT_Outset = 2,
-  FX_STROKEALIGNMENT_Left = 3,
-  FX_STROKEALIGNMENT_Right = 4
-};
-
-enum FX_HatchStyle {
-  FX_HATCHSTYLE_Horizontal = 0,
-  FX_HATCHSTYLE_Vertical = 1,
-  FX_HATCHSTYLE_ForwardDiagonal = 2,
-  FX_HATCHSTYLE_BackwardDiagonal = 3,
-  FX_HATCHSTYLE_Cross = 4,
-  FX_HATCHSTYLE_DiagonalCross = 5,
-  FX_HATCHSTYLE_05Percent = 6,
-  FX_HATCHSTYLE_10Percent = 7,
-  FX_HATCHSTYLE_20Percent = 8,
-  FX_HATCHSTYLE_25Percent = 9,
-  FX_HATCHSTYLE_30Percent = 10,
-  FX_HATCHSTYLE_40Percent = 11,
-  FX_HATCHSTYLE_50Percent = 12,
-  FX_HATCHSTYLE_60Percent = 13,
-  FX_HATCHSTYLE_70Percent = 14,
-  FX_HATCHSTYLE_75Percent = 15,
-  FX_HATCHSTYLE_80Percent = 16,
-  FX_HATCHSTYLE_90Percent = 17,
-  FX_HATCHSTYLE_LightDownwardDiagonal = 18,
-  FX_HATCHSTYLE_LightUpwardDiagonal = 19,
-  FX_HATCHSTYLE_DarkDownwardDiagonal = 20,
-  FX_HATCHSTYLE_DarkUpwardDiagonal = 21,
-  FX_HATCHSTYLE_WideDownwardDiagonal = 22,
-  FX_HATCHSTYLE_WideUpwardDiagonal = 23,
-  FX_HATCHSTYLE_LightVertical = 24,
-  FX_HATCHSTYLE_LightHorizontal = 25,
-  FX_HATCHSTYLE_NarrowVertical = 26,
-  FX_HATCHSTYLE_NarrowHorizontal = 27,
-  FX_HATCHSTYLE_DarkVertical = 28,
-  FX_HATCHSTYLE_DarkHorizontal = 29,
-  FX_HATCHSTYLE_DashedDownwardDiagonal = 30,
-  FX_HATCHSTYLE_DashedUpwardDiagonal = 31,
-  FX_HATCHSTYLE_DashedHorizontal = 32,
-  FX_HATCHSTYLE_DashedVertical = 33,
-  FX_HATCHSTYLE_SmallConfetti = 34,
-  FX_HATCHSTYLE_LargeConfetti = 35,
-  FX_HATCHSTYLE_ZigZag = 36,
-  FX_HATCHSTYLE_Wave = 37,
-  FX_HATCHSTYLE_DiagonalBrick = 38,
-  FX_HATCHSTYLE_HorizontalBrick = 39,
-  FX_HATCHSTYLE_Weave = 40,
-  FX_HATCHSTYLE_Plaid = 41,
-  FX_HATCHSTYLE_Divot = 42,
-  FX_HATCHSTYLE_DottedGrid = 43,
-  FX_HATCHSTYLE_DottedDiamond = 44,
-  FX_HATCHSTYLE_Shingle = 45,
-  FX_HATCHSTYLE_Trellis = 46,
-  FX_HATCHSTYLE_Sphere = 47,
-  FX_HATCHSTYLE_SmallGrid = 48,
-  FX_HATCHSTYLE_SmallCheckerBoard = 49,
-  FX_HATCHSTYLE_LargeCheckerBoard = 50,
-  FX_HATCHSTYLE_OutlinedDiamond = 51,
-  FX_HATCHSTYLE_SolidDiamond = 52
+enum class FX_HatchStyle {
+  Horizontal = 0,
+  Vertical = 1,
+  ForwardDiagonal = 2,
+  BackwardDiagonal = 3,
+  Cross = 4,
+  DiagonalCross = 5
 };
 
 class CFX_RenderDevice;
 
 class CFX_Graphics {
  public:
-  CFX_Graphics();
-  virtual ~CFX_Graphics();
+  explicit CFX_Graphics(CFX_RenderDevice* renderDevice);
+  ~CFX_Graphics();
 
-  FWL_Error Create(CFX_RenderDevice* renderDevice, bool isAntialiasing = true);
-  FWL_Error Create(int32_t width,
-                   int32_t height,
-                   FXDIB_Format format,
-                   bool isNative = true,
-                   bool isAntialiasing = true);
+  void SaveGraphState();
+  void RestoreGraphState();
 
-  FWL_Error GetDeviceCap(const int32_t capID, FX_DeviceCap& capVal);
-  FWL_Error IsPrinterDevice(bool& isPrinter);
-  FWL_Error EnableAntialiasing(bool isAntialiasing);
-
-  FWL_Error SaveGraphState();
-  FWL_Error RestoreGraphState();
-
-  FWL_Error GetLineCap(CFX_GraphStateData::LineCap& lineCap) const;
-  FWL_Error GetDashCount(int32_t& dashCount) const;
-  FWL_Error GetLineDash(FX_FLOAT& dashPhase, FX_FLOAT* dashArray) const;
-  FWL_Error GetLineJoin(CFX_GraphStateData::LineJoin& lineJoin) const;
-  FWL_Error GetMiterLimit(FX_FLOAT& miterLimit) const;
-  FWL_Error GetLineWidth(FX_FLOAT& lineWidth) const;
-  FWL_Error GetStrokeAlignment(FX_StrokeAlignment& strokeAlignment) const;
-  FWL_Error GetClipRect(CFX_RectF& rect) const;
+  CFX_RectF GetClipRect() const;
   CFX_Matrix* GetMatrix();
   CFX_RenderDevice* GetRenderDevice();
 
-  FWL_Error SetLineCap(CFX_GraphStateData::LineCap lineCap);
-  FWL_Error SetLineDash(FX_FLOAT dashPhase,
-                        FX_FLOAT* dashArray,
-                        int32_t dashCount);
-  FWL_Error SetLineDash(FX_DashStyle dashStyle);
-  FWL_Error SetLineJoin(CFX_GraphStateData::LineJoin lineJoin);
-  FWL_Error SetMiterLimit(FX_FLOAT miterLimit);
-  FWL_Error SetLineWidth(FX_FLOAT lineWidth, bool isActOnDash = false);
-  FWL_Error SetStrokeAlignment(FX_StrokeAlignment strokeAlignment);
-  FWL_Error SetStrokeColor(CFX_Color* color);
-  FWL_Error SetFillColor(CFX_Color* color);
-  FWL_Error SetClipRect(const CFX_RectF& rect);
-  FWL_Error SetFont(CFX_Font* font);
-  FWL_Error SetFontSize(const FX_FLOAT size);
-  FWL_Error SetFontHScale(const FX_FLOAT scale);
-  FWL_Error SetCharSpacing(const FX_FLOAT spacing);
-  FWL_Error SetTextDrawingMode(const int32_t mode);
-
-  FWL_Error StrokePath(CFX_Path* path, CFX_Matrix* matrix = nullptr);
-  FWL_Error FillPath(CFX_Path* path,
-                     FX_FillMode fillMode = FXFILL_WINDING,
-                     CFX_Matrix* matrix = nullptr);
-  FWL_Error ClipPath(CFX_Path* path,
-                     FX_FillMode fillMode = FXFILL_WINDING,
-                     CFX_Matrix* matrix = nullptr);
-  FWL_Error DrawImage(CFX_DIBSource* source,
-                      const CFX_PointF& point,
-                      CFX_Matrix* matrix = nullptr);
-  FWL_Error StretchImage(CFX_DIBSource* source,
-                         const CFX_RectF& rect,
-                         CFX_Matrix* matrix = nullptr);
-  FWL_Error ConcatMatrix(const CFX_Matrix* matrix);
-  FWL_Error ClearClip();
-  FWL_Error ShowText(const CFX_PointF& point,
-                     const CFX_WideString& text,
-                     CFX_Matrix* matrix = nullptr);
-  void CalcTextRect(CFX_RectF& rect,
-                    const CFX_WideString& text,
-                    bool isMultiline = false,
+  void SetLineCap(CFX_GraphStateData::LineCap lineCap);
+  void SetLineDash(FX_FLOAT dashPhase, FX_FLOAT* dashArray, int32_t dashCount);
+  void SetLineDash(FX_DashStyle dashStyle);
+  void SetLineWidth(FX_FLOAT lineWidth, bool isActOnDash = false);
+  void SetStrokeColor(CFX_Color* color);
+  void SetFillColor(CFX_Color* color);
+  void SetClipRect(const CFX_RectF& rect);
+  void StrokePath(CFX_Path* path, CFX_Matrix* matrix = nullptr);
+  void FillPath(CFX_Path* path,
+                FX_FillMode fillMode = FXFILL_WINDING,
+                CFX_Matrix* matrix = nullptr);
+  void StretchImage(CFX_DIBSource* source,
+                    const CFX_RectF& rect,
                     CFX_Matrix* matrix = nullptr);
-  FWL_Error Transfer(CFX_Graphics* graphics, const CFX_Matrix* matrix);
-  FWL_Error Transfer(CFX_Graphics* graphics,
-                     FX_FLOAT srcLeft,
-                     FX_FLOAT srcTop,
-                     const CFX_RectF& dstRect,
-                     const CFX_Matrix* matrix);
-
-  FWL_Error InverseRect(const CFX_RectF& rect);
-  FWL_Error XorDIBitmap(const CFX_DIBitmap* srcBitmap, const CFX_RectF& rect);
-  FWL_Error EqvDIBitmap(const CFX_DIBitmap* srcBitmap, const CFX_RectF& rect);
+  void ConcatMatrix(const CFX_Matrix* matrix);
 
  protected:
   int32_t m_type;
@@ -189,53 +79,32 @@
     TInfo& operator=(const TInfo& other);
 
     CFX_GraphStateData graphState;
-    bool isAntialiasing;
-    FX_StrokeAlignment strokeAlignment;
     CFX_Matrix CTM;
     bool isActOnDash;
     CFX_Color* strokeColor;
     CFX_Color* fillColor;
-    CFX_Font* font;
-    FX_FLOAT fontSize;
-    FX_FLOAT fontHScale;
-    FX_FLOAT fontSpacing;
   } m_info;
 
-  FWL_Error RenderDeviceSetLineDash(FX_DashStyle dashStyle);
-  FWL_Error RenderDeviceStrokePath(CFX_Path* path, CFX_Matrix* matrix);
-  FWL_Error RenderDeviceFillPath(CFX_Path* path,
-                                 FX_FillMode fillMode,
-                                 CFX_Matrix* matrix);
-  FWL_Error RenderDeviceDrawImage(CFX_DIBSource* source,
-                                  const CFX_PointF& point,
-                                  CFX_Matrix* matrix);
-  FWL_Error RenderDeviceStretchImage(CFX_DIBSource* source,
-                                     const CFX_RectF& rect,
-                                     CFX_Matrix* matrix);
-  FWL_Error RenderDeviceShowText(const CFX_PointF& point,
-                                 const CFX_WideString& text,
-                                 CFX_Matrix* matrix);
-
-  FWL_Error StrokePathWithPattern(CFX_Path* path, CFX_Matrix* matrix);
-  FWL_Error StrokePathWithShading(CFX_Path* path, CFX_Matrix* matrix);
-
-  FWL_Error FillPathWithPattern(CFX_Path* path,
-                                FX_FillMode fillMode,
-                                CFX_Matrix* matrix);
-  FWL_Error FillPathWithShading(CFX_Path* path,
-                                FX_FillMode fillMode,
+  void RenderDeviceSetLineDash(FX_DashStyle dashStyle);
+  void RenderDeviceStrokePath(CFX_Path* path, CFX_Matrix* matrix);
+  void RenderDeviceFillPath(CFX_Path* path,
+                            FX_FillMode fillMode,
+                            CFX_Matrix* matrix);
+  void RenderDeviceStretchImage(CFX_DIBSource* source,
+                                const CFX_RectF& rect,
                                 CFX_Matrix* matrix);
 
-  FWL_Error SetDIBitsWithMatrix(CFX_DIBSource* source, CFX_Matrix* matrix);
-  FWL_Error CalcTextInfo(const CFX_WideString& text,
-                         uint32_t* charCodes,
-                         FXTEXT_CHARPOS* charPos,
-                         CFX_RectF& rect);
+  void FillPathWithPattern(CFX_Path* path,
+                           FX_FillMode fillMode,
+                           CFX_Matrix* matrix);
+  void FillPathWithShading(CFX_Path* path,
+                           FX_FillMode fillMode,
+                           CFX_Matrix* matrix);
+
+  void SetDIBitsWithMatrix(CFX_DIBSource* source, CFX_Matrix* matrix);
 
   CFX_RenderDevice* m_renderDevice;
-  CFX_ArrayTemplate<TInfo*> m_infoStack;
-  std::unique_ptr<CAGG_Graphics> m_aggGraphics;
-  friend class CAGG_Graphics;
+  std::vector<std::unique_ptr<TInfo>> m_infoStack;
 };
 
 #endif  // XFA_FXGRAPHICS_CFX_GRAPHICS_H_
diff --git a/xfa/fxgraphics/cfx_path.cpp b/xfa/fxgraphics/cfx_path.cpp
index 3288631..d56eb13 100644
--- a/xfa/fxgraphics/cfx_path.cpp
+++ b/xfa/fxgraphics/cfx_path.cpp
@@ -8,171 +8,144 @@
 
 #include "core/fxge/cfx_pathdata.h"
 #include "third_party/base/ptr_util.h"
-#include "xfa/fxgraphics/cfx_path_generator.h"
 
 CFX_Path::CFX_Path() {}
 
-FWL_Error CFX_Path::Create() {
-  if (m_generator)
-    return FWL_Error::PropertyInvalid;
-
-  m_generator = pdfium::MakeUnique<CFX_PathGenerator>();
-  return FWL_Error::Succeeded;
-}
-
 CFX_Path::~CFX_Path() {}
 
-FWL_Error CFX_Path::MoveTo(FX_FLOAT x, FX_FLOAT y) {
-  if (!m_generator)
-    return FWL_Error::PropertyInvalid;
-  m_generator->MoveTo(x, y);
-  return FWL_Error::Succeeded;
+void CFX_Path::Clear() {
+  data_.Clear();
 }
 
-FWL_Error CFX_Path::LineTo(FX_FLOAT x, FX_FLOAT y) {
-  if (!m_generator)
-    return FWL_Error::PropertyInvalid;
-  m_generator->LineTo(x, y);
-  return FWL_Error::Succeeded;
+void CFX_Path::Close() {
+  data_.ClosePath();
 }
 
-FWL_Error CFX_Path::BezierTo(FX_FLOAT ctrlX1,
-                             FX_FLOAT ctrlY1,
-                             FX_FLOAT ctrlX2,
-                             FX_FLOAT ctrlY2,
-                             FX_FLOAT toX,
-                             FX_FLOAT toY) {
-  if (!m_generator)
-    return FWL_Error::PropertyInvalid;
-  m_generator->BezierTo(ctrlX1, ctrlY1, ctrlX2, ctrlY2, toX, toY);
-  return FWL_Error::Succeeded;
+void CFX_Path::MoveTo(const CFX_PointF& point) {
+  data_.AppendPoint(point, FXPT_TYPE::MoveTo, false);
 }
 
-FWL_Error CFX_Path::ArcTo(FX_FLOAT left,
-                          FX_FLOAT top,
-                          FX_FLOAT width,
-                          FX_FLOAT height,
-                          FX_FLOAT startAngle,
-                          FX_FLOAT sweepAngle) {
-  if (!m_generator)
-    return FWL_Error::PropertyInvalid;
-  m_generator->ArcTo(left + width / 2, top + height / 2, width / 2, height / 2,
-                     startAngle, sweepAngle);
-  return FWL_Error::Succeeded;
+void CFX_Path::LineTo(const CFX_PointF& point) {
+  data_.AppendPoint(point, FXPT_TYPE::LineTo, false);
 }
 
-FWL_Error CFX_Path::Close() {
-  if (!m_generator)
-    return FWL_Error::PropertyInvalid;
-  m_generator->Close();
-  return FWL_Error::Succeeded;
+void CFX_Path::BezierTo(const CFX_PointF& c1,
+                        const CFX_PointF& c2,
+                        const CFX_PointF& to) {
+  data_.AppendPoint(c1, FXPT_TYPE::BezierTo, false);
+  data_.AppendPoint(c2, FXPT_TYPE::BezierTo, false);
+  data_.AppendPoint(to, FXPT_TYPE::BezierTo, false);
 }
 
-FWL_Error CFX_Path::AddLine(FX_FLOAT x1,
-                            FX_FLOAT y1,
-                            FX_FLOAT x2,
-                            FX_FLOAT y2) {
-  if (!m_generator)
-    return FWL_Error::PropertyInvalid;
-  m_generator->AddLine(x1, y1, x2, y2);
-  return FWL_Error::Succeeded;
+void CFX_Path::ArcTo(const CFX_PointF& pos,
+                     const CFX_SizeF& size,
+                     FX_FLOAT start_angle,
+                     FX_FLOAT sweep_angle) {
+  CFX_SizeF new_size = size / 2.0f;
+  ArcToInternal(CFX_PointF(pos.x + new_size.width, pos.y + new_size.height),
+                new_size, start_angle, sweep_angle);
 }
 
-FWL_Error CFX_Path::AddBezier(FX_FLOAT startX,
-                              FX_FLOAT startY,
-                              FX_FLOAT ctrlX1,
-                              FX_FLOAT ctrlY1,
-                              FX_FLOAT ctrlX2,
-                              FX_FLOAT ctrlY2,
-                              FX_FLOAT endX,
-                              FX_FLOAT endY) {
-  if (!m_generator)
-    return FWL_Error::PropertyInvalid;
-  m_generator->AddBezier(startX, startY, ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX,
-                         endY);
-  return FWL_Error::Succeeded;
+void CFX_Path::ArcToInternal(const CFX_PointF& pos,
+                             const CFX_SizeF& size,
+                             FX_FLOAT start_angle,
+                             FX_FLOAT sweep_angle) {
+  FX_FLOAT x0 = FXSYS_cos(sweep_angle / 2);
+  FX_FLOAT y0 = FXSYS_sin(sweep_angle / 2);
+  FX_FLOAT tx = ((1.0f - x0) * 4) / (3 * 1.0f);
+  FX_FLOAT ty = y0 - ((tx * x0) / y0);
+
+  CFX_PointF points[] = {CFX_PointF(x0 + tx, -ty), CFX_PointF(x0 + tx, ty)};
+  FX_FLOAT sn = FXSYS_sin(start_angle + sweep_angle / 2);
+  FX_FLOAT cs = FXSYS_cos(start_angle + sweep_angle / 2);
+
+  CFX_PointF bezier;
+  bezier.x = pos.x + (size.width * ((points[0].x * cs) - (points[0].y * sn)));
+  bezier.y = pos.y + (size.height * ((points[0].x * sn) + (points[0].y * cs)));
+  data_.AppendPoint(bezier, FXPT_TYPE::BezierTo, false);
+
+  bezier.x = pos.x + (size.width * ((points[1].x * cs) - (points[1].y * sn)));
+  bezier.y = pos.y + (size.height * ((points[1].x * sn) + (points[1].y * cs)));
+  data_.AppendPoint(bezier, FXPT_TYPE::BezierTo, false);
+
+  bezier.x = pos.x + (size.width * FXSYS_cos(start_angle + sweep_angle));
+  bezier.y = pos.y + (size.height * FXSYS_sin(start_angle + sweep_angle));
+  data_.AppendPoint(bezier, FXPT_TYPE::BezierTo, false);
 }
 
-FWL_Error CFX_Path::AddRectangle(FX_FLOAT left,
-                                 FX_FLOAT top,
-                                 FX_FLOAT width,
-                                 FX_FLOAT height) {
-  if (!m_generator)
-    return FWL_Error::PropertyInvalid;
-  m_generator->AddRectangle(left, top, left + width, top + height);
-  return FWL_Error::Succeeded;
+void CFX_Path::AddLine(const CFX_PointF& p1, const CFX_PointF& p2) {
+  data_.AppendPoint(p1, FXPT_TYPE::MoveTo, false);
+  data_.AppendPoint(p2, FXPT_TYPE::LineTo, false);
 }
 
-FWL_Error CFX_Path::AddEllipse(FX_FLOAT left,
-                               FX_FLOAT top,
-                               FX_FLOAT width,
-                               FX_FLOAT height) {
-  if (!m_generator)
-    return FWL_Error::PropertyInvalid;
-  m_generator->AddEllipse(left + width / 2, top + height / 2, width / 2,
-                          height / 2);
-  return FWL_Error::Succeeded;
+void CFX_Path::AddRectangle(FX_FLOAT left,
+                            FX_FLOAT top,
+                            FX_FLOAT width,
+                            FX_FLOAT height) {
+  data_.AppendRect(left, top, left + width, top + height);
 }
 
-FWL_Error CFX_Path::AddEllipse(const CFX_RectF& rect) {
-  if (!m_generator)
-    return FWL_Error::PropertyInvalid;
-  m_generator->AddEllipse(rect.left + rect.Width() / 2,
-                          rect.top + rect.Height() / 2, rect.Width() / 2,
-                          rect.Height() / 2);
-  return FWL_Error::Succeeded;
+void CFX_Path::AddEllipse(const CFX_RectF& rect) {
+  AddArc(rect.TopLeft(), rect.Size(), 0, FX_PI * 2);
 }
 
-FWL_Error CFX_Path::AddArc(FX_FLOAT left,
-                           FX_FLOAT top,
-                           FX_FLOAT width,
-                           FX_FLOAT height,
-                           FX_FLOAT startAngle,
-                           FX_FLOAT sweepAngle) {
-  if (!m_generator)
-    return FWL_Error::PropertyInvalid;
-  m_generator->AddArc(left + width / 2, top + height / 2, width / 2, height / 2,
-                      startAngle, sweepAngle);
-  return FWL_Error::Succeeded;
+void CFX_Path::AddArc(const CFX_PointF& original_pos,
+                      const CFX_SizeF& original_size,
+                      FX_FLOAT start_angle,
+                      FX_FLOAT sweep_angle) {
+  if (sweep_angle == 0)
+    return;
+
+  const FX_FLOAT bezier_arc_angle_epsilon = 0.01f;
+  while (start_angle > FX_PI * 2)
+    start_angle -= FX_PI * 2;
+  while (start_angle < 0)
+    start_angle += FX_PI * 2;
+  if (sweep_angle >= FX_PI * 2)
+    sweep_angle = FX_PI * 2;
+  if (sweep_angle <= -FX_PI * 2)
+    sweep_angle = -FX_PI * 2;
+
+  CFX_SizeF size = original_size / 2;
+  CFX_PointF pos(original_pos.x + size.width, original_pos.y + size.height);
+  data_.AppendPoint(pos + CFX_PointF(size.width * FXSYS_cos(start_angle),
+                                     size.height * FXSYS_sin(start_angle)),
+                    FXPT_TYPE::MoveTo, false);
+
+  FX_FLOAT total_sweep = 0;
+  FX_FLOAT local_sweep = 0;
+  FX_FLOAT prev_sweep = 0;
+  bool done = false;
+  do {
+    if (sweep_angle < 0) {
+      prev_sweep = total_sweep;
+      local_sweep = -FX_PI / 2;
+      total_sweep -= FX_PI / 2;
+      if (total_sweep <= sweep_angle + bezier_arc_angle_epsilon) {
+        local_sweep = sweep_angle - prev_sweep;
+        done = true;
+      }
+    } else {
+      prev_sweep = total_sweep;
+      local_sweep = FX_PI / 2;
+      total_sweep += FX_PI / 2;
+      if (total_sweep >= sweep_angle - bezier_arc_angle_epsilon) {
+        local_sweep = sweep_angle - prev_sweep;
+        done = true;
+      }
+    }
+
+    ArcToInternal(pos, size, start_angle, local_sweep);
+    start_angle += local_sweep;
+  } while (!done);
 }
 
-FWL_Error CFX_Path::AddPie(FX_FLOAT left,
-                           FX_FLOAT top,
-                           FX_FLOAT width,
-                           FX_FLOAT height,
-                           FX_FLOAT startAngle,
-                           FX_FLOAT sweepAngle) {
-  if (!m_generator)
-    return FWL_Error::PropertyInvalid;
-  m_generator->AddPie(left + width / 2, top + height / 2, width / 2, height / 2,
-                      startAngle, sweepAngle);
-  return FWL_Error::Succeeded;
+void CFX_Path::AddSubpath(CFX_Path* path) {
+  if (!path)
+    return;
+  data_.Append(&path->data_, nullptr);
 }
 
-FWL_Error CFX_Path::AddSubpath(CFX_Path* path) {
-  if (!m_generator)
-    return FWL_Error::PropertyInvalid;
-  m_generator->AddPathData(path->GetPathData());
-  return FWL_Error::Succeeded;
-}
-
-FWL_Error CFX_Path::Clear() {
-  if (!m_generator)
-    return FWL_Error::PropertyInvalid;
-  m_generator->GetPathData()->SetPointCount(0);
-  return FWL_Error::Succeeded;
-}
-
-bool CFX_Path::IsEmpty() const {
-  if (!m_generator)
-    return false;
-  if (m_generator->GetPathData()->GetPointCount() == 0)
-    return true;
-  return false;
-}
-
-CFX_PathData* CFX_Path::GetPathData() const {
-  if (!m_generator)
-    return nullptr;
-  return m_generator->GetPathData();
+void CFX_Path::TransformBy(const CFX_Matrix& mt) {
+  data_.Transform(&mt);
 }
diff --git a/xfa/fxgraphics/cfx_path.h b/xfa/fxgraphics/cfx_path.h
index 9171a91..2678316 100644
--- a/xfa/fxgraphics/cfx_path.h
+++ b/xfa/fxgraphics/cfx_path.h
@@ -7,74 +7,52 @@
 #ifndef XFA_FXGRAPHICS_CFX_PATH_H_
 #define XFA_FXGRAPHICS_CFX_PATH_H_
 
-#include <memory>
-
 #include "core/fxcrt/fx_system.h"
+#include "core/fxge/cfx_pathdata.h"
 #include "xfa/fxgraphics/cfx_graphics.h"
 
-class CFX_PathData;
-class CFX_PathGenerator;
-
 class CFX_Path final {
  public:
   CFX_Path();
   ~CFX_Path();
 
-  FWL_Error Create();
-  FWL_Error MoveTo(FX_FLOAT x, FX_FLOAT y);
-  FWL_Error LineTo(FX_FLOAT x, FX_FLOAT y);
-  FWL_Error BezierTo(FX_FLOAT ctrlX1,
-                     FX_FLOAT ctrlY1,
-                     FX_FLOAT ctrlX2,
-                     FX_FLOAT ctrlY2,
-                     FX_FLOAT toX,
-                     FX_FLOAT toY);
-  FWL_Error ArcTo(FX_FLOAT left,
-                  FX_FLOAT top,
-                  FX_FLOAT width,
-                  FX_FLOAT height,
-                  FX_FLOAT startAngle,
-                  FX_FLOAT sweepAngle);
-  FWL_Error Close();
+  const CFX_PathData* GetPathData() const { return &data_; }
 
-  FWL_Error AddLine(FX_FLOAT x1, FX_FLOAT y1, FX_FLOAT x2, FX_FLOAT y2);
-  FWL_Error AddBezier(FX_FLOAT startX,
-                      FX_FLOAT startY,
-                      FX_FLOAT ctrlX1,
-                      FX_FLOAT ctrlY1,
-                      FX_FLOAT ctrlX2,
-                      FX_FLOAT ctrlY2,
-                      FX_FLOAT endX,
-                      FX_FLOAT endY);
-  FWL_Error AddRectangle(FX_FLOAT left,
-                         FX_FLOAT top,
-                         FX_FLOAT width,
-                         FX_FLOAT height);
-  FWL_Error AddEllipse(FX_FLOAT left,
-                       FX_FLOAT top,
-                       FX_FLOAT width,
-                       FX_FLOAT height);
-  FWL_Error AddEllipse(const CFX_RectF& rect);
-  FWL_Error AddArc(FX_FLOAT left,
-                   FX_FLOAT top,
-                   FX_FLOAT width,
-                   FX_FLOAT height,
-                   FX_FLOAT startAngle,
-                   FX_FLOAT sweepAngle);
-  FWL_Error AddPie(FX_FLOAT left,
-                   FX_FLOAT top,
-                   FX_FLOAT width,
-                   FX_FLOAT height,
-                   FX_FLOAT startAngle,
-                   FX_FLOAT sweepAngle);
-  FWL_Error AddSubpath(CFX_Path* path);
-  FWL_Error Clear();
+  void Clear();
+  bool IsEmpty() const { return data_.GetPoints().empty(); }
+  void TransformBy(const CFX_Matrix& mt);
 
-  bool IsEmpty() const;
-  CFX_PathData* GetPathData() const;
+  void Close();
+  void MoveTo(const CFX_PointF& point);
+  void LineTo(const CFX_PointF& point);
+  void BezierTo(const CFX_PointF& c1,
+                const CFX_PointF& c2,
+                const CFX_PointF& to);
+  void ArcTo(const CFX_PointF& pos,
+             const CFX_SizeF& size,
+             FX_FLOAT startAngle,
+             FX_FLOAT sweepAngle);
+
+  void AddLine(const CFX_PointF& p1, const CFX_PointF& p2);
+  void AddRectangle(FX_FLOAT left,
+                    FX_FLOAT top,
+                    FX_FLOAT width,
+                    FX_FLOAT height);
+  void AddEllipse(const CFX_RectF& rect);
+  void AddArc(const CFX_PointF& pos,
+              const CFX_SizeF& size,
+              FX_FLOAT startAngle,
+              FX_FLOAT sweepAngle);
+
+  void AddSubpath(CFX_Path* path);
 
  private:
-  std::unique_ptr<CFX_PathGenerator> m_generator;
+  void ArcToInternal(const CFX_PointF& pos,
+                     const CFX_SizeF& size,
+                     FX_FLOAT start_angle,
+                     FX_FLOAT sweep_angle);
+
+  CFX_PathData data_;
 };
 
 #endif  // XFA_FXGRAPHICS_CFX_PATH_H_
diff --git a/xfa/fxgraphics/cfx_path_generator.cpp b/xfa/fxgraphics/cfx_path_generator.cpp
deleted file mode 100644
index 0122b1c..0000000
--- a/xfa/fxgraphics/cfx_path_generator.cpp
+++ /dev/null
@@ -1,206 +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/fxgraphics/cfx_path_generator.h"
-
-#include "core/fxge/cfx_pathdata.h"
-#include "core/fxge/cfx_renderdevice.h"
-
-CFX_PathGenerator::CFX_PathGenerator() : m_pPathData(new CFX_PathData) {}
-
-CFX_PathGenerator::~CFX_PathGenerator() {}
-
-void CFX_PathGenerator::AddPathData(CFX_PathData* pPathData) {
-  if (pPathData && pPathData->GetPointCount() > 0) {
-    int nCount = pPathData->GetPointCount();
-    FX_PATHPOINT* pPoints = pPathData->GetPoints();
-    AddPathData(pPoints, nCount);
-  }
-}
-
-void CFX_PathGenerator::AddPathData(FX_PATHPOINT* pPoints, int nCount) {
-  if (pPoints && nCount > 0) {
-    int nOldCount = m_pPathData->GetPointCount();
-    m_pPathData->AddPointCount(nCount);
-    FX_PATHPOINT* pDstPoints = m_pPathData->GetPoints();
-    FXSYS_memcpy(pDstPoints + nOldCount, pPoints,
-                 sizeof(FX_PATHPOINT) * nCount);
-  }
-}
-
-void CFX_PathGenerator::MoveTo(FX_FLOAT x, FX_FLOAT y) {
-  m_pPathData->AddPointCount(1);
-  m_pPathData->SetPoint(m_pPathData->GetPointCount() - 1, x, y, FXPT_MOVETO);
-}
-
-void CFX_PathGenerator::LineTo(FX_FLOAT x, FX_FLOAT y) {
-  m_pPathData->AddPointCount(1);
-  m_pPathData->SetPoint(m_pPathData->GetPointCount() - 1, x, y, FXPT_LINETO);
-}
-
-void CFX_PathGenerator::BezierTo(FX_FLOAT ctrl_x1,
-                                 FX_FLOAT ctrl_y1,
-                                 FX_FLOAT ctrl_x2,
-                                 FX_FLOAT ctrl_y2,
-                                 FX_FLOAT to_x,
-                                 FX_FLOAT to_y) {
-  int old_count = m_pPathData->GetPointCount();
-  m_pPathData->AddPointCount(3);
-  m_pPathData->SetPoint(old_count, ctrl_x1, ctrl_y1, FXPT_BEZIERTO);
-  m_pPathData->SetPoint(old_count + 1, ctrl_x2, ctrl_y2, FXPT_BEZIERTO);
-  m_pPathData->SetPoint(old_count + 2, to_x, to_y, FXPT_BEZIERTO);
-}
-
-void CFX_PathGenerator::Close() {
-  if (m_pPathData->GetPointCount() > 0) {
-    int index = m_pPathData->GetPointCount() - 1;
-    FX_PATHPOINT* pPoints = m_pPathData->GetPoints();
-    pPoints[index].m_Flag |= FXPT_CLOSEFIGURE;
-  }
-}
-
-void CFX_PathGenerator::AddLine(FX_FLOAT x1,
-                                FX_FLOAT y1,
-                                FX_FLOAT x2,
-                                FX_FLOAT y2) {
-  int old_count = m_pPathData->GetPointCount();
-  m_pPathData->AddPointCount(2);
-  m_pPathData->SetPoint(old_count, x1, y1, FXPT_MOVETO);
-  m_pPathData->SetPoint(old_count + 1, x2, y2, FXPT_LINETO);
-}
-
-void CFX_PathGenerator::AddBezier(FX_FLOAT start_x,
-                                  FX_FLOAT start_y,
-                                  FX_FLOAT ctrl_x1,
-                                  FX_FLOAT ctrl_y1,
-                                  FX_FLOAT ctrl_x2,
-                                  FX_FLOAT ctrl_y2,
-                                  FX_FLOAT end_x,
-                                  FX_FLOAT end_y) {
-  int old_count = m_pPathData->GetPointCount();
-  m_pPathData->AddPointCount(4);
-  m_pPathData->SetPoint(old_count, start_x, start_y, FXPT_MOVETO);
-  m_pPathData->SetPoint(old_count + 1, ctrl_x1, ctrl_y1, FXPT_BEZIERTO);
-  m_pPathData->SetPoint(old_count + 2, ctrl_x2, ctrl_y2, FXPT_BEZIERTO);
-  m_pPathData->SetPoint(old_count + 3, end_x, end_y, FXPT_BEZIERTO);
-}
-
-void CFX_PathGenerator::AddRectangle(FX_FLOAT x1,
-                                     FX_FLOAT y1,
-                                     FX_FLOAT x2,
-                                     FX_FLOAT y2) {
-  m_pPathData->AppendRect(x1, y1, x2, y2);
-}
-
-void CFX_PathGenerator::AddEllipse(FX_FLOAT x,
-                                   FX_FLOAT y,
-                                   FX_FLOAT width,
-                                   FX_FLOAT height) {
-  AddArc(x, y, width, height, 0, FX_PI * 2);
-}
-
-void CFX_PathGenerator::ArcTo(FX_FLOAT x,
-                              FX_FLOAT y,
-                              FX_FLOAT width,
-                              FX_FLOAT height,
-                              FX_FLOAT start_angle,
-                              FX_FLOAT sweep_angle) {
-  FX_FLOAT x0 = FXSYS_cos(sweep_angle / 2);
-  FX_FLOAT y0 = FXSYS_sin(sweep_angle / 2);
-  FX_FLOAT tx = ((1.0f - x0) * 4) / (3 * 1.0f);
-  FX_FLOAT ty = y0 - ((tx * x0) / y0);
-  FX_FLOAT px[3], py[3];
-  px[0] = x0 + tx;
-  py[0] = -ty;
-  px[1] = x0 + tx;
-  py[1] = ty;
-  FX_FLOAT sn = FXSYS_sin(start_angle + sweep_angle / 2);
-  FX_FLOAT cs = FXSYS_cos(start_angle + sweep_angle / 2);
-  int old_count = m_pPathData->GetPointCount();
-  m_pPathData->AddPointCount(3);
-  FX_FLOAT bezier_x, bezier_y;
-  bezier_x = x + (width * ((px[0] * cs) - (py[0] * sn)));
-  bezier_y = y + (height * ((px[0] * sn) + (py[0] * cs)));
-  m_pPathData->SetPoint(old_count, bezier_x, bezier_y, FXPT_BEZIERTO);
-  bezier_x = x + (width * ((px[1] * cs) - (py[1] * sn)));
-  bezier_y = y + (height * ((px[1] * sn) + (py[1] * cs)));
-  m_pPathData->SetPoint(old_count + 1, bezier_x, bezier_y, FXPT_BEZIERTO);
-  bezier_x = x + (width * FXSYS_cos(start_angle + sweep_angle));
-  bezier_y = y + (height * FXSYS_sin(start_angle + sweep_angle));
-  m_pPathData->SetPoint(old_count + 2, bezier_x, bezier_y, FXPT_BEZIERTO);
-}
-
-void CFX_PathGenerator::AddArc(FX_FLOAT x,
-                               FX_FLOAT y,
-                               FX_FLOAT width,
-                               FX_FLOAT height,
-                               FX_FLOAT start_angle,
-                               FX_FLOAT sweep_angle) {
-  if (sweep_angle == 0) {
-    return;
-  }
-
-  const FX_FLOAT bezier_arc_angle_epsilon = 0.01f;
-  while (start_angle > FX_PI * 2) {
-    start_angle -= FX_PI * 2;
-  }
-  while (start_angle < 0) {
-    start_angle += FX_PI * 2;
-  }
-  if (sweep_angle >= FX_PI * 2) {
-    sweep_angle = FX_PI * 2;
-  }
-  if (sweep_angle <= -FX_PI * 2) {
-    sweep_angle = -FX_PI * 2;
-  }
-  m_pPathData->AddPointCount(1);
-  m_pPathData->SetPoint(m_pPathData->GetPointCount() - 1,
-                        x + (width * FXSYS_cos(start_angle)),
-                        y + (height * FXSYS_sin(start_angle)), FXPT_MOVETO);
-  FX_FLOAT total_sweep = 0, local_sweep = 0, prev_sweep = 0;
-  bool done = false;
-  do {
-    if (sweep_angle < 0) {
-      prev_sweep = total_sweep;
-      local_sweep = -FX_PI / 2;
-      total_sweep -= FX_PI / 2;
-      if (total_sweep <= sweep_angle + bezier_arc_angle_epsilon) {
-        local_sweep = sweep_angle - prev_sweep;
-        done = true;
-      }
-    } else {
-      prev_sweep = total_sweep;
-      local_sweep = FX_PI / 2;
-      total_sweep += FX_PI / 2;
-      if (total_sweep >= sweep_angle - bezier_arc_angle_epsilon) {
-        local_sweep = sweep_angle - prev_sweep;
-        done = true;
-      }
-    }
-    ArcTo(x, y, width, height, start_angle, local_sweep);
-    start_angle += local_sweep;
-  } while (!done);
-}
-
-void CFX_PathGenerator::AddPie(FX_FLOAT x,
-                               FX_FLOAT y,
-                               FX_FLOAT width,
-                               FX_FLOAT height,
-                               FX_FLOAT start_angle,
-                               FX_FLOAT sweep_angle) {
-  if (sweep_angle == 0) {
-    int old_count = m_pPathData->GetPointCount();
-    m_pPathData->AddPointCount(2);
-    m_pPathData->SetPoint(old_count, x, y, FXPT_MOVETO);
-    m_pPathData->SetPoint(old_count + 1, x + (width * FXSYS_cos(start_angle)),
-                          y + (height * FXSYS_sin(start_angle)), FXPT_LINETO);
-    return;
-  }
-  AddArc(x, y, width, height, start_angle, sweep_angle);
-  m_pPathData->AddPointCount(1);
-  m_pPathData->SetPoint(m_pPathData->GetPointCount() - 1, x, y,
-                        FXPT_LINETO | FXPT_CLOSEFIGURE);
-}
diff --git a/xfa/fxgraphics/cfx_path_generator.h b/xfa/fxgraphics/cfx_path_generator.h
deleted file mode 100644
index 75e3a57..0000000
--- a/xfa/fxgraphics/cfx_path_generator.h
+++ /dev/null
@@ -1,68 +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_FXGRAPHICS_CFX_PATH_GENERATOR_H_
-#define XFA_FXGRAPHICS_CFX_PATH_GENERATOR_H_
-
-#include <memory>
-
-#include "core/fxge/cfx_pathdata.h"
-
-class CFX_PathGenerator {
- public:
-  CFX_PathGenerator();
-  ~CFX_PathGenerator();
-
-  CFX_PathData* GetPathData() const { return m_pPathData.get(); }
-
-  void AddPathData(CFX_PathData* path_data);
-  void AddPathData(FX_PATHPOINT* points, int count);
-
-  void MoveTo(FX_FLOAT x, FX_FLOAT y);
-  void LineTo(FX_FLOAT x, FX_FLOAT y);
-  void BezierTo(FX_FLOAT ctrl_x1,
-                FX_FLOAT ctrl_y1,
-                FX_FLOAT ctrl_x2,
-                FX_FLOAT ctrl_y2,
-                FX_FLOAT to_x,
-                FX_FLOAT to_y);
-  void Close();
-  void ArcTo(FX_FLOAT x,
-             FX_FLOAT y,
-             FX_FLOAT width,
-             FX_FLOAT height,
-             FX_FLOAT start_angle,
-             FX_FLOAT sweep_angle);
-
-  void AddLine(FX_FLOAT x1, FX_FLOAT y1, FX_FLOAT x2, FX_FLOAT y2);
-  void AddBezier(FX_FLOAT start_x,
-                 FX_FLOAT start_y,
-                 FX_FLOAT ctrl_x1,
-                 FX_FLOAT ctrl_y1,
-                 FX_FLOAT ctrl_x2,
-                 FX_FLOAT ctrl_y2,
-                 FX_FLOAT end_x,
-                 FX_FLOAT end_y);
-  void AddRectangle(FX_FLOAT x1, FX_FLOAT y1, FX_FLOAT x2, FX_FLOAT y2);
-  void AddEllipse(FX_FLOAT x, FX_FLOAT y, FX_FLOAT width, FX_FLOAT height);
-  void AddArc(FX_FLOAT x,
-              FX_FLOAT y,
-              FX_FLOAT width,
-              FX_FLOAT height,
-              FX_FLOAT start_angle,
-              FX_FLOAT sweep_angle);
-  void AddPie(FX_FLOAT x,
-              FX_FLOAT y,
-              FX_FLOAT width,
-              FX_FLOAT height,
-              FX_FLOAT start_angle,
-              FX_FLOAT sweep_angle);
-
- protected:
-  std::unique_ptr<CFX_PathData> m_pPathData;
-};
-
-#endif  // XFA_FXGRAPHICS_CFX_PATH_GENERATOR_H_
diff --git a/xfa/fxgraphics/cfx_pattern.cpp b/xfa/fxgraphics/cfx_pattern.cpp
index f70a78d..a20ec24 100644
--- a/xfa/fxgraphics/cfx_pattern.cpp
+++ b/xfa/fxgraphics/cfx_pattern.cpp
@@ -11,16 +11,10 @@
                          const FX_ARGB backArgb,
                          CFX_Matrix* matrix)
     : m_hatchStyle(hatchStyle), m_foreArgb(foreArgb), m_backArgb(backArgb) {
-  ASSERT(m_hatchStyle >= FX_HATCHSTYLE_Horizontal &&
-         m_hatchStyle <= FX_HATCHSTYLE_SolidDiamond);
-
-  if (matrix) {
-    // TODO(dsinclair): Add a Set(const CFX_Matrix&) method. pdfium:436
-    m_matrix.Set(matrix->a, matrix->b, matrix->c, matrix->d, matrix->e,
-                 matrix->f);
-  } else {
+  if (matrix)
+    m_matrix = *matrix;
+  else
     m_matrix.SetIdentity();
-  }
 }
 
 CFX_Pattern::~CFX_Pattern() {}