Pdfium 27d718ebb2989631d6b4d3425e1fceb4b3bc795b

Same as used by Chrome for Android 65.0.3325.109

- use system's zlib, freetype, libjpeg
- don't use xfa, v8, skia

Test: atest CtsPdfTestCases
Fixes: 72134075
Change-Id: Ic144d41e667a0c9310b69625b53850dec5fb3006
diff --git a/fpdfsdk/DEPS b/fpdfsdk/DEPS
index e077225..95ddfe1 100644
--- a/fpdfsdk/DEPS
+++ b/fpdfsdk/DEPS
@@ -1,9 +1,10 @@
 include_rules = [
   '+core',
+  '+fxjs',
   '+public',
   '+v8',
   '+xfa/fwl',
-  '+xfa/fxbarcode',
+  '+fxbarcode',
   '+xfa/fxfa',
   '+xfa/fxgraphics',
   ]
diff --git a/fpdfsdk/cba_annotiterator.cpp b/fpdfsdk/cba_annotiterator.cpp
index cc842ba..d1c9599 100644
--- a/fpdfsdk/cba_annotiterator.cpp
+++ b/fpdfsdk/cba_annotiterator.cpp
@@ -34,7 +34,7 @@
       m_pPageView(pPageView),
       m_nAnnotSubtype(nAnnotSubtype) {
   CPDF_Page* pPDFPage = m_pPageView->GetPDFPage();
-  CFX_ByteString sTabs = pPDFPage->m_pFormDict->GetStringFor("Tabs");
+  ByteString sTabs = pPDFPage->m_pFormDict->GetStringFor("Tabs");
   if (sTabs == "R")
     m_eTabOrder = ROW;
   else if (sTabs == "C")
@@ -73,7 +73,7 @@
 }
 
 void CBA_AnnotIterator::CollectAnnots(std::vector<CPDFSDK_Annot*>* pArray) {
-  for (auto pAnnot : m_pPageView->GetAnnotList()) {
+  for (auto* pAnnot : m_pPageView->GetAnnotList()) {
     if (pAnnot->GetAnnotSubtype() == m_nAnnotSubtype &&
         !pAnnot->IsSignatureWidget()) {
       pArray->push_back(pAnnot);
@@ -113,7 +113,7 @@
 
       while (!sa.empty()) {
         int nLeftTopIndex = -1;
-        FX_FLOAT fTop = 0.0f;
+        float fTop = 0.0f;
         for (int i = sa.size() - 1; i >= 0; i--) {
           CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
           if (rcAnnot.top > fTop) {
@@ -129,7 +129,7 @@
         std::vector<size_t> aSelect;
         for (size_t i = 0; i < sa.size(); ++i) {
           CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
-          FX_FLOAT fCenterY = (rcAnnot.top + rcAnnot.bottom) / 2.0f;
+          float fCenterY = (rcAnnot.top + rcAnnot.bottom) / 2.0f;
           if (fCenterY > rcLeftTop.bottom && fCenterY < rcLeftTop.top)
             aSelect.push_back(i);
         }
@@ -145,7 +145,7 @@
 
       while (!sa.empty()) {
         int nLeftTopIndex = -1;
-        FX_FLOAT fLeft = -1.0f;
+        float fLeft = -1.0f;
         for (int i = sa.size() - 1; i >= 0; --i) {
           CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
           if (fLeft < 0) {
@@ -164,7 +164,7 @@
         std::vector<size_t> aSelect;
         for (size_t i = 0; i < sa.size(); ++i) {
           CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
-          FX_FLOAT fCenterX = (rcAnnot.left + rcAnnot.right) / 2.0f;
+          float fCenterX = (rcAnnot.left + rcAnnot.right) / 2.0f;
           if (fCenterX > rcLeftTop.left && fCenterX < rcLeftTop.right)
             aSelect.push_back(i);
         }
diff --git a/fpdfsdk/cba_annotiterator.h b/fpdfsdk/cba_annotiterator.h
index 5cbe8e3..8f9768d 100644
--- a/fpdfsdk/cba_annotiterator.h
+++ b/fpdfsdk/cba_annotiterator.h
@@ -12,6 +12,7 @@
 #include "core/fpdfdoc/cpdf_annot.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/unowned_ptr.h"
 
 class CPDFSDK_Annot;
 class CPDFSDK_PageView;
@@ -37,7 +38,7 @@
                            std::vector<size_t>* aSelect);
 
   TabOrder m_eTabOrder;
-  CPDFSDK_PageView* m_pPageView;
+  UnownedPtr<CPDFSDK_PageView> m_pPageView;
   CPDF_Annot::Subtype m_nAnnotSubtype;
   std::vector<CPDFSDK_Annot*> m_Annots;
 };
diff --git a/fpdfsdk/cfx_systemhandler.cpp b/fpdfsdk/cfx_systemhandler.cpp
index b6dc19d..bbb0293 100644
--- a/fpdfsdk/cfx_systemhandler.cpp
+++ b/fpdfsdk/cfx_systemhandler.cpp
@@ -9,6 +9,8 @@
 #include <memory>
 
 #include "core/fpdfapi/parser/cpdf_document.h"
+#include "core/fxcrt/fx_codepage.h"
+#include "core/fxge/cfx_font.h"
 #include "core/fxge/cfx_fontmapper.h"
 #include "core/fxge/cfx_fontmgr.h"
 #include "core/fxge/cfx_gemodule.h"
@@ -21,20 +23,26 @@
 namespace {
 
 int CharSet2CP(int charset) {
-  if (charset == FXFONT_SHIFTJIS_CHARSET)
-    return 932;
-  if (charset == FXFONT_GB2312_CHARSET)
-    return 936;
-  if (charset == FXFONT_HANGUL_CHARSET)
-    return 949;
-  if (charset == FXFONT_CHINESEBIG5_CHARSET)
-    return 950;
-  return 0;
+  if (charset == FX_CHARSET_ShiftJIS)
+    return FX_CODEPAGE_ShiftJIS;
+  if (charset == FX_CHARSET_ChineseSimplified)
+    return FX_CODEPAGE_ChineseSimplified;
+  if (charset == FX_CHARSET_Hangul)
+    return FX_CODEPAGE_Hangul;
+  if (charset == FX_CHARSET_ChineseTraditional)
+    return FX_CODEPAGE_ChineseTraditional;
+  return FX_CODEPAGE_DefANSI;
 }
 
 }  // namespace
 
-void CFX_SystemHandler::InvalidateRect(CPDFSDK_Widget* widget, FX_RECT rect) {
+CFX_SystemHandler::CFX_SystemHandler(CPDFSDK_FormFillEnvironment* pFormFillEnv)
+    : m_pFormFillEnv(pFormFillEnv) {}
+
+CFX_SystemHandler::~CFX_SystemHandler() {}
+
+void CFX_SystemHandler::InvalidateRect(CPDFSDK_Widget* widget,
+                                       const CFX_FloatRect& rect) {
   CPDFSDK_PageView* pPageView = widget->GetPageView();
   UnderlyingPageType* pPage = widget->GetUnderlyingPage();
   if (!pPage || !pPageView)
@@ -43,17 +51,15 @@
   CFX_Matrix page2device;
   pPageView->GetCurrentMatrix(page2device);
 
-  CFX_Matrix device2page;
-  device2page.SetReverse(page2device);
+  CFX_Matrix device2page = page2device.GetInverse();
 
-  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)));
+  CFX_PointF left_top = device2page.Transform(CFX_PointF(rect.left, rect.top));
+  CFX_PointF right_bottom =
+      device2page.Transform(CFX_PointF(rect.right, rect.bottom));
 
   CFX_FloatRect rcPDF(left_top.x, right_bottom.y, right_bottom.x, left_top.y);
   rcPDF.Normalize();
-  m_pFormFillEnv->Invalidate(pPage, rcPDF.ToFxRect());
+  m_pFormFillEnv->Invalidate(pPage, rcPDF.GetOuterRect());
 }
 
 void CFX_SystemHandler::OutputSelectedRect(CFFL_FormFiller* pFormFiller,
@@ -84,7 +90,7 @@
   m_pFormFillEnv->SetCursor(nCursorType);
 }
 
-bool CFX_SystemHandler::FindNativeTrueTypeFont(CFX_ByteString sFontFaceName) {
+bool CFX_SystemHandler::FindNativeTrueTypeFont(ByteString sFontFaceName) {
   CFX_FontMgr* pFontMgr = CFX_GEModule::Get()->GetFontMgr();
   if (!pFontMgr)
     return false;
@@ -97,11 +103,11 @@
     pFontMapper->LoadInstalledFonts();
 
   for (const auto& font : pFontMapper->m_InstalledTTFonts) {
-    if (font.Compare(sFontFaceName.AsStringC()))
+    if (font.Compare(sFontFaceName.AsStringView()))
       return true;
   }
   for (const auto& fontPair : pFontMapper->m_LocalizedTTFonts) {
-    if (fontPair.first.Compare(sFontFaceName.AsStringC()))
+    if (fontPair.first.Compare(sFontFaceName.AsStringView()))
       return true;
   }
   return false;
@@ -109,12 +115,12 @@
 
 CPDF_Font* CFX_SystemHandler::AddNativeTrueTypeFontToPDF(
     CPDF_Document* pDoc,
-    CFX_ByteString sFontFaceName,
+    ByteString sFontFaceName,
     uint8_t nCharset) {
   if (!pDoc)
     return nullptr;
 
-  std::unique_ptr<CFX_Font> pFXFont(new CFX_Font);
+  auto pFXFont = pdfium::MakeUnique<CFX_Font>();
   pFXFont->LoadSubst(sFontFaceName, true, 0, 0, 0, CharSet2CP(nCharset), false);
   return pDoc->AddFont(pFXFont.get(), nCharset, false);
 }
@@ -127,15 +133,3 @@
 void CFX_SystemHandler::KillTimer(int32_t nID) {
   m_pFormFillEnv->KillTimer(nID);
 }
-
-bool CFX_SystemHandler::IsSHIFTKeyDown(uint32_t nFlag) const {
-  return !!m_pFormFillEnv->IsSHIFTKeyDown(nFlag);
-}
-
-bool CFX_SystemHandler::IsCTRLKeyDown(uint32_t nFlag) const {
-  return !!m_pFormFillEnv->IsCTRLKeyDown(nFlag);
-}
-
-bool CFX_SystemHandler::IsALTKeyDown(uint32_t nFlag) const {
-  return !!m_pFormFillEnv->IsALTKeyDown(nFlag);
-}
diff --git a/fpdfsdk/cfx_systemhandler.h b/fpdfsdk/cfx_systemhandler.h
index 82cfc53..f9138cc 100644
--- a/fpdfsdk/cfx_systemhandler.h
+++ b/fpdfsdk/cfx_systemhandler.h
@@ -8,7 +8,9 @@
 #define FPDFSDK_CFX_SYSTEMHANDLER_H_
 
 #include "core/fxcrt/fx_coordinates.h"
+#include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/unowned_ptr.h"
 
 using TimerCallback = void (*)(int32_t idEvent);
 
@@ -49,30 +51,23 @@
 
 class CFX_SystemHandler {
  public:
-  explicit CFX_SystemHandler(CPDFSDK_FormFillEnvironment* pFormFillEnv)
-      : m_pFormFillEnv(pFormFillEnv) {}
-  ~CFX_SystemHandler() {}
+  explicit CFX_SystemHandler(CPDFSDK_FormFillEnvironment* pFormFillEnv);
+  ~CFX_SystemHandler();
 
-  void InvalidateRect(CPDFSDK_Widget* widget, FX_RECT rect);
+  void InvalidateRect(CPDFSDK_Widget* widget, const CFX_FloatRect& rect);
   void OutputSelectedRect(CFFL_FormFiller* pFormFiller, CFX_FloatRect& rect);
   bool IsSelectionImplemented() const;
-
   void SetCursor(int32_t nCursorType);
-
-  bool FindNativeTrueTypeFont(CFX_ByteString sFontFaceName);
+  bool FindNativeTrueTypeFont(ByteString sFontFaceName);
   CPDF_Font* AddNativeTrueTypeFontToPDF(CPDF_Document* pDoc,
-                                        CFX_ByteString sFontFaceName,
+                                        ByteString sFontFaceName,
                                         uint8_t nCharset);
 
   int32_t SetTimer(int32_t uElapse, TimerCallback lpTimerFunc);
   void KillTimer(int32_t nID);
 
-  bool IsSHIFTKeyDown(uint32_t nFlag) const;
-  bool IsCTRLKeyDown(uint32_t nFlag) const;
-  bool IsALTKeyDown(uint32_t nFlag) const;
-
  private:
-  CPDFSDK_FormFillEnvironment* const m_pFormFillEnv;
+  UnownedPtr<CPDFSDK_FormFillEnvironment> const m_pFormFillEnv;
 };
 
 #endif  // FPDFSDK_CFX_SYSTEMHANDLER_H_
diff --git a/fpdfsdk/cpdfsdk_annot.cpp b/fpdfsdk/cpdfsdk_annot.cpp
index 4dcce48..e105ed9 100644
--- a/fpdfsdk/cpdfsdk_annot.cpp
+++ b/fpdfsdk/cpdfsdk_annot.cpp
@@ -23,7 +23,7 @@
 }  // namespace
 
 CPDFSDK_Annot::CPDFSDK_Annot(CPDFSDK_PageView* pPageView)
-    : m_pPageView(pPageView), m_bSelected(false) {}
+    : m_pPageView(pPageView) {}
 
 CPDFSDK_Annot::~CPDFSDK_Annot() {}
 
@@ -43,11 +43,11 @@
 
 #endif  // PDF_ENABLE_XFA
 
-FX_FLOAT CPDFSDK_Annot::GetMinWidth() const {
+float CPDFSDK_Annot::GetMinWidth() const {
   return kMinWidth;
 }
 
-FX_FLOAT CPDFSDK_Annot::GetMinHeight() const {
+float CPDFSDK_Annot::GetMinHeight() const {
   return kMinHeight;
 }
 
@@ -73,18 +73,6 @@
   return CFX_FloatRect();
 }
 
-void CPDFSDK_Annot::Annot_OnDraw(CFX_RenderDevice* pDevice,
-                                 CFX_Matrix* pUser2Device,
-                                 CPDF_RenderOptions* pOptions) {}
-
-bool CPDFSDK_Annot::IsSelected() {
-  return m_bSelected;
-}
-
-void CPDFSDK_Annot::SetSelected(bool bSelected) {
-  m_bSelected = bSelected;
-}
-
 UnderlyingPageType* CPDFSDK_Annot::GetUnderlyingPage() {
 #ifdef PDF_ENABLE_XFA
   return GetPDFXFAPage();
diff --git a/fpdfsdk/cpdfsdk_annot.h b/fpdfsdk/cpdfsdk_annot.h
index 36e7b56..a6c4066 100644
--- a/fpdfsdk/cpdfsdk_annot.h
+++ b/fpdfsdk/cpdfsdk_annot.h
@@ -10,8 +10,8 @@
 #include "core/fpdfdoc/cpdf_aaction.h"
 #include "core/fpdfdoc/cpdf_annot.h"
 #include "core/fpdfdoc/cpdf_defaultappearance.h"
-#include "core/fxcrt/cfx_observable.h"
-#include "core/fxcrt/fx_basic.h"
+#include "core/fxcrt/observable.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "fpdfsdk/cfx_systemhandler.h"
 #include "fpdfsdk/fsdk_common.h"
 #include "fpdfsdk/fsdk_define.h"
@@ -22,7 +22,7 @@
 class CPDF_RenderOptions;
 class CPDFSDK_PageView;
 
-class CPDFSDK_Annot : public CFX_Observable<CPDFSDK_Annot> {
+class CPDFSDK_Annot : public Observable<CPDFSDK_Annot> {
  public:
   explicit CPDFSDK_Annot(CPDFSDK_PageView* pPageView);
   virtual ~CPDFSDK_Annot();
@@ -32,18 +32,14 @@
   virtual CXFA_FFWidget* GetXFAWidget() const;
 #endif  // PDF_ENABLE_XFA
 
-  virtual FX_FLOAT GetMinWidth() const;
-  virtual FX_FLOAT GetMinHeight() const;
+  virtual float GetMinWidth() const;
+  virtual float GetMinHeight() const;
   virtual int GetLayoutOrder() const;
   virtual CPDF_Annot* GetPDFAnnot() const;
   virtual CPDF_Annot::Subtype GetAnnotSubtype() const;
   virtual bool IsSignatureWidget() const;
   virtual CFX_FloatRect GetRect() const;
-
   virtual void SetRect(const CFX_FloatRect& rect);
-  virtual void Annot_OnDraw(CFX_RenderDevice* pDevice,
-                            CFX_Matrix* pUser2Device,
-                            CPDF_RenderOptions* pOptions);
 
   UnderlyingPageType* GetUnderlyingPage();
   CPDF_Page* GetPDFPage();
@@ -51,15 +47,10 @@
   CPDFXFA_Page* GetPDFXFAPage();
 #endif  // PDF_ENABLE_XFA
 
-  void SetPage(CPDFSDK_PageView* pPageView);
-  CPDFSDK_PageView* GetPageView() const { return m_pPageView; }
-
-  bool IsSelected();
-  void SetSelected(bool bSelected);
+  CPDFSDK_PageView* GetPageView() const { return m_pPageView.Get(); }
 
  protected:
-  CPDFSDK_PageView* m_pPageView;
-  bool m_bSelected;
+  UnownedPtr<CPDFSDK_PageView> const m_pPageView;
 };
 
 #endif  // FPDFSDK_CPDFSDK_ANNOT_H_
diff --git a/fpdfsdk/cpdfsdk_annothandlermgr.cpp b/fpdfsdk/cpdfsdk_annothandlermgr.cpp
index c499067..2966b4d 100644
--- a/fpdfsdk/cpdfsdk_annothandlermgr.cpp
+++ b/fpdfsdk/cpdfsdk_annothandlermgr.cpp
@@ -17,23 +17,25 @@
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 #include "fpdfsdk/cpdfsdk_pageview.h"
 #include "fpdfsdk/cpdfsdk_widgethandler.h"
+#include "third_party/base/ptr_util.h"
 
 #ifdef PDF_ENABLE_XFA
 #include "fpdfsdk/cpdfsdk_xfawidgethandler.h"
 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
-#include "xfa/fxfa/xfa_ffpageview.h"
-#include "xfa/fxfa/xfa_ffwidget.h"
+#include "xfa/fxfa/cxfa_ffpageview.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
 #endif  // PDF_ENABLE_XFA
 
 CPDFSDK_AnnotHandlerMgr::CPDFSDK_AnnotHandlerMgr(
     CPDFSDK_FormFillEnvironment* pFormFillEnv)
-    : m_pBAAnnotHandler(new CPDFSDK_BAAnnotHandler()),
-      m_pWidgetHandler(new CPDFSDK_WidgetHandler(pFormFillEnv)),
+    : m_pBAAnnotHandler(pdfium::MakeUnique<CPDFSDK_BAAnnotHandler>()),
+      m_pWidgetHandler(pdfium::MakeUnique<CPDFSDK_WidgetHandler>(pFormFillEnv))
 #ifdef PDF_ENABLE_XFA
-      m_pXFAWidgetHandler(new CPDFSDK_XFAWidgetHandler(pFormFillEnv)),
+      ,
+      m_pXFAWidgetHandler(
+          pdfium::MakeUnique<CPDFSDK_XFAWidgetHandler>(pFormFillEnv))
 #endif  // PDF_ENABLE_XFA
-      m_pFormFillEnv(pFormFillEnv) {
-  m_pWidgetHandler->SetFormFiller(m_pFormFillEnv->GetInteractiveFormFiller());
+{
 }
 
 CPDFSDK_AnnotHandlerMgr::~CPDFSDK_AnnotHandlerMgr() {}
@@ -74,6 +76,16 @@
   GetAnnotHandler(pAnnot)->OnLoad(pAnnot);
 }
 
+WideString CPDFSDK_AnnotHandlerMgr::Annot_GetSelectedText(
+    CPDFSDK_Annot* pAnnot) {
+  return GetAnnotHandler(pAnnot)->GetSelectedText(pAnnot);
+}
+
+void CPDFSDK_AnnotHandlerMgr::Annot_ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                                                     const WideString& text) {
+  GetAnnotHandler(pAnnot)->ReplaceSelection(pAnnot, text);
+}
+
 IPDFSDK_AnnotHandler* CPDFSDK_AnnotHandlerMgr::GetAnnotHandler(
     CPDFSDK_Annot* pAnnot) const {
   return GetAnnotHandler(pAnnot->GetAnnotSubtype());
@@ -198,16 +210,16 @@
 bool CPDFSDK_AnnotHandlerMgr::Annot_OnKeyDown(CPDFSDK_Annot* pAnnot,
                                               int nKeyCode,
                                               int nFlag) {
-  if (m_pFormFillEnv->IsCTRLKeyDown(nFlag) ||
-      m_pFormFillEnv->IsALTKeyDown(nFlag)) {
+  if (CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag) ||
+      CPDFSDK_FormFillEnvironment::IsALTKeyDown(nFlag)) {
     return GetAnnotHandler(pAnnot)->OnKeyDown(pAnnot, nKeyCode, nFlag);
   }
 
   CPDFSDK_PageView* pPage = pAnnot->GetPageView();
   CPDFSDK_Annot* pFocusAnnot = pPage->GetFocusAnnot();
   if (pFocusAnnot && (nKeyCode == FWL_VKEY_Tab)) {
-    CPDFSDK_Annot::ObservedPtr pNext(
-        GetNextAnnot(pFocusAnnot, !m_pFormFillEnv->IsSHIFTKeyDown(nFlag)));
+    CPDFSDK_Annot::ObservedPtr pNext(GetNextAnnot(
+        pFocusAnnot, !CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag)));
     if (pNext && pNext.Get() != pFocusAnnot) {
       pPage->GetFormFillEnv()->SetFocusAnnot(&pNext);
       return true;
diff --git a/fpdfsdk/cpdfsdk_annothandlermgr.h b/fpdfsdk/cpdfsdk_annothandlermgr.h
index cbda02c..df4e1a2 100644
--- a/fpdfsdk/cpdfsdk_annothandlermgr.h
+++ b/fpdfsdk/cpdfsdk_annothandlermgr.h
@@ -11,8 +11,8 @@
 #include <memory>
 
 #include "core/fpdfdoc/cpdf_annot.h"
-#include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_coordinates.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "fpdfsdk/cpdfsdk_annot.h"
 
 class CFX_Matrix;
@@ -42,6 +42,9 @@
   void Annot_OnCreate(CPDFSDK_Annot* pAnnot);
   void Annot_OnLoad(CPDFSDK_Annot* pAnnot);
 
+  WideString Annot_GetSelectedText(CPDFSDK_Annot* pAnnot);
+  void Annot_ReplaceSelection(CPDFSDK_Annot* pAnnot, const WideString& text);
+
   IPDFSDK_AnnotHandler* GetAnnotHandler(CPDFSDK_Annot* pAnnot) const;
   void Annot_OnDraw(CPDFSDK_PageView* pPageView,
                     CPDFSDK_Annot* pAnnot,
@@ -111,8 +114,6 @@
 #ifdef PDF_ENABLE_XFA
   std::unique_ptr<CPDFSDK_XFAWidgetHandler> m_pXFAWidgetHandler;
 #endif  // PDF_ENABLE_XFA
-
-  CPDFSDK_FormFillEnvironment* m_pFormFillEnv;
 };
 
 #endif  // FPDFSDK_CPDFSDK_ANNOTHANDLERMGR_H_
diff --git a/fpdfsdk/cpdfsdk_annotiteration.cpp b/fpdfsdk/cpdfsdk_annotiteration.cpp
index dd99ade..d256950 100644
--- a/fpdfsdk/cpdfsdk_annotiteration.cpp
+++ b/fpdfsdk/cpdfsdk_annotiteration.cpp
@@ -33,7 +33,7 @@
     std::reverse(copiedList.begin(), copiedList.end());
 
   m_List.reserve(copiedList.size());
-  for (const auto& pAnnot : copiedList)
+  for (auto* pAnnot : copiedList)
     m_List.emplace_back(pAnnot);
 }
 
diff --git a/fpdfsdk/cpdfsdk_baannot.cpp b/fpdfsdk/cpdfsdk_baannot.cpp
index 3eedf15..a157880 100644
--- a/fpdfsdk/cpdfsdk_baannot.cpp
+++ b/fpdfsdk/cpdfsdk_baannot.cpp
@@ -27,7 +27,7 @@
 CPDFSDK_BAAnnot::~CPDFSDK_BAAnnot() {}
 
 CPDF_Annot* CPDFSDK_BAAnnot::GetPDFAnnot() const {
-  return m_pAnnot;
+  return m_pAnnot.Get();
 }
 
 CPDF_Annot* CPDFSDK_BAAnnot::GetPDFPopupAnnot() const {
@@ -38,6 +38,13 @@
   return m_pAnnot->GetAnnotDict();
 }
 
+CPDF_Dictionary* CPDFSDK_BAAnnot::GetAPDict() const {
+  CPDF_Dictionary* pAPDict = m_pAnnot->GetAnnotDict()->GetDictFor("AP");
+  if (!pAPDict)
+    pAPDict = m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Dictionary>("AP");
+  return pAPDict;
+}
+
 void CPDFSDK_BAAnnot::SetRect(const CFX_FloatRect& rect) {
   ASSERT(rect.right - rect.left >= GetMinWidth());
   ASSERT(rect.top - rect.bottom >= GetMinHeight());
@@ -54,10 +61,10 @@
 }
 
 void CPDFSDK_BAAnnot::DrawAppearance(CFX_RenderDevice* pDevice,
-                                     const CFX_Matrix* pUser2Device,
+                                     const CFX_Matrix& mtUser2Device,
                                      CPDF_Annot::AppearanceMode mode,
                                      const CPDF_RenderOptions* pOptions) {
-  m_pAnnot->DrawAppearance(m_pPageView->GetPDFPage(), pDevice, pUser2Device,
+  m_pAnnot->DrawAppearance(m_pPageView->GetPDFPage(), pDevice, mtUser2Device,
                            mode, pOptions);
 }
 
@@ -71,7 +78,7 @@
     return false;
 
   // Choose the right sub-ap
-  const FX_CHAR* ap_entry = "N";
+  const char* ap_entry = "N";
   if (mode == CPDF_Annot::Down)
     ap_entry = "D";
   else if (mode == CPDF_Annot::Rollover)
@@ -94,7 +101,7 @@
   m_pAnnot->ClearCachedAP();
 }
 
-void CPDFSDK_BAAnnot::SetContents(const CFX_WideString& sContents) {
+void CPDFSDK_BAAnnot::SetContents(const WideString& sContents) {
   if (sContents.IsEmpty()) {
     m_pAnnot->GetAnnotDict()->RemoveFor("Contents");
   } else {
@@ -103,11 +110,11 @@
   }
 }
 
-CFX_WideString CPDFSDK_BAAnnot::GetContents() const {
+WideString CPDFSDK_BAAnnot::GetContents() const {
   return m_pAnnot->GetAnnotDict()->GetUnicodeTextFor("Contents");
 }
 
-void CPDFSDK_BAAnnot::SetAnnotName(const CFX_WideString& sName) {
+void CPDFSDK_BAAnnot::SetAnnotName(const WideString& sName) {
   if (sName.IsEmpty()) {
     m_pAnnot->GetAnnotDict()->RemoveFor("NM");
   } else {
@@ -116,13 +123,13 @@
   }
 }
 
-CFX_WideString CPDFSDK_BAAnnot::GetAnnotName() const {
+WideString CPDFSDK_BAAnnot::GetAnnotName() const {
   return m_pAnnot->GetAnnotDict()->GetUnicodeTextFor("NM");
 }
 
 void CPDFSDK_BAAnnot::SetModifiedDate(const FX_SYSTEMTIME& st) {
   CPDFSDK_DateTime dt(st);
-  CFX_ByteString str = dt.ToPDFDateTimeString();
+  ByteString str = dt.ToPDFDateTimeString();
   if (str.IsEmpty())
     m_pAnnot->GetAnnotDict()->RemoveFor("M");
   else
@@ -131,7 +138,7 @@
 
 FX_SYSTEMTIME CPDFSDK_BAAnnot::GetModifiedDate() const {
   FX_SYSTEMTIME systime;
-  CFX_ByteString str = m_pAnnot->GetAnnotDict()->GetStringFor("M");
+  ByteString str = m_pAnnot->GetAnnotDict()->GetStringFor("M");
   CPDFSDK_DateTime dt(str);
   dt.ToSystemTime(systime);
   return systime;
@@ -146,14 +153,14 @@
   return m_pAnnot->GetAnnotDict()->GetIntegerFor("F");
 }
 
-void CPDFSDK_BAAnnot::SetAppState(const CFX_ByteString& str) {
+void CPDFSDK_BAAnnot::SetAppState(const ByteString& str) {
   if (str.IsEmpty())
     m_pAnnot->GetAnnotDict()->RemoveFor("AS");
   else
     m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_String>("AS", str, false);
 }
 
-CFX_ByteString CPDFSDK_BAAnnot::GetAppState() const {
+ByteString CPDFSDK_BAAnnot::GetAppState() const {
   return m_pAnnot->GetAnnotDict()->GetStringFor("AS");
 }
 
@@ -218,7 +225,7 @@
 BorderStyle CPDFSDK_BAAnnot::GetBorderStyle() const {
   CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDictFor("BS");
   if (pBSDict) {
-    CFX_ByteString sBorderStyle = pBSDict->GetStringFor("S", "S");
+    ByteString sBorderStyle = pBSDict->GetStringFor("S", "S");
     if (sBorderStyle == "S")
       return BorderStyle::SOLID;
     if (sBorderStyle == "D")
@@ -245,11 +252,11 @@
 
 void CPDFSDK_BAAnnot::SetColor(FX_COLORREF color) {
   CPDF_Array* pArray = m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Array>("C");
-  pArray->AddNew<CPDF_Number>(static_cast<FX_FLOAT>(FXSYS_GetRValue(color)) /
+  pArray->AddNew<CPDF_Number>(static_cast<float>(FXSYS_GetRValue(color)) /
                               255.0f);
-  pArray->AddNew<CPDF_Number>(static_cast<FX_FLOAT>(FXSYS_GetGValue(color)) /
+  pArray->AddNew<CPDF_Number>(static_cast<float>(FXSYS_GetGValue(color)) /
                               255.0f);
-  pArray->AddNew<CPDF_Number>(static_cast<FX_FLOAT>(FXSYS_GetBValue(color)) /
+  pArray->AddNew<CPDF_Number>(static_cast<float>(FXSYS_GetBValue(color)) /
                               255.0f);
 }
 
@@ -261,28 +268,28 @@
   if (CPDF_Array* pEntry = m_pAnnot->GetAnnotDict()->GetArrayFor("C")) {
     size_t nCount = pEntry->GetCount();
     if (nCount == 1) {
-      FX_FLOAT g = pEntry->GetNumberAt(0) * 255;
+      float g = pEntry->GetNumberAt(0) * 255;
 
       color = FXSYS_RGB((int)g, (int)g, (int)g);
 
       return true;
     } else if (nCount == 3) {
-      FX_FLOAT r = pEntry->GetNumberAt(0) * 255;
-      FX_FLOAT g = pEntry->GetNumberAt(1) * 255;
-      FX_FLOAT b = pEntry->GetNumberAt(2) * 255;
+      float r = pEntry->GetNumberAt(0) * 255;
+      float g = pEntry->GetNumberAt(1) * 255;
+      float b = pEntry->GetNumberAt(2) * 255;
 
       color = FXSYS_RGB((int)r, (int)g, (int)b);
 
       return true;
     } else if (nCount == 4) {
-      FX_FLOAT c = pEntry->GetNumberAt(0);
-      FX_FLOAT m = pEntry->GetNumberAt(1);
-      FX_FLOAT y = pEntry->GetNumberAt(2);
-      FX_FLOAT k = pEntry->GetNumberAt(3);
+      float c = pEntry->GetNumberAt(0);
+      float m = pEntry->GetNumberAt(1);
+      float y = pEntry->GetNumberAt(2);
+      float k = pEntry->GetNumberAt(3);
 
-      FX_FLOAT r = 1.0f - std::min(1.0f, c + k);
-      FX_FLOAT g = 1.0f - std::min(1.0f, m + k);
-      FX_FLOAT b = 1.0f - std::min(1.0f, y + k);
+      float r = 1.0f - std::min(1.0f, c + k);
+      float g = 1.0f - std::min(1.0f, m + k);
+      float b = 1.0f - std::min(1.0f, y + k);
 
       color = FXSYS_RGB((int)(r * 255), (int)(g * 255), (int)(b * 255));
 
@@ -293,50 +300,6 @@
   return false;
 }
 
-void CPDFSDK_BAAnnot::WriteAppearance(const CFX_ByteString& sAPType,
-                                      const CFX_FloatRect& rcBBox,
-                                      const CFX_Matrix& matrix,
-                                      const CFX_ByteString& sContents,
-                                      const CFX_ByteString& sAPState) {
-  CPDF_Dictionary* pAPDict = m_pAnnot->GetAnnotDict()->GetDictFor("AP");
-  if (!pAPDict)
-    pAPDict = m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Dictionary>("AP");
-
-  CPDF_Stream* pStream = nullptr;
-  CPDF_Dictionary* pParentDict = nullptr;
-  if (sAPState.IsEmpty()) {
-    pParentDict = pAPDict;
-    pStream = pAPDict->GetStreamFor(sAPType);
-  } else {
-    CPDF_Dictionary* pAPTypeDict = pAPDict->GetDictFor(sAPType);
-    if (!pAPTypeDict)
-      pAPTypeDict = pAPDict->SetNewFor<CPDF_Dictionary>(sAPType);
-
-    pParentDict = pAPTypeDict;
-    pStream = pAPTypeDict->GetStreamFor(sAPState);
-  }
-
-  if (!pStream) {
-    CPDF_Document* pDoc = m_pPageView->GetPDFDocument();
-    pStream = pDoc->NewIndirect<CPDF_Stream>();
-    pParentDict->SetNewFor<CPDF_Reference>(sAPType, pDoc, pStream->GetObjNum());
-  }
-
-  CPDF_Dictionary* pStreamDict = pStream->GetDict();
-  if (!pStreamDict) {
-    auto pNewDict = pdfium::MakeUnique<CPDF_Dictionary>(
-        m_pAnnot->GetDocument()->GetByteStringPool());
-    pStreamDict = pNewDict.get();
-    pStreamDict->SetNewFor<CPDF_Name>("Type", "XObject");
-    pStreamDict->SetNewFor<CPDF_Name>("Subtype", "Form");
-    pStreamDict->SetNewFor<CPDF_Number>("FormType", 1);
-    pStream->InitStream(nullptr, 0, std::move(pNewDict));
-  }
-  pStreamDict->SetMatrixFor("Matrix", matrix);
-  pStreamDict->SetRectFor("BBox", rcBBox);
-  pStream->SetData((uint8_t*)sContents.c_str(), sContents.GetLength());
-}
-
 bool CPDFSDK_BAAnnot::IsVisible() const {
   uint32_t nFlags = GetFlags();
   return !((nFlags & ANNOTFLAG_INVISIBLE) || (nFlags & ANNOTFLAG_HIDDEN) ||
@@ -383,18 +346,17 @@
   if (eAAT == CPDF_AAction::ButtonUp)
     return GetAction();
 
-  return CPDF_Action();
-}
-
-void CPDFSDK_BAAnnot::Annot_OnDraw(CFX_RenderDevice* pDevice,
-                                   CFX_Matrix* pUser2Device,
-                                   CPDF_RenderOptions* pOptions) {
-  m_pAnnot->GetAPForm(m_pPageView->GetPDFPage(), CPDF_Annot::Normal);
-  m_pAnnot->DrawAppearance(m_pPageView->GetPDFPage(), pDevice, pUser2Device,
-                           CPDF_Annot::Normal, nullptr);
+  return CPDF_Action(nullptr);
 }
 
 void CPDFSDK_BAAnnot::SetOpenState(bool bOpenState) {
   if (CPDF_Annot* pAnnot = m_pAnnot->GetPopupAnnot())
     pAnnot->SetOpenState(bOpenState);
 }
+
+int CPDFSDK_BAAnnot::GetLayoutOrder() const {
+  if (m_pAnnot->GetSubtype() == CPDF_Annot::Subtype::POPUP)
+    return 1;
+
+  return CPDFSDK_Annot::GetLayoutOrder();
+}
diff --git a/fpdfsdk/cpdfsdk_baannot.h b/fpdfsdk/cpdfsdk_baannot.h
index 2da5723..ac3c0cb 100644
--- a/fpdfsdk/cpdfsdk_baannot.h
+++ b/fpdfsdk/cpdfsdk_baannot.h
@@ -32,18 +32,17 @@
   void SetRect(const CFX_FloatRect& rect) override;
   CFX_FloatRect GetRect() const override;
   CPDF_Annot* GetPDFAnnot() const override;
-  void Annot_OnDraw(CFX_RenderDevice* pDevice,
-                    CFX_Matrix* pUser2Device,
-                    CPDF_RenderOptions* pOptions) override;
 
   CPDF_Dictionary* GetAnnotDict() const;
   CPDF_Annot* GetPDFPopupAnnot() const;
 
-  void SetContents(const CFX_WideString& sContents);
-  CFX_WideString GetContents() const;
+  CPDF_Dictionary* GetAPDict() const;
 
-  void SetAnnotName(const CFX_WideString& sName);
-  CFX_WideString GetAnnotName() const;
+  void SetContents(const WideString& sContents);
+  WideString GetContents() const;
+
+  void SetAnnotName(const WideString& sName);
+  WideString GetAnnotName() const;
 
   void SetModifiedDate(const FX_SYSTEMTIME& st);
   FX_SYSTEMTIME GetModifiedDate() const;
@@ -51,8 +50,8 @@
   void SetFlags(uint32_t nFlags);
   uint32_t GetFlags() const;
 
-  void SetAppState(const CFX_ByteString& str);
-  CFX_ByteString GetAppState() const;
+  void SetAppState(const ByteString& str);
+  ByteString GetAppState() const;
 
   void SetStructParent(int key);
   int GetStructParent() const;
@@ -81,7 +80,7 @@
   virtual bool IsAppearanceValid();
   virtual bool IsAppearanceValid(CPDF_Annot::AppearanceMode mode);
   virtual void DrawAppearance(CFX_RenderDevice* pDevice,
-                              const CFX_Matrix* pUser2Device,
+                              const CFX_Matrix& mtUser2Device,
                               CPDF_Annot::AppearanceMode mode,
                               const CPDF_RenderOptions* pOptions);
 
@@ -91,16 +90,12 @@
 
   void ClearCachedAP();
 
-  void WriteAppearance(const CFX_ByteString& sAPType,
-                       const CFX_FloatRect& rcBBox,
-                       const CFX_Matrix& matrix,
-                       const CFX_ByteString& sContents,
-                       const CFX_ByteString& sAPState = "");
-
   void SetOpenState(bool bState);
 
+  int GetLayoutOrder() const override;
+
  protected:
-  CPDF_Annot* const m_pAnnot;
+  UnownedPtr<CPDF_Annot> const m_pAnnot;
 };
 
 #endif  // FPDFSDK_CPDFSDK_BAANNOT_H_
diff --git a/fpdfsdk/cpdfsdk_baannothandler.cpp b/fpdfsdk/cpdfsdk_baannothandler.cpp
index fa83932..027527e 100644
--- a/fpdfsdk/cpdfsdk_baannothandler.cpp
+++ b/fpdfsdk/cpdfsdk_baannothandler.cpp
@@ -73,7 +73,7 @@
 #endif  // PDF_ENABLE_XFA
   if (bDrawAnnots && pAnnot->GetAnnotSubtype() == CPDF_Annot::Subtype::POPUP) {
     static_cast<CPDFSDK_BAAnnot*>(pAnnot)->DrawAppearance(
-        pDevice, pUser2Device, CPDF_Annot::Normal, nullptr);
+        pDevice, *pUser2Device, CPDF_Annot::Normal, nullptr);
   }
 }
 
@@ -193,6 +193,13 @@
   return pAnnot->GetRect();
 }
 
+WideString CPDFSDK_BAAnnotHandler::GetSelectedText(CPDFSDK_Annot* pAnnot) {
+  return WideString();
+}
+
+void CPDFSDK_BAAnnotHandler::ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                                              const WideString& text) {}
+
 bool CPDFSDK_BAAnnotHandler::HitTest(CPDFSDK_PageView* pPageView,
                                      CPDFSDK_Annot* pAnnot,
                                      const CFX_PointF& point) {
diff --git a/fpdfsdk/cpdfsdk_baannothandler.h b/fpdfsdk/cpdfsdk_baannothandler.h
index d5f170f..7bf8034 100644
--- a/fpdfsdk/cpdfsdk_baannothandler.h
+++ b/fpdfsdk/cpdfsdk_baannothandler.h
@@ -7,7 +7,6 @@
 #ifndef FPDFSDK_CPDFSDK_BAANNOTHANDLER_H_
 #define FPDFSDK_CPDFSDK_BAANNOTHANDLER_H_
 
-#include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "fpdfsdk/ipdfsdk_annothandler.h"
 
@@ -37,6 +36,8 @@
   void ReleaseAnnot(CPDFSDK_Annot* pAnnot) override;
   CFX_FloatRect GetViewBBox(CPDFSDK_PageView* pPageView,
                             CPDFSDK_Annot* pAnnot) override;
+  WideString GetSelectedText(CPDFSDK_Annot* pAnnot) override;
+  void ReplaceSelection(CPDFSDK_Annot* pAnnot, const WideString& text) override;
   bool HitTest(CPDFSDK_PageView* pPageView,
                CPDFSDK_Annot* pAnnot,
                const CFX_PointF& point) override;
diff --git a/fpdfsdk/cpdfsdk_datetime.cpp b/fpdfsdk/cpdfsdk_datetime.cpp
index 72f50a6..332ae8e 100644
--- a/fpdfsdk/cpdfsdk_datetime.cpp
+++ b/fpdfsdk/cpdfsdk_datetime.cpp
@@ -6,7 +6,7 @@
 
 #include "fpdfsdk/cpdfsdk_datetime.h"
 
-#include "core/fxcrt/fx_ext.h"
+#include "core/fxcrt/fx_extension.h"
 
 namespace {
 
@@ -63,7 +63,7 @@
   ResetDateTime();
 }
 
-CPDFSDK_DateTime::CPDFSDK_DateTime(const CFX_ByteString& dtStr) {
+CPDFSDK_DateTime::CPDFSDK_DateTime(const ByteString& dtStr) {
   ResetDateTime();
   FromPDFDateTimeString(dtStr);
 }
@@ -129,7 +129,7 @@
 }
 
 CPDFSDK_DateTime& CPDFSDK_DateTime::FromPDFDateTimeString(
-    const CFX_ByteString& dtStr) {
+    const ByteString& dtStr) {
   int strLength = dtStr.GetLength();
   if (strLength <= 0)
     return *this;
@@ -143,10 +143,10 @@
 
   int j = 0;
   int k = 0;
-  FX_CHAR ch;
+  char ch;
   while (i < strLength && j < 4) {
     ch = dtStr[i];
-    k = k * 10 + FXSYS_toDecimalDigit(ch);
+    k = k * 10 + FXSYS_DecimalCharToInt(ch);
     j++;
     if (!std::isdigit(ch))
       break;
@@ -160,7 +160,7 @@
   k = 0;
   while (i < strLength && j < 2) {
     ch = dtStr[i];
-    k = k * 10 + FXSYS_toDecimalDigit(ch);
+    k = k * 10 + FXSYS_DecimalCharToInt(ch);
     j++;
     if (!std::isdigit(ch))
       break;
@@ -174,7 +174,7 @@
   k = 0;
   while (i < strLength && j < 2) {
     ch = dtStr[i];
-    k = k * 10 + FXSYS_toDecimalDigit(ch);
+    k = k * 10 + FXSYS_DecimalCharToInt(ch);
     j++;
     if (!std::isdigit(ch))
       break;
@@ -188,7 +188,7 @@
   k = 0;
   while (i < strLength && j < 2) {
     ch = dtStr[i];
-    k = k * 10 + FXSYS_toDecimalDigit(ch);
+    k = k * 10 + FXSYS_DecimalCharToInt(ch);
     j++;
     if (!std::isdigit(ch))
       break;
@@ -202,7 +202,7 @@
   k = 0;
   while (i < strLength && j < 2) {
     ch = dtStr[i];
-    k = k * 10 + FXSYS_toDecimalDigit(ch);
+    k = k * 10 + FXSYS_DecimalCharToInt(ch);
     j++;
     if (!std::isdigit(ch))
       break;
@@ -216,7 +216,7 @@
   k = 0;
   while (i < strLength && j < 2) {
     ch = dtStr[i];
-    k = k * 10 + FXSYS_toDecimalDigit(ch);
+    k = k * 10 + FXSYS_DecimalCharToInt(ch);
     j++;
     if (!std::isdigit(ch))
       break;
@@ -237,7 +237,7 @@
   k = 0;
   while (i < strLength && j < 2) {
     ch = dtStr[i];
-    k = k * 10 + FXSYS_toDecimalDigit(ch);
+    k = k * 10 + FXSYS_DecimalCharToInt(ch);
     j++;
     if (!std::isdigit(ch))
       break;
@@ -253,7 +253,7 @@
   k = 0;
   while (i < strLength && j < 2) {
     ch = dtStr[i];
-    k = k * 10 + FXSYS_toDecimalDigit(ch);
+    k = k * 10 + FXSYS_DecimalCharToInt(ch);
     j++;
     if (!std::isdigit(ch))
       break;
@@ -263,34 +263,29 @@
   return *this;
 }
 
-CFX_ByteString CPDFSDK_DateTime::ToCommonDateTimeString() {
-  CFX_ByteString str1;
-  str1.Format("%04d-%02u-%02u %02u:%02u:%02u ", m_year, m_month, m_day, m_hour,
-              m_minute, m_second);
-  if (m_tzHour < 0)
-    str1 += "-";
-  else
-    str1 += "+";
-  CFX_ByteString str2;
-  str2.Format("%02d:%02u", std::abs(static_cast<int>(m_tzHour)), m_tzMinute);
-  return str1 + str2;
+ByteString CPDFSDK_DateTime::ToCommonDateTimeString() {
+  return ByteString::Format("%04d-%02u-%02u %02u:%02u:%02u ", m_year, m_month,
+                            m_day, m_hour, m_minute, m_second) +
+         (m_tzHour < 0 ? "-" : "+") +
+         ByteString::Format("%02d:%02u", std::abs(static_cast<int>(m_tzHour)),
+                            m_tzMinute);
 }
 
-CFX_ByteString CPDFSDK_DateTime::ToPDFDateTimeString() {
-  CFX_ByteString dtStr;
+ByteString CPDFSDK_DateTime::ToPDFDateTimeString() {
+  ByteString dtStr;
   char tempStr[32];
   memset(tempStr, 0, sizeof(tempStr));
   FXSYS_snprintf(tempStr, sizeof(tempStr) - 1, "D:%04d%02u%02u%02u%02u%02u",
                  m_year, m_month, m_day, m_hour, m_minute, m_second);
-  dtStr = CFX_ByteString(tempStr);
+  dtStr = ByteString(tempStr);
   if (m_tzHour < 0)
-    dtStr += CFX_ByteString("-");
+    dtStr += ByteString("-");
   else
-    dtStr += CFX_ByteString("+");
+    dtStr += ByteString("+");
   memset(tempStr, 0, sizeof(tempStr));
   FXSYS_snprintf(tempStr, sizeof(tempStr) - 1, "%02d'%02u'",
                  std::abs(static_cast<int>(m_tzHour)), m_tzMinute);
-  dtStr += CFX_ByteString(tempStr);
+  dtStr += ByteString(tempStr);
   return dtStr;
 }
 
diff --git a/fpdfsdk/cpdfsdk_datetime.h b/fpdfsdk/cpdfsdk_datetime.h
index 6b612b2..cbd3c36 100644
--- a/fpdfsdk/cpdfsdk_datetime.h
+++ b/fpdfsdk/cpdfsdk_datetime.h
@@ -7,7 +7,7 @@
 #ifndef FPDFSDK_CPDFSDK_DATETIME_H_
 #define FPDFSDK_CPDFSDK_DATETIME_H_
 
-#if _FX_OS_ == _FX_ANDROID_
+#if _FX_OS_ == _FX_OS_ANDROID_
 #include <time.h>
 #else
 #include <ctime>
@@ -18,16 +18,16 @@
 class CPDFSDK_DateTime {
  public:
   CPDFSDK_DateTime();
-  explicit CPDFSDK_DateTime(const CFX_ByteString& dtStr);
+  explicit CPDFSDK_DateTime(const ByteString& dtStr);
   explicit CPDFSDK_DateTime(const FX_SYSTEMTIME& st);
   CPDFSDK_DateTime(const CPDFSDK_DateTime& datetime);
 
   bool operator==(const CPDFSDK_DateTime& datetime) const;
   bool operator!=(const CPDFSDK_DateTime& datetime) const;
 
-  CPDFSDK_DateTime& FromPDFDateTimeString(const CFX_ByteString& dtStr);
-  CFX_ByteString ToCommonDateTimeString();
-  CFX_ByteString ToPDFDateTimeString();
+  CPDFSDK_DateTime& FromPDFDateTimeString(const ByteString& dtStr);
+  ByteString ToCommonDateTimeString();
+  ByteString ToPDFDateTimeString();
   void ToSystemTime(FX_SYSTEMTIME& st);
   time_t ToTime_t() const;
   CPDFSDK_DateTime ToGMT() const;
diff --git a/fpdfsdk/cpdfsdk_formfillenvironment.cpp b/fpdfsdk/cpdfsdk_formfillenvironment.cpp
index 4ef766d..955c184 100644
--- a/fpdfsdk/cpdfsdk_formfillenvironment.cpp
+++ b/fpdfsdk/cpdfsdk_formfillenvironment.cpp
@@ -7,6 +7,7 @@
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 
 #include <memory>
+#include <utility>
 
 #include "core/fpdfapi/parser/cpdf_array.h"
 #include "core/fpdfdoc/cpdf_docjsactions.h"
@@ -16,14 +17,14 @@
 #include "fpdfsdk/cpdfsdk_widget.h"
 #include "fpdfsdk/formfiller/cffl_interactiveformfiller.h"
 #include "fpdfsdk/fsdk_actionhandler.h"
-#include "fpdfsdk/javascript/ijs_runtime.h"
+#include "fxjs/ijs_runtime.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
 // NOTE: |bsUTF16LE| must outlive the use of the result. Care must be taken
 // since modifying the result would impact |bsUTF16LE|.
-FPDF_WIDESTRING AsFPDFWideString(CFX_ByteString* bsUTF16LE) {
+FPDF_WIDESTRING AsFPDFWideString(ByteString* bsUTF16LE) {
   return reinterpret_cast<FPDF_WIDESTRING>(
       bsUTF16LE->GetBuffer(bsUTF16LE->GetLength()));
 }
@@ -35,7 +36,7 @@
     FPDF_FORMFILLINFO* pFFinfo)
     : m_pInfo(pFFinfo),
       m_pUnderlyingDoc(pDoc),
-      m_pSysHandler(new CFX_SystemHandler(this)),
+      m_pSysHandler(pdfium::MakeUnique<CFX_SystemHandler>(this)),
       m_bChangeMask(false),
       m_bBeingDestroyed(false) {}
 
@@ -60,25 +61,25 @@
     m_pInfo->Release(m_pInfo);
 }
 
-int CPDFSDK_FormFillEnvironment::JS_appAlert(const FX_WCHAR* Msg,
-                                             const FX_WCHAR* Title,
+int CPDFSDK_FormFillEnvironment::JS_appAlert(const wchar_t* Msg,
+                                             const wchar_t* Title,
                                              uint32_t Type,
                                              uint32_t Icon) {
   if (!m_pInfo || !m_pInfo->m_pJsPlatform ||
       !m_pInfo->m_pJsPlatform->app_alert) {
     return -1;
   }
-  CFX_ByteString bsMsg = CFX_WideString(Msg).UTF16LE_Encode();
-  CFX_ByteString bsTitle = CFX_WideString(Title).UTF16LE_Encode();
+  ByteString bsMsg = WideString(Msg).UTF16LE_Encode();
+  ByteString bsTitle = WideString(Title).UTF16LE_Encode();
   return m_pInfo->m_pJsPlatform->app_alert(
       m_pInfo->m_pJsPlatform, AsFPDFWideString(&bsMsg),
       AsFPDFWideString(&bsTitle), Type, Icon);
 }
 
-int CPDFSDK_FormFillEnvironment::JS_appResponse(const FX_WCHAR* Question,
-                                                const FX_WCHAR* Title,
-                                                const FX_WCHAR* Default,
-                                                const FX_WCHAR* cLabel,
+int CPDFSDK_FormFillEnvironment::JS_appResponse(const wchar_t* Question,
+                                                const wchar_t* Title,
+                                                const wchar_t* Default,
+                                                const wchar_t* cLabel,
                                                 FPDF_BOOL bPassword,
                                                 void* response,
                                                 int length) {
@@ -86,10 +87,10 @@
       !m_pInfo->m_pJsPlatform->app_response) {
     return -1;
   }
-  CFX_ByteString bsQuestion = CFX_WideString(Question).UTF16LE_Encode();
-  CFX_ByteString bsTitle = CFX_WideString(Title).UTF16LE_Encode();
-  CFX_ByteString bsDefault = CFX_WideString(Default).UTF16LE_Encode();
-  CFX_ByteString bsLabel = CFX_WideString(cLabel).UTF16LE_Encode();
+  ByteString bsQuestion = WideString(Question).UTF16LE_Encode();
+  ByteString bsTitle = WideString(Title).UTF16LE_Encode();
+  ByteString bsDefault = WideString(Default).UTF16LE_Encode();
+  ByteString bsLabel = WideString(cLabel).UTF16LE_Encode();
   return m_pInfo->m_pJsPlatform->app_response(
       m_pInfo->m_pJsPlatform, AsFPDFWideString(&bsQuestion),
       AsFPDFWideString(&bsTitle), AsFPDFWideString(&bsDefault),
@@ -104,54 +105,54 @@
   m_pInfo->m_pJsPlatform->app_beep(m_pInfo->m_pJsPlatform, nType);
 }
 
-CFX_WideString CPDFSDK_FormFillEnvironment::JS_fieldBrowse() {
+WideString CPDFSDK_FormFillEnvironment::JS_fieldBrowse() {
   if (!m_pInfo || !m_pInfo->m_pJsPlatform ||
       !m_pInfo->m_pJsPlatform->Field_browse) {
-    return CFX_WideString();
+    return WideString();
   }
   const int nRequiredLen =
       m_pInfo->m_pJsPlatform->Field_browse(m_pInfo->m_pJsPlatform, nullptr, 0);
   if (nRequiredLen <= 0)
-    return CFX_WideString();
+    return WideString();
 
-  std::unique_ptr<char[]> pBuff(new char[nRequiredLen]);
-  memset(pBuff.get(), 0, nRequiredLen);
+  std::vector<uint8_t> pBuff(nRequiredLen);
   const int nActualLen = m_pInfo->m_pJsPlatform->Field_browse(
-      m_pInfo->m_pJsPlatform, pBuff.get(), nRequiredLen);
+      m_pInfo->m_pJsPlatform, pBuff.data(), nRequiredLen);
   if (nActualLen <= 0 || nActualLen > nRequiredLen)
-    return CFX_WideString();
+    return WideString();
 
-  return CFX_WideString::FromLocal(CFX_ByteStringC(pBuff.get(), nActualLen));
+  pBuff.resize(nActualLen);
+  return WideString::FromLocal(ByteStringView(pBuff));
 }
 
-CFX_WideString CPDFSDK_FormFillEnvironment::JS_docGetFilePath() {
+WideString CPDFSDK_FormFillEnvironment::JS_docGetFilePath() {
   if (!m_pInfo || !m_pInfo->m_pJsPlatform ||
       !m_pInfo->m_pJsPlatform->Doc_getFilePath) {
-    return CFX_WideString();
+    return WideString();
   }
   const int nRequiredLen = m_pInfo->m_pJsPlatform->Doc_getFilePath(
       m_pInfo->m_pJsPlatform, nullptr, 0);
   if (nRequiredLen <= 0)
-    return CFX_WideString();
+    return WideString();
 
-  std::unique_ptr<char[]> pBuff(new char[nRequiredLen]);
-  memset(pBuff.get(), 0, nRequiredLen);
+  std::vector<uint8_t> pBuff(nRequiredLen);
   const int nActualLen = m_pInfo->m_pJsPlatform->Doc_getFilePath(
-      m_pInfo->m_pJsPlatform, pBuff.get(), nRequiredLen);
+      m_pInfo->m_pJsPlatform, pBuff.data(), nRequiredLen);
   if (nActualLen <= 0 || nActualLen > nRequiredLen)
-    return CFX_WideString();
+    return WideString();
 
-  return CFX_WideString::FromLocal(CFX_ByteStringC(pBuff.get(), nActualLen));
+  pBuff.resize(nActualLen);
+  return WideString::FromLocal(ByteStringView(pBuff));
 }
 
 void CPDFSDK_FormFillEnvironment::JS_docSubmitForm(void* formData,
                                                    int length,
-                                                   const FX_WCHAR* URL) {
+                                                   const wchar_t* URL) {
   if (!m_pInfo || !m_pInfo->m_pJsPlatform ||
       !m_pInfo->m_pJsPlatform->Doc_submitForm) {
     return;
   }
-  CFX_ByteString bsDestination = CFX_WideString(URL).UTF16LE_Encode();
+  ByteString bsDestination = WideString(URL).UTF16LE_Encode();
   m_pInfo->m_pJsPlatform->Doc_submitForm(m_pInfo->m_pJsPlatform, formData,
                                          length,
                                          AsFPDFWideString(&bsDestination));
@@ -160,20 +161,20 @@
 void CPDFSDK_FormFillEnvironment::JS_docmailForm(void* mailData,
                                                  int length,
                                                  FPDF_BOOL bUI,
-                                                 const FX_WCHAR* To,
-                                                 const FX_WCHAR* Subject,
-                                                 const FX_WCHAR* CC,
-                                                 const FX_WCHAR* BCC,
-                                                 const FX_WCHAR* Msg) {
+                                                 const wchar_t* To,
+                                                 const wchar_t* Subject,
+                                                 const wchar_t* CC,
+                                                 const wchar_t* BCC,
+                                                 const wchar_t* Msg) {
   if (!m_pInfo || !m_pInfo->m_pJsPlatform ||
       !m_pInfo->m_pJsPlatform->Doc_mail) {
     return;
   }
-  CFX_ByteString bsTo = CFX_WideString(To).UTF16LE_Encode();
-  CFX_ByteString bsSubject = CFX_WideString(Subject).UTF16LE_Encode();
-  CFX_ByteString bsCC = CFX_WideString(CC).UTF16LE_Encode();
-  CFX_ByteString bsBcc = CFX_WideString(BCC).UTF16LE_Encode();
-  CFX_ByteString bsMsg = CFX_WideString(Msg).UTF16LE_Encode();
+  ByteString bsTo = WideString(To).UTF16LE_Encode();
+  ByteString bsSubject = WideString(Subject).UTF16LE_Encode();
+  ByteString bsCC = WideString(CC).UTF16LE_Encode();
+  ByteString bsBcc = WideString(BCC).UTF16LE_Encode();
+  ByteString bsMsg = WideString(Msg).UTF16LE_Encode();
   m_pInfo->m_pJsPlatform->Doc_mail(
       m_pInfo->m_pJsPlatform, mailData, length, bUI, AsFPDFWideString(&bsTo),
       AsFPDFWideString(&bsSubject), AsFPDFWideString(&bsCC),
@@ -219,7 +220,7 @@
   return m_pAnnotHandlerMgr.get();
 }
 
-CPDFSDK_ActionHandler* CPDFSDK_FormFillEnvironment::GetActionHander() {
+CPDFSDK_ActionHandler* CPDFSDK_FormFillEnvironment::GetActionHandler() {
   if (!m_pActionHandler)
     m_pActionHandler = pdfium::MakeUnique<CPDFSDK_ActionHandler>();
   return m_pActionHandler.get();
@@ -232,7 +233,7 @@
   return m_pFormFiller.get();
 }
 
-void CPDFSDK_FormFillEnvironment::Invalidate(FPDF_PAGE page,
+void CPDFSDK_FormFillEnvironment::Invalidate(UnderlyingPageType* page,
                                              const FX_RECT& rect) {
   if (m_pInfo && m_pInfo->FFI_Invalidate) {
     m_pInfo->FFI_Invalidate(m_pInfo, page, rect.left, rect.top, rect.right,
@@ -241,7 +242,7 @@
 }
 
 void CPDFSDK_FormFillEnvironment::OutputSelectedRect(
-    FPDF_PAGE page,
+    UnderlyingPageType* page,
     const CFX_FloatRect& rect) {
   if (m_pInfo && m_pInfo->FFI_OutputSelectedRect) {
     m_pInfo->FFI_OutputSelectedRect(m_pInfo, page, rect.left, rect.top,
@@ -288,33 +289,14 @@
     m_pInfo->FFI_OnChange(m_pInfo);
 }
 
-bool CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(uint32_t nFlag) const {
-  return (nFlag & FWL_EVENTFLAG_ShiftKey) != 0;
-}
-
-bool CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(uint32_t nFlag) const {
-  return (nFlag & FWL_EVENTFLAG_ControlKey) != 0;
-}
-
-bool CPDFSDK_FormFillEnvironment::IsALTKeyDown(uint32_t nFlag) const {
-  return (nFlag & FWL_EVENTFLAG_AltKey) != 0;
-}
-
-FPDF_PAGE CPDFSDK_FormFillEnvironment::GetPage(FPDF_DOCUMENT document,
-                                               int nPageIndex) {
-  if (m_pInfo && m_pInfo->FFI_GetPage)
-    return m_pInfo->FFI_GetPage(m_pInfo, document, nPageIndex);
-  return nullptr;
-}
-
-FPDF_PAGE CPDFSDK_FormFillEnvironment::GetCurrentPage(FPDF_DOCUMENT document) {
+FPDF_PAGE CPDFSDK_FormFillEnvironment::GetCurrentPage(
+    UnderlyingDocumentType* document) {
   if (m_pInfo && m_pInfo->FFI_GetCurrentPage)
     return m_pInfo->FFI_GetCurrentPage(m_pInfo, document);
   return nullptr;
 }
 
-void CPDFSDK_FormFillEnvironment::ExecuteNamedAction(
-    const FX_CHAR* namedAction) {
+void CPDFSDK_FormFillEnvironment::ExecuteNamedAction(const char* namedAction) {
   if (m_pInfo && m_pInfo->FFI_ExecuteNamedAction)
     m_pInfo->FFI_ExecuteNamedAction(m_pInfo, namedAction);
 }
@@ -327,7 +309,7 @@
     m_pInfo->FFI_SetTextFieldFocus(m_pInfo, focusText, nTextLen, bFocus);
 }
 
-void CPDFSDK_FormFillEnvironment::DoURIAction(const FX_CHAR* bsURI) {
+void CPDFSDK_FormFillEnvironment::DoURIAction(const char* bsURI) {
   if (m_pInfo && m_pInfo->FFI_DoURIAction)
     m_pInfo->FFI_DoURIAction(m_pInfo, bsURI);
 }
@@ -343,7 +325,7 @@
 }
 
 #ifdef PDF_ENABLE_XFA
-void CPDFSDK_FormFillEnvironment::DisplayCaret(FPDF_PAGE page,
+void CPDFSDK_FormFillEnvironment::DisplayCaret(CPDFXFA_Page* page,
                                                FPDF_BOOL bVisible,
                                                double left,
                                                double top,
@@ -355,53 +337,49 @@
   }
 }
 
-int CPDFSDK_FormFillEnvironment::GetCurrentPageIndex(FPDF_DOCUMENT document) {
+int CPDFSDK_FormFillEnvironment::GetCurrentPageIndex(
+    CPDFXFA_Context* document) {
   if (!m_pInfo || !m_pInfo->FFI_GetCurrentPageIndex)
     return -1;
   return m_pInfo->FFI_GetCurrentPageIndex(m_pInfo, document);
 }
 
-void CPDFSDK_FormFillEnvironment::SetCurrentPage(FPDF_DOCUMENT document,
+void CPDFSDK_FormFillEnvironment::SetCurrentPage(CPDFXFA_Context* document,
                                                  int iCurPage) {
   if (m_pInfo && m_pInfo->FFI_SetCurrentPage)
     m_pInfo->FFI_SetCurrentPage(m_pInfo, document, iCurPage);
 }
 
-CFX_WideString CPDFSDK_FormFillEnvironment::GetPlatform() {
+WideString CPDFSDK_FormFillEnvironment::GetPlatform() {
   if (!m_pInfo || !m_pInfo->FFI_GetPlatform)
-    return L"";
+    return WideString();
 
   int nRequiredLen = m_pInfo->FFI_GetPlatform(m_pInfo, nullptr, 0);
   if (nRequiredLen <= 0)
-    return L"";
+    return WideString();
 
-  char* pbuff = new char[nRequiredLen];
-  memset(pbuff, 0, nRequiredLen);
-  int nActualLen = m_pInfo->FFI_GetPlatform(m_pInfo, pbuff, nRequiredLen);
-  if (nActualLen <= 0 || nActualLen > nRequiredLen) {
-    delete[] pbuff;
-    return L"";
-  }
-  CFX_ByteString bsRet = CFX_ByteString(pbuff, nActualLen);
-  CFX_WideString wsRet = CFX_WideString::FromUTF16LE(
-      (unsigned short*)bsRet.GetBuffer(bsRet.GetLength()),
-      bsRet.GetLength() / sizeof(unsigned short));
-  delete[] pbuff;
-  return wsRet;
+  std::vector<uint8_t> pBuff(nRequiredLen);
+  int nActualLen =
+      m_pInfo->FFI_GetPlatform(m_pInfo, pBuff.data(), nRequiredLen);
+  if (nActualLen <= 0 || nActualLen > nRequiredLen)
+    return WideString();
+
+  return WideString::FromUTF16LE(reinterpret_cast<uint16_t*>(pBuff.data()),
+                                 nActualLen / sizeof(uint16_t));
 }
 
-void CPDFSDK_FormFillEnvironment::GotoURL(FPDF_DOCUMENT document,
-                                          const CFX_WideStringC& wsURL) {
+void CPDFSDK_FormFillEnvironment::GotoURL(CPDFXFA_Context* document,
+                                          const WideStringView& wsURL) {
   if (!m_pInfo || !m_pInfo->FFI_GotoURL)
     return;
 
-  CFX_ByteString bsTo = CFX_WideString(wsURL).UTF16LE_Encode();
+  ByteString bsTo = WideString(wsURL).UTF16LE_Encode();
   FPDF_WIDESTRING pTo = (FPDF_WIDESTRING)bsTo.GetBuffer(wsURL.GetLength());
   m_pInfo->FFI_GotoURL(m_pInfo, document, pTo);
-  bsTo.ReleaseBuffer();
+  bsTo.ReleaseBuffer(bsTo.GetStringLength());
 }
 
-void CPDFSDK_FormFillEnvironment::GetPageViewRect(FPDF_PAGE page,
+void CPDFSDK_FormFillEnvironment::GetPageViewRect(CPDFXFA_Page* page,
                                                   FS_RECTF& dstRect) {
   if (!m_pInfo || !m_pInfo->FFI_GetPageViewRect)
     return;
@@ -411,14 +389,16 @@
   double right;
   double bottom;
   m_pInfo->FFI_GetPageViewRect(m_pInfo, page, &left, &top, &right, &bottom);
+  if (top < bottom)
+    std::swap(top, bottom);
 
   dstRect.left = static_cast<float>(left);
-  dstRect.top = static_cast<float>(top < bottom ? bottom : top);
-  dstRect.bottom = static_cast<float>(top < bottom ? top : bottom);
+  dstRect.top = static_cast<float>(top);
+  dstRect.bottom = static_cast<float>(bottom);
   dstRect.right = static_cast<float>(right);
 }
 
-bool CPDFSDK_FormFillEnvironment::PopupMenu(FPDF_PAGE page,
+bool CPDFSDK_FormFillEnvironment::PopupMenu(CPDFXFA_Page* page,
                                             FPDF_WIDGET hWidget,
                                             int menuFlag,
                                             CFX_PointF pt) {
@@ -461,12 +441,12 @@
   return nullptr;
 }
 
-CFX_RetainPtr<IFX_SeekableReadStream>
-CPDFSDK_FormFillEnvironment::DownloadFromURL(const FX_WCHAR* url) {
+RetainPtr<IFX_SeekableReadStream> CPDFSDK_FormFillEnvironment::DownloadFromURL(
+    const wchar_t* url) {
   if (!m_pInfo || !m_pInfo->FFI_DownloadFromURL)
     return nullptr;
 
-  CFX_ByteString bstrURL = CFX_WideString(url).UTF16LE_Encode();
+  ByteString bstrURL = WideString(url).UTF16LE_Encode();
   FPDF_WIDESTRING wsURL =
       (FPDF_WIDESTRING)bstrURL.GetBuffer(bstrURL.GetLength());
 
@@ -474,30 +454,30 @@
   return MakeSeekableStream(fileHandler);
 }
 
-CFX_WideString CPDFSDK_FormFillEnvironment::PostRequestURL(
-    const FX_WCHAR* wsURL,
-    const FX_WCHAR* wsData,
-    const FX_WCHAR* wsContentType,
-    const FX_WCHAR* wsEncode,
-    const FX_WCHAR* wsHeader) {
+WideString CPDFSDK_FormFillEnvironment::PostRequestURL(
+    const wchar_t* wsURL,
+    const wchar_t* wsData,
+    const wchar_t* wsContentType,
+    const wchar_t* wsEncode,
+    const wchar_t* wsHeader) {
   if (!m_pInfo || !m_pInfo->FFI_PostRequestURL)
     return L"";
 
-  CFX_ByteString bsURL = CFX_WideString(wsURL).UTF16LE_Encode();
+  ByteString bsURL = WideString(wsURL).UTF16LE_Encode();
   FPDF_WIDESTRING URL = (FPDF_WIDESTRING)bsURL.GetBuffer(bsURL.GetLength());
 
-  CFX_ByteString bsData = CFX_WideString(wsData).UTF16LE_Encode();
+  ByteString bsData = WideString(wsData).UTF16LE_Encode();
   FPDF_WIDESTRING data = (FPDF_WIDESTRING)bsData.GetBuffer(bsData.GetLength());
 
-  CFX_ByteString bsContentType = CFX_WideString(wsContentType).UTF16LE_Encode();
+  ByteString bsContentType = WideString(wsContentType).UTF16LE_Encode();
   FPDF_WIDESTRING contentType =
       (FPDF_WIDESTRING)bsContentType.GetBuffer(bsContentType.GetLength());
 
-  CFX_ByteString bsEncode = CFX_WideString(wsEncode).UTF16LE_Encode();
+  ByteString bsEncode = WideString(wsEncode).UTF16LE_Encode();
   FPDF_WIDESTRING encode =
       (FPDF_WIDESTRING)bsEncode.GetBuffer(bsEncode.GetLength());
 
-  CFX_ByteString bsHeader = CFX_WideString(wsHeader).UTF16LE_Encode();
+  ByteString bsHeader = WideString(wsHeader).UTF16LE_Encode();
   FPDF_WIDESTRING header =
       (FPDF_WIDESTRING)bsHeader.GetBuffer(bsHeader.GetLength());
 
@@ -506,53 +486,48 @@
   m_pInfo->FFI_PostRequestURL(m_pInfo, URL, data, contentType, encode, header,
                               &response);
 
-  CFX_WideString wsRet = CFX_WideString::FromUTF16LE(
+  WideString wsRet = WideString::FromUTF16LE(
       (FPDF_WIDESTRING)response.str, response.len / sizeof(FPDF_WIDESTRING));
   FPDF_BStr_Clear(&response);
 
   return wsRet;
 }
 
-FPDF_BOOL CPDFSDK_FormFillEnvironment::PutRequestURL(const FX_WCHAR* wsURL,
-                                                     const FX_WCHAR* wsData,
-                                                     const FX_WCHAR* wsEncode) {
+FPDF_BOOL CPDFSDK_FormFillEnvironment::PutRequestURL(const wchar_t* wsURL,
+                                                     const wchar_t* wsData,
+                                                     const wchar_t* wsEncode) {
   if (!m_pInfo || !m_pInfo->FFI_PutRequestURL)
     return false;
 
-  CFX_ByteString bsURL = CFX_WideString(wsURL).UTF16LE_Encode();
+  ByteString bsURL = WideString(wsURL).UTF16LE_Encode();
   FPDF_WIDESTRING URL = (FPDF_WIDESTRING)bsURL.GetBuffer(bsURL.GetLength());
 
-  CFX_ByteString bsData = CFX_WideString(wsData).UTF16LE_Encode();
+  ByteString bsData = WideString(wsData).UTF16LE_Encode();
   FPDF_WIDESTRING data = (FPDF_WIDESTRING)bsData.GetBuffer(bsData.GetLength());
 
-  CFX_ByteString bsEncode = CFX_WideString(wsEncode).UTF16LE_Encode();
+  ByteString bsEncode = WideString(wsEncode).UTF16LE_Encode();
   FPDF_WIDESTRING encode =
       (FPDF_WIDESTRING)bsEncode.GetBuffer(bsEncode.GetLength());
 
   return m_pInfo->FFI_PutRequestURL(m_pInfo, URL, data, encode);
 }
 
-CFX_WideString CPDFSDK_FormFillEnvironment::GetLanguage() {
+WideString CPDFSDK_FormFillEnvironment::GetLanguage() {
   if (!m_pInfo || !m_pInfo->FFI_GetLanguage)
-    return L"";
+    return WideString();
 
   int nRequiredLen = m_pInfo->FFI_GetLanguage(m_pInfo, nullptr, 0);
   if (nRequiredLen <= 0)
-    return L"";
+    return WideString();
 
-  char* pbuff = new char[nRequiredLen];
-  memset(pbuff, 0, nRequiredLen);
-  int nActualLen = m_pInfo->FFI_GetLanguage(m_pInfo, pbuff, nRequiredLen);
-  if (nActualLen <= 0 || nActualLen > nRequiredLen) {
-    delete[] pbuff;
-    return L"";
-  }
-  CFX_ByteString bsRet = CFX_ByteString(pbuff, nActualLen);
-  CFX_WideString wsRet = CFX_WideString::FromUTF16LE(
-      (FPDF_WIDESTRING)bsRet.GetBuffer(bsRet.GetLength()),
-      bsRet.GetLength() / sizeof(FPDF_WIDESTRING));
-  delete[] pbuff;
-  return wsRet;
+  std::vector<uint8_t> pBuff(nRequiredLen);
+  int nActualLen =
+      m_pInfo->FFI_GetLanguage(m_pInfo, pBuff.data(), nRequiredLen);
+  if (nActualLen <= 0 || nActualLen > nRequiredLen)
+    return WideString();
+
+  return WideString::FromUTF16LE(reinterpret_cast<uint16_t*>(pBuff.data()),
+                                 nActualLen / sizeof(uint16_t));
 }
 
 void CPDFSDK_FormFillEnvironment::PageEvent(int iPageCount,
@@ -579,8 +554,10 @@
   if (!renew)
     return nullptr;
 
-  CPDFSDK_PageView* pPageView = new CPDFSDK_PageView(this, pUnderlyingPage);
-  m_PageMap[pUnderlyingPage].reset(pPageView);
+  auto pNew = pdfium::MakeUnique<CPDFSDK_PageView>(this, pUnderlyingPage);
+  CPDFSDK_PageView* pPageView = pNew.get();
+  m_PageMap[pUnderlyingPage] = std::move(pNew);
+
   // Delay to load all the annotations, to avoid endless loop.
   pPageView->LoadFXAnnots();
   return pPageView;
@@ -588,13 +565,12 @@
 
 CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetCurrentView() {
   UnderlyingPageType* pPage =
-      UnderlyingFromFPDFPage(GetCurrentPage(m_pUnderlyingDoc));
+      UnderlyingFromFPDFPage(GetCurrentPage(m_pUnderlyingDoc.Get()));
   return pPage ? GetPageView(pPage, true) : nullptr;
 }
 
 CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetPageView(int nIndex) {
-  UnderlyingPageType* pTempPage =
-      UnderlyingFromFPDFPage(GetPage(m_pUnderlyingDoc, nIndex));
+  UnderlyingPageType* pTempPage = GetPage(nIndex);
   if (!pTempPage)
     return nullptr;
 
@@ -606,15 +582,10 @@
   CPDF_Document* pPDFDoc = GetPDFDocument();
   CPDF_DocJSActions docJS(pPDFDoc);
   int iCount = docJS.CountJSActions();
-  if (iCount < 1)
-    return;
   for (int i = 0; i < iCount; i++) {
-    CFX_ByteString csJSName;
-    CPDF_Action jsAction = docJS.GetJSAction(i, csJSName);
-    if (GetActionHander()) {
-      GetActionHander()->DoAction_JavaScript(
-          jsAction, CFX_WideString::FromLocal(csJSName.AsStringC()), this);
-    }
+    WideString csJSName;
+    CPDF_Action jsAction = docJS.GetJSActionAndName(i, &csJSName);
+    GetActionHandler()->DoAction_JavaScript(jsAction, csJSName, this);
   }
 }
 
@@ -622,27 +593,26 @@
   if (!m_pUnderlyingDoc)
     return false;
 
-  CPDF_Dictionary* pRoot = GetPDFDocument()->GetRoot();
+  const CPDF_Dictionary* pRoot = GetPDFDocument()->GetRoot();
   if (!pRoot)
     return false;
 
   CPDF_Object* pOpenAction = pRoot->GetDictFor("OpenAction");
   if (!pOpenAction)
     pOpenAction = pRoot->GetArrayFor("OpenAction");
-
   if (!pOpenAction)
     return false;
 
   if (pOpenAction->IsArray())
     return true;
 
-  if (CPDF_Dictionary* pDict = pOpenAction->AsDictionary()) {
-    CPDF_Action action(pDict);
-    if (GetActionHander())
-      GetActionHander()->DoAction_DocOpen(action, this);
-    return true;
-  }
-  return false;
+  CPDF_Dictionary* pDict = pOpenAction->AsDictionary();
+  if (!pDict)
+    return false;
+
+  CPDF_Action action(pDict);
+  GetActionHandler()->DoAction_DocOpen(action, this);
+  return true;
 }
 
 void CPDFSDK_FormFillEnvironment::RemovePageView(
@@ -673,7 +643,10 @@
 }
 
 UnderlyingPageType* CPDFSDK_FormFillEnvironment::GetPage(int nIndex) {
-  return UnderlyingFromFPDFPage(GetPage(m_pUnderlyingDoc, nIndex));
+  if (!m_pInfo || !m_pInfo->FFI_GetPage)
+    return nullptr;
+  return UnderlyingFromFPDFPage(
+      m_pInfo->FFI_GetPage(m_pInfo, m_pUnderlyingDoc.Get(), nIndex));
 }
 
 CPDFSDK_InterForm* CPDFSDK_FormFillEnvironment::GetInterForm() {
@@ -702,59 +675,58 @@
   if (!*pAnnot)
     return false;
 
+  CPDFSDK_PageView* pPageView = (*pAnnot)->GetPageView();
+  if (!pPageView || !pPageView->IsValid())
+    return false;
+
+  CPDFSDK_AnnotHandlerMgr* pAnnotHandler = GetAnnotHandlerMgr();
+  if (m_pFocusAnnot)
+    return false;
+
 #ifdef PDF_ENABLE_XFA
   CPDFSDK_Annot::ObservedPtr pLastFocusAnnot(m_pFocusAnnot.Get());
+  if (!pAnnotHandler->Annot_OnChangeFocus(pAnnot, &pLastFocusAnnot))
+    return false;
 #endif  // PDF_ENABLE_XFA
-  CPDFSDK_PageView* pPageView = (*pAnnot)->GetPageView();
-  if (pPageView && pPageView->IsValid()) {
-    CPDFSDK_AnnotHandlerMgr* pAnnotHandler = GetAnnotHandlerMgr();
-    if (!m_pFocusAnnot) {
-#ifdef PDF_ENABLE_XFA
-      if (!pAnnotHandler->Annot_OnChangeFocus(pAnnot, &pLastFocusAnnot))
-        return false;
-#endif  // PDF_ENABLE_XFA
-      if (!pAnnotHandler->Annot_OnSetFocus(pAnnot, 0))
-        return false;
-      if (!m_pFocusAnnot) {
-        m_pFocusAnnot.Reset(pAnnot->Get());
-        return true;
-      }
-    }
-  }
-  return false;
+  if (!pAnnotHandler->Annot_OnSetFocus(pAnnot, 0))
+    return false;
+  if (m_pFocusAnnot)
+    return false;
+
+  m_pFocusAnnot.Reset(pAnnot->Get());
+  return true;
 }
 
 bool CPDFSDK_FormFillEnvironment::KillFocusAnnot(uint32_t nFlag) {
-  if (m_pFocusAnnot) {
-    CPDFSDK_AnnotHandlerMgr* pAnnotHandler = GetAnnotHandlerMgr();
-    CPDFSDK_Annot::ObservedPtr pFocusAnnot(m_pFocusAnnot.Get());
-    m_pFocusAnnot.Reset();
+  if (!m_pFocusAnnot)
+    return false;
+
+  CPDFSDK_AnnotHandlerMgr* pAnnotHandler = GetAnnotHandlerMgr();
+  CPDFSDK_Annot::ObservedPtr pFocusAnnot(m_pFocusAnnot.Get());
+  m_pFocusAnnot.Reset();
 
 #ifdef PDF_ENABLE_XFA
-    CPDFSDK_Annot::ObservedPtr pNull;
-    if (!pAnnotHandler->Annot_OnChangeFocus(&pNull, &pFocusAnnot))
-      return false;
+  CPDFSDK_Annot::ObservedPtr pNull;
+  if (!pAnnotHandler->Annot_OnChangeFocus(&pNull, &pFocusAnnot))
+    return false;
 #endif  // PDF_ENABLE_XFA
 
-    if (pAnnotHandler->Annot_OnKillFocus(&pFocusAnnot, nFlag)) {
-      if (pFocusAnnot->GetAnnotSubtype() == CPDF_Annot::Subtype::WIDGET) {
-        CPDFSDK_Widget* pWidget =
-            static_cast<CPDFSDK_Widget*>(pFocusAnnot.Get());
-        int nFieldType = pWidget->GetFieldType();
-        if (FIELDTYPE_TEXTFIELD == nFieldType ||
-            FIELDTYPE_COMBOBOX == nFieldType) {
-          OnSetFieldInputFocus(nullptr, 0, false);
-        }
-      }
-      if (!m_pFocusAnnot)
-        return true;
-    } else {
-      m_pFocusAnnot.Reset(pFocusAnnot.Get());
+  if (!pAnnotHandler->Annot_OnKillFocus(&pFocusAnnot, nFlag)) {
+    m_pFocusAnnot.Reset(pFocusAnnot.Get());
+    return false;
+  }
+
+  if (pFocusAnnot->GetAnnotSubtype() == CPDF_Annot::Subtype::WIDGET) {
+    CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pFocusAnnot.Get());
+    FormFieldType fieldType = pWidget->GetFieldType();
+    if (fieldType == FormFieldType::kTextField ||
+        fieldType == FormFieldType::kComboBox) {
+      OnSetFieldInputFocus(nullptr, 0, false);
     }
   }
-  return false;
+  return !m_pFocusAnnot;
 }
 
-bool CPDFSDK_FormFillEnvironment::GetPermissions(int nFlag) {
+bool CPDFSDK_FormFillEnvironment::GetPermissions(int nFlag) const {
   return !!(GetPDFDocument()->GetUserPermissions() & nFlag);
 }
diff --git a/fpdfsdk/cpdfsdk_formfillenvironment.h b/fpdfsdk/cpdfsdk_formfillenvironment.h
index eead873..31a1c51 100644
--- a/fpdfsdk/cpdfsdk_formfillenvironment.h
+++ b/fpdfsdk/cpdfsdk_formfillenvironment.h
@@ -14,7 +14,7 @@
 #include "core/fpdfapi/page/cpdf_page.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fpdfdoc/cpdf_occontext.h"
-#include "core/fxcrt/cfx_observable.h"
+#include "core/fxcrt/observable.h"
 #include "fpdfsdk/cfx_systemhandler.h"
 #include "fpdfsdk/cpdfsdk_annot.h"
 #include "fpdfsdk/fsdk_define.h"
@@ -29,13 +29,34 @@
 class CPDFSDK_PageView;
 class IJS_Runtime;
 
+// The CPDFSDK_FormFillEnvironment is "owned" by the embedder across the
+// C API as a FPDF_FormHandle, and may pop out of existence at any time,
+// so long as the associated embedder-owned FPDF_Document outlives it.
+// Pointers from objects in the FPDF_Document ownership hierarchy should
+// be ObservedPtr<> so as to clear themselves when the embedder "exits"
+// the form fill environment.  Pointers from objects in this ownership
+// heirarcy to objects in the FPDF_Document ownership hierarcy should be
+// UnownedPtr<>, as should pointers from objects in this ownership
+// hierarcy back to the form fill environment itself, so as to flag any
+// lingering lifetime issues via the memory tools.
+
 class CPDFSDK_FormFillEnvironment
-    : public CFX_Observable<CPDFSDK_FormFillEnvironment> {
+    : public Observable<CPDFSDK_FormFillEnvironment> {
  public:
   CPDFSDK_FormFillEnvironment(UnderlyingDocumentType* pDoc,
                               FPDF_FORMFILLINFO* pFFinfo);
   ~CPDFSDK_FormFillEnvironment();
 
+  static bool IsSHIFTKeyDown(uint32_t nFlag) {
+    return !!(nFlag & FWL_EVENTFLAG_ShiftKey);
+  }
+  static bool IsCTRLKeyDown(uint32_t nFlag) {
+    return !!(nFlag & FWL_EVENTFLAG_ControlKey);
+  }
+  static bool IsALTKeyDown(uint32_t nFlag) {
+    return !!(nFlag & FWL_EVENTFLAG_AltKey);
+  }
+
   CPDFSDK_PageView* GetPageView(UnderlyingPageType* pPage, bool renew);
   CPDFSDK_PageView* GetPageView(int nIndex);
   CPDFSDK_PageView* GetCurrentView();
@@ -56,20 +77,18 @@
                     const CPDF_Document* pSrcDoc,
                     const std::vector<uint16_t>& arrSrcPages);
 
-  int GetPageCount() { return m_pUnderlyingDoc->GetPageCount(); }
-  bool GetPermissions(int nFlag);
+  int GetPageCount() const { return m_pUnderlyingDoc->GetPageCount(); }
+  bool GetPermissions(int nFlag) const;
 
   bool GetChangeMark() const { return m_bChangeMask; }
   void SetChangeMark() { m_bChangeMask = true; }
   void ClearChangeMark() { m_bChangeMask = false; }
 
-  UnderlyingPageType* GetPage(int nIndex);
-
   void ProcJavascriptFun();
   bool ProcOpenAction();
 
-  void Invalidate(FPDF_PAGE page, const FX_RECT& rect);
-  void OutputSelectedRect(FPDF_PAGE page, const CFX_FloatRect& rect);
+  void Invalidate(UnderlyingPageType* page, const FX_RECT& rect);
+  void OutputSelectedRect(UnderlyingPageType* page, const CFX_FloatRect& rect);
 
   void SetCursor(int nCursorType);
   int SetTimer(int uElapse, TimerCallback lpTimerFunc);
@@ -77,25 +96,21 @@
   FX_SYSTEMTIME GetLocalTime() const;
 
   void OnChange();
-  bool IsSHIFTKeyDown(uint32_t nFlag) const;
-  bool IsCTRLKeyDown(uint32_t nFlag) const;
-  bool IsALTKeyDown(uint32_t nFlag) const;
 
-  FPDF_PAGE GetPage(FPDF_DOCUMENT document, int nPageIndex);
-  FPDF_PAGE GetCurrentPage(FPDF_DOCUMENT document);
+  FPDF_PAGE GetCurrentPage(UnderlyingDocumentType* document);
 
-  void ExecuteNamedAction(const FX_CHAR* namedAction);
+  void ExecuteNamedAction(const char* namedAction);
   void OnSetFieldInputFocus(FPDF_WIDESTRING focusText,
                             FPDF_DWORD nTextLen,
                             bool bFocus);
-  void DoURIAction(const FX_CHAR* bsURI);
+  void DoURIAction(const char* bsURI);
   void DoGoToAction(int nPageIndex,
                     int zoomMode,
                     float* fPosArray,
                     int sizeOfArray);
 
   UnderlyingDocumentType* GetUnderlyingDocument() const {
-    return m_pUnderlyingDoc;
+    return m_pUnderlyingDoc.Get();
   }
 
 #ifdef PDF_ENABLE_XFA
@@ -103,27 +118,27 @@
     return m_pUnderlyingDoc ? m_pUnderlyingDoc->GetPDFDoc() : nullptr;
   }
 
-  CPDFXFA_Context* GetXFAContext() const { return m_pUnderlyingDoc; }
+  CPDFXFA_Context* GetXFAContext() const { return m_pUnderlyingDoc.Get(); }
   void ResetXFADocument() { m_pUnderlyingDoc = nullptr; }
 
   int GetPageViewCount() const { return m_PageMap.size(); }
 
-  void DisplayCaret(FPDF_PAGE page,
+  void DisplayCaret(CPDFXFA_Page* page,
                     FPDF_BOOL bVisible,
                     double left,
                     double top,
                     double right,
                     double bottom);
-  int GetCurrentPageIndex(FPDF_DOCUMENT document);
-  void SetCurrentPage(FPDF_DOCUMENT document, int iCurPage);
+  int GetCurrentPageIndex(CPDFXFA_Context* document);
+  void SetCurrentPage(CPDFXFA_Context* document, int iCurPage);
 
   // TODO(dsinclair): This should probably change to PDFium?
-  CFX_WideString FFI_GetAppName() const { return CFX_WideString(L"Acrobat"); }
+  WideString FFI_GetAppName() const { return WideString(L"Acrobat"); }
 
-  CFX_WideString GetPlatform();
-  void GotoURL(FPDF_DOCUMENT document, const CFX_WideStringC& wsURL);
-  void GetPageViewRect(FPDF_PAGE page, FS_RECTF& dstRect);
-  bool PopupMenu(FPDF_PAGE page,
+  WideString GetPlatform();
+  void GotoURL(CPDFXFA_Context* document, const WideStringView& wsURL);
+  void GetPageViewRect(CPDFXFA_Page* page, FS_RECTF& dstRect);
+  bool PopupMenu(CPDFXFA_Page* page,
                  FPDF_WIDGET hWidget,
                  int menuFlag,
                  CFX_PointF pt);
@@ -141,45 +156,45 @@
   FPDF_FILEHANDLER* OpenFile(int fileType,
                              FPDF_WIDESTRING wsURL,
                              const char* mode);
-  CFX_RetainPtr<IFX_SeekableReadStream> DownloadFromURL(const FX_WCHAR* url);
-  CFX_WideString PostRequestURL(const FX_WCHAR* wsURL,
-                                const FX_WCHAR* wsData,
-                                const FX_WCHAR* wsContentType,
-                                const FX_WCHAR* wsEncode,
-                                const FX_WCHAR* wsHeader);
-  FPDF_BOOL PutRequestURL(const FX_WCHAR* wsURL,
-                          const FX_WCHAR* wsData,
-                          const FX_WCHAR* wsEncode);
-  CFX_WideString GetLanguage();
+  RetainPtr<IFX_SeekableReadStream> DownloadFromURL(const wchar_t* url);
+  WideString PostRequestURL(const wchar_t* wsURL,
+                            const wchar_t* wsData,
+                            const wchar_t* wsContentType,
+                            const wchar_t* wsEncode,
+                            const wchar_t* wsHeader);
+  FPDF_BOOL PutRequestURL(const wchar_t* wsURL,
+                          const wchar_t* wsData,
+                          const wchar_t* wsEncode);
+  WideString GetLanguage();
 
   void PageEvent(int iPageCount, uint32_t dwEventType) const;
 #else   // PDF_ENABLE_XFA
-  CPDF_Document* GetPDFDocument() const { return m_pUnderlyingDoc; }
+  CPDF_Document* GetPDFDocument() const { return m_pUnderlyingDoc.Get(); }
 #endif  // PDF_ENABLE_XFA
 
-  int JS_appAlert(const FX_WCHAR* Msg,
-                  const FX_WCHAR* Title,
+  int JS_appAlert(const wchar_t* Msg,
+                  const wchar_t* Title,
                   uint32_t Type,
                   uint32_t Icon);
-  int JS_appResponse(const FX_WCHAR* Question,
-                     const FX_WCHAR* Title,
-                     const FX_WCHAR* Default,
-                     const FX_WCHAR* cLabel,
+  int JS_appResponse(const wchar_t* Question,
+                     const wchar_t* Title,
+                     const wchar_t* Default,
+                     const wchar_t* cLabel,
                      FPDF_BOOL bPassword,
                      void* response,
                      int length);
   void JS_appBeep(int nType);
-  CFX_WideString JS_fieldBrowse();
-  CFX_WideString JS_docGetFilePath();
-  void JS_docSubmitForm(void* formData, int length, const FX_WCHAR* URL);
+  WideString JS_fieldBrowse();
+  WideString JS_docGetFilePath();
+  void JS_docSubmitForm(void* formData, int length, const wchar_t* URL);
   void JS_docmailForm(void* mailData,
                       int length,
                       FPDF_BOOL bUI,
-                      const FX_WCHAR* To,
-                      const FX_WCHAR* Subject,
-                      const FX_WCHAR* CC,
-                      const FX_WCHAR* BCC,
-                      const FX_WCHAR* Msg);
+                      const wchar_t* To,
+                      const wchar_t* Subject,
+                      const wchar_t* CC,
+                      const wchar_t* BCC,
+                      const wchar_t* Msg);
   void JS_docprint(FPDF_BOOL bUI,
                    int nStart,
                    int nEnd,
@@ -191,7 +206,7 @@
   void JS_docgotoPage(int nPageNum);
 
   bool IsJSInitiated() const { return m_pInfo && m_pInfo->m_pJsPlatform; }
-  CFX_ByteString GetAppName() const { return ""; }
+  ByteString GetAppName() const { return ""; }
   CFX_SystemHandler* GetSysHandler() const { return m_pSysHandler.get(); }
   FPDF_FORMFILLINFO* GetFormFillInfo() const { return m_pInfo; }
 
@@ -199,18 +214,20 @@
   CFFL_InteractiveFormFiller* GetInteractiveFormFiller();
   CPDFSDK_AnnotHandlerMgr* GetAnnotHandlerMgr();  // Creates if not present.
   IJS_Runtime* GetJSRuntime();                    // Creates if not present.
-  CPDFSDK_ActionHandler* GetActionHander();       // Creates if not present.
+  CPDFSDK_ActionHandler* GetActionHandler();      // Creates if not present.
   CPDFSDK_InterForm* GetInterForm();              // Creates if not present.
 
  private:
+  UnderlyingPageType* GetPage(int nIndex);
+
+  FPDF_FORMFILLINFO* const m_pInfo;
   std::unique_ptr<CPDFSDK_AnnotHandlerMgr> m_pAnnotHandlerMgr;
   std::unique_ptr<CPDFSDK_ActionHandler> m_pActionHandler;
   std::unique_ptr<IJS_Runtime> m_pJSRuntime;
-  FPDF_FORMFILLINFO* const m_pInfo;
   std::map<UnderlyingPageType*, std::unique_ptr<CPDFSDK_PageView>> m_PageMap;
   std::unique_ptr<CPDFSDK_InterForm> m_pInterForm;
   CPDFSDK_Annot::ObservedPtr m_pFocusAnnot;
-  UnderlyingDocumentType* m_pUnderlyingDoc;
+  UnownedPtr<UnderlyingDocumentType> m_pUnderlyingDoc;
   std::unique_ptr<CFFL_InteractiveFormFiller> m_pFormFiller;
   std::unique_ptr<CFX_SystemHandler> m_pSysHandler;
   bool m_bChangeMask;
diff --git a/fpdfsdk/cpdfsdk_interform.cpp b/fpdfsdk/cpdfsdk_interform.cpp
index 4ebcf8a..e19d47b 100644
--- a/fpdfsdk/cpdfsdk_interform.cpp
+++ b/fpdfsdk/cpdfsdk_interform.cpp
@@ -8,6 +8,8 @@
 
 #include <algorithm>
 #include <memory>
+#include <sstream>
+#include <string>
 #include <vector>
 
 #include "core/fpdfapi/page/cpdf_page.h"
@@ -19,7 +21,6 @@
 #include "core/fpdfdoc/cpdf_interform.h"
 #include "core/fxge/cfx_graphstatedata.h"
 #include "core/fxge/cfx_pathdata.h"
-#include "core/fxge/cfx_renderdevice.h"
 #include "fpdfsdk/cba_annotiterator.h"
 #include "fpdfsdk/cpdfsdk_annot.h"
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
@@ -28,11 +29,9 @@
 #include "fpdfsdk/formfiller/cffl_formfiller.h"
 #include "fpdfsdk/fsdk_actionhandler.h"
 #include "fpdfsdk/fsdk_define.h"
-#include "fpdfsdk/fxedit/fxet_edit.h"
 #include "fpdfsdk/ipdfsdk_annothandler.h"
-#include "fpdfsdk/javascript/ijs_event_context.h"
-#include "fpdfsdk/javascript/ijs_runtime.h"
-#include "fpdfsdk/pdfwindow/PWL_Utils.h"
+#include "fxjs/ijs_event_context.h"
+#include "fxjs/ijs_runtime.h"
 #include "third_party/base/stl_util.h"
 
 #ifdef PDF_ENABLE_XFA
@@ -40,24 +39,56 @@
 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
 #include "fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h"
 #include "xfa/fxfa/cxfa_eventparam.h"
-#include "xfa/fxfa/xfa_ffdocview.h"
-#include "xfa/fxfa/xfa_ffwidget.h"
-#include "xfa/fxfa/xfa_ffwidgethandler.h"
+#include "xfa/fxfa/cxfa_ffdocview.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
+#include "xfa/fxfa/cxfa_ffwidgethandler.h"
 #endif  // PDF_ENABLE_XFA
 
+namespace {
+
+bool IsFormFieldTypeComboOrText(FormFieldType fieldType) {
+  switch (fieldType) {
+    case FormFieldType::kComboBox:
+    case FormFieldType::kTextField:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#ifdef PDF_ENABLE_XFA
+bool IsFormFieldTypeXFA(FormFieldType fieldType) {
+  switch (fieldType) {
+    case FormFieldType::kXFA:
+    case FormFieldType::kXFA_CheckBox:
+    case FormFieldType::kXFA_ComboBox:
+    case FormFieldType::kXFA_ImageField:
+    case FormFieldType::kXFA_ListBox:
+    case FormFieldType::kXFA_PushButton:
+    case FormFieldType::kXFA_Signature:
+    case FormFieldType::kXFA_TextField:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif  // PDF_ENABLE_XFA
+
+}  // namespace
+
 CPDFSDK_InterForm::CPDFSDK_InterForm(CPDFSDK_FormFillEnvironment* pFormFillEnv)
     : m_pFormFillEnv(pFormFillEnv),
-      m_pInterForm(new CPDF_InterForm(m_pFormFillEnv->GetPDFDocument())),
+      m_pInterForm(
+          pdfium::MakeUnique<CPDF_InterForm>(m_pFormFillEnv->GetPDFDocument())),
 #ifdef PDF_ENABLE_XFA
       m_bXfaCalculate(true),
       m_bXfaValidationsEnabled(true),
 #endif  // PDF_ENABLE_XFA
       m_bCalculate(true),
       m_bBusy(false),
-      m_iHighlightAlpha(0) {
+      m_HighlightAlpha(0) {
   m_pInterForm->SetFormNotify(this);
-  for (int i = 0; i < kNumFieldTypes; ++i)
-    m_bNeedHightlight[i] = false;
+  RemoveAllHighLights();
 }
 
 CPDFSDK_InterForm::~CPDFSDK_InterForm() {
@@ -73,8 +104,8 @@
 
 CPDFSDK_Widget* CPDFSDK_InterForm::GetSibling(CPDFSDK_Widget* pWidget,
                                               bool bNext) const {
-  std::unique_ptr<CBA_AnnotIterator> pIterator(new CBA_AnnotIterator(
-      pWidget->GetPageView(), CPDF_Annot::Subtype::WIDGET));
+  auto pIterator = pdfium::MakeUnique<CBA_AnnotIterator>(
+      pWidget->GetPageView(), CPDF_Annot::Subtype::WIDGET);
 
   if (bNext)
     return static_cast<CPDFSDK_Widget*>(pIterator->GetNextAnnot(pWidget));
@@ -116,7 +147,7 @@
 }
 
 void CPDFSDK_InterForm::GetWidgets(
-    const CFX_WideString& sFieldName,
+    const WideString& sFieldName,
     std::vector<CPDFSDK_Annot::ObservedPtr>* widgets) const {
   for (int i = 0, sz = m_pInterForm->CountFields(sFieldName); i < sz; ++i) {
     CPDF_FormField* pFormField = m_pInterForm->GetField(i, sFieldName);
@@ -237,8 +268,8 @@
     if (!pField)
       continue;
 
-    int nType = pField->GetFieldType();
-    if (nType != FIELDTYPE_COMBOBOX && nType != FIELDTYPE_TEXTFIELD)
+    FormFieldType fieldType = pField->GetFieldType();
+    if (!IsFormFieldTypeComboOrText(fieldType))
       continue;
 
     CPDF_AAction aAction = pField->GetAdditionalAction();
@@ -249,17 +280,17 @@
     if (!action.GetDict())
       continue;
 
-    CFX_WideString csJS = action.GetJavaScript();
+    WideString csJS = action.GetJavaScript();
     if (csJS.IsEmpty())
       continue;
 
     IJS_EventContext* pContext = pRuntime->NewEventContext();
-    CFX_WideString sOldValue = pField->GetValue();
-    CFX_WideString sValue = sOldValue;
+    WideString sOldValue = pField->GetValue();
+    WideString sValue = sOldValue;
     bool bRC = true;
     pContext->OnField_Calculate(pFormField, pField, sValue, bRC);
 
-    CFX_WideString sInfo;
+    WideString sInfo;
     bool bRet = pContext->RunScript(csJS, &sInfo);
     pRuntime->ReleaseEventContext(pContext);
     if (bRet && bRC && sValue.Compare(sOldValue) != 0)
@@ -268,16 +299,16 @@
   m_bBusy = false;
 }
 
-CFX_WideString CPDFSDK_InterForm::OnFormat(CPDF_FormField* pFormField,
-                                           bool& bFormatted) {
-  CFX_WideString sValue = pFormField->GetValue();
+WideString CPDFSDK_InterForm::OnFormat(CPDF_FormField* pFormField,
+                                       bool& bFormatted) {
+  WideString sValue = pFormField->GetValue();
   if (!m_pFormFillEnv->IsJSInitiated()) {
     bFormatted = false;
     return sValue;
   }
 
   IJS_Runtime* pRuntime = m_pFormFillEnv->GetJSRuntime();
-  if (pFormField->GetFieldType() == FIELDTYPE_COMBOBOX &&
+  if (pFormField->GetFieldType() == FormFieldType::kComboBox &&
       pFormField->CountSelectedItems() > 0) {
     int index = pFormField->GetSelectedIndex(0);
     if (index >= 0)
@@ -290,13 +321,13 @@
   if (aAction.GetDict() && aAction.ActionExist(CPDF_AAction::Format)) {
     CPDF_Action action = aAction.GetAction(CPDF_AAction::Format);
     if (action.GetDict()) {
-      CFX_WideString script = action.GetJavaScript();
+      WideString script = action.GetJavaScript();
       if (!script.IsEmpty()) {
-        CFX_WideString Value = sValue;
+        WideString Value = sValue;
 
         IJS_EventContext* pContext = pRuntime->NewEventContext();
         pContext->OnField_Format(pFormField, Value, true);
-        CFX_WideString sInfo;
+        WideString sInfo;
         bool bRet = pContext->RunScript(script, &sInfo);
         pRuntime->ReleaseEventContext(pContext);
         if (bRet) {
@@ -310,7 +341,7 @@
 }
 
 void CPDFSDK_InterForm::ResetFieldAppearance(CPDF_FormField* pFormField,
-                                             const CFX_WideString* sValue,
+                                             const WideString* sValue,
                                              bool bValueChanged) {
   for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
     CPDF_FormControl* pFormCtrl = pFormField->GetControl(i);
@@ -321,22 +352,24 @@
 }
 
 void CPDFSDK_InterForm::UpdateField(CPDF_FormField* pFormField) {
-  auto formfiller = m_pFormFillEnv->GetInteractiveFormFiller();
+  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();
-      m_pFormFillEnv->Invalidate(
-          pPage, formfiller->GetViewBBox(
-                     m_pFormFillEnv->GetPageView(pPage, false), pWidget));
-    }
+    CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl);
+    if (!pWidget)
+      continue;
+
+    UnderlyingPageType* pPage = pWidget->GetUnderlyingPage();
+    FX_RECT rect = formfiller->GetViewBBox(
+        m_pFormFillEnv->GetPageView(pPage, false), pWidget);
+    m_pFormFillEnv->Invalidate(pPage, rect);
   }
 }
 
 bool CPDFSDK_InterForm::OnKeyStrokeCommit(CPDF_FormField* pFormField,
-                                          const CFX_WideString& csValue) {
+                                          const WideString& csValue) {
   CPDF_AAction aAction = pFormField->GetAdditionalAction();
   if (!aAction.GetDict() || !aAction.ActionExist(CPDF_AAction::KeyStroke))
     return true;
@@ -345,18 +378,18 @@
   if (!action.GetDict())
     return true;
 
-  CPDFSDK_ActionHandler* pActionHandler = m_pFormFillEnv->GetActionHander();
+  CPDFSDK_ActionHandler* pActionHandler = m_pFormFillEnv->GetActionHandler();
   PDFSDK_FieldAction fa;
-  fa.bModifier = m_pFormFillEnv->IsCTRLKeyDown(0);
-  fa.bShift = m_pFormFillEnv->IsSHIFTKeyDown(0);
+  fa.bModifier = false;
+  fa.bShift = false;
   fa.sValue = csValue;
-  pActionHandler->DoAction_FieldJavaScript(action, CPDF_AAction::KeyStroke,
-                                           m_pFormFillEnv, pFormField, fa);
+  pActionHandler->DoAction_FieldJavaScript(
+      action, CPDF_AAction::KeyStroke, m_pFormFillEnv.Get(), pFormField, fa);
   return fa.bRC;
 }
 
 bool CPDFSDK_InterForm::OnValidate(CPDF_FormField* pFormField,
-                                   const CFX_WideString& csValue) {
+                                   const WideString& csValue) {
   CPDF_AAction aAction = pFormField->GetAdditionalAction();
   if (!aAction.GetDict() || !aAction.ActionExist(CPDF_AAction::Validate))
     return true;
@@ -365,13 +398,13 @@
   if (!action.GetDict())
     return true;
 
-  CPDFSDK_ActionHandler* pActionHandler = m_pFormFillEnv->GetActionHander();
+  CPDFSDK_ActionHandler* pActionHandler = m_pFormFillEnv->GetActionHandler();
   PDFSDK_FieldAction fa;
-  fa.bModifier = m_pFormFillEnv->IsCTRLKeyDown(0);
-  fa.bShift = m_pFormFillEnv->IsSHIFTKeyDown(0);
+  fa.bModifier = false;
+  fa.bShift = false;
   fa.sValue = csValue;
-  pActionHandler->DoAction_FieldJavaScript(action, CPDF_AAction::Validate,
-                                           m_pFormFillEnv, pFormField, fa);
+  pActionHandler->DoAction_FieldJavaScript(
+      action, CPDF_AAction::Validate, m_pFormFillEnv.Get(), pFormField, fa);
   return fa.bRC;
 }
 
@@ -409,7 +442,7 @@
 }
 
 bool CPDFSDK_InterForm::DoAction_SubmitForm(const CPDF_Action& action) {
-  CFX_WideString sDestination = action.GetFilePath();
+  WideString sDestination = action.GetFilePath();
   if (sDestination.IsEmpty())
     return false;
 
@@ -433,30 +466,36 @@
   return SubmitForm(sDestination, false);
 }
 
-bool CPDFSDK_InterForm::SubmitFields(const CFX_WideString& csDestination,
+bool CPDFSDK_InterForm::SubmitFields(const WideString& csDestination,
                                      const std::vector<CPDF_FormField*>& fields,
                                      bool bIncludeOrExclude,
                                      bool bUrlEncoded) {
-  CFX_ByteTextBuf textBuf;
-  ExportFieldsToFDFTextBuf(fields, bIncludeOrExclude, textBuf);
+  ByteString textBuf = ExportFieldsToFDFTextBuf(fields, bIncludeOrExclude);
 
-  uint8_t* pBuffer = textBuf.GetBuffer();
-  FX_STRSIZE nBufSize = textBuf.GetLength();
-
-  if (bUrlEncoded && !FDFToURLEncodedData(pBuffer, nBufSize))
+  size_t nBufSize = textBuf.GetLength();
+  if (nBufSize == 0)
     return false;
 
+  uint8_t* pLocalBuffer = FX_Alloc(uint8_t, nBufSize);
+  memcpy(pLocalBuffer, textBuf.c_str(), nBufSize);
+  uint8_t* pBuffer = pLocalBuffer;
+
+  if (bUrlEncoded && !FDFToURLEncodedData(pBuffer, nBufSize)) {
+    FX_Free(pLocalBuffer);
+    return false;
+  }
+
   m_pFormFillEnv->JS_docSubmitForm(pBuffer, nBufSize, csDestination.c_str());
+
+  if (pBuffer != pLocalBuffer)
+    FX_Free(pBuffer);
+
+  FX_Free(pLocalBuffer);
+
   return true;
 }
 
-bool CPDFSDK_InterForm::FDFToURLEncodedData(CFX_WideString csFDFFile,
-                                            CFX_WideString csTxtFile) {
-  return true;
-}
-
-bool CPDFSDK_InterForm::FDFToURLEncodedData(uint8_t*& pBuf,
-                                            FX_STRSIZE& nBufSize) {
+bool CPDFSDK_InterForm::FDFToURLEncodedData(uint8_t*& pBuf, size_t& nBufSize) {
   std::unique_ptr<CFDF_Document> pFDF =
       CFDF_Document::ParseMemory(pBuf, nBufSize);
   if (!pFDF)
@@ -470,49 +509,46 @@
   if (!pFields)
     return false;
 
-  CFX_ByteTextBuf fdfEncodedData;
+  std::ostringstream fdfEncodedData;
   for (uint32_t i = 0; i < pFields->GetCount(); i++) {
     CPDF_Dictionary* pField = pFields->GetDictAt(i);
     if (!pField)
       continue;
-    CFX_WideString name;
+    WideString name;
     name = pField->GetUnicodeTextFor("T");
-    CFX_ByteString name_b = CFX_ByteString::FromUnicode(name);
-    CFX_ByteString csBValue = pField->GetStringFor("V");
-    CFX_WideString csWValue = PDF_DecodeText(csBValue);
-    CFX_ByteString csValue_b = CFX_ByteString::FromUnicode(csWValue);
+    ByteString name_b = ByteString::FromUnicode(name);
+    ByteString csBValue = pField->GetStringFor("V");
+    WideString csWValue = PDF_DecodeText(csBValue);
+    ByteString csValue_b = ByteString::FromUnicode(csWValue);
 
     fdfEncodedData << name_b.GetBuffer(name_b.GetLength());
-    name_b.ReleaseBuffer();
+    name_b.ReleaseBuffer(name_b.GetStringLength());
     fdfEncodedData << "=";
     fdfEncodedData << csValue_b.GetBuffer(csValue_b.GetLength());
-    csValue_b.ReleaseBuffer();
+    csValue_b.ReleaseBuffer(csValue_b.GetStringLength());
     if (i != pFields->GetCount() - 1)
       fdfEncodedData << "&";
   }
 
-  nBufSize = fdfEncodedData.GetLength();
+  nBufSize = fdfEncodedData.tellp();
+  if (nBufSize == 0)
+    return false;
+
   pBuf = FX_Alloc(uint8_t, nBufSize);
-  FXSYS_memcpy(pBuf, fdfEncodedData.GetBuffer(), nBufSize);
+  memcpy(pBuf, fdfEncodedData.str().c_str(), nBufSize);
   return true;
 }
 
-bool CPDFSDK_InterForm::ExportFieldsToFDFTextBuf(
+ByteString CPDFSDK_InterForm::ExportFieldsToFDFTextBuf(
     const std::vector<CPDF_FormField*>& fields,
-    bool bIncludeOrExclude,
-    CFX_ByteTextBuf& textBuf) {
-  std::unique_ptr<CFDF_Document> pFDF =
-      m_pInterForm->ExportToFDF(m_pFormFillEnv->JS_docGetFilePath().AsStringC(),
-                                fields, bIncludeOrExclude, false);
-  return pFDF ? pFDF->WriteBuf(textBuf) : false;
+    bool bIncludeOrExclude) {
+  std::unique_ptr<CFDF_Document> pFDF = m_pInterForm->ExportToFDF(
+      m_pFormFillEnv->JS_docGetFilePath(), fields, bIncludeOrExclude, false);
+
+  return pFDF ? pFDF->WriteToString() : ByteString();
 }
 
-CFX_WideString CPDFSDK_InterForm::GetTemporaryFileName(
-    const CFX_WideString& sFileExt) {
-  return L"";
-}
-
-bool CPDFSDK_InterForm::SubmitForm(const CFX_WideString& sDestination,
+bool CPDFSDK_InterForm::SubmitForm(const WideString& sDestination,
                                    bool bUrlEncoded) {
   if (sDestination.IsEmpty())
     return false;
@@ -520,31 +556,41 @@
   if (!m_pFormFillEnv || !m_pInterForm)
     return false;
 
-  std::unique_ptr<CFDF_Document> pFDFDoc = m_pInterForm->ExportToFDF(
-      m_pFormFillEnv->JS_docGetFilePath().AsStringC(), false);
+  std::unique_ptr<CFDF_Document> pFDFDoc =
+      m_pInterForm->ExportToFDF(m_pFormFillEnv->JS_docGetFilePath(), false);
   if (!pFDFDoc)
     return false;
 
-  CFX_ByteTextBuf FdfBuffer;
-  if (!pFDFDoc->WriteBuf(FdfBuffer))
+  ByteString fdfBuffer = pFDFDoc->WriteToString();
+
+  if (fdfBuffer.IsEmpty())
     return false;
 
-  uint8_t* pBuffer = FdfBuffer.GetBuffer();
-  FX_STRSIZE nBufSize = FdfBuffer.GetLength();
-  if (bUrlEncoded && !FDFToURLEncodedData(pBuffer, nBufSize))
+  uint8_t* pLocalBuffer = FX_Alloc(uint8_t, fdfBuffer.GetLength());
+  memcpy(pLocalBuffer, fdfBuffer.c_str(), fdfBuffer.GetLength());
+  uint8_t* pBuffer = pLocalBuffer;
+
+  size_t nBufSize = fdfBuffer.GetLength();
+  if (bUrlEncoded && !FDFToURLEncodedData(pBuffer, nBufSize)) {
+    FX_Free(pLocalBuffer);
     return false;
+  }
 
   m_pFormFillEnv->JS_docSubmitForm(pBuffer, nBufSize, sDestination.c_str());
-  if (bUrlEncoded)
+
+  if (pBuffer != pLocalBuffer)
     FX_Free(pBuffer);
 
+  FX_Free(pLocalBuffer);
+
   return true;
 }
 
-bool CPDFSDK_InterForm::ExportFormToFDFTextBuf(CFX_ByteTextBuf& textBuf) {
-  std::unique_ptr<CFDF_Document> pFDF = m_pInterForm->ExportToFDF(
-      m_pFormFillEnv->JS_docGetFilePath().AsStringC(), false);
-  return pFDF && pFDF->WriteBuf(textBuf);
+ByteString CPDFSDK_InterForm::ExportFormToFDFTextBuf() {
+  std::unique_ptr<CFDF_Document> pFDF =
+      m_pInterForm->ExportToFDF(m_pFormFillEnv->JS_docGetFilePath(), false);
+
+  return pFDF ? pFDF->WriteToString() : ByteString();
 }
 
 bool CPDFSDK_InterForm::DoAction_ResetForm(const CPDF_Action& action) {
@@ -571,7 +617,7 @@
   std::vector<CPDF_FormField*> fields;
   for (CPDF_Object* pObject : objects) {
     if (pObject && pObject->IsString()) {
-      CFX_WideString csName = pObject->GetUnicodeText();
+      WideString csName = pObject->GetUnicodeText();
       CPDF_FormField* pField = m_pInterForm->GetField(0, csName);
       if (pField)
         fields.push_back(pField);
@@ -581,9 +627,9 @@
 }
 
 int CPDFSDK_InterForm::BeforeValueChange(CPDF_FormField* pField,
-                                         const CFX_WideString& csValue) {
-  int nType = pField->GetFieldType();
-  if (nType != FIELDTYPE_COMBOBOX && nType != FIELDTYPE_TEXTFIELD)
+                                         const WideString& csValue) {
+  FormFieldType fieldType = pField->GetFieldType();
+  if (!IsFormFieldTypeComboOrText(fieldType))
     return 0;
 
   if (!OnKeyStrokeCommit(pField, csValue))
@@ -599,19 +645,19 @@
 #ifdef PDF_ENABLE_XFA
   SynchronizeField(pField, false);
 #endif  // PDF_ENABLE_XFA
-  int nType = pField->GetFieldType();
-  if (nType == FIELDTYPE_COMBOBOX || nType == FIELDTYPE_TEXTFIELD) {
+  FormFieldType fieldType = pField->GetFieldType();
+  if (IsFormFieldTypeComboOrText(fieldType)) {
     OnCalculate(pField);
     bool bFormatted = false;
-    CFX_WideString sValue = OnFormat(pField, bFormatted);
+    WideString sValue = OnFormat(pField, bFormatted);
     ResetFieldAppearance(pField, bFormatted ? &sValue : nullptr, true);
     UpdateField(pField);
   }
 }
 
 int CPDFSDK_InterForm::BeforeSelectionChange(CPDF_FormField* pField,
-                                             const CFX_WideString& csValue) {
-  if (pField->GetFieldType() != FIELDTYPE_LISTBOX)
+                                             const WideString& csValue) {
+  if (pField->GetFieldType() != FormFieldType::kListBox)
     return 0;
 
   if (!OnKeyStrokeCommit(pField, csValue))
@@ -624,7 +670,7 @@
 }
 
 void CPDFSDK_InterForm::AfterSelectionChange(CPDF_FormField* pField) {
-  if (pField->GetFieldType() != FIELDTYPE_LISTBOX)
+  if (pField->GetFieldType() != FormFieldType::kListBox)
     return;
 
   OnCalculate(pField);
@@ -633,8 +679,9 @@
 }
 
 void CPDFSDK_InterForm::AfterCheckedStatusChange(CPDF_FormField* pField) {
-  int nType = pField->GetFieldType();
-  if (nType != FIELDTYPE_CHECKBOX && nType != FIELDTYPE_RADIOBUTTON)
+  FormFieldType fieldType = pField->GetFieldType();
+  if (fieldType != FormFieldType::kCheckBox &&
+      fieldType != FormFieldType::kRadioButton)
     return;
 
   OnCalculate(pField);
@@ -657,40 +704,56 @@
   OnCalculate(nullptr);
 }
 
-bool CPDFSDK_InterForm::IsNeedHighLight(int nFieldType) {
-  if (nFieldType < 1 || nFieldType > kNumFieldTypes)
+bool CPDFSDK_InterForm::IsNeedHighLight(FormFieldType fieldType) {
+  if (fieldType == FormFieldType::kUnknown)
     return false;
-  return m_bNeedHightlight[nFieldType - 1];
+
+#ifdef PDF_ENABLE_XFA
+  // For the XFA fields, we need to return if the specific field type has
+  // highlight enabled or if the general XFA field type has it enabled.
+  if (IsFormFieldTypeXFA(fieldType)) {
+    if (!m_NeedsHighlight[static_cast<size_t>(fieldType)])
+      return m_NeedsHighlight[static_cast<size_t>(FormFieldType::kXFA)];
+  }
+#endif  // PDF_ENABLE_XFA
+  return m_NeedsHighlight[static_cast<size_t>(fieldType)];
 }
 
-void CPDFSDK_InterForm::RemoveAllHighLight() {
-  for (int i = 0; i < kNumFieldTypes; ++i)
-    m_bNeedHightlight[i] = false;
+void CPDFSDK_InterForm::RemoveAllHighLights() {
+  std::fill(m_HighlightColor, m_HighlightColor + kFormFieldTypeCount,
+            FXSYS_RGB(255, 255, 255));
+  std::fill(m_NeedsHighlight, m_NeedsHighlight + kFormFieldTypeCount, false);
 }
 
-void CPDFSDK_InterForm::SetHighlightColor(FX_COLORREF clr, int nFieldType) {
-  if (nFieldType < 0 || nFieldType > kNumFieldTypes)
+void CPDFSDK_InterForm::SetHighlightColor(FX_COLORREF clr,
+                                          FormFieldType fieldType) {
+  if (fieldType == FormFieldType::kUnknown)
     return;
-  switch (nFieldType) {
-    case 0: {
-      for (int i = 0; i < kNumFieldTypes; ++i) {
-        m_aHighlightColor[i] = clr;
-        m_bNeedHightlight[i] = true;
-      }
-      break;
-    }
-    default: {
-      m_aHighlightColor[nFieldType - 1] = clr;
-      m_bNeedHightlight[nFieldType - 1] = true;
-      break;
-    }
+
+  m_HighlightColor[static_cast<size_t>(fieldType)] = clr;
+  m_NeedsHighlight[static_cast<size_t>(fieldType)] = true;
+}
+
+void CPDFSDK_InterForm::SetAllHighlightColors(FX_COLORREF clr) {
+  for (auto type : kFormFieldTypes) {
+    m_HighlightColor[static_cast<size_t>(type)] = clr;
+    m_NeedsHighlight[static_cast<size_t>(type)] = true;
   }
 }
 
-FX_COLORREF CPDFSDK_InterForm::GetHighlightColor(int nFieldType) {
-  if (nFieldType < 0 || nFieldType > kNumFieldTypes)
+FX_COLORREF CPDFSDK_InterForm::GetHighlightColor(FormFieldType fieldType) {
+  if (fieldType == FormFieldType::kUnknown)
     return FXSYS_RGB(255, 255, 255);
-  if (nFieldType == 0)
-    return m_aHighlightColor[0];
-  return m_aHighlightColor[nFieldType - 1];
+
+#ifdef PDF_ENABLE_XFA
+  // For the XFA fields, we need to return the specific field type highlight
+  // colour or the general XFA field type colour if present.
+  if (IsFormFieldTypeXFA(fieldType)) {
+    if (!m_NeedsHighlight[static_cast<size_t>(fieldType)] &&
+        m_NeedsHighlight[static_cast<size_t>(FormFieldType::kXFA)]) {
+      return m_HighlightColor[static_cast<size_t>(FormFieldType::kXFA)];
+    }
+  }
+#endif  // PDF_ENABLE_XFA
+  return m_HighlightColor[static_cast<size_t>(fieldType)];
 }
diff --git a/fpdfsdk/cpdfsdk_interform.h b/fpdfsdk/cpdfsdk_interform.h
index 032399c..ee960ff 100644
--- a/fpdfsdk/cpdfsdk_interform.h
+++ b/fpdfsdk/cpdfsdk_interform.h
@@ -13,7 +13,7 @@
 
 #include "core/fpdfdoc/cpdf_action.h"
 #include "core/fpdfdoc/ipdf_formnotify.h"
-#include "core/fxcrt/fx_basic.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "core/fxge/fx_dib.h"
 #include "fpdfsdk/cpdfsdk_widget.h"
 
@@ -35,13 +35,15 @@
   ~CPDFSDK_InterForm() override;
 
   CPDF_InterForm* GetInterForm() const { return m_pInterForm.get(); }
-  CPDFSDK_FormFillEnvironment* GetFormFillEnv() const { return m_pFormFillEnv; }
+  CPDFSDK_FormFillEnvironment* GetFormFillEnv() const {
+    return m_pFormFillEnv.Get();
+  }
 
   bool HighlightWidgets();
 
   CPDFSDK_Widget* GetSibling(CPDFSDK_Widget* pWidget, bool bNext) const;
   CPDFSDK_Widget* GetWidget(CPDF_FormControl* pControl) const;
-  void GetWidgets(const CFX_WideString& sFieldName,
+  void GetWidgets(const WideString& sFieldName,
                   std::vector<CPDFSDK_Annot::ObservedPtr>* widgets) const;
   void GetWidgets(CPDF_FormField* pField,
                   std::vector<CPDFSDK_Annot::ObservedPtr>* widgets) const;
@@ -63,14 +65,13 @@
   void SynchronizeField(CPDF_FormField* pFormField, bool bSynchronizeElse);
 #endif  // PDF_ENABLE_XFA
 
-  bool OnKeyStrokeCommit(CPDF_FormField* pFormField,
-                         const CFX_WideString& csValue);
-  bool OnValidate(CPDF_FormField* pFormField, const CFX_WideString& csValue);
+  bool OnKeyStrokeCommit(CPDF_FormField* pFormField, const WideString& csValue);
+  bool OnValidate(CPDF_FormField* pFormField, const WideString& csValue);
   void OnCalculate(CPDF_FormField* pFormField = nullptr);
-  CFX_WideString OnFormat(CPDF_FormField* pFormField, bool& bFormatted);
+  WideString OnFormat(CPDF_FormField* pFormField, bool& bFormatted);
 
   void ResetFieldAppearance(CPDF_FormField* pFormField,
-                            const CFX_WideString* sValue,
+                            const WideString* sValue,
                             bool bValueChanged);
   void UpdateField(CPDF_FormField* pFormField);
 
@@ -82,31 +83,31 @@
   std::vector<CPDF_FormField*> GetFieldFromObjects(
       const std::vector<CPDF_Object*>& objects) const;
   bool IsValidField(CPDF_Dictionary* pFieldDict);
-  bool SubmitFields(const CFX_WideString& csDestination,
+  bool SubmitFields(const WideString& csDestination,
                     const std::vector<CPDF_FormField*>& fields,
                     bool bIncludeOrExclude,
                     bool bUrlEncoded);
-  bool SubmitForm(const CFX_WideString& sDestination, bool bUrlEncoded);
-  bool ExportFormToFDFTextBuf(CFX_ByteTextBuf& textBuf);
-  bool ExportFieldsToFDFTextBuf(const std::vector<CPDF_FormField*>& fields,
-                                bool bIncludeOrExclude,
-                                CFX_ByteTextBuf& textBuf);
-  CFX_WideString GetTemporaryFileName(const CFX_WideString& sFileExt);
+  bool SubmitForm(const WideString& sDestination, bool bUrlEncoded);
+  ByteString ExportFormToFDFTextBuf();
+  ByteString ExportFieldsToFDFTextBuf(
+      const std::vector<CPDF_FormField*>& fields,
+      bool bIncludeOrExclude);
 
-  bool IsNeedHighLight(int nFieldType);
-  void RemoveAllHighLight();
-  void SetHighlightAlpha(uint8_t alpha) { m_iHighlightAlpha = alpha; }
-  uint8_t GetHighlightAlpha() { return m_iHighlightAlpha; }
-  void SetHighlightColor(FX_COLORREF clr, int nFieldType);
-  FX_COLORREF GetHighlightColor(int nFieldType);
+  bool IsNeedHighLight(FormFieldType fieldType);
+  void RemoveAllHighLights();
+  void SetHighlightAlpha(uint8_t alpha) { m_HighlightAlpha = alpha; }
+  uint8_t GetHighlightAlpha() { return m_HighlightAlpha; }
+  void SetHighlightColor(FX_COLORREF clr, FormFieldType fieldType);
+  void SetAllHighlightColors(FX_COLORREF clr);
+  FX_COLORREF GetHighlightColor(FormFieldType fieldType);
 
  private:
   // IPDF_FormNotify:
   int BeforeValueChange(CPDF_FormField* pField,
-                        const CFX_WideString& csValue) override;
+                        const WideString& csValue) override;
   void AfterValueChange(CPDF_FormField* pField) override;
   int BeforeSelectionChange(CPDF_FormField* pField,
-                            const CFX_WideString& csValue) override;
+                            const WideString& csValue) override;
   void AfterSelectionChange(CPDF_FormField* pField) override;
   void AfterCheckedStatusChange(CPDF_FormField* pField) override;
   int BeforeFormReset(CPDF_InterForm* pForm) override;
@@ -114,30 +115,26 @@
   int BeforeFormImportData(CPDF_InterForm* pForm) override;
   void AfterFormImportData(CPDF_InterForm* pForm) override;
 
-  bool FDFToURLEncodedData(CFX_WideString csFDFFile, CFX_WideString csTxtFile);
-  bool FDFToURLEncodedData(uint8_t*& pBuf, FX_STRSIZE& nBufSize);
+  bool FDFToURLEncodedData(uint8_t*& pBuf, size_t& nBufSize);
   int GetPageIndexByAnnotDict(CPDF_Document* pDocument,
                               CPDF_Dictionary* pAnnotDict) const;
 
   using CPDFSDK_WidgetMap = std::map<CPDF_FormControl*, CPDFSDK_Widget*>;
 
-  CPDFSDK_FormFillEnvironment* m_pFormFillEnv;  // Not owned.
+  UnownedPtr<CPDFSDK_FormFillEnvironment> m_pFormFillEnv;
   std::unique_ptr<CPDF_InterForm> m_pInterForm;
   CPDFSDK_WidgetMap m_Map;
 #ifdef PDF_ENABLE_XFA
   std::map<CXFA_FFWidget*, CPDFSDK_XFAWidget*> m_XFAMap;
   bool m_bXfaCalculate;
   bool m_bXfaValidationsEnabled;
-  static const int kNumFieldTypes = 7;
-#else   // PDF_ENABLE_XFA
-  static const int kNumFieldTypes = 6;
 #endif  // PDF_ENABLE_XFA
   bool m_bCalculate;
   bool m_bBusy;
 
-  FX_COLORREF m_aHighlightColor[kNumFieldTypes];
-  uint8_t m_iHighlightAlpha;
-  bool m_bNeedHightlight[kNumFieldTypes];
+  uint8_t m_HighlightAlpha;
+  FX_COLORREF m_HighlightColor[kFormFieldTypeCount];
+  bool m_NeedsHighlight[kFormFieldTypeCount];
 };
 
 #endif  // FPDFSDK_CPDFSDK_INTERFORM_H_
diff --git a/fpdfsdk/cpdfsdk_pageview.cpp b/fpdfsdk/cpdfsdk_pageview.cpp
index c67948d..c1b5221 100644
--- a/fpdfsdk/cpdfsdk_pageview.cpp
+++ b/fpdfsdk/cpdfsdk_pageview.cpp
@@ -13,8 +13,8 @@
 #include "core/fpdfapi/render/cpdf_renderoptions.h"
 #include "core/fpdfdoc/cpdf_annotlist.h"
 #include "core/fpdfdoc/cpdf_interform.h"
+#include "core/fxcrt/autorestorer.h"
 #include "fpdfsdk/cpdfsdk_annot.h"
-#include "fpdfsdk/cpdfsdk_annothandlermgr.h"
 #include "fpdfsdk/cpdfsdk_annotiteration.h"
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 #include "fpdfsdk/cpdfsdk_interform.h"
@@ -22,11 +22,11 @@
 
 #ifdef PDF_ENABLE_XFA
 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
-#include "xfa/fxfa/xfa_ffdocview.h"
-#include "xfa/fxfa/xfa_ffpageview.h"
-#include "xfa/fxfa/xfa_ffwidgethandler.h"
-#include "xfa/fxfa/xfa_rendercontext.h"
-#include "xfa/fxgraphics/cfx_graphics.h"
+#include "xfa/fxfa/cxfa_ffdocview.h"
+#include "xfa/fxfa/cxfa_ffpageview.h"
+#include "xfa/fxfa/cxfa_ffwidgethandler.h"
+#include "xfa/fxfa/cxfa_rendercontext.h"
+#include "xfa/fxgraphics/cxfa_graphics.h"
 #endif  // PDF_ENABLE_XFA
 
 CPDFSDK_PageView::CPDFSDK_PageView(CPDFSDK_FormFillEnvironment* pFormFillEnv,
@@ -36,23 +36,17 @@
 #ifndef PDF_ENABLE_XFA
       m_bOwnsPage(false),
 #endif  // PDF_ENABLE_XFA
-      m_bEnterWidget(false),
-      m_bExitWidget(false),
       m_bOnWidget(false),
       m_bValid(false),
       m_bLocked(false),
       m_bBeingDestroyed(false) {
   CPDFSDK_InterForm* pInterForm = pFormFillEnv->GetInterForm();
-  if (pInterForm) {
-    CPDF_InterForm* pPDFInterForm = pInterForm->GetInterForm();
+  CPDF_InterForm* pPDFInterForm = pInterForm->GetInterForm();
 #ifdef PDF_ENABLE_XFA
-    if (page->GetPDFPage())
-      pPDFInterForm->FixPageFields(page->GetPDFPage());
+  if (page->GetPDFPage())
+    pPDFInterForm->FixPageFields(page->GetPDFPage());
 #else   // PDF_ENABLE_XFA
-    pPDFInterForm->FixPageFields(page);
-#endif  // PDF_ENABLE_XFA
-  }
-#ifndef PDF_ENABLE_XFA
+  pPDFInterForm->FixPageFields(page);
   m_page->SetView(this);
 #endif  // PDF_ENABLE_XFA
 }
@@ -94,20 +88,18 @@
   if (!pPage)
     return;
 
-  if (pPage->GetContext()->GetDocType() == DOCTYPE_DYNAMIC_XFA) {
-    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()));
+  if (pPage->GetContext()->GetFormType() == FormType::kXFAFull) {
+    CFX_RectF rectClip(
+        static_cast<float>(pClip.left), static_cast<float>(pClip.top),
+        static_cast<float>(pClip.Width()), static_cast<float>(pClip.Height()));
+
+    CXFA_Graphics gs(pDevice);
     gs.SetClipRect(rectClip);
-    std::unique_ptr<CXFA_RenderContext> pRenderContext(new CXFA_RenderContext);
-    CXFA_RenderOptions renderOptions;
-    renderOptions.m_bHighlight = true;
+
     CXFA_FFPageView* xfaView = pPage->GetXFAPageView();
-    pRenderContext->StartRender(xfaView, &gs, *pUser2Device, renderOptions);
-    pRenderContext->DoRender();
-    pRenderContext->StopRender();
+    CXFA_RenderContext renderContext(xfaView, rectClip, *pUser2Device);
+    renderContext.DoRender(&gs);
+
     CXFA_FFDocView* docView = xfaView->GetDocView();
     if (!docView)
       return;
@@ -116,7 +108,7 @@
       return;
     // Render the focus widget
     docView->GetWidgetHandler()->RenderWidget(annot->GetXFAWidget(), &gs,
-                                              pUser2Device, false);
+                                              *pUser2Device, false);
     return;
   }
 #endif  // PDF_ENABLE_XFA
@@ -125,7 +117,8 @@
   CPDFSDK_AnnotIteration annotIteration(this, true);
   for (const auto& pSDKAnnot : annotIteration) {
     m_pFormFillEnv->GetAnnotHandlerMgr()->Annot_OnDraw(
-        this, pSDKAnnot.Get(), pDevice, pUser2Device, pOptions->m_bDrawAnnots);
+        this, pSDKAnnot.Get(), pDevice, pUser2Device,
+        pOptions->GetDrawAnnots());
   }
 }
 
@@ -181,16 +174,21 @@
 bool CPDFSDK_PageView::DeleteAnnot(CPDFSDK_Annot* pAnnot) {
   if (!pAnnot)
     return false;
+
   CPDFXFA_Page* pPage = pAnnot->GetPDFXFAPage();
-  if (!pPage || (pPage->GetContext()->GetDocType() != DOCTYPE_STATIC_XFA &&
-                 pPage->GetContext()->GetDocType() != DOCTYPE_DYNAMIC_XFA))
+  if (!pPage || !pPage->GetContext()->ContainsXFAForm())
     return false;
 
+  CPDFSDK_Annot::ObservedPtr pObserved(pAnnot);
   if (GetFocusAnnot() == pAnnot)
-    m_pFormFillEnv->KillFocusAnnot(0);
-  CPDFSDK_AnnotHandlerMgr* pAnnotHandler = m_pFormFillEnv->GetAnnotHandlerMgr();
-  if (pAnnotHandler)
-    pAnnotHandler->ReleaseAnnot(pAnnot);
+    m_pFormFillEnv->KillFocusAnnot(0);  // May invoke JS, invalidating pAnnot.
+
+  if (pObserved) {
+    CPDFSDK_AnnotHandlerMgr* pAnnotHandler =
+        m_pFormFillEnv->GetAnnotHandlerMgr();
+    if (pAnnotHandler)
+      pAnnotHandler->ReleaseAnnot(pObserved.Get());
+  }
 
   auto it = std::find(m_SDKAnnotArray.begin(), m_SDKAnnotArray.end(), pAnnot);
   if (it != m_SDKAnnotArray.end())
@@ -207,7 +205,7 @@
 #ifdef PDF_ENABLE_XFA
     return m_page->GetContext()->GetPDFDoc();
 #else   // PDF_ENABLE_XFA
-    return m_page->m_pDocument;
+    return m_page->m_pDocument.Get();
 #endif  // PDF_ENABLE_XFA
   }
   return nullptr;
@@ -242,6 +240,35 @@
 }
 #endif  // PDF_ENABLE_XFA
 
+WideString CPDFSDK_PageView::GetSelectedText() {
+  if (CPDFSDK_Annot* pAnnot = GetFocusAnnot()) {
+    CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
+        m_pFormFillEnv->GetAnnotHandlerMgr();
+    return pAnnotHandlerMgr->Annot_GetSelectedText(pAnnot);
+  }
+
+  return WideString();
+}
+
+void CPDFSDK_PageView::ReplaceSelection(const WideString& text) {
+  if (CPDFSDK_Annot* pAnnot = GetFocusAnnot()) {
+    CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
+        m_pFormFillEnv->GetAnnotHandlerMgr();
+    pAnnotHandlerMgr->Annot_ReplaceSelection(pAnnot, text);
+  }
+}
+
+bool CPDFSDK_PageView::OnFocus(const CFX_PointF& point, uint32_t nFlag) {
+  CPDFSDK_Annot::ObservedPtr pAnnot(GetFXWidgetAtPoint(point));
+  if (!pAnnot) {
+    m_pFormFillEnv->KillFocusAnnot(nFlag);
+    return false;
+  }
+
+  m_pFormFillEnv->SetFocusAnnot(&pAnnot);
+  return true;
+}
+
 bool CPDFSDK_PageView::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
   CPDFSDK_Annot::ObservedPtr pAnnot(GetFXWidgetAtPoint(point));
   if (!pAnnot) {
@@ -311,34 +338,48 @@
   CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
       m_pFormFillEnv->GetAnnotHandlerMgr();
   CPDFSDK_Annot::ObservedPtr pFXAnnot(GetFXAnnotAtPoint(point));
+
+  if (m_bOnWidget && m_pCaptureWidget != pFXAnnot)
+    ExitWidget(pAnnotHandlerMgr, true, nFlag);
+
   if (pFXAnnot) {
-    if (m_pCaptureWidget && m_pCaptureWidget != pFXAnnot) {
-      m_bExitWidget = true;
-      m_bEnterWidget = false;
-      pAnnotHandlerMgr->Annot_OnMouseExit(this, &m_pCaptureWidget, nFlag);
+    if (!m_bOnWidget) {
+      EnterWidget(pAnnotHandlerMgr, &pFXAnnot, nFlag);
+
+      // Annot_OnMouseEnter may have invalidated pFXAnnot.
+      if (!pFXAnnot) {
+        ExitWidget(pAnnotHandlerMgr, false, nFlag);
+        return true;
+      }
     }
-    m_pCaptureWidget.Reset(pFXAnnot.Get());
-    m_bOnWidget = true;
-    if (!m_bEnterWidget) {
-      m_bEnterWidget = true;
-      m_bExitWidget = false;
-      pAnnotHandlerMgr->Annot_OnMouseEnter(this, &pFXAnnot, nFlag);
-    }
+
     pAnnotHandlerMgr->Annot_OnMouseMove(this, &pFXAnnot, nFlag, point);
     return true;
   }
-  if (m_bOnWidget) {
-    m_bOnWidget = false;
-    m_bExitWidget = true;
-    m_bEnterWidget = false;
-    if (m_pCaptureWidget) {
-      pAnnotHandlerMgr->Annot_OnMouseExit(this, &m_pCaptureWidget, nFlag);
-      m_pCaptureWidget.Reset();
-    }
-  }
+
   return false;
 }
 
+void CPDFSDK_PageView::EnterWidget(CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr,
+                                   CPDFSDK_Annot::ObservedPtr* pAnnot,
+                                   uint32_t nFlag) {
+  m_bOnWidget = true;
+  m_pCaptureWidget.Reset(pAnnot->Get());
+  pAnnotHandlerMgr->Annot_OnMouseEnter(this, pAnnot, nFlag);
+}
+
+void CPDFSDK_PageView::ExitWidget(CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr,
+                                  bool callExitCallback,
+                                  uint32_t nFlag) {
+  m_bOnWidget = false;
+  if (m_pCaptureWidget) {
+    if (callExitCallback)
+      pAnnotHandlerMgr->Annot_OnMouseExit(this, &m_pCaptureWidget, nFlag);
+
+    m_pCaptureWidget.Reset();
+  }
+}
+
 bool CPDFSDK_PageView::OnMouseWheel(double deltaX,
                                     double deltaY,
                                     const CFX_PointF& point,
@@ -349,8 +390,8 @@
 
   CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
       m_pFormFillEnv->GetAnnotHandlerMgr();
-  return pAnnotHandlerMgr->Annot_OnMouseWheel(this, &pAnnot, nFlag, (int)deltaY,
-                                              point);
+  return pAnnotHandlerMgr->Annot_OnMouseWheel(this, &pAnnot, nFlag,
+                                              static_cast<int>(deltaY), point);
 }
 
 bool CPDFSDK_PageView::OnChar(int nChar, uint32_t nFlag) {
@@ -380,22 +421,22 @@
   CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
       m_pFormFillEnv->GetAnnotHandlerMgr();
 
-  SetLock(true);
+  AutoRestorer<bool> lock(&m_bLocked);
+  m_bLocked = true;
 
 #ifdef PDF_ENABLE_XFA
-  CFX_RetainPtr<CPDFXFA_Page> protector(m_page);
-  if (m_pFormFillEnv->GetXFAContext()->GetDocType() == DOCTYPE_DYNAMIC_XFA) {
+  RetainPtr<CPDFXFA_Page> protector(m_page);
+  if (m_pFormFillEnv->GetXFAContext()->GetFormType() == FormType::kXFAFull) {
     CXFA_FFPageView* pageView = m_page->GetXFAPageView();
-    std::unique_ptr<IXFA_WidgetIterator> pWidgetHander(
+    std::unique_ptr<IXFA_WidgetIterator> pWidgetHandler(
         pageView->CreateWidgetIterator(
             XFA_TRAVERSEWAY_Form,
             XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable));
-    if (!pWidgetHander) {
-      SetLock(false);
+    if (!pWidgetHandler) {
       return;
     }
 
-    while (CXFA_FFWidget* pXFAAnnot = pWidgetHander->MoveToNext()) {
+    while (CXFA_FFWidget* pXFAAnnot = pWidgetHandler->MoveToNext()) {
       CPDFSDK_Annot* pAnnot = pAnnotHandlerMgr->NewAnnot(pXFAAnnot, this);
       if (!pAnnot)
         continue;
@@ -403,7 +444,6 @@
       pAnnotHandlerMgr->Annot_OnLoad(pAnnot);
     }
 
-    SetLock(false);
     return;
   }
 #endif  // PDF_ENABLE_XFA
@@ -426,18 +466,16 @@
     m_SDKAnnotArray.push_back(pAnnot);
     pAnnotHandlerMgr->Annot_OnLoad(pAnnot);
   }
-
-  SetLock(false);
 }
 
 void CPDFSDK_PageView::UpdateRects(const std::vector<CFX_FloatRect>& rects) {
   for (const auto& rc : rects)
-    m_pFormFillEnv->Invalidate(m_page, rc.ToFxRect());
+    m_pFormFillEnv->Invalidate(m_page, rc.GetOuterRect());
 }
 
 void CPDFSDK_PageView::UpdateView(CPDFSDK_Annot* pAnnot) {
   CFX_FloatRect rcWindow = pAnnot->GetRect();
-  m_pFormFillEnv->Invalidate(m_page, rcWindow.ToFxRect());
+  m_pFormFillEnv->Invalidate(m_page, rcWindow.GetOuterRect());
 }
 
 int CPDFSDK_PageView::GetPageIndex() const {
@@ -445,21 +483,18 @@
     return -1;
 
 #ifdef PDF_ENABLE_XFA
-  int nDocType = m_page->GetContext()->GetDocType();
-  switch (nDocType) {
-    case DOCTYPE_DYNAMIC_XFA: {
+  switch (m_page->GetContext()->GetFormType()) {
+    case FormType::kXFAFull: {
       CXFA_FFPageView* pPageView = m_page->GetXFAPageView();
       return pPageView ? pPageView->GetPageIndex() : -1;
     }
-    case DOCTYPE_STATIC_XFA:
-    case DOCTYPE_PDF:
-      return GetPageIndexForStaticPDF();
-    default:
-      return -1;
+    case FormType::kNone:
+    case FormType::kAcroForm:
+    case FormType::kXFAForeground:
+      break;
   }
-#else   // PDF_ENABLE_XFA
-  return GetPageIndexForStaticPDF();
 #endif  // PDF_ENABLE_XFA
+  return GetPageIndexForStaticPDF();
 }
 
 bool CPDFSDK_PageView::IsValidAnnot(const CPDF_Annot* p) const {
@@ -486,7 +521,7 @@
 }
 
 int CPDFSDK_PageView::GetPageIndexForStaticPDF() const {
-  CPDF_Dictionary* pDict = GetPDFPage()->m_pFormDict;
+  CPDF_Dictionary* pDict = GetPDFPage()->m_pFormDict.Get();
   CPDF_Document* pDoc = m_pFormFillEnv->GetPDFDocument();
   return (pDoc && pDict) ? pDoc->GetPageIndex(pDict->GetObjNum()) : -1;
 }
diff --git a/fpdfsdk/cpdfsdk_pageview.h b/fpdfsdk/cpdfsdk_pageview.h
index bcd5177..03f3ab6 100644
--- a/fpdfsdk/cpdfsdk_pageview.h
+++ b/fpdfsdk/cpdfsdk_pageview.h
@@ -12,7 +12,9 @@
 
 #include "core/fpdfapi/page/cpdf_page.h"
 #include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "fpdfsdk/cpdfsdk_annot.h"
+#include "fpdfsdk/cpdfsdk_annothandlermgr.h"
 
 class CFX_RenderDevice;
 class CPDF_AnnotList;
@@ -55,7 +57,14 @@
 
   CPDF_Page* GetPDFPage() const;
   CPDF_Document* GetPDFDocument();
-  CPDFSDK_FormFillEnvironment* GetFormFillEnv() const { return m_pFormFillEnv; }
+  CPDFSDK_FormFillEnvironment* GetFormFillEnv() const {
+    return m_pFormFillEnv.Get();
+  }
+
+  WideString GetSelectedText();
+  void ReplaceSelection(const WideString& text);
+
+  bool OnFocus(const CFX_PointF& 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
@@ -81,7 +90,6 @@
   void SetValid(bool bValid) { m_bValid = bValid; }
   bool IsValid() { return m_bValid; }
 
-  void SetLock(bool bLocked) { m_bLocked = bLocked; }
   bool IsLocked() { return m_bLocked; }
 
   void SetBeingDestroyed() { m_bBeingDestroyed = true; }
@@ -98,17 +106,22 @@
 
   int GetPageIndexForStaticPDF() const;
 
+  void EnterWidget(CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr,
+                   CPDFSDK_Annot::ObservedPtr* pAnnot,
+                   uint32_t nFlag);
+  void ExitWidget(CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr,
+                  bool callExitCallback,
+                  uint32_t nFlag);
+
   CFX_Matrix m_curMatrix;
   UnderlyingPageType* const m_page;
   std::unique_ptr<CPDF_AnnotList> m_pAnnotList;
   std::vector<CPDFSDK_Annot*> m_SDKAnnotArray;
-  CPDFSDK_FormFillEnvironment* const m_pFormFillEnv;  // Not owned.
+  UnownedPtr<CPDFSDK_FormFillEnvironment> const m_pFormFillEnv;
   CPDFSDK_Annot::ObservedPtr m_pCaptureWidget;
 #ifndef PDF_ENABLE_XFA
   bool m_bOwnsPage;
 #endif  // PDF_ENABLE_XFA
-  bool m_bEnterWidget;
-  bool m_bExitWidget;
   bool m_bOnWidget;
   bool m_bValid;
   bool m_bLocked;
diff --git a/fpdfsdk/cpdfsdk_widget.cpp b/fpdfsdk/cpdfsdk_widget.cpp
index cd86f7a..2adc46f 100644
--- a/fpdfsdk/cpdfsdk_widget.cpp
+++ b/fpdfsdk/cpdfsdk_widget.cpp
@@ -7,6 +7,7 @@
 #include "fpdfsdk/cpdfsdk_widget.h"
 
 #include <memory>
+#include <sstream>
 
 #include "core/fpdfapi/parser/cpdf_array.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
@@ -28,17 +29,17 @@
 #include "fpdfsdk/formfiller/cba_fontmap.h"
 #include "fpdfsdk/fsdk_actionhandler.h"
 #include "fpdfsdk/fsdk_define.h"
-#include "fpdfsdk/fxedit/fxet_edit.h"
-#include "fpdfsdk/pdfwindow/PWL_Edit.h"
-#include "fpdfsdk/pdfwindow/PWL_Utils.h"
+#include "fpdfsdk/pwl/cpwl_appstream.h"
+#include "fpdfsdk/pwl/cpwl_edit.h"
 
 #ifdef PDF_ENABLE_XFA
 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
 #include "xfa/fxfa/cxfa_eventparam.h"
-#include "xfa/fxfa/fxfa_widget.h"
-#include "xfa/fxfa/xfa_ffdocview.h"
-#include "xfa/fxfa/xfa_ffwidget.h"
-#include "xfa/fxfa/xfa_ffwidgethandler.h"
+#include "xfa/fxfa/cxfa_ffdocview.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
+#include "xfa/fxfa/cxfa_ffwidgethandler.h"
+#include "xfa/fxfa/cxfa_widgetacc.h"
+#include "xfa/fxfa/parser/cxfa_node.h"
 #endif  // PDF_ENABLE_XFA
 
 namespace {
@@ -57,7 +58,7 @@
                                CPDFSDK_InterForm* pInterForm)
     : CPDFSDK_BAAnnot(pAnnot, pPageView),
       m_pInterForm(pInterForm),
-      m_nAppAge(0),
+      m_nAppearanceAge(0),
       m_nValueAge(0)
 #ifdef PDF_ENABLE_XFA
       ,
@@ -72,11 +73,11 @@
 #ifdef PDF_ENABLE_XFA
 CXFA_FFWidget* CPDFSDK_Widget::GetMixXFAWidget() const {
   CPDFXFA_Context* pContext = m_pPageView->GetFormFillEnv()->GetXFAContext();
-  if (pContext->GetDocType() == DOCTYPE_STATIC_XFA) {
+  if (pContext->GetFormType() == FormType::kXFAForeground) {
     if (!m_hMixXFAWidget) {
       if (CXFA_FFDocView* pDocView = pContext->GetXFADocView()) {
-        CFX_WideString sName;
-        if (GetFieldType() == FIELDTYPE_RADIOBUTTON) {
+        WideString sName;
+        if (GetFieldType() == FormFieldType::kRadioButton) {
           sName = GetAnnotName();
           if (sName.IsEmpty())
             sName = GetName();
@@ -88,36 +89,35 @@
           m_hMixXFAWidget = pDocView->GetWidgetByName(sName, nullptr);
       }
     }
-    return m_hMixXFAWidget;
+    return m_hMixXFAWidget.Get();
   }
-
   return nullptr;
 }
 
 CXFA_FFWidget* CPDFSDK_Widget::GetGroupMixXFAWidget() {
   CPDFXFA_Context* pContext = m_pPageView->GetFormFillEnv()->GetXFAContext();
-  if (pContext->GetDocType() == DOCTYPE_STATIC_XFA) {
-    if (CXFA_FFDocView* pDocView = pContext->GetXFADocView()) {
-      CFX_WideString sName = GetName();
-      if (!sName.IsEmpty())
-        return pDocView->GetWidgetByName(sName, nullptr);
-    }
-  }
+  if (pContext->GetFormType() != FormType::kXFAForeground)
+    return nullptr;
 
-  return nullptr;
+  CXFA_FFDocView* pDocView = pContext->GetXFADocView();
+  if (!pDocView)
+    return nullptr;
+
+  WideString sName = GetName();
+  return !sName.IsEmpty() ? pDocView->GetWidgetByName(sName, nullptr) : nullptr;
 }
 
 CXFA_FFWidgetHandler* CPDFSDK_Widget::GetXFAWidgetHandler() const {
   CPDFXFA_Context* pContext = m_pPageView->GetFormFillEnv()->GetXFAContext();
-  if (pContext->GetDocType() == DOCTYPE_STATIC_XFA) {
-    if (!m_pWidgetHandler) {
-      if (CXFA_FFDocView* pDocView = pContext->GetXFADocView())
-        m_pWidgetHandler = pDocView->GetWidgetHandler();
-    }
-    return m_pWidgetHandler;
-  }
+  if (pContext->GetFormType() != FormType::kXFAForeground)
+    return nullptr;
 
-  return nullptr;
+  if (!m_pWidgetHandler) {
+    CXFA_FFDocView* pDocView = pContext->GetXFADocView();
+    if (pDocView)
+      m_pWidgetHandler = pDocView->GetWidgetHandler();
+  }
+  return m_pWidgetHandler.Get();
 }
 
 static XFA_EVENTTYPE GetXFAEventType(PDFSDK_XFAAActionType eXFAAAT) {
@@ -165,11 +165,8 @@
       eEventType = XFA_EVENT_Exit;
       break;
     case CPDF_AAction::PageOpen:
-      break;
     case CPDF_AAction::PageClose:
-      break;
     case CPDF_AAction::PageVisible:
-      break;
     case CPDF_AAction::PageInvisible:
       break;
     case CPDF_AAction::KeyStroke:
@@ -189,6 +186,9 @@
     case CPDF_AAction::PrintDocument:
     case CPDF_AAction::DocumentPrinted:
       break;
+    case CPDF_AAction::NumberOfActions:
+      NOTREACHED();
+      break;
   }
 
   return eEventType;
@@ -205,18 +205,18 @@
 
   XFA_EVENTTYPE eEventType = GetXFAEventType(eXFAAAT);
 
-  CXFA_WidgetAcc* pAcc;
   if ((eEventType == XFA_EVENT_Click || eEventType == XFA_EVENT_Change) &&
-      GetFieldType() == FIELDTYPE_RADIOBUTTON) {
+      GetFieldType() == FormFieldType::kRadioButton) {
     if (CXFA_FFWidget* hGroupWidget = GetGroupMixXFAWidget()) {
-      pAcc = hGroupWidget->GetDataAcc();
-      if (pXFAWidgetHandler->HasEvent(pAcc, eEventType))
+      if (pXFAWidgetHandler->HasEvent(hGroupWidget->GetNode()->GetWidgetAcc(),
+                                      eEventType)) {
         return true;
+      }
     }
   }
 
-  pAcc = hWidget->GetDataAcc();
-  return pXFAWidgetHandler->HasEvent(pAcc, eEventType);
+  return pXFAWidgetHandler->HasEvent(hWidget->GetNode()->GetWidgetAcc(),
+                                     eEventType);
 }
 
 bool CPDFSDK_Widget::OnXFAAAction(PDFSDK_XFAAActionType eXFAAAT,
@@ -250,14 +250,14 @@
   if (data.nSelEnd > data.nSelStart)
     param.m_wsNewText.Delete(data.nSelStart, data.nSelEnd - data.nSelStart);
 
-  for (int i = 0; i < data.sChange.GetLength(); i++)
-    param.m_wsNewText.Insert(data.nSelStart, data.sChange[i]);
-  param.m_wsPrevText = data.sValue;
+  for (const auto& c : data.sChange)
+    param.m_wsNewText.Insert(data.nSelStart, c);
 
+  param.m_wsPrevText = data.sValue;
   if ((eEventType == XFA_EVENT_Click || eEventType == XFA_EVENT_Change) &&
-      GetFieldType() == FIELDTYPE_RADIOBUTTON) {
+      GetFieldType() == FormFieldType::kRadioButton) {
     if (CXFA_FFWidget* hGroupWidget = GetGroupMixXFAWidget()) {
-      CXFA_WidgetAcc* pAcc = hGroupWidget->GetDataAcc();
+      CXFA_WidgetAcc* pAcc = hGroupWidget->GetNode()->GetWidgetAcc();
       param.m_pTarget = pAcc;
       if (pXFAWidgetHandler->ProcessEvent(pAcc, &param) !=
           XFA_EVENTERROR_Success) {
@@ -265,7 +265,7 @@
       }
     }
   }
-  CXFA_WidgetAcc* pAcc = hWidget->GetDataAcc();
+  CXFA_WidgetAcc* pAcc = hWidget->GetNode()->GetWidgetAcc();
   param.m_pTarget = pAcc;
   int32_t nRet = pXFAWidgetHandler->ProcessEvent(pAcc, &param);
 
@@ -280,48 +280,52 @@
   if (!hWidget)
     return;
 
-  CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc();
+  CXFA_WidgetAcc* pWidgetAcc = hWidget->GetNode()->GetWidgetAcc();
   if (!pWidgetAcc)
     return;
 
   CPDF_FormField* pFormField = GetFormField();
   switch (GetFieldType()) {
-    case FIELDTYPE_CHECKBOX:
-    case FIELDTYPE_RADIOBUTTON: {
+    case FormFieldType::kCheckBox:
+    case FormFieldType::kRadioButton: {
       CPDF_FormControl* pFormCtrl = GetFormControl();
       XFA_CHECKSTATE eCheckState =
           pFormCtrl->IsChecked() ? XFA_CHECKSTATE_On : XFA_CHECKSTATE_Off;
       pWidgetAcc->SetCheckState(eCheckState, true);
       break;
     }
-    case FIELDTYPE_TEXTFIELD:
-      pWidgetAcc->SetValue(pFormField->GetValue(), XFA_VALUEPICTURE_Edit);
+    case FormFieldType::kTextField:
+      pWidgetAcc->SetValue(XFA_VALUEPICTURE_Edit, pFormField->GetValue());
       break;
-    case FIELDTYPE_LISTBOX: {
+    case FormFieldType::kListBox: {
       pWidgetAcc->ClearAllSelections();
 
       for (int i = 0, sz = pFormField->CountSelectedItems(); i < sz; i++) {
         int nIndex = pFormField->GetSelectedIndex(i);
-        if (nIndex > -1 && nIndex < pWidgetAcc->CountChoiceListItems())
+        if (nIndex > -1 && nIndex < pWidgetAcc->CountChoiceListItems(false))
           pWidgetAcc->SetItemState(nIndex, true, false, false, true);
       }
       break;
     }
-    case FIELDTYPE_COMBOBOX: {
+    case FormFieldType::kComboBox: {
       pWidgetAcc->ClearAllSelections();
 
       for (int i = 0, sz = pFormField->CountSelectedItems(); i < sz; i++) {
         int nIndex = pFormField->GetSelectedIndex(i);
-        if (nIndex > -1 && nIndex < pWidgetAcc->CountChoiceListItems())
+        if (nIndex > -1 && nIndex < pWidgetAcc->CountChoiceListItems(false))
           pWidgetAcc->SetItemState(nIndex, true, false, false, true);
       }
-      pWidgetAcc->SetValue(pFormField->GetValue(), XFA_VALUEPICTURE_Edit);
+      pWidgetAcc->SetValue(XFA_VALUEPICTURE_Edit, pFormField->GetValue());
       break;
     }
+    default:
+      break;
   }
 
-  if (bSynchronizeElse)
-    pWidgetAcc->ProcessValueChanged();
+  if (bSynchronizeElse) {
+    CPDFXFA_Context* context = m_pPageView->GetFormFillEnv()->GetXFAContext();
+    context->GetXFADocView()->ProcessValueChanged(pWidgetAcc);
+  }
 }
 
 void CPDFSDK_Widget::SynchronizeXFAValue() {
@@ -358,36 +362,35 @@
   ASSERT(pFormControl);
 
   switch (pFormField->GetFieldType()) {
-    case FIELDTYPE_CHECKBOX: {
-      if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc()) {
+    case FormFieldType::kCheckBox: {
+      if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetNode()->GetWidgetAcc()) {
         pFormField->CheckControl(
             pFormField->GetControlIndex(pFormControl),
             pWidgetAcc->GetCheckState() == XFA_CHECKSTATE_On, true);
       }
       break;
     }
-    case FIELDTYPE_RADIOBUTTON: {
+    case FormFieldType::kRadioButton: {
       // TODO(weili): Check whether we need to handle checkbox and radio
       // button differently, otherwise, merge these two cases.
-      if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc()) {
+      if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetNode()->GetWidgetAcc()) {
         pFormField->CheckControl(
             pFormField->GetControlIndex(pFormControl),
             pWidgetAcc->GetCheckState() == XFA_CHECKSTATE_On, true);
       }
       break;
     }
-    case FIELDTYPE_TEXTFIELD: {
-      if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc()) {
-        CFX_WideString sValue;
-        pWidgetAcc->GetValue(sValue, XFA_VALUEPICTURE_Display);
-        pFormField->SetValue(sValue, true);
+    case FormFieldType::kTextField: {
+      if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetNode()->GetWidgetAcc()) {
+        pFormField->SetValue(pWidgetAcc->GetValue(XFA_VALUEPICTURE_Display),
+                             true);
       }
       break;
     }
-    case FIELDTYPE_LISTBOX: {
+    case FormFieldType::kListBox: {
       pFormField->ClearSelection(false);
 
-      if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc()) {
+      if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetNode()->GetWidgetAcc()) {
         for (int i = 0, sz = pWidgetAcc->CountSelectedItems(); i < sz; i++) {
           int nIndex = pWidgetAcc->GetSelectedItem(i);
 
@@ -398,10 +401,10 @@
       }
       break;
     }
-    case FIELDTYPE_COMBOBOX: {
+    case FormFieldType::kComboBox: {
       pFormField->ClearSelection(false);
 
-      if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc()) {
+      if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetNode()->GetWidgetAcc()) {
         for (int i = 0, sz = pWidgetAcc->CountSelectedItems(); i < sz; i++) {
           int nIndex = pWidgetAcc->GetSelectedItem(i);
 
@@ -409,13 +412,13 @@
             pFormField->SetItemSelection(nIndex, true, true);
           }
         }
-
-        CFX_WideString sValue;
-        pWidgetAcc->GetValue(sValue, XFA_VALUEPICTURE_Display);
-        pFormField->SetValue(sValue, true);
+        pFormField->SetValue(pWidgetAcc->GetValue(XFA_VALUEPICTURE_Display),
+                             true);
       }
       break;
     }
+    default:
+      break;
   }
 }
 
@@ -426,36 +429,36 @@
   ASSERT(hWidget);
 
   switch (pFormField->GetFieldType()) {
-    case FIELDTYPE_LISTBOX: {
+    case FormFieldType::kListBox: {
       pFormField->ClearSelection(false);
       pFormField->ClearOptions(true);
 
-      if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc()) {
-        for (int i = 0, sz = pWidgetAcc->CountChoiceListItems(); i < sz; i++) {
-          CFX_WideString swText;
-          pWidgetAcc->GetChoiceListItem(swText, i);
-
-          pFormField->InsertOption(swText, i, true);
+      if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetNode()->GetWidgetAcc()) {
+        for (int i = 0, sz = pWidgetAcc->CountChoiceListItems(false); i < sz;
+             i++) {
+          pFormField->InsertOption(
+              pWidgetAcc->GetChoiceListItem(i, false).value_or(L""), i, true);
         }
       }
       break;
     }
-    case FIELDTYPE_COMBOBOX: {
+    case FormFieldType::kComboBox: {
       pFormField->ClearSelection(false);
       pFormField->ClearOptions(false);
 
-      if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc()) {
-        for (int i = 0, sz = pWidgetAcc->CountChoiceListItems(); i < sz; i++) {
-          CFX_WideString swText;
-          pWidgetAcc->GetChoiceListItem(swText, i);
-
-          pFormField->InsertOption(swText, i, false);
+      if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetNode()->GetWidgetAcc()) {
+        for (int i = 0, sz = pWidgetAcc->CountChoiceListItems(false); i < sz;
+             i++) {
+          pFormField->InsertOption(
+              pWidgetAcc->GetChoiceListItem(i, false).value_or(L""), i, false);
         }
       }
 
       pFormField->SetValue(L"", true);
       break;
     }
+    default:
+      break;
   }
 }
 #endif  // PDF_ENABLE_XFA
@@ -466,7 +469,7 @@
     return false;
 
   // Choose the right sub-ap
-  const FX_CHAR* ap_entry = "N";
+  const char* ap_entry = "N";
   if (mode == CPDF_Annot::Down)
     ap_entry = "D";
   else if (mode == CPDF_Annot::Rollover)
@@ -479,34 +482,35 @@
   if (!psub)
     return false;
 
-  int nFieldType = GetFieldType();
-  switch (nFieldType) {
-    case FIELDTYPE_PUSHBUTTON:
-    case FIELDTYPE_COMBOBOX:
-    case FIELDTYPE_LISTBOX:
-    case FIELDTYPE_TEXTFIELD:
-    case FIELDTYPE_SIGNATURE:
+  FormFieldType fieldType = GetFieldType();
+  switch (fieldType) {
+    case FormFieldType::kPushButton:
+    case FormFieldType::kComboBox:
+    case FormFieldType::kListBox:
+    case FormFieldType::kTextField:
+    case FormFieldType::kSignature:
       return psub->IsStream();
-    case FIELDTYPE_CHECKBOX:
-    case FIELDTYPE_RADIOBUTTON:
+    case FormFieldType::kCheckBox:
+    case FormFieldType::kRadioButton:
       if (CPDF_Dictionary* pSubDict = psub->AsDictionary()) {
         return !!pSubDict->GetStreamFor(GetAppState());
       }
       return false;
+    default:
+      return true;
   }
-  return true;
 }
 
-int CPDFSDK_Widget::GetFieldType() const {
+FormFieldType CPDFSDK_Widget::GetFieldType() const {
   CPDF_FormField* pField = GetFormField();
-  return pField ? pField->GetFieldType() : FIELDTYPE_UNKNOWN;
+  return pField ? pField->GetFieldType() : FormFieldType::kUnknown;
 }
 
 bool CPDFSDK_Widget::IsAppearanceValid() {
 #ifdef PDF_ENABLE_XFA
   CPDFXFA_Context* pContext = m_pPageView->GetFormFillEnv()->GetXFAContext();
-  int nDocType = pContext->GetDocType();
-  if (nDocType != DOCTYPE_PDF && nDocType != DOCTYPE_STATIC_XFA)
+  FormType formType = pContext->GetFormType();
+  if (formType == FormType::kXFAFull)
     return true;
 #endif  // PDF_ENABLE_XFA
   return CPDFSDK_BAAnnot::IsAppearanceValid();
@@ -525,7 +529,7 @@
 }
 
 bool CPDFSDK_Widget::IsSignatureWidget() const {
-  return GetFieldType() == FIELDTYPE_SIGNATURE;
+  return GetFieldType() == FormFieldType::kSignature;
 }
 
 CPDF_FormField* CPDFSDK_Widget::GetFormField() const {
@@ -551,7 +555,7 @@
 }
 
 #ifdef PDF_ENABLE_XFA
-CFX_WideString CPDFSDK_Widget::GetName() const {
+WideString CPDFSDK_Widget::GetName() const {
   CPDF_FormField* pFormField = GetFormField();
   return pFormField->GetFullName();
 }
@@ -561,14 +565,14 @@
   CPDF_FormControl* pFormCtrl = GetFormControl();
   int iColorType = 0;
   color = ARGBToColorRef(pFormCtrl->GetBackgroundColor(iColorType));
-  return iColorType != COLORTYPE_TRANSPARENT;
+  return iColorType != CFX_Color::kTransparent;
 }
 
 bool CPDFSDK_Widget::GetBorderColor(FX_COLORREF& color) const {
   CPDF_FormControl* pFormCtrl = GetFormControl();
   int iColorType = 0;
   color = ARGBToColorRef(pFormCtrl->GetBorderColor(iColorType));
-  return iColorType != COLORTYPE_TRANSPARENT;
+  return iColorType != CFX_Color::kTransparent;
 }
 
 bool CPDFSDK_Widget::GetTextColor(FX_COLORREF& color) const {
@@ -578,26 +582,24 @@
     return false;
 
   FX_ARGB argb;
-  int iColorType = COLORTYPE_TRANSPARENT;
+  int iColorType = CFX_Color::kTransparent;
   da.GetColor(argb, iColorType);
   color = ARGBToColorRef(argb);
-  return iColorType != COLORTYPE_TRANSPARENT;
+  return iColorType != CFX_Color::kTransparent;
 }
 
-FX_FLOAT CPDFSDK_Widget::GetFontSize() const {
+float CPDFSDK_Widget::GetFontSize() const {
   CPDF_FormControl* pFormCtrl = GetFormControl();
   CPDF_DefaultAppearance pDa = pFormCtrl->GetDefaultAppearance();
-  CFX_ByteString csFont = "";
-  FX_FLOAT fFontSize = 0.0f;
-  pDa.GetFont(csFont, fFontSize);
-
+  float fFontSize;
+  pDa.GetFont(&fFontSize);
   return fFontSize;
 }
 
 int CPDFSDK_Widget::GetSelectedIndex(int nIndex) const {
 #ifdef PDF_ENABLE_XFA
   if (CXFA_FFWidget* hWidget = GetMixXFAWidget()) {
-    if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc()) {
+    if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetNode()->GetWidgetAcc()) {
       if (nIndex < pWidgetAcc->CountSelectedItems())
         return pWidgetAcc->GetSelectedItem(nIndex);
     }
@@ -608,28 +610,26 @@
 }
 
 #ifdef PDF_ENABLE_XFA
-CFX_WideString CPDFSDK_Widget::GetValue(bool bDisplay) const {
+WideString CPDFSDK_Widget::GetValue(bool bDisplay) const {
   if (CXFA_FFWidget* hWidget = GetMixXFAWidget()) {
-    if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc()) {
-      CFX_WideString sValue;
-      pWidgetAcc->GetValue(
-          sValue, bDisplay ? XFA_VALUEPICTURE_Display : XFA_VALUEPICTURE_Edit);
-      return sValue;
+    if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetNode()->GetWidgetAcc()) {
+      return pWidgetAcc->GetValue(bDisplay ? XFA_VALUEPICTURE_Display
+                                           : XFA_VALUEPICTURE_Edit);
     }
   }
 #else
-CFX_WideString CPDFSDK_Widget::GetValue() const {
+WideString CPDFSDK_Widget::GetValue() const {
 #endif  // PDF_ENABLE_XFA
   CPDF_FormField* pFormField = GetFormField();
   return pFormField->GetValue();
 }
 
-CFX_WideString CPDFSDK_Widget::GetDefaultValue() const {
+WideString CPDFSDK_Widget::GetDefaultValue() const {
   CPDF_FormField* pFormField = GetFormField();
   return pFormField->GetDefaultValue();
 }
 
-CFX_WideString CPDFSDK_Widget::GetOptionLabel(int nIndex) const {
+WideString CPDFSDK_Widget::GetOptionLabel(int nIndex) const {
   CPDF_FormField* pFormField = GetFormField();
   return pFormField->GetOptionLabel(nIndex);
 }
@@ -642,8 +642,8 @@
 bool CPDFSDK_Widget::IsOptionSelected(int nIndex) const {
 #ifdef PDF_ENABLE_XFA
   if (CXFA_FFWidget* hWidget = GetMixXFAWidget()) {
-    if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc()) {
-      if (nIndex > -1 && nIndex < pWidgetAcc->CountChoiceListItems())
+    if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetNode()->GetWidgetAcc()) {
+      if (nIndex > -1 && nIndex < pWidgetAcc->CountChoiceListItems(false))
         return pWidgetAcc->GetItemState(nIndex);
 
       return false;
@@ -662,7 +662,7 @@
 bool CPDFSDK_Widget::IsChecked() const {
 #ifdef PDF_ENABLE_XFA
   if (CXFA_FFWidget* hWidget = GetMixXFAWidget()) {
-    if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc())
+    if (CXFA_WidgetAcc* pWidgetAcc = hWidget->GetNode()->GetWidgetAcc())
       return pWidgetAcc->GetCheckState() == XFA_CHECKSTATE_On;
   }
 #endif  // PDF_ENABLE_XFA
@@ -693,7 +693,7 @@
 #endif  // PDF_ENABLE_XFA
 }
 
-void CPDFSDK_Widget::SetValue(const CFX_WideString& sValue, bool bNotify) {
+void CPDFSDK_Widget::SetValue(const WideString& sValue, bool bNotify) {
   CPDF_FormField* pFormField = GetFormField();
   pFormField->SetValue(sValue, bNotify);
 #ifdef PDF_ENABLE_XFA
@@ -702,7 +702,7 @@
 #endif  // PDF_ENABLE_XFA
 }
 
-void CPDFSDK_Widget::SetDefaultValue(const CFX_WideString& sValue) {}
+void CPDFSDK_Widget::SetDefaultValue(const WideString& sValue) {}
 void CPDFSDK_Widget::SetOptionSelection(int index,
                                         bool bSelected,
                                         bool bNotify) {
@@ -740,10 +740,10 @@
 #ifdef PDF_ENABLE_XFA
 void CPDFSDK_Widget::ResetAppearance(bool bValueChanged) {
   switch (GetFieldType()) {
-    case FIELDTYPE_TEXTFIELD:
-    case FIELDTYPE_COMBOBOX: {
+    case FormFieldType::kTextField:
+    case FormFieldType::kComboBox: {
       bool bFormatted = false;
-      CFX_WideString sValue = OnFormat(bFormatted);
+      WideString sValue = OnFormat(bFormatted);
       ResetAppearance(bFormatted ? &sValue : nullptr, true);
       break;
     }
@@ -754,43 +754,42 @@
 }
 #endif  // PDF_ENABLE_XFA
 
-void CPDFSDK_Widget::ResetAppearance(const CFX_WideString* sValue,
+void CPDFSDK_Widget::ResetAppearance(const WideString* sValue,
                                      bool bValueChanged) {
   SetAppModified();
 
-  m_nAppAge++;
-  if (m_nAppAge > 999999)
-    m_nAppAge = 0;
+  m_nAppearanceAge++;
   if (bValueChanged)
     m_nValueAge++;
 
-  int nFieldType = GetFieldType();
-
-  switch (nFieldType) {
-    case FIELDTYPE_PUSHBUTTON:
-      ResetAppearance_PushButton();
+  CPWL_AppStream appStream(this, GetAPDict());
+  switch (GetFieldType()) {
+    case FormFieldType::kPushButton:
+      appStream.SetAsPushButton();
       break;
-    case FIELDTYPE_CHECKBOX:
-      ResetAppearance_CheckBox();
+    case FormFieldType::kCheckBox:
+      appStream.SetAsCheckBox();
       break;
-    case FIELDTYPE_RADIOBUTTON:
-      ResetAppearance_RadioButton();
+    case FormFieldType::kRadioButton:
+      appStream.SetAsRadioButton();
       break;
-    case FIELDTYPE_COMBOBOX:
-      ResetAppearance_ComboBox(sValue);
+    case FormFieldType::kComboBox:
+      appStream.SetAsComboBox(sValue);
       break;
-    case FIELDTYPE_LISTBOX:
-      ResetAppearance_ListBox();
+    case FormFieldType::kListBox:
+      appStream.SetAsListBox();
       break;
-    case FIELDTYPE_TEXTFIELD:
-      ResetAppearance_TextField(sValue);
+    case FormFieldType::kTextField:
+      appStream.SetAsTextField(sValue);
+      break;
+    default:
       break;
   }
 
   m_pAnnot->ClearCachedAP();
 }
 
-CFX_WideString CPDFSDK_Widget::OnFormat(bool& bFormatted) {
+WideString CPDFSDK_Widget::OnFormat(bool& bFormatted) {
   CPDF_FormField* pFormField = GetFormField();
   ASSERT(pFormField);
   return m_pInterForm->OnFormat(pFormField, bFormatted);
@@ -803,13 +802,13 @@
 }
 
 void CPDFSDK_Widget::DrawAppearance(CFX_RenderDevice* pDevice,
-                                    const CFX_Matrix* pUser2Device,
+                                    const CFX_Matrix& mtUser2Device,
                                     CPDF_Annot::AppearanceMode mode,
                                     const CPDF_RenderOptions* pOptions) {
-  int nFieldType = GetFieldType();
+  FormFieldType fieldType = GetFieldType();
 
-  if ((nFieldType == FIELDTYPE_CHECKBOX ||
-       nFieldType == FIELDTYPE_RADIOBUTTON) &&
+  if ((fieldType == FormFieldType::kCheckBox ||
+       fieldType == FormFieldType::kRadioButton) &&
       mode == CPDF_Annot::Normal &&
       !IsWidgetAppearanceValid(CPDF_Annot::Normal)) {
     CFX_PathData pathData;
@@ -822,10 +821,10 @@
     CFX_GraphStateData gsd;
     gsd.m_LineWidth = 0.0f;
 
-    pDevice->DrawPath(&pathData, pUser2Device, &gsd, 0, 0xFFAAAAAA,
+    pDevice->DrawPath(&pathData, &mtUser2Device, &gsd, 0, 0xFFAAAAAA,
                       FXFILL_ALTERNATE);
   } else {
-    CPDFSDK_BAAnnot::DrawAppearance(pDevice, pUser2Device, mode, pOptions);
+    CPDFSDK_BAAnnot::DrawAppearance(pDevice, mtUser2Device, mode, pOptions);
   }
 }
 
@@ -837,8 +836,8 @@
 
 void CPDFSDK_Widget::DrawShadow(CFX_RenderDevice* pDevice,
                                 CPDFSDK_PageView* pPageView) {
-  int nFieldType = GetFieldType();
-  if (!m_pInterForm->IsNeedHighLight(nFieldType))
+  FormFieldType fieldType = GetFieldType();
+  if (!m_pInterForm->IsNeedHighLight(fieldType))
     return;
 
   CFX_Matrix page2device;
@@ -858,791 +857,12 @@
   FX_RECT rcDev = rcDevice.ToFxRect();
   pDevice->FillRect(
       &rcDev, ArgbEncode(static_cast<int>(m_pInterForm->GetHighlightAlpha()),
-                         m_pInterForm->GetHighlightColor(nFieldType)));
-}
-
-void CPDFSDK_Widget::ResetAppearance_PushButton() {
-  CPDF_FormControl* pControl = GetFormControl();
-  CFX_FloatRect rcWindow = GetRotatedRect();
-  int32_t nLayout = 0;
-  switch (pControl->GetTextPosition()) {
-    case TEXTPOS_ICON:
-      nLayout = PPBL_ICON;
-      break;
-    case TEXTPOS_BELOW:
-      nLayout = PPBL_ICONTOPLABELBOTTOM;
-      break;
-    case TEXTPOS_ABOVE:
-      nLayout = PPBL_LABELTOPICONBOTTOM;
-      break;
-    case TEXTPOS_RIGHT:
-      nLayout = PPBL_ICONLEFTLABELRIGHT;
-      break;
-    case TEXTPOS_LEFT:
-      nLayout = PPBL_LABELLEFTICONRIGHT;
-      break;
-    case TEXTPOS_OVERLAID:
-      nLayout = PPBL_LABELOVERICON;
-      break;
-    default:
-      nLayout = PPBL_LABEL;
-      break;
-  }
-
-  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]);
-
-  pControl->GetOriginalBorderColor(iColorType, fc);
-  if (iColorType > 0)
-    crBorder = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
-
-  FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth();
-  CPWL_Dash dsBorder(3, 0, 0);
-  CPWL_Color crLeftTop;
-  CPWL_Color crRightBottom;
-
-  BorderStyle nBorderStyle = GetBorderStyle();
-  switch (nBorderStyle) {
-    case BorderStyle::DASH:
-      dsBorder = CPWL_Dash(3, 3, 0);
-      break;
-    case BorderStyle::BEVELED:
-      fBorderWidth *= 2;
-      crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1);
-      crRightBottom = crBackground / 2.0f;
-      break;
-    case BorderStyle::INSET:
-      fBorderWidth *= 2;
-      crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0.5);
-      crRightBottom = CPWL_Color(COLORTYPE_GRAY, 0.75);
-      break;
-    default:
-      break;
-  }
-
-  CFX_FloatRect rcClient = CPWL_Utils::DeflateRect(rcWindow, fBorderWidth);
-
-  CPWL_Color crText(COLORTYPE_GRAY, 0);
-
-  FX_FLOAT fFontSize = 12.0f;
-  CFX_ByteString csNameTag;
-
-  CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
-  if (da.HasColor()) {
-    da.GetColor(iColorType, fc);
-    crText = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
-  }
-
-  if (da.HasFont())
-    da.GetFont(csNameTag, fFontSize);
-
-  CFX_WideString csWCaption;
-  CFX_WideString csNormalCaption, csRolloverCaption, csDownCaption;
-
-  if (pControl->HasMKEntry("CA"))
-    csNormalCaption = pControl->GetNormalCaption();
-
-  if (pControl->HasMKEntry("RC"))
-    csRolloverCaption = pControl->GetRolloverCaption();
-
-  if (pControl->HasMKEntry("AC"))
-    csDownCaption = pControl->GetDownCaption();
-
-  CPDF_Stream* pNormalIcon = nullptr;
-  CPDF_Stream* pRolloverIcon = nullptr;
-  CPDF_Stream* pDownIcon = nullptr;
-
-  if (pControl->HasMKEntry("I"))
-    pNormalIcon = pControl->GetNormalIcon();
-
-  if (pControl->HasMKEntry("RI"))
-    pRolloverIcon = pControl->GetRolloverIcon();
-
-  if (pControl->HasMKEntry("IX"))
-    pDownIcon = pControl->GetDownIcon();
-
-  if (pNormalIcon) {
-    if (CPDF_Dictionary* pImageDict = pNormalIcon->GetDict()) {
-      if (pImageDict->GetStringFor("Name").IsEmpty())
-        pImageDict->SetNewFor<CPDF_String>("Name", "ImgA", false);
-    }
-  }
-
-  if (pRolloverIcon) {
-    if (CPDF_Dictionary* pImageDict = pRolloverIcon->GetDict()) {
-      if (pImageDict->GetStringFor("Name").IsEmpty())
-        pImageDict->SetNewFor<CPDF_String>("Name", "ImgB", false);
-    }
-  }
-
-  if (pDownIcon) {
-    if (CPDF_Dictionary* pImageDict = pDownIcon->GetDict()) {
-      if (pImageDict->GetStringFor("Name").IsEmpty())
-        pImageDict->SetNewFor<CPDF_String>("Name", "ImgC", false);
-    }
-  }
-
-  CPDF_IconFit iconFit = pControl->GetIconFit();
-
-  CBA_FontMap font_map(this, m_pInterForm->GetFormFillEnv()->GetSysHandler());
-  font_map.SetAPType("N");
-
-  CFX_ByteString csAP =
-      CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground) +
-      CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
-                                     crLeftTop, crRightBottom, nBorderStyle,
-                                     dsBorder) +
-      CPWL_Utils::GetPushButtonAppStream(
-          iconFit.GetFittingBounds() ? rcWindow : rcClient, &font_map,
-          pNormalIcon, iconFit, csNormalCaption, crText, fFontSize, nLayout);
-
-  WriteAppearance("N", GetRotatedRect(), GetMatrix(), csAP);
-  if (pNormalIcon)
-    AddImageToAppearance("N", pNormalIcon);
-
-  CPDF_FormControl::HighlightingMode eHLM = pControl->GetHighlightingMode();
-  if (eHLM == CPDF_FormControl::Push || eHLM == CPDF_FormControl::Toggle) {
-    if (csRolloverCaption.IsEmpty() && !pRolloverIcon) {
-      csRolloverCaption = csNormalCaption;
-      pRolloverIcon = pNormalIcon;
-    }
-
-    font_map.SetAPType("R");
-
-    csAP = CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground) +
-           CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
-                                          crLeftTop, crRightBottom,
-                                          nBorderStyle, dsBorder) +
-           CPWL_Utils::GetPushButtonAppStream(
-               iconFit.GetFittingBounds() ? rcWindow : rcClient, &font_map,
-               pRolloverIcon, iconFit, csRolloverCaption, crText, fFontSize,
-               nLayout);
-
-    WriteAppearance("R", GetRotatedRect(), GetMatrix(), csAP);
-    if (pRolloverIcon)
-      AddImageToAppearance("R", pRolloverIcon);
-
-    if (csDownCaption.IsEmpty() && !pDownIcon) {
-      csDownCaption = csNormalCaption;
-      pDownIcon = pNormalIcon;
-    }
-
-    switch (nBorderStyle) {
-      case BorderStyle::BEVELED: {
-        CPWL_Color crTemp = crLeftTop;
-        crLeftTop = crRightBottom;
-        crRightBottom = crTemp;
-        break;
-      }
-      case BorderStyle::INSET: {
-        crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0);
-        crRightBottom = CPWL_Color(COLORTYPE_GRAY, 1);
-        break;
-      }
-      default:
-        break;
-    }
-
-    font_map.SetAPType("D");
-
-    csAP = CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
-           CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
-                                          crLeftTop, crRightBottom,
-                                          nBorderStyle, dsBorder) +
-           CPWL_Utils::GetPushButtonAppStream(
-               iconFit.GetFittingBounds() ? rcWindow : rcClient, &font_map,
-               pDownIcon, iconFit, csDownCaption, crText, fFontSize, nLayout);
-
-    WriteAppearance("D", GetRotatedRect(), GetMatrix(), csAP);
-    if (pDownIcon)
-      AddImageToAppearance("D", pDownIcon);
-  } else {
-    RemoveAppearance("D");
-    RemoveAppearance("R");
-  }
-}
-
-void CPDFSDK_Widget::ResetAppearance_CheckBox() {
-  CPDF_FormControl* pControl = GetFormControl();
-  CPWL_Color crBackground, crBorder, crText;
-  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]);
-
-  pControl->GetOriginalBorderColor(iColorType, fc);
-  if (iColorType > 0)
-    crBorder = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
-
-  FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth();
-  CPWL_Dash dsBorder(3, 0, 0);
-  CPWL_Color crLeftTop, crRightBottom;
-
-  BorderStyle nBorderStyle = GetBorderStyle();
-  switch (nBorderStyle) {
-    case BorderStyle::DASH:
-      dsBorder = CPWL_Dash(3, 3, 0);
-      break;
-    case BorderStyle::BEVELED:
-      fBorderWidth *= 2;
-      crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1);
-      crRightBottom = crBackground / 2.0f;
-      break;
-    case BorderStyle::INSET:
-      fBorderWidth *= 2;
-      crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0.5);
-      crRightBottom = CPWL_Color(COLORTYPE_GRAY, 0.75);
-      break;
-    default:
-      break;
-  }
-
-  CFX_FloatRect rcWindow = GetRotatedRect();
-  CFX_FloatRect rcClient = CPWL_Utils::DeflateRect(rcWindow, fBorderWidth);
-  CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
-  if (da.HasColor()) {
-    da.GetColor(iColorType, fc);
-    crText = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
-  }
-
-  int32_t nStyle = 0;
-  CFX_WideString csWCaption = pControl->GetNormalCaption();
-  if (csWCaption.GetLength() > 0) {
-    switch (csWCaption[0]) {
-      case L'l':
-        nStyle = PCS_CIRCLE;
-        break;
-      case L'8':
-        nStyle = PCS_CROSS;
-        break;
-      case L'u':
-        nStyle = PCS_DIAMOND;
-        break;
-      case L'n':
-        nStyle = PCS_SQUARE;
-        break;
-      case L'H':
-        nStyle = PCS_STAR;
-        break;
-      default:  // L'4'
-        nStyle = PCS_CHECK;
-        break;
-    }
-  } else {
-    nStyle = PCS_CHECK;
-  }
-
-  CFX_ByteString csAP_N_ON =
-      CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground) +
-      CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
-                                     crLeftTop, crRightBottom, nBorderStyle,
-                                     dsBorder);
-
-  CFX_ByteString csAP_N_OFF = csAP_N_ON;
-
-  switch (nBorderStyle) {
-    case BorderStyle::BEVELED: {
-      CPWL_Color crTemp = crLeftTop;
-      crLeftTop = crRightBottom;
-      crRightBottom = crTemp;
-      break;
-    }
-    case BorderStyle::INSET: {
-      crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0);
-      crRightBottom = CPWL_Color(COLORTYPE_GRAY, 1);
-      break;
-    }
-    default:
-      break;
-  }
-
-  CFX_ByteString 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;
-
-  csAP_N_ON += CPWL_Utils::GetCheckBoxAppStream(rcClient, nStyle, crText);
-  csAP_D_ON += CPWL_Utils::GetCheckBoxAppStream(rcClient, nStyle, crText);
-
-  WriteAppearance("N", GetRotatedRect(), GetMatrix(), csAP_N_ON,
-                  pControl->GetCheckedAPState());
-  WriteAppearance("N", GetRotatedRect(), GetMatrix(), csAP_N_OFF, "Off");
-
-  WriteAppearance("D", GetRotatedRect(), GetMatrix(), csAP_D_ON,
-                  pControl->GetCheckedAPState());
-  WriteAppearance("D", GetRotatedRect(), GetMatrix(), csAP_D_OFF, "Off");
-
-  CFX_ByteString csAS = GetAppState();
-  if (csAS.IsEmpty())
-    SetAppState("Off");
-}
-
-void CPDFSDK_Widget::ResetAppearance_RadioButton() {
-  CPDF_FormControl* pControl = GetFormControl();
-  CPWL_Color crBackground, crBorder, crText;
-  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]);
-
-  pControl->GetOriginalBorderColor(iColorType, fc);
-  if (iColorType > 0)
-    crBorder = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
-
-  FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth();
-  CPWL_Dash dsBorder(3, 0, 0);
-  CPWL_Color crLeftTop;
-  CPWL_Color crRightBottom;
-  BorderStyle nBorderStyle = GetBorderStyle();
-  switch (nBorderStyle) {
-    case BorderStyle::DASH:
-      dsBorder = CPWL_Dash(3, 3, 0);
-      break;
-    case BorderStyle::BEVELED:
-      fBorderWidth *= 2;
-      crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1);
-      crRightBottom = crBackground / 2.0f;
-      break;
-    case BorderStyle::INSET:
-      fBorderWidth *= 2;
-      crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0.5);
-      crRightBottom = CPWL_Color(COLORTYPE_GRAY, 0.75);
-      break;
-    default:
-      break;
-  }
-
-  CFX_FloatRect rcWindow = GetRotatedRect();
-  CFX_FloatRect rcClient = CPWL_Utils::DeflateRect(rcWindow, fBorderWidth);
-
-  CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
-  if (da.HasColor()) {
-    da.GetColor(iColorType, fc);
-    crText = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
-  }
-
-  int32_t nStyle = 0;
-  CFX_WideString csWCaption = pControl->GetNormalCaption();
-  if (csWCaption.GetLength() > 0) {
-    switch (csWCaption[0]) {
-      default:  // L'l':
-        nStyle = PCS_CIRCLE;
-        break;
-      case L'8':
-        nStyle = PCS_CROSS;
-        break;
-      case L'u':
-        nStyle = PCS_DIAMOND;
-        break;
-      case L'n':
-        nStyle = PCS_SQUARE;
-        break;
-      case L'H':
-        nStyle = PCS_STAR;
-        break;
-      case L'4':
-        nStyle = PCS_CHECK;
-        break;
-    }
-  } else {
-    nStyle = PCS_CIRCLE;
-  }
-
-  CFX_ByteString csAP_N_ON;
-
-  CFX_FloatRect rcCenter =
-      CPWL_Utils::DeflateRect(CPWL_Utils::GetCenterSquare(rcWindow), 1.0f);
-
-  if (nStyle == PCS_CIRCLE) {
-    if (nBorderStyle == BorderStyle::BEVELED) {
-      crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1);
-      crRightBottom = crBackground - 0.25f;
-    } else if (nBorderStyle == BorderStyle::INSET) {
-      crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0.5f);
-      crRightBottom = CPWL_Color(COLORTYPE_GRAY, 0.75f);
-    }
-
-    csAP_N_ON = CPWL_Utils::GetCircleFillAppStream(rcCenter, crBackground) +
-                CPWL_Utils::GetCircleBorderAppStream(
-                    rcCenter, fBorderWidth, crBorder, crLeftTop, crRightBottom,
-                    nBorderStyle, dsBorder);
-  } else {
-    csAP_N_ON = CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground) +
-                CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
-                                               crLeftTop, crRightBottom,
-                                               nBorderStyle, dsBorder);
-  }
-
-  CFX_ByteString csAP_N_OFF = csAP_N_ON;
-
-  switch (nBorderStyle) {
-    case BorderStyle::BEVELED: {
-      CPWL_Color crTemp = crLeftTop;
-      crLeftTop = crRightBottom;
-      crRightBottom = crTemp;
-      break;
-    }
-    case BorderStyle::INSET: {
-      crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0);
-      crRightBottom = CPWL_Color(COLORTYPE_GRAY, 1);
-      break;
-    }
-    default:
-      break;
-  }
-
-  CFX_ByteString csAP_D_ON;
-
-  if (nStyle == PCS_CIRCLE) {
-    CPWL_Color crBK = crBackground - 0.25f;
-    if (nBorderStyle == BorderStyle::BEVELED) {
-      crLeftTop = crBackground - 0.25f;
-      crRightBottom = CPWL_Color(COLORTYPE_GRAY, 1);
-      crBK = crBackground;
-    } else if (nBorderStyle == BorderStyle::INSET) {
-      crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0);
-      crRightBottom = CPWL_Color(COLORTYPE_GRAY, 1);
-    }
-
-    csAP_D_ON = CPWL_Utils::GetCircleFillAppStream(rcCenter, crBK) +
-                CPWL_Utils::GetCircleBorderAppStream(
-                    rcCenter, fBorderWidth, crBorder, crLeftTop, crRightBottom,
-                    nBorderStyle, dsBorder);
-  } else {
-    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;
-
-  csAP_N_ON += CPWL_Utils::GetRadioButtonAppStream(rcClient, nStyle, crText);
-  csAP_D_ON += CPWL_Utils::GetRadioButtonAppStream(rcClient, nStyle, crText);
-
-  WriteAppearance("N", GetRotatedRect(), GetMatrix(), csAP_N_ON,
-                  pControl->GetCheckedAPState());
-  WriteAppearance("N", GetRotatedRect(), GetMatrix(), csAP_N_OFF, "Off");
-
-  WriteAppearance("D", GetRotatedRect(), GetMatrix(), csAP_D_ON,
-                  pControl->GetCheckedAPState());
-  WriteAppearance("D", GetRotatedRect(), GetMatrix(), csAP_D_OFF, "Off");
-
-  CFX_ByteString csAS = GetAppState();
-  if (csAS.IsEmpty())
-    SetAppState("Off");
-}
-
-void CPDFSDK_Widget::ResetAppearance_ComboBox(const CFX_WideString* sValue) {
-  CPDF_FormControl* pControl = GetFormControl();
-  CPDF_FormField* pField = pControl->GetField();
-  CFX_ByteTextBuf sBody, sLines;
-
-  CFX_FloatRect rcClient = GetClientRect();
-  CFX_FloatRect rcButton = rcClient;
-  rcButton.left = rcButton.right - 13;
-  rcButton.Normalize();
-
-  std::unique_ptr<CFX_Edit> pEdit(new CFX_Edit);
-  pEdit->EnableRefresh(false);
-
-  CBA_FontMap font_map(this, m_pInterForm->GetFormFillEnv()->GetSysHandler());
-  pEdit->SetFontMap(&font_map);
-
-  CFX_FloatRect rcEdit = rcClient;
-  rcEdit.right = rcButton.left;
-  rcEdit.Normalize();
-
-  pEdit->SetPlateRect(rcEdit);
-  pEdit->SetAlignmentV(1, true);
-
-  FX_FLOAT fFontSize = GetFontSize();
-  if (IsFloatZero(fFontSize))
-    pEdit->SetAutoFontSize(true, true);
-  else
-    pEdit->SetFontSize(fFontSize);
-
-  pEdit->Initialize();
-
-  if (sValue) {
-    pEdit->SetText(*sValue);
-  } else {
-    int32_t nCurSel = pField->GetSelectedIndex(0);
-    if (nCurSel < 0)
-      pEdit->SetText(pField->GetValue());
-    else
-      pEdit->SetText(pField->GetOptionLabel(nCurSel));
-  }
-
-  CFX_FloatRect rcContent = pEdit->GetContentRect();
-
-  CFX_ByteString sEdit =
-      CPWL_Utils::GetEditAppStream(pEdit.get(), CFX_PointF());
-  if (sEdit.GetLength() > 0) {
-    sBody << "/Tx BMC\n"
-          << "q\n";
-    if (rcContent.Width() > rcEdit.Width() ||
-        rcContent.Height() > rcEdit.Height()) {
-      sBody << rcEdit.left << " " << rcEdit.bottom << " " << rcEdit.Width()
-            << " " << rcEdit.Height() << " re\nW\nn\n";
-    }
-
-    CPWL_Color crText = GetTextPWLColor();
-    sBody << "BT\n"
-          << CPWL_Utils::GetColorAppStream(crText) << sEdit << "ET\n"
-          << "Q\nEMC\n";
-  }
-
-  sBody << CPWL_Utils::GetDropButtonAppStream(rcButton);
-
-  CFX_ByteString sAP = GetBackgroundAppStream() + GetBorderAppStream() +
-                       sLines.AsStringC() + sBody.AsStringC();
-
-  WriteAppearance("N", GetRotatedRect(), GetMatrix(), sAP);
-}
-
-void CPDFSDK_Widget::ResetAppearance_ListBox() {
-  CPDF_FormControl* pControl = GetFormControl();
-  CPDF_FormField* pField = pControl->GetField();
-  CFX_FloatRect rcClient = GetClientRect();
-  CFX_ByteTextBuf sBody, sLines;
-
-  std::unique_ptr<CFX_Edit> pEdit(new CFX_Edit);
-  pEdit->EnableRefresh(false);
-
-  CBA_FontMap font_map(this, m_pInterForm->GetFormFillEnv()->GetSysHandler());
-  pEdit->SetFontMap(&font_map);
-
-  pEdit->SetPlateRect(CFX_FloatRect(rcClient.left, 0.0f, rcClient.right, 0.0f));
-
-  FX_FLOAT fFontSize = GetFontSize();
-
-  pEdit->SetFontSize(IsFloatZero(fFontSize) ? 12.0f : fFontSize);
-
-  pEdit->Initialize();
-
-  CFX_ByteTextBuf sList;
-  FX_FLOAT fy = rcClient.top;
-
-  int32_t nTop = pField->GetTopVisibleIndex();
-  int32_t nCount = pField->CountOptions();
-  int32_t nSelCount = pField->CountSelectedItems();
-
-  for (int32_t i = nTop; i < nCount; ++i) {
-    bool bSelected = false;
-    for (int32_t j = 0; j < nSelCount; ++j) {
-      if (pField->GetSelectedIndex(j) == i) {
-        bSelected = true;
-        break;
-      }
-    }
-
-    pEdit->SetText(pField->GetOptionLabel(i));
-
-    CFX_FloatRect rcContent = pEdit->GetContentRect();
-    FX_FLOAT fItemHeight = rcContent.Height();
-
-    if (bSelected) {
-      CFX_FloatRect rcItem =
-          CFX_FloatRect(rcClient.left, fy - fItemHeight, rcClient.right, fy);
-      sList << "q\n"
-            << CPWL_Utils::GetColorAppStream(
-                   CPWL_Color(COLORTYPE_RGB, 0, 51.0f / 255.0f,
-                              113.0f / 255.0f),
-                   true)
-            << rcItem.left << " " << rcItem.bottom << " " << rcItem.Width()
-            << " " << rcItem.Height() << " re f\n"
-            << "Q\n";
-
-      sList << "BT\n"
-            << CPWL_Utils::GetColorAppStream(CPWL_Color(COLORTYPE_GRAY, 1),
-                                             true)
-            << 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_PointF(0.0f, fy))
-            << "ET\n";
-    }
-
-    fy -= fItemHeight;
-  }
-
-  if (sList.GetSize() > 0) {
-    sBody << "/Tx BMC\n"
-          << "q\n"
-          << rcClient.left << " " << rcClient.bottom << " " << rcClient.Width()
-          << " " << rcClient.Height() << " re\nW\nn\n";
-    sBody << sList << "Q\nEMC\n";
-  }
-
-  CFX_ByteString sAP = GetBackgroundAppStream() + GetBorderAppStream() +
-                       sLines.AsStringC() + sBody.AsStringC();
-
-  WriteAppearance("N", GetRotatedRect(), GetMatrix(), sAP);
-}
-
-void CPDFSDK_Widget::ResetAppearance_TextField(const CFX_WideString* sValue) {
-  CPDF_FormControl* pControl = GetFormControl();
-  CPDF_FormField* pField = pControl->GetField();
-  CFX_ByteTextBuf sBody, sLines;
-
-  std::unique_ptr<CFX_Edit> pEdit(new CFX_Edit);
-  pEdit->EnableRefresh(false);
-
-  CBA_FontMap font_map(this, m_pInterForm->GetFormFillEnv()->GetSysHandler());
-  pEdit->SetFontMap(&font_map);
-
-  CFX_FloatRect rcClient = GetClientRect();
-  pEdit->SetPlateRect(rcClient);
-  pEdit->SetAlignmentH(pControl->GetControlAlignment(), true);
-
-  uint32_t dwFieldFlags = pField->GetFieldFlags();
-  bool bMultiLine = (dwFieldFlags >> 12) & 1;
-
-  if (bMultiLine) {
-    pEdit->SetMultiLine(true, true);
-    pEdit->SetAutoReturn(true, true);
-  } else {
-    pEdit->SetAlignmentV(1, true);
-  }
-
-  uint16_t subWord = 0;
-  if ((dwFieldFlags >> 13) & 1) {
-    subWord = '*';
-    pEdit->SetPasswordChar(subWord, true);
-  }
-
-  int nMaxLen = pField->GetMaxLen();
-  bool bCharArray = (dwFieldFlags >> 24) & 1;
-  FX_FLOAT fFontSize = GetFontSize();
-
-#ifdef PDF_ENABLE_XFA
-  CFX_WideString sValueTmp;
-  if (!sValue && GetMixXFAWidget()) {
-    sValueTmp = GetValue(true);
-    sValue = &sValueTmp;
-  }
-#endif  // PDF_ENABLE_XFA
-
-  if (nMaxLen > 0) {
-    if (bCharArray) {
-      pEdit->SetCharArray(nMaxLen);
-
-      if (IsFloatZero(fFontSize)) {
-        fFontSize = CPWL_Edit::GetCharArrayAutoFontSize(font_map.GetPDFFont(0),
-                                                        rcClient, nMaxLen);
-      }
-    } else {
-      if (sValue)
-        nMaxLen = sValue->GetLength();
-      pEdit->SetLimitChar(nMaxLen);
-    }
-  }
-
-  if (IsFloatZero(fFontSize))
-    pEdit->SetAutoFontSize(true, true);
-  else
-    pEdit->SetFontSize(fFontSize);
-
-  pEdit->Initialize();
-  pEdit->SetText(sValue ? *sValue : pField->GetValue());
-
-  CFX_FloatRect rcContent = pEdit->GetContentRect();
-  CFX_ByteString sEdit = CPWL_Utils::GetEditAppStream(
-      pEdit.get(), CFX_PointF(), nullptr, !bCharArray, subWord);
-
-  if (sEdit.GetLength() > 0) {
-    sBody << "/Tx BMC\n"
-          << "q\n";
-    if (rcContent.Width() > rcClient.Width() ||
-        rcContent.Height() > rcClient.Height()) {
-      sBody << rcClient.left << " " << rcClient.bottom << " "
-            << rcClient.Width() << " " << rcClient.Height() << " re\nW\nn\n";
-    }
-    CPWL_Color crText = GetTextPWLColor();
-    sBody << "BT\n"
-          << CPWL_Utils::GetColorAppStream(crText) << sEdit << "ET\n"
-          << "Q\nEMC\n";
-  }
-
-  if (bCharArray) {
-    switch (GetBorderStyle()) {
-      case BorderStyle::SOLID: {
-        CFX_ByteString sColor =
-            CPWL_Utils::GetColorAppStream(GetBorderPWLColor(), false);
-        if (sColor.GetLength() > 0) {
-          sLines << "q\n"
-                 << GetBorderWidth() << " w\n"
-                 << CPWL_Utils::GetColorAppStream(GetBorderPWLColor(), false)
-                 << " 2 J 0 j\n";
-
-          for (int32_t i = 1; i < nMaxLen; ++i) {
-            sLines << rcClient.left +
-                          ((rcClient.right - rcClient.left) / nMaxLen) * i
-                   << " " << rcClient.bottom << " m\n"
-                   << rcClient.left +
-                          ((rcClient.right - rcClient.left) / nMaxLen) * i
-                   << " " << rcClient.top << " l S\n";
-          }
-
-          sLines << "Q\n";
-        }
-        break;
-      }
-      case BorderStyle::DASH: {
-        CFX_ByteString sColor =
-            CPWL_Utils::GetColorAppStream(GetBorderPWLColor(), false);
-        if (sColor.GetLength() > 0) {
-          CPWL_Dash dsBorder = CPWL_Dash(3, 3, 0);
-
-          sLines << "q\n"
-                 << GetBorderWidth() << " w\n"
-                 << CPWL_Utils::GetColorAppStream(GetBorderPWLColor(), false)
-                 << "[" << dsBorder.nDash << " " << dsBorder.nGap << "] "
-                 << dsBorder.nPhase << " d\n";
-
-          for (int32_t i = 1; i < nMaxLen; ++i) {
-            sLines << rcClient.left +
-                          ((rcClient.right - rcClient.left) / nMaxLen) * i
-                   << " " << rcClient.bottom << " m\n"
-                   << rcClient.left +
-                          ((rcClient.right - rcClient.left) / nMaxLen) * i
-                   << " " << rcClient.top << " l S\n";
-          }
-
-          sLines << "Q\n";
-        }
-        break;
-      }
-      default:
-        break;
-    }
-  }
-
-  CFX_ByteString sAP = GetBackgroundAppStream() + GetBorderAppStream() +
-                       sLines.AsStringC() + sBody.AsStringC();
-  WriteAppearance("N", GetRotatedRect(), GetMatrix(), sAP);
+                         m_pInterForm->GetHighlightColor(fieldType)));
 }
 
 CFX_FloatRect CPDFSDK_Widget::GetClientRect() const {
   CFX_FloatRect rcWindow = GetRotatedRect();
-  FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth();
+  float fBorderWidth = (float)GetBorderWidth();
   switch (GetBorderStyle()) {
     case BorderStyle::BEVELED:
     case BorderStyle::INSET:
@@ -1651,14 +871,13 @@
     default:
       break;
   }
-
-  return CPWL_Utils::DeflateRect(rcWindow, fBorderWidth);
+  return rcWindow.GetDeflated(fBorderWidth, fBorderWidth);
 }
 
 CFX_FloatRect CPDFSDK_Widget::GetRotatedRect() const {
   CFX_FloatRect rectAnnot = GetRect();
-  FX_FLOAT fWidth = rectAnnot.right - rectAnnot.left;
-  FX_FLOAT fHeight = rectAnnot.top - rectAnnot.bottom;
+  float fWidth = rectAnnot.right - rectAnnot.left;
+  float fHeight = rectAnnot.top - rectAnnot.bottom;
 
   CPDF_FormControl* pControl = GetFormControl();
   CFX_FloatRect rcPDFWindow;
@@ -1677,58 +896,16 @@
   return rcPDFWindow;
 }
 
-CFX_ByteString CPDFSDK_Widget::GetBackgroundAppStream() const {
-  CPWL_Color crBackground = GetFillPWLColor();
-  if (crBackground.nColorType != COLORTYPE_TRANSPARENT)
-    return CPWL_Utils::GetRectFillAppStream(GetRotatedRect(), crBackground);
-
-  return "";
-}
-
-CFX_ByteString CPDFSDK_Widget::GetBorderAppStream() const {
-  CFX_FloatRect rcWindow = GetRotatedRect();
-  CPWL_Color crBorder = GetBorderPWLColor();
-  CPWL_Color crBackground = GetFillPWLColor();
-  CPWL_Color crLeftTop, crRightBottom;
-
-  FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth();
-  CPWL_Dash dsBorder(3, 0, 0);
-
-  BorderStyle nBorderStyle = GetBorderStyle();
-  switch (nBorderStyle) {
-    case BorderStyle::DASH:
-      dsBorder = CPWL_Dash(3, 3, 0);
-      break;
-    case BorderStyle::BEVELED:
-      fBorderWidth *= 2;
-      crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1);
-      crRightBottom = crBackground / 2.0f;
-      break;
-    case BorderStyle::INSET:
-      fBorderWidth *= 2;
-      crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0.5);
-      crRightBottom = CPWL_Color(COLORTYPE_GRAY, 0.75);
-      break;
-    default:
-      break;
-  }
-
-  return CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
-                                        crLeftTop, crRightBottom, nBorderStyle,
-                                        dsBorder);
-}
-
 CFX_Matrix CPDFSDK_Widget::GetMatrix() const {
   CFX_Matrix mt;
   CPDF_FormControl* pControl = GetFormControl();
   CFX_FloatRect rcAnnot = GetRect();
-  FX_FLOAT fWidth = rcAnnot.right - rcAnnot.left;
-  FX_FLOAT fHeight = rcAnnot.top - rcAnnot.bottom;
+  float fWidth = rcAnnot.right - rcAnnot.left;
+  float fHeight = rcAnnot.top - rcAnnot.bottom;
 
   switch (abs(pControl->GetRotation() % 360)) {
-    case 0:
     default:
-      mt = CFX_Matrix(1, 0, 0, 1, 0, 0);
+    case 0:
       break;
     case 90:
       mt = CFX_Matrix(0, 1, -1, 0, fWidth, 0);
@@ -1744,75 +921,47 @@
   return mt;
 }
 
-CPWL_Color CPDFSDK_Widget::GetTextPWLColor() const {
-  CPWL_Color crText = CPWL_Color(COLORTYPE_GRAY, 0);
+CFX_Color CPDFSDK_Widget::GetTextPWLColor() const {
+  CFX_Color crText = CFX_Color(CFX_Color::kGray, 0);
 
   CPDF_FormControl* pFormCtrl = GetFormControl();
   CPDF_DefaultAppearance da = pFormCtrl->GetDefaultAppearance();
   if (da.HasColor()) {
     int32_t iColorType;
-    FX_FLOAT fc[4];
+    float fc[4];
     da.GetColor(iColorType, fc);
-    crText = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
+    crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
   }
 
   return crText;
 }
 
-CPWL_Color CPDFSDK_Widget::GetBorderPWLColor() const {
-  CPWL_Color crBorder;
+CFX_Color CPDFSDK_Widget::GetBorderPWLColor() const {
+  CFX_Color crBorder;
 
   CPDF_FormControl* pFormCtrl = GetFormControl();
   int32_t iColorType;
-  FX_FLOAT fc[4];
+  float fc[4];
   pFormCtrl->GetOriginalBorderColor(iColorType, fc);
   if (iColorType > 0)
-    crBorder = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
+    crBorder = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
 
   return crBorder;
 }
 
-CPWL_Color CPDFSDK_Widget::GetFillPWLColor() const {
-  CPWL_Color crFill;
+CFX_Color CPDFSDK_Widget::GetFillPWLColor() const {
+  CFX_Color crFill;
 
   CPDF_FormControl* pFormCtrl = GetFormControl();
   int32_t iColorType;
-  FX_FLOAT fc[4];
+  float fc[4];
   pFormCtrl->GetOriginalBackgroundColor(iColorType, fc);
   if (iColorType > 0)
-    crFill = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
+    crFill = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
 
   return crFill;
 }
 
-void CPDFSDK_Widget::AddImageToAppearance(const CFX_ByteString& sAPType,
-                                          CPDF_Stream* pImage) {
-  CPDF_Dictionary* pAPDict = m_pAnnot->GetAnnotDict()->GetDictFor("AP");
-  CPDF_Stream* pStream = pAPDict->GetStreamFor(sAPType);
-  CPDF_Dictionary* pStreamDict = pStream->GetDict();
-  CFX_ByteString sImageAlias = "IMG";
-
-  if (CPDF_Dictionary* pImageDict = pImage->GetDict()) {
-    sImageAlias = pImageDict->GetStringFor("Name");
-    if (sImageAlias.IsEmpty())
-      sImageAlias = "IMG";
-  }
-
-  CPDF_Document* pDoc = m_pPageView->GetPDFDocument();
-  CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
-  if (!pStreamResList)
-    pStreamResList = pStreamDict->SetNewFor<CPDF_Dictionary>("Resources");
-
-  CPDF_Dictionary* pXObject =
-      pStreamResList->SetNewFor<CPDF_Dictionary>("XObject");
-  pXObject->SetNewFor<CPDF_Reference>(sImageAlias, pDoc, pImage->GetObjNum());
-}
-
-void CPDFSDK_Widget::RemoveAppearance(const CFX_ByteString& sAPType) {
-  if (CPDF_Dictionary* pAPDict = m_pAnnot->GetAnnotDict()->GetDictFor("AP"))
-    pAPDict->RemoveFor(sAPType);
-}
-
 bool CPDFSDK_Widget::OnAAction(CPDF_AAction::AActionType type,
                                PDFSDK_FieldAction& data,
                                CPDFSDK_PageView* pPageView) {
@@ -1843,7 +992,7 @@
           param.m_wsNewText.Insert(data.nSelStart, data.sChange[i]);
         param.m_wsPrevText = data.sValue;
 
-        CXFA_WidgetAcc* pAcc = hWidget->GetDataAcc();
+        CXFA_WidgetAcc* pAcc = hWidget->GetNode()->GetWidgetAcc();
         param.m_pTarget = pAcc;
         int32_t nRet = pXFAWidgetHandler->ProcessEvent(pAcc, &param);
 
@@ -1859,7 +1008,7 @@
 
   CPDF_Action action = GetAAction(type);
   if (action.GetDict() && action.GetType() != CPDF_Action::Unknown) {
-    CPDFSDK_ActionHandler* pActionHandler = pFormFillEnv->GetActionHander();
+    CPDFSDK_ActionHandler* pActionHandler = pFormFillEnv->GetActionHandler();
     return pActionHandler->DoAction_Field(action, type, pFormFillEnv,
                                           GetFormField(), data);
   }
@@ -1893,18 +1042,10 @@
       break;
   }
 
-  return CPDF_Action();
+  return CPDF_Action(nullptr);
 }
 
-CFX_WideString CPDFSDK_Widget::GetAlternateName() const {
+WideString CPDFSDK_Widget::GetAlternateName() const {
   CPDF_FormField* pFormField = GetFormField();
   return pFormField->GetAlternateName();
 }
-
-int32_t CPDFSDK_Widget::GetAppearanceAge() const {
-  return m_nAppAge;
-}
-
-int32_t CPDFSDK_Widget::GetValueAge() const {
-  return m_nValueAge;
-}
diff --git a/fpdfsdk/cpdfsdk_widget.h b/fpdfsdk/cpdfsdk_widget.h
index 21e5169..4b11150 100644
--- a/fpdfsdk/cpdfsdk_widget.h
+++ b/fpdfsdk/cpdfsdk_widget.h
@@ -14,9 +14,10 @@
 #include "core/fpdfdoc/cpdf_annot.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/unowned_ptr.h"
+#include "core/fxge/cfx_color.h"
 #include "fpdfsdk/cpdfsdk_baannot.h"
 #include "fpdfsdk/pdfsdk_fieldaction.h"
-#include "fpdfsdk/pdfwindow/cpwl_color.h"
 
 class CFX_RenderDevice;
 class CPDF_Annot;
@@ -70,23 +71,23 @@
 
   int GetLayoutOrder() const override;
 
-  int GetFieldType() const;
+  FormFieldType GetFieldType() const;
   int GetFieldFlags() const;
   int GetRotate() const;
 
   bool GetFillColor(FX_COLORREF& color) const;
   bool GetBorderColor(FX_COLORREF& color) const;
   bool GetTextColor(FX_COLORREF& color) const;
-  FX_FLOAT GetFontSize() const;
+  float GetFontSize() const;
 
   int GetSelectedIndex(int nIndex) const;
 #ifndef PDF_ENABLE_XFA
-  CFX_WideString GetValue() const;
+  WideString GetValue() const;
 #else
-  CFX_WideString GetValue(bool bDisplay = true) const;
+  WideString GetValue(bool bDisplay = true) const;
 #endif  // PDF_ENABLE_XFA
-  CFX_WideString GetDefaultValue() const;
-  CFX_WideString GetOptionLabel(int nIndex) const;
+  WideString GetDefaultValue() const;
+  WideString GetOptionLabel(int nIndex) const;
   int CountOptions() const;
   bool IsOptionSelected(int nIndex) const;
   int GetTopVisibleIndex() const;
@@ -94,13 +95,13 @@
   int GetAlignment() const;
   int GetMaxLen() const;
 #ifdef PDF_ENABLE_XFA
-  CFX_WideString GetName() const;
+  WideString GetName() const;
 #endif  // PDF_ENABLE_XFA
-  CFX_WideString GetAlternateName() const;
+  WideString GetAlternateName() const;
 
   void SetCheck(bool bChecked, bool bNotify);
-  void SetValue(const CFX_WideString& sValue, bool bNotify);
-  void SetDefaultValue(const CFX_WideString& sValue);
+  void SetValue(const WideString& sValue, bool bNotify);
+  void SetDefaultValue(const WideString& sValue);
   void SetOptionSelection(int index, bool bSelected, bool bNotify);
   void ClearSelection(bool bNotify);
   void SetTopVisibleIndex(int index);
@@ -108,16 +109,16 @@
 #ifdef PDF_ENABLE_XFA
   void ResetAppearance(bool bValueChanged);
 #endif  // PDF_ENABLE_XFA
-  void ResetAppearance(const CFX_WideString* sValue, bool bValueChanged);
+  void ResetAppearance(const WideString* sValue, bool bValueChanged);
   void ResetFieldAppearance(bool bValueChanged);
   void UpdateField();
-  CFX_WideString OnFormat(bool& bFormatted);
+  WideString OnFormat(bool& bFormatted);
 
   bool OnAAction(CPDF_AAction::AActionType type,
                  PDFSDK_FieldAction& data,
                  CPDFSDK_PageView* pPageView);
 
-  CPDFSDK_InterForm* GetInterForm() const { return m_pInterForm; }
+  CPDFSDK_InterForm* GetInterForm() const { return m_pInterForm.Get(); }
   CPDF_FormField* GetFormField() const;
   CPDF_FormControl* GetFormControl() const;
   static CPDF_FormControl* GetFormControl(CPDF_InterForm* pInterForm,
@@ -129,45 +130,31 @@
   void ClearAppModified();
   bool IsAppModified() const;
 
-  int32_t GetAppearanceAge() const;
-  int32_t GetValueAge() const;
+  uint32_t GetAppearanceAge() const { return m_nAppearanceAge; }
+  uint32_t GetValueAge() const { return m_nValueAge; }
 
   bool IsWidgetAppearanceValid(CPDF_Annot::AppearanceMode mode);
   void DrawAppearance(CFX_RenderDevice* pDevice,
-                      const CFX_Matrix* pUser2Device,
+                      const CFX_Matrix& mtUser2Device,
                       CPDF_Annot::AppearanceMode mode,
                       const CPDF_RenderOptions* pOptions) override;
 
- private:
-  void ResetAppearance_PushButton();
-  void ResetAppearance_CheckBox();
-  void ResetAppearance_RadioButton();
-  void ResetAppearance_ComboBox(const CFX_WideString* sValue);
-  void ResetAppearance_ListBox();
-  void ResetAppearance_TextField(const CFX_WideString* sValue);
-
+  CFX_Matrix GetMatrix() const;
   CFX_FloatRect GetClientRect() const;
   CFX_FloatRect GetRotatedRect() const;
+  CFX_Color GetTextPWLColor() const;
+  CFX_Color GetBorderPWLColor() const;
+  CFX_Color GetFillPWLColor() const;
 
-  CFX_ByteString GetBackgroundAppStream() const;
-  CFX_ByteString GetBorderAppStream() const;
-  CFX_Matrix GetMatrix() const;
-
-  CPWL_Color GetTextPWLColor() const;
-  CPWL_Color GetBorderPWLColor() const;
-  CPWL_Color GetFillPWLColor() const;
-
-  void AddImageToAppearance(const CFX_ByteString& sAPType, CPDF_Stream* pImage);
-  void RemoveAppearance(const CFX_ByteString& sAPType);
-
-  CPDFSDK_InterForm* const m_pInterForm;
+ private:
+  UnownedPtr<CPDFSDK_InterForm> const m_pInterForm;
   bool m_bAppModified;
-  int32_t m_nAppAge;
-  int32_t m_nValueAge;
+  uint32_t m_nAppearanceAge;
+  uint32_t m_nValueAge;
 
 #ifdef PDF_ENABLE_XFA
-  mutable CXFA_FFWidget* m_hMixXFAWidget;
-  mutable CXFA_FFWidgetHandler* m_pWidgetHandler;
+  mutable UnownedPtr<CXFA_FFWidget> m_hMixXFAWidget;
+  mutable UnownedPtr<CXFA_FFWidgetHandler> m_pWidgetHandler;
 #endif  // PDF_ENABLE_XFA
 };
 
diff --git a/fpdfsdk/cpdfsdk_widgethandler.cpp b/fpdfsdk/cpdfsdk_widgethandler.cpp
index e85d24c..dcce7b6 100644
--- a/fpdfsdk/cpdfsdk_widgethandler.cpp
+++ b/fpdfsdk/cpdfsdk_widgethandler.cpp
@@ -25,7 +25,8 @@
 
 CPDFSDK_WidgetHandler::CPDFSDK_WidgetHandler(
     CPDFSDK_FormFillEnvironment* pFormFillEnv)
-    : m_pFormFillEnv(pFormFillEnv), m_pFormFiller(nullptr) {}
+    : m_pFormFillEnv(pFormFillEnv),
+      m_pFormFiller(pFormFillEnv->GetInteractiveFormFiller()) {}
 
 CPDFSDK_WidgetHandler::~CPDFSDK_WidgetHandler() {}
 
@@ -42,12 +43,11 @@
   if ((nFieldFlags & FIELDFLAG_READONLY) == FIELDFLAG_READONLY)
     return false;
 
-  if (pWidget->GetFieldType() == FIELDTYPE_PUSHBUTTON)
+  if (pWidget->GetFieldType() == FormFieldType::kPushButton)
     return true;
 
   CPDF_Page* pPage = pWidget->GetPDFPage();
-  CPDF_Document* pDocument = pPage->m_pDocument;
-  uint32_t dwPermissions = pDocument->GetUserPermissions();
+  uint32_t dwPermissions = pPage->m_pDocument->GetUserPermissions();
   return (dwPermissions & FPDFPERM_FILL_FORM) ||
          (dwPermissions & FPDFPERM_ANNOT_FORM);
 }
@@ -95,7 +95,7 @@
                                    bool bDrawAnnots) {
   if (pAnnot->IsSignatureWidget()) {
     static_cast<CPDFSDK_BAAnnot*>(pAnnot)->DrawAppearance(
-        pDevice, pUser2Device, CPDF_Annot::Normal, nullptr);
+        pDevice, *pUser2Device, CPDF_Annot::Normal, nullptr);
   } else {
     if (m_pFormFiller)
       m_pFormFiller->OnDraw(pPageView, pAnnot, pDevice, pUser2Device);
@@ -227,18 +227,23 @@
   if (!pWidget->IsAppearanceValid())
     pWidget->ResetAppearance(nullptr, false);
 
-  int nFieldType = pWidget->GetFieldType();
-  if (nFieldType == FIELDTYPE_TEXTFIELD || nFieldType == FIELDTYPE_COMBOBOX) {
+  FormFieldType fieldType = pWidget->GetFieldType();
+  if (fieldType == FormFieldType::kTextField ||
+      fieldType == FormFieldType::kComboBox) {
     bool bFormatted = false;
-    CFX_WideString sValue = pWidget->OnFormat(bFormatted);
-    if (bFormatted && nFieldType == FIELDTYPE_COMBOBOX)
+    CPDFSDK_Annot::ObservedPtr pObserved(pWidget);
+    WideString sValue = pWidget->OnFormat(bFormatted);
+    if (!pObserved)
+      return;
+
+    if (bFormatted && fieldType == FormFieldType::kComboBox)
       pWidget->ResetAppearance(&sValue, false);
   }
 
 #ifdef PDF_ENABLE_XFA
   CPDFSDK_PageView* pPageView = pAnnot->GetPageView();
   CPDFXFA_Context* pContext = pPageView->GetFormFillEnv()->GetXFAContext();
-  if (pContext->GetDocType() == DOCTYPE_STATIC_XFA) {
+  if (pContext->GetFormType() == FormType::kXFAForeground) {
     if (!pWidget->IsAppearanceValid() && !pWidget->GetValue().IsEmpty())
       pWidget->ResetAppearance(false);
   }
@@ -273,8 +278,20 @@
                                                  CPDFSDK_Annot* pAnnot) {
   if (!pAnnot->IsSignatureWidget() && m_pFormFiller)
     return CFX_FloatRect(m_pFormFiller->GetViewBBox(pPageView, pAnnot));
+  return CFX_FloatRect();
+}
 
-  return CFX_FloatRect(0, 0, 0, 0);
+WideString CPDFSDK_WidgetHandler::GetSelectedText(CPDFSDK_Annot* pAnnot) {
+  if (!pAnnot->IsSignatureWidget() && m_pFormFiller)
+    return m_pFormFiller->GetSelectedText(pAnnot);
+
+  return WideString();
+}
+
+void CPDFSDK_WidgetHandler::ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                                             const WideString& text) {
+  if (!pAnnot->IsSignatureWidget() && m_pFormFiller)
+    m_pFormFiller->ReplaceSelection(pAnnot, text);
 }
 
 bool CPDFSDK_WidgetHandler::HitTest(CPDFSDK_PageView* pPageView,
diff --git a/fpdfsdk/cpdfsdk_widgethandler.h b/fpdfsdk/cpdfsdk_widgethandler.h
index 6e4d50b..f8aa7de 100644
--- a/fpdfsdk/cpdfsdk_widgethandler.h
+++ b/fpdfsdk/cpdfsdk_widgethandler.h
@@ -7,8 +7,8 @@
 #ifndef FPDFSDK_CPDFSDK_WIDGETHANDLER_H_
 #define FPDFSDK_CPDFSDK_WIDGETHANDLER_H_
 
-#include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_coordinates.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "fpdfsdk/ipdfsdk_annothandler.h"
 
 class CFFL_InteractiveFormFiller;
@@ -37,6 +37,8 @@
   void ReleaseAnnot(CPDFSDK_Annot* pAnnot) override;
   CFX_FloatRect GetViewBBox(CPDFSDK_PageView* pPageView,
                             CPDFSDK_Annot* pAnnot) override;
+  WideString GetSelectedText(CPDFSDK_Annot* pAnnot) override;
+  void ReplaceSelection(CPDFSDK_Annot* pAnnot, const WideString& text) override;
   bool HitTest(CPDFSDK_PageView* pPageView,
                CPDFSDK_Annot* pAnnot,
                const CFX_PointF& point) override;
@@ -96,14 +98,13 @@
                          CPDFSDK_Annot::ObservedPtr* pNewAnnot) override;
 #endif  // PDF_ENABLE_XFA
 
-  void SetFormFiller(CFFL_InteractiveFormFiller* pFiller) {
-    m_pFormFiller = pFiller;
+  CFFL_InteractiveFormFiller* GetFormFiller() const {
+    return m_pFormFiller.Get();
   }
-  CFFL_InteractiveFormFiller* GetFormFiller() { return m_pFormFiller; }
 
  private:
-  CPDFSDK_FormFillEnvironment* m_pFormFillEnv;
-  CFFL_InteractiveFormFiller* m_pFormFiller;
+  UnownedPtr<CPDFSDK_FormFillEnvironment> const m_pFormFillEnv;
+  UnownedPtr<CFFL_InteractiveFormFiller> const m_pFormFiller;
 };
 
 #endif  // FPDFSDK_CPDFSDK_WIDGETHANDLER_H_
diff --git a/fpdfsdk/cpdfsdk_xfawidget.cpp b/fpdfsdk/cpdfsdk_xfawidget.cpp
index b30e5f3..af08023 100644
--- a/fpdfsdk/cpdfsdk_xfawidget.cpp
+++ b/fpdfsdk/cpdfsdk_xfawidget.cpp
@@ -7,7 +7,7 @@
 #include "fpdfsdk/cpdfsdk_xfawidget.h"
 
 #include "fpdfsdk/ipdfsdk_annothandler.h"
-#include "xfa/fxfa/xfa_ffwidget.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
 
 CPDFSDK_XFAWidget::CPDFSDK_XFAWidget(CXFA_FFWidget* pAnnot,
                                      CPDFSDK_PageView* pPageView,
@@ -16,12 +16,14 @@
       m_pInterForm(pInterForm),
       m_hXFAWidget(pAnnot) {}
 
+CPDFSDK_XFAWidget::~CPDFSDK_XFAWidget() {}
+
 bool CPDFSDK_XFAWidget::IsXFAField() {
   return true;
 }
 
 CXFA_FFWidget* CPDFSDK_XFAWidget::GetXFAWidget() const {
-  return m_hXFAWidget;
+  return m_hXFAWidget.Get();
 }
 
 CPDF_Annot::Subtype CPDFSDK_XFAWidget::GetAnnotSubtype() const {
diff --git a/fpdfsdk/cpdfsdk_xfawidget.h b/fpdfsdk/cpdfsdk_xfawidget.h
index 9d0be75..d2635eb 100644
--- a/fpdfsdk/cpdfsdk_xfawidget.h
+++ b/fpdfsdk/cpdfsdk_xfawidget.h
@@ -9,6 +9,7 @@
 
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "fpdfsdk/cpdfsdk_annot.h"
 
 class CPDFSDK_InterForm;
@@ -20,18 +21,19 @@
   CPDFSDK_XFAWidget(CXFA_FFWidget* pAnnot,
                     CPDFSDK_PageView* pPageView,
                     CPDFSDK_InterForm* pInterForm);
-  ~CPDFSDK_XFAWidget() override {}
+  ~CPDFSDK_XFAWidget() override;
 
+  // CPDFSDK_Annot:
   bool IsXFAField() override;
   CXFA_FFWidget* GetXFAWidget() const override;
   CPDF_Annot::Subtype GetAnnotSubtype() const override;
   CFX_FloatRect GetRect() const override;
 
-  CPDFSDK_InterForm* GetInterForm() { return m_pInterForm; }
+  CPDFSDK_InterForm* GetInterForm() const { return m_pInterForm.Get(); }
 
  private:
-  CPDFSDK_InterForm* m_pInterForm;
-  CXFA_FFWidget* m_hXFAWidget;
+  UnownedPtr<CPDFSDK_InterForm> m_pInterForm;
+  UnownedPtr<CXFA_FFWidget> m_hXFAWidget;
 };
 
 #endif  // FPDFSDK_CPDFSDK_XFAWIDGET_H_
diff --git a/fpdfsdk/cpdfsdk_xfawidgethandler.cpp b/fpdfsdk/cpdfsdk_xfawidgethandler.cpp
index 653eb8a..897e16d 100644
--- a/fpdfsdk/cpdfsdk_xfawidgethandler.cpp
+++ b/fpdfsdk/cpdfsdk_xfawidgethandler.cpp
@@ -15,12 +15,13 @@
 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
 #include "xfa/fwl/cfwl_app.h"
 #include "xfa/fwl/fwl_widgethit.h"
+#include "xfa/fxfa/cxfa_ffdocview.h"
+#include "xfa/fxfa/cxfa_ffpageview.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
+#include "xfa/fxfa/cxfa_ffwidgethandler.h"
 #include "xfa/fxfa/fxfa_basic.h"
-#include "xfa/fxfa/xfa_ffdocview.h"
-#include "xfa/fxfa/xfa_ffpageview.h"
-#include "xfa/fxfa/xfa_ffwidget.h"
-#include "xfa/fxfa/xfa_ffwidgethandler.h"
-#include "xfa/fxgraphics/cfx_graphics.h"
+#include "xfa/fxfa/parser/cxfa_node.h"
+#include "xfa/fxgraphics/cxfa_graphics.h"
 
 CPDFSDK_XFAWidgetHandler::CPDFSDK_XFAWidgetHandler(
     CPDFSDK_FormFillEnvironment* pFormFillEnv)
@@ -53,14 +54,14 @@
   ASSERT(pPageView);
   ASSERT(pAnnot);
 
-  CFX_Graphics gs(pDevice);
+  CXFA_Graphics gs(pDevice);
 
   CFX_Matrix mt = *pUser2Device;
   bool bIsHighlight = false;
   if (pPageView->GetFormFillEnv()->GetFocusAnnot() != pAnnot)
     bIsHighlight = true;
 
-  GetXFAWidgetHandler(pAnnot)->RenderWidget(pAnnot->GetXFAWidget(), &gs, &mt,
+  GetXFAWidgetHandler(pAnnot)->RenderWidget(pAnnot->GetXFAWidget(), &gs, mt,
                                             bIsHighlight);
 
   // to do highlight and shadow
@@ -81,7 +82,8 @@
   ASSERT(pAnnot);
 
   CFX_RectF rcBBox;
-  XFA_Element eType = pAnnot->GetXFAWidget()->GetDataAcc()->GetUIType();
+  XFA_Element eType =
+      pAnnot->GetXFAWidget()->GetNode()->GetWidgetAcc()->GetUIType();
   if (eType == XFA_Element::Signature)
     rcBBox = pAnnot->GetXFAWidget()->GetBBox(XFA_WidgetStatus_Visible, true);
   else
@@ -97,6 +99,23 @@
   return rcWidget;
 }
 
+WideString CPDFSDK_XFAWidgetHandler::GetSelectedText(CPDFSDK_Annot* pAnnot) {
+  if (!pAnnot)
+    return WideString();
+
+  CXFA_FFWidgetHandler* pWidgetHandler = GetXFAWidgetHandler(pAnnot);
+  return pWidgetHandler->GetSelectedText(pAnnot->GetXFAWidget());
+}
+
+void CPDFSDK_XFAWidgetHandler::ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                                                const WideString& text) {
+  if (!pAnnot)
+    return;
+
+  CXFA_FFWidgetHandler* pWidgetHandler = GetXFAWidgetHandler(pAnnot);
+  return pWidgetHandler->PasteText(pAnnot->GetXFAWidget(), text);
+}
+
 bool CPDFSDK_XFAWidgetHandler::HitTest(CPDFSDK_PageView* pPageView,
                                        CPDFSDK_Annot* pAnnot,
                                        const CFX_PointF& point) {
diff --git a/fpdfsdk/cpdfsdk_xfawidgethandler.h b/fpdfsdk/cpdfsdk_xfawidgethandler.h
index 3903103..e0dccbe 100644
--- a/fpdfsdk/cpdfsdk_xfawidgethandler.h
+++ b/fpdfsdk/cpdfsdk_xfawidgethandler.h
@@ -7,8 +7,8 @@
 #ifndef FPDFSDK_CPDFSDK_XFAWIDGETHANDLER_H_
 #define FPDFSDK_CPDFSDK_XFAWIDGETHANDLER_H_
 
-#include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_coordinates.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "fpdfsdk/ipdfsdk_annothandler.h"
 
 class CFX_Matrix;
@@ -32,6 +32,8 @@
   void ReleaseAnnot(CPDFSDK_Annot* pAnnot) override;
   CFX_FloatRect GetViewBBox(CPDFSDK_PageView* pPageView,
                             CPDFSDK_Annot* pAnnot) override;
+  WideString GetSelectedText(CPDFSDK_Annot* pAnnot) override;
+  void ReplaceSelection(CPDFSDK_Annot* pAnnot, const WideString& text) override;
   bool HitTest(CPDFSDK_PageView* pPageView,
                CPDFSDK_Annot* pAnnot,
                const CFX_PointF& point) override;
@@ -92,7 +94,7 @@
   CXFA_FFWidgetHandler* GetXFAWidgetHandler(CPDFSDK_Annot* pAnnot);
   uint32_t GetFWLFlags(uint32_t dwFlag);
 
-  CPDFSDK_FormFillEnvironment* m_pFormFillEnv;
+  UnownedPtr<CPDFSDK_FormFillEnvironment> const m_pFormFillEnv;
 };
 
 #endif  // FPDFSDK_CPDFSDK_XFAWIDGETHANDLER_H_
diff --git a/fpdfsdk/formfiller/cba_fontmap.cpp b/fpdfsdk/formfiller/cba_fontmap.cpp
index 750b416..d675676 100644
--- a/fpdfsdk/formfiller/cba_fontmap.cpp
+++ b/fpdfsdk/formfiller/cba_fontmap.cpp
@@ -28,7 +28,7 @@
       m_sAPType("N") {
   CPDF_Page* pPage = pAnnot->GetPDFPage();
 
-  m_pDocument = pPage->m_pDocument;
+  m_pDocument = pPage->m_pDocument.Get();
   m_pAnnotDict = pAnnot->GetPDFAnnot()->GetAnnotDict();
   Initialize();
 }
@@ -38,14 +38,14 @@
 void CBA_FontMap::Reset() {
   Empty();
   m_pDefaultFont = nullptr;
-  m_sDefaultFontName = "";
+  m_sDefaultFontName.clear();
 }
 
 void CBA_FontMap::Initialize() {
-  int32_t nCharset = FXFONT_DEFAULT_CHARSET;
+  int32_t nCharset = FX_CHARSET_Default;
 
   if (!m_pDefaultFont) {
-    m_pDefaultFont = GetAnnotDefaultFont(m_sDefaultFontName);
+    m_pDefaultFont = GetAnnotDefaultFont(&m_sDefaultFontName);
     if (m_pDefaultFont) {
       if (const CFX_SubstFont* pSubstFont = m_pDefaultFont->GetSubstFont()) {
         nCharset = pSubstFont->m_Charset;
@@ -54,21 +54,21 @@
             m_sDefaultFontName == "Wingdings2" ||
             m_sDefaultFontName == "Wingdings3" ||
             m_sDefaultFontName == "Webdings")
-          nCharset = FXFONT_SYMBOL_CHARSET;
+          nCharset = FX_CHARSET_Symbol;
         else
-          nCharset = FXFONT_ANSI_CHARSET;
+          nCharset = FX_CHARSET_ANSI;
       }
-      AddFontData(m_pDefaultFont, m_sDefaultFontName, nCharset);
-      AddFontToAnnotDict(m_pDefaultFont, m_sDefaultFontName);
+      AddFontData(m_pDefaultFont.Get(), m_sDefaultFontName, nCharset);
+      AddFontToAnnotDict(m_pDefaultFont.Get(), m_sDefaultFontName);
     }
   }
 
-  if (nCharset != FXFONT_ANSI_CHARSET)
+  if (nCharset != FX_CHARSET_ANSI)
     CPWL_FontMap::Initialize();
 }
 
 void CBA_FontMap::SetDefaultFont(CPDF_Font* pFont,
-                                 const CFX_ByteString& sFontName) {
+                                 const ByteString& sFontName) {
   ASSERT(pFont);
 
   if (m_pDefaultFont)
@@ -77,19 +77,19 @@
   m_pDefaultFont = pFont;
   m_sDefaultFontName = sFontName;
 
-  int32_t nCharset = FXFONT_DEFAULT_CHARSET;
+  int32_t nCharset = FX_CHARSET_Default;
   if (const CFX_SubstFont* pSubstFont = m_pDefaultFont->GetSubstFont())
     nCharset = pSubstFont->m_Charset;
-  AddFontData(m_pDefaultFont, m_sDefaultFontName, nCharset);
+  AddFontData(m_pDefaultFont.Get(), m_sDefaultFontName, nCharset);
 }
 
-CPDF_Font* CBA_FontMap::FindFontSameCharset(CFX_ByteString& sFontAlias,
+CPDF_Font* CBA_FontMap::FindFontSameCharset(ByteString* sFontAlias,
                                             int32_t nCharset) {
   if (m_pAnnotDict->GetStringFor("Subtype") != "Widget")
     return nullptr;
 
   CPDF_Document* pDocument = GetDocument();
-  CPDF_Dictionary* pRootDict = pDocument->GetRoot();
+  const CPDF_Dictionary* pRootDict = pDocument->GetRoot();
   if (!pRootDict)
     return nullptr;
 
@@ -105,11 +105,11 @@
 }
 
 CPDF_Document* CBA_FontMap::GetDocument() {
-  return m_pDocument;
+  return m_pDocument.Get();
 }
 
 CPDF_Font* CBA_FontMap::FindResFontSameCharset(CPDF_Dictionary* pResDict,
-                                               CFX_ByteString& sFontAlias,
+                                               ByteString* sFontAlias,
                                                int32_t nCharset) {
   if (!pResDict)
     return nullptr;
@@ -121,7 +121,7 @@
   CPDF_Document* pDocument = GetDocument();
   CPDF_Font* pFind = nullptr;
   for (const auto& it : *pFonts) {
-    const CFX_ByteString& csKey = it.first;
+    const ByteString& csKey = it.first;
     if (!it.second)
       continue;
 
@@ -138,20 +138,19 @@
     if (!pSubst)
       continue;
     if (pSubst->m_Charset == nCharset) {
-      sFontAlias = csKey;
+      *sFontAlias = csKey;
       pFind = pFont;
     }
   }
   return pFind;
 }
 
-void CBA_FontMap::AddedFont(CPDF_Font* pFont,
-                            const CFX_ByteString& sFontAlias) {
+void CBA_FontMap::AddedFont(CPDF_Font* pFont, const ByteString& sFontAlias) {
   AddFontToAnnotDict(pFont, sFontAlias);
 }
 
 void CBA_FontMap::AddFontToAnnotDict(CPDF_Font* pFont,
-                                     const CFX_ByteString& sAlias) {
+                                     const ByteString& sAlias) {
   if (!pFont)
     return;
 
@@ -167,7 +166,7 @@
   CPDF_Stream* pStream = pAPDict->GetStreamFor(m_sAPType);
   if (!pStream) {
     pStream = m_pDocument->NewIndirect<CPDF_Stream>();
-    pAPDict->SetNewFor<CPDF_Reference>(m_sAPType, m_pDocument,
+    pAPDict->SetNewFor<CPDF_Reference>(m_sAPType, m_pDocument.Get(),
                                        pStream->GetObjNum());
   }
 
@@ -185,64 +184,65 @@
   CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictFor("Font");
   if (!pStreamResFontList) {
     pStreamResFontList = m_pDocument->NewIndirect<CPDF_Dictionary>();
-    pStreamResList->SetNewFor<CPDF_Reference>("Font", m_pDocument,
+    pStreamResList->SetNewFor<CPDF_Reference>("Font", m_pDocument.Get(),
                                               pStreamResFontList->GetObjNum());
   }
   if (!pStreamResFontList->KeyExist(sAlias)) {
     pStreamResFontList->SetNewFor<CPDF_Reference>(
-        sAlias, m_pDocument, pFont->GetFontDict()->GetObjNum());
+        sAlias, m_pDocument.Get(), pFont->GetFontDict()->GetObjNum());
   }
 }
 
-CPDF_Font* CBA_FontMap::GetAnnotDefaultFont(CFX_ByteString& sAlias) {
+CPDF_Font* CBA_FontMap::GetAnnotDefaultFont(ByteString* sAlias) {
   CPDF_Dictionary* pAcroFormDict = nullptr;
   const bool bWidget = (m_pAnnotDict->GetStringFor("Subtype") == "Widget");
   if (bWidget) {
-    if (CPDF_Dictionary* pRootDict = m_pDocument->GetRoot())
+    const CPDF_Dictionary* pRootDict = m_pDocument->GetRoot();
+    if (pRootDict)
       pAcroFormDict = pRootDict->GetDictFor("AcroForm");
   }
 
-  CFX_ByteString sDA;
-  CPDF_Object* pObj = FPDF_GetFieldAttr(m_pAnnotDict, "DA");
+  ByteString sDA;
+  CPDF_Object* pObj = FPDF_GetFieldAttr(m_pAnnotDict.Get(), "DA");
   if (pObj)
     sDA = pObj->GetString();
 
   if (bWidget) {
     if (sDA.IsEmpty()) {
       pObj = FPDF_GetFieldAttr(pAcroFormDict, "DA");
-      sDA = pObj ? pObj->GetString() : CFX_ByteString();
+      sDA = pObj ? pObj->GetString() : ByteString();
     }
   }
   if (sDA.IsEmpty())
     return nullptr;
 
-  CPDF_SimpleParser syntax(sDA.AsStringC());
+  CPDF_SimpleParser syntax(sDA.AsStringView());
   syntax.FindTagParamFromStart("Tf", 2);
-  CFX_ByteString sFontName(syntax.GetWord());
-  sAlias = PDF_NameDecode(sFontName).Mid(1);
-  CPDF_Dictionary* pFontDict = nullptr;
 
+  ByteString sFontName(syntax.GetWord());
+  ByteString sDecodedFontName = PDF_NameDecode(sFontName);
+  *sAlias = sDecodedFontName.Right(sDecodedFontName.GetLength() - 1);
+
+  CPDF_Dictionary* pFontDict = nullptr;
   if (CPDF_Dictionary* pAPDict = m_pAnnotDict->GetDictFor("AP")) {
     if (CPDF_Dictionary* pNormalDict = pAPDict->GetDictFor("N")) {
       if (CPDF_Dictionary* pNormalResDict =
               pNormalDict->GetDictFor("Resources")) {
         if (CPDF_Dictionary* pResFontDict = pNormalResDict->GetDictFor("Font"))
-          pFontDict = pResFontDict->GetDictFor(sAlias);
+          pFontDict = pResFontDict->GetDictFor(*sAlias);
       }
     }
   }
-
   if (bWidget && !pFontDict && pAcroFormDict) {
     if (CPDF_Dictionary* pDRDict = pAcroFormDict->GetDictFor("DR")) {
       if (CPDF_Dictionary* pDRFontDict = pDRDict->GetDictFor("Font"))
-        pFontDict = pDRFontDict->GetDictFor(sAlias);
+        pFontDict = pDRFontDict->GetDictFor(*sAlias);
     }
   }
-
   return pFontDict ? m_pDocument->LoadFont(pFontDict) : nullptr;
 }
 
-void CBA_FontMap::SetAPType(const CFX_ByteString& sAPType) {
+void CBA_FontMap::SetAPType(const ByteString& sAPType) {
   m_sAPType = sAPType;
 
   Reset();
diff --git a/fpdfsdk/formfiller/cba_fontmap.h b/fpdfsdk/formfiller/cba_fontmap.h
index c0e569a..45df8c8 100644
--- a/fpdfsdk/formfiller/cba_fontmap.h
+++ b/fpdfsdk/formfiller/cba_fontmap.h
@@ -7,7 +7,8 @@
 #ifndef FPDFSDK_FORMFILLER_CBA_FONTMAP_H_
 #define FPDFSDK_FORMFILLER_CBA_FONTMAP_H_
 
-#include "fpdfsdk/pdfwindow/PWL_FontMap.h"
+#include "core/fxcrt/unowned_ptr.h"
+#include "fpdfsdk/pwl/cpwl_font_map.h"
 
 class CPDF_Dictionary;
 class CPDFSDK_Annot;
@@ -17,30 +18,29 @@
   CBA_FontMap(CPDFSDK_Annot* pAnnot, CFX_SystemHandler* pSystemHandler);
   ~CBA_FontMap() override;
 
-  void SetDefaultFont(CPDF_Font* pFont, const CFX_ByteString& sFontName);
-
   void Reset();
-  void SetAPType(const CFX_ByteString& sAPType);
+  void SetDefaultFont(CPDF_Font* pFont, const ByteString& sFontName);
+  void SetAPType(const ByteString& sAPType);
 
  private:
   // CPWL_FontMap:
   void Initialize() override;
   CPDF_Document* GetDocument() override;
-  CPDF_Font* FindFontSameCharset(CFX_ByteString& sFontAlias,
+  CPDF_Font* FindFontSameCharset(ByteString* sFontAlias,
                                  int32_t nCharset) override;
-  void AddedFont(CPDF_Font* pFont, const CFX_ByteString& sFontAlias) override;
+  void AddedFont(CPDF_Font* pFont, const ByteString& sFontAlias) override;
 
   CPDF_Font* FindResFontSameCharset(CPDF_Dictionary* pResDict,
-                                    CFX_ByteString& sFontAlias,
+                                    ByteString* sFontAlias,
                                     int32_t nCharset);
-  CPDF_Font* GetAnnotDefaultFont(CFX_ByteString& csNameTag);
-  void AddFontToAnnotDict(CPDF_Font* pFont, const CFX_ByteString& sAlias);
+  CPDF_Font* GetAnnotDefaultFont(ByteString* csNameTag);
+  void AddFontToAnnotDict(CPDF_Font* pFont, const ByteString& sAlias);
 
-  CPDF_Document* m_pDocument;
-  CPDF_Dictionary* m_pAnnotDict;
-  CPDF_Font* m_pDefaultFont;
-  CFX_ByteString m_sDefaultFontName;
-  CFX_ByteString m_sAPType;
+  UnownedPtr<CPDF_Document> m_pDocument;
+  UnownedPtr<CPDF_Dictionary> m_pAnnotDict;
+  UnownedPtr<CPDF_Font> m_pDefaultFont;
+  ByteString m_sDefaultFontName;
+  ByteString m_sAPType;
 };
 
 #endif  // FPDFSDK_FORMFILLER_CBA_FONTMAP_H_
diff --git a/fpdfsdk/formfiller/cffl_button.cpp b/fpdfsdk/formfiller/cffl_button.cpp
new file mode 100644
index 0000000..dab0045
--- /dev/null
+++ b/fpdfsdk/formfiller/cffl_button.cpp
@@ -0,0 +1,103 @@
+// 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/formfiller/cffl_button.h"
+
+CFFL_Button::CFFL_Button(CPDFSDK_FormFillEnvironment* pApp,
+                         CPDFSDK_Widget* pWidget)
+    : CFFL_FormFiller(pApp, pWidget), m_bMouseIn(false), m_bMouseDown(false) {}
+
+CFFL_Button::~CFFL_Button() {}
+
+void CFFL_Button::OnMouseEnter(CPDFSDK_PageView* pPageView,
+                               CPDFSDK_Annot* pAnnot) {
+  m_bMouseIn = true;
+  InvalidateRect(GetViewBBox(pPageView, pAnnot));
+}
+
+void CFFL_Button::OnMouseExit(CPDFSDK_PageView* pPageView,
+                              CPDFSDK_Annot* pAnnot) {
+  m_bMouseIn = false;
+  InvalidateRect(GetViewBBox(pPageView, pAnnot));
+  EndTimer();
+  ASSERT(m_pWidget);
+}
+
+bool CFFL_Button::OnLButtonDown(CPDFSDK_PageView* pPageView,
+                                CPDFSDK_Annot* pAnnot,
+                                uint32_t nFlags,
+                                const CFX_PointF& point) {
+  if (!pAnnot->GetRect().Contains(point))
+    return false;
+
+  m_bMouseDown = true;
+  m_bValid = true;
+  InvalidateRect(GetViewBBox(pPageView, pAnnot));
+  return true;
+}
+
+bool CFFL_Button::OnLButtonUp(CPDFSDK_PageView* pPageView,
+                              CPDFSDK_Annot* pAnnot,
+                              uint32_t nFlags,
+                              const CFX_PointF& point) {
+  if (!pAnnot->GetRect().Contains(point))
+    return false;
+
+  m_bMouseDown = false;
+  m_pWidget->GetPDFPage();
+  InvalidateRect(GetViewBBox(pPageView, pAnnot));
+  return true;
+}
+
+bool CFFL_Button::OnMouseMove(CPDFSDK_PageView* pPageView,
+                              CPDFSDK_Annot* pAnnot,
+                              uint32_t nFlags,
+                              const CFX_PointF& point) {
+  return true;
+}
+
+void CFFL_Button::OnDraw(CPDFSDK_PageView* pPageView,
+                         CPDFSDK_Annot* pAnnot,
+                         CFX_RenderDevice* pDevice,
+                         const CFX_Matrix& mtUser2Device) {
+  ASSERT(pPageView);
+  CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot);
+  CPDF_FormControl* pCtrl = pWidget->GetFormControl();
+  if (pCtrl->GetHighlightingMode() != CPDF_FormControl::Push) {
+    pWidget->DrawAppearance(pDevice, mtUser2Device, CPDF_Annot::Normal,
+                            nullptr);
+    return;
+  }
+  if (m_bMouseDown) {
+    if (pWidget->IsWidgetAppearanceValid(CPDF_Annot::Down)) {
+      pWidget->DrawAppearance(pDevice, mtUser2Device, CPDF_Annot::Down,
+                              nullptr);
+    } else {
+      pWidget->DrawAppearance(pDevice, mtUser2Device, CPDF_Annot::Normal,
+                              nullptr);
+    }
+    return;
+  }
+  if (m_bMouseIn) {
+    if (pWidget->IsWidgetAppearanceValid(CPDF_Annot::Rollover)) {
+      pWidget->DrawAppearance(pDevice, mtUser2Device, CPDF_Annot::Rollover,
+                              nullptr);
+    } else {
+      pWidget->DrawAppearance(pDevice, mtUser2Device, CPDF_Annot::Normal,
+                              nullptr);
+    }
+    return;
+  }
+
+  pWidget->DrawAppearance(pDevice, mtUser2Device, CPDF_Annot::Normal, nullptr);
+}
+
+void CFFL_Button::OnDrawDeactive(CPDFSDK_PageView* pPageView,
+                                 CPDFSDK_Annot* pAnnot,
+                                 CFX_RenderDevice* pDevice,
+                                 const CFX_Matrix& mtUser2Device) {
+  OnDraw(pPageView, pAnnot, pDevice, mtUser2Device);
+}
diff --git a/fpdfsdk/formfiller/cffl_button.h b/fpdfsdk/formfiller/cffl_button.h
new file mode 100644
index 0000000..ad2eb5b
--- /dev/null
+++ b/fpdfsdk/formfiller/cffl_button.h
@@ -0,0 +1,56 @@
+// Copyright 2017 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FPDFSDK_FORMFILLER_CFFL_BUTTON_H_
+#define FPDFSDK_FORMFILLER_CFFL_BUTTON_H_
+
+#include "core/fxcrt/fx_coordinates.h"
+#include "fpdfsdk/formfiller/cffl_formfiller.h"
+
+class CFX_RenderDevice;
+class CFX_Matrix;
+class CPDFSDK_Annot;
+class CPDFSDK_FormFillEnvironment;
+class CPDFSDK_PageView;
+class CPDFSDK_Widget;
+
+class CFFL_Button : public CFFL_FormFiller {
+ public:
+  CFFL_Button(CPDFSDK_FormFillEnvironment* pFormFillEnv,
+              CPDFSDK_Widget* pWidget);
+  ~CFFL_Button() override;
+
+  // CFFL_FormFiller
+  void OnMouseEnter(CPDFSDK_PageView* pPageView,
+                    CPDFSDK_Annot* pAnnot) override;
+  void OnMouseExit(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot) override;
+  bool OnLButtonDown(CPDFSDK_PageView* pPageView,
+                     CPDFSDK_Annot* pAnnot,
+                     uint32_t nFlags,
+                     const CFX_PointF& point) override;
+  bool OnLButtonUp(CPDFSDK_PageView* pPageView,
+                   CPDFSDK_Annot* pAnnot,
+                   uint32_t nFlags,
+                   const CFX_PointF& point) override;
+  bool OnMouseMove(CPDFSDK_PageView* pPageView,
+                   CPDFSDK_Annot* pAnnot,
+                   uint32_t nFlags,
+                   const CFX_PointF& point) override;
+  void OnDraw(CPDFSDK_PageView* pPageView,
+              CPDFSDK_Annot* pAnnot,
+              CFX_RenderDevice* pDevice,
+              const CFX_Matrix& mtUser2Device) override;
+  void OnDrawDeactive(CPDFSDK_PageView* pPageView,
+                      CPDFSDK_Annot* pAnnot,
+                      CFX_RenderDevice* pDevice,
+                      const CFX_Matrix& mtUser2Device) override;
+
+ private:
+  bool m_bMouseIn;
+  bool m_bMouseDown;
+};
+
+#endif  // FPDFSDK_FORMFILLER_CFFL_BUTTON_H_
diff --git a/fpdfsdk/formfiller/cffl_checkbox.cpp b/fpdfsdk/formfiller/cffl_checkbox.cpp
index c233c13..e9c72ef 100644
--- a/fpdfsdk/formfiller/cffl_checkbox.cpp
+++ b/fpdfsdk/formfiller/cffl_checkbox.cpp
@@ -9,7 +9,7 @@
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 #include "fpdfsdk/cpdfsdk_widget.h"
 #include "fpdfsdk/formfiller/cffl_formfiller.h"
-#include "fpdfsdk/pdfwindow/PWL_SpecialButton.h"
+#include "fpdfsdk/pwl/cpwl_special_button.h"
 #include "public/fpdf_fwlevent.h"
 
 CFFL_CheckBox::CFFL_CheckBox(CPDFSDK_FormFillEnvironment* pApp,
@@ -18,9 +18,8 @@
 
 CFFL_CheckBox::~CFFL_CheckBox() {}
 
-CPWL_Wnd* CFFL_CheckBox::NewPDFWindow(const PWL_CREATEPARAM& cp,
-                                      CPDFSDK_PageView* pPageView) {
-  CPWL_CheckBox* pWnd = new CPWL_CheckBox();
+CPWL_Wnd* CFFL_CheckBox::NewPDFWindow(const CPWL_Wnd::CreateParams& cp) {
+  auto* pWnd = new CPWL_CheckBox();
   pWnd->Create(cp);
   pWnd->SetCheck(m_pWidget->IsChecked());
   return pWnd;
@@ -46,24 +45,27 @@
       CPDFSDK_PageView* pPageView = pAnnot->GetPageView();
       ASSERT(pPageView);
 
-      bool bReset = false;
-      bool bExit = false;
-      CPDFSDK_Annot::ObservedPtr pObserved(m_pWidget);
-      m_pFormFillEnv->GetInteractiveFormFiller()->OnButtonUp(
-          &pObserved, pPageView, bReset, bExit, nFlags);
+      CPDFSDK_Annot::ObservedPtr pObserved(m_pWidget.Get());
+      if (m_pFormFillEnv->GetInteractiveFormFiller()->OnButtonUp(
+              &pObserved, pPageView, nFlags)) {
+        if (!pObserved)
+          m_pWidget = nullptr;
+        return true;
+      }
       if (!pObserved) {
         m_pWidget = nullptr;
         return true;
       }
-      if (bReset || bExit)
-        return true;
 
       CFFL_FormFiller::OnChar(pAnnot, nChar, nFlags);
-      if (CPWL_CheckBox* pWnd = (CPWL_CheckBox*)GetPDFWindow(pPageView, true))
-        pWnd->SetCheck(!pWnd->IsChecked());
 
-      CommitData(pPageView, nFlags);
-      return true;
+      CPWL_CheckBox* pWnd = GetCheckBox(pPageView, true);
+      if (pWnd) {
+        CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot);
+        pWnd->SetCheck(!pWidget->IsChecked());
+      }
+
+      return CommitData(pPageView, nFlags);
     }
     default:
       return CFFL_FormFiller::OnChar(pAnnot, nChar, nFlags);
@@ -76,41 +78,52 @@
                                 const CFX_PointF& point) {
   CFFL_Button::OnLButtonUp(pPageView, pAnnot, nFlags, point);
 
-  if (IsValid()) {
-    if (CPWL_CheckBox* pWnd = (CPWL_CheckBox*)GetPDFWindow(pPageView, true)) {
-      CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)pAnnot;
-      pWnd->SetCheck(!pWidget->IsChecked());
-    }
+  if (!IsValid())
+    return true;
 
-    if (!CommitData(pPageView, nFlags))
-      return false;
+  CPWL_CheckBox* pWnd = GetCheckBox(pPageView, true);
+  if (pWnd) {
+    CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot);
+    pWnd->SetCheck(!pWidget->IsChecked());
   }
 
-  return true;
+  return CommitData(pPageView, nFlags);
 }
 
 bool CFFL_CheckBox::IsDataChanged(CPDFSDK_PageView* pPageView) {
-  CPWL_CheckBox* pWnd = (CPWL_CheckBox*)GetPDFWindow(pPageView, false);
+  CPWL_CheckBox* pWnd = GetCheckBox(pPageView, false);
   return pWnd && pWnd->IsChecked() != m_pWidget->IsChecked();
 }
 
 void CFFL_CheckBox::SaveData(CPDFSDK_PageView* pPageView) {
-  if (CPWL_CheckBox* pWnd = (CPWL_CheckBox*)GetPDFWindow(pPageView, false)) {
-    bool bNewChecked = pWnd->IsChecked();
+  CPWL_CheckBox* pWnd = GetCheckBox(pPageView, false);
+  if (!pWnd)
+    return;
 
-    if (bNewChecked) {
-      CPDF_FormField* pField = m_pWidget->GetFormField();
-      for (int32_t i = 0, sz = pField->CountControls(); i < sz; i++) {
-        if (CPDF_FormControl* pCtrl = pField->GetControl(i)) {
-          if (pCtrl->IsChecked()) {
-            break;
-          }
+  bool bNewChecked = pWnd->IsChecked();
+  if (bNewChecked) {
+    CPDF_FormField* pField = m_pWidget->GetFormField();
+    for (int32_t i = 0, sz = pField->CountControls(); i < sz; i++) {
+      if (CPDF_FormControl* pCtrl = pField->GetControl(i)) {
+        if (pCtrl->IsChecked()) {
+          break;
         }
       }
     }
-
-    m_pWidget->SetCheck(bNewChecked, false);
-    m_pWidget->UpdateField();
-    SetChangeMark();
   }
+  CPDFSDK_Widget::ObservedPtr observed_widget(m_pWidget.Get());
+  CFFL_CheckBox::ObservedPtr observed_this(this);
+
+  m_pWidget->SetCheck(bNewChecked, false);
+  if (!observed_widget)
+    return;
+  m_pWidget->UpdateField();
+  if (!observed_widget || !observed_this)
+    return;
+  SetChangeMark();
+}
+
+CPWL_CheckBox* CFFL_CheckBox::GetCheckBox(CPDFSDK_PageView* pPageView,
+                                          bool bNew) {
+  return static_cast<CPWL_CheckBox*>(GetPDFWindow(pPageView, bNew));
 }
diff --git a/fpdfsdk/formfiller/cffl_checkbox.h b/fpdfsdk/formfiller/cffl_checkbox.h
index 79ddc84..8ef3de6 100644
--- a/fpdfsdk/formfiller/cffl_checkbox.h
+++ b/fpdfsdk/formfiller/cffl_checkbox.h
@@ -7,16 +7,17 @@
 #ifndef FPDFSDK_FORMFILLER_CFFL_CHECKBOX_H_
 #define FPDFSDK_FORMFILLER_CFFL_CHECKBOX_H_
 
-#include "fpdfsdk/formfiller/cffl_formfiller.h"
+#include "fpdfsdk/formfiller/cffl_button.h"
+
+class CPWL_CheckBox;
 
 class CFFL_CheckBox : public CFFL_Button {
  public:
   CFFL_CheckBox(CPDFSDK_FormFillEnvironment* pApp, CPDFSDK_Widget* pWidget);
   ~CFFL_CheckBox() override;
 
-  // CFFL_Button
-  CPWL_Wnd* NewPDFWindow(const PWL_CREATEPARAM& cp,
-                         CPDFSDK_PageView* pPageView) override;
+  // CFFL_Button:
+  CPWL_Wnd* NewPDFWindow(const CPWL_Wnd::CreateParams& cp) override;
   bool OnKeyDown(CPDFSDK_Annot* pAnnot,
                  uint32_t nKeyCode,
                  uint32_t nFlags) override;
@@ -27,6 +28,9 @@
                    const CFX_PointF& point) override;
   bool IsDataChanged(CPDFSDK_PageView* pPageView) override;
   void SaveData(CPDFSDK_PageView* pPageView) override;
+
+ private:
+  CPWL_CheckBox* GetCheckBox(CPDFSDK_PageView* pPageView, bool bNew);
 };
 
 #endif  // FPDFSDK_FORMFILLER_CFFL_CHECKBOX_H_
diff --git a/fpdfsdk/formfiller/cffl_combobox.cpp b/fpdfsdk/formfiller/cffl_combobox.cpp
index c8438a3..d9b12f5 100644
--- a/fpdfsdk/formfiller/cffl_combobox.cpp
+++ b/fpdfsdk/formfiller/cffl_combobox.cpp
@@ -9,14 +9,14 @@
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 #include "fpdfsdk/cpdfsdk_widget.h"
 #include "fpdfsdk/formfiller/cba_fontmap.h"
-#include "fpdfsdk/formfiller/cffl_formfiller.h"
 #include "fpdfsdk/formfiller/cffl_interactiveformfiller.h"
 #include "fpdfsdk/fsdk_common.h"
-#include "fpdfsdk/pdfwindow/PWL_ComboBox.h"
+#include "fpdfsdk/pwl/cpwl_combo_box.h"
+#include "third_party/base/ptr_util.h"
 
 CFFL_ComboBox::CFFL_ComboBox(CPDFSDK_FormFillEnvironment* pApp,
-                             CPDFSDK_Annot* pAnnot)
-    : CFFL_FormFiller(pApp, pAnnot), m_pFontMap(nullptr) {
+                             CPDFSDK_Widget* pWidget)
+    : CFFL_TextObject(pApp, pWidget) {
   m_State.nIndex = 0;
   m_State.nStart = 0;
   m_State.nEnd = 0;
@@ -30,28 +30,20 @@
   // The font map should be stored somewhere more appropriate so it will live
   // until the PWL_Edit is done with it. pdfium:566
   DestroyWindows();
-  delete m_pFontMap;
 }
 
-PWL_CREATEPARAM CFFL_ComboBox::GetCreateParam() {
-  PWL_CREATEPARAM cp = CFFL_FormFiller::GetCreateParam();
-
-  int nFlags = m_pWidget->GetFieldFlags();
-  if (nFlags & FIELDFLAG_EDIT) {
+CPWL_Wnd::CreateParams CFFL_ComboBox::GetCreateParam() {
+  CPWL_Wnd::CreateParams cp = CFFL_TextObject::GetCreateParam();
+  if (m_pWidget->GetFieldFlags() & FIELDFLAG_EDIT)
     cp.dwFlags |= PCBS_ALLOWCUSTOMTEXT;
-  }
 
-  if (!m_pFontMap)
-    m_pFontMap = new CBA_FontMap(m_pWidget, GetSystemHandler());
-  cp.pFontMap = m_pFontMap;
+  cp.pFontMap = MaybeCreateFontMap();
   cp.pFocusHandler = this;
-
   return cp;
 }
 
-CPWL_Wnd* CFFL_ComboBox::NewPDFWindow(const PWL_CREATEPARAM& cp,
-                                      CPDFSDK_PageView* pPageView) {
-  CPWL_ComboBox* pWnd = new CPWL_ComboBox();
+CPWL_Wnd* CFFL_ComboBox::NewPDFWindow(const CPWL_Wnd::CreateParams& cp) {
+  auto* pWnd = new CPWL_ComboBox();
   pWnd->AttachFFLData(this);
   pWnd->Create(cp);
 
@@ -60,7 +52,7 @@
   pWnd->SetFillerNotify(pFormFiller);
 
   int32_t nCurSel = m_pWidget->GetSelectedIndex(0);
-  CFX_WideString swText;
+  WideString swText;
   if (nCurSel < 0)
     swText = m_pWidget->GetValue();
   else
@@ -78,7 +70,7 @@
 bool CFFL_ComboBox::OnChar(CPDFSDK_Annot* pAnnot,
                            uint32_t nChar,
                            uint32_t nFlags) {
-  return CFFL_FormFiller::OnChar(pAnnot, nChar, nFlags);
+  return CFFL_TextObject::OnChar(pAnnot, nChar, nFlags);
 }
 
 bool CFFL_ComboBox::IsDataChanged(CPDFSDK_PageView* pPageView) {
@@ -102,7 +94,7 @@
   if (!pWnd)
     return;
 
-  CFX_WideString swText = pWnd->GetText();
+  WideString swText = pWnd->GetText();
   int32_t nCurSel = pWnd->GetSelect();
 
   bool bSetValue = false;
@@ -116,11 +108,16 @@
     m_pWidget->GetSelectedIndex(0);
     m_pWidget->SetOptionSelection(nCurSel, true, false);
   }
+  CPDFSDK_Widget::ObservedPtr observed_widget(m_pWidget.Get());
+  CFFL_ComboBox::ObservedPtr observed_this(this);
 
   m_pWidget->ResetFieldAppearance(true);
+  if (!observed_widget)
+    return;
   m_pWidget->UpdateField();
+  if (!observed_widget || !observed_this)
+    return;
   SetChangeMark();
-
   m_pWidget->GetPDFPage();
 }
 
@@ -135,7 +132,7 @@
           fa.bFieldFull = pEdit->IsTextFull();
           int nSelStart = 0;
           int nSelEnd = 0;
-          pEdit->GetSel(nSelStart, nSelEnd);
+          pEdit->GetSelection(nSelStart, nSelEnd);
           fa.nSelEnd = nSelEnd;
           fa.nSelStart = nSelStart;
           fa.sValue = pEdit->GetText();
@@ -173,7 +170,7 @@
       if (CPWL_ComboBox* pComboBox =
               static_cast<CPWL_ComboBox*>(GetPDFWindow(pPageView, false))) {
         if (CPWL_Edit* pEdit = pComboBox->GetEdit()) {
-          pEdit->SetSel(fa.nSelStart, fa.nSelEnd);
+          pEdit->SetSelection(fa.nSelStart, fa.nSelEnd);
           pEdit->ReplaceSel(fa.sChange);
         }
       }
@@ -206,7 +203,7 @@
     m_State.nIndex = pComboBox->GetSelect();
 
     if (CPWL_Edit* pEdit = pComboBox->GetEdit()) {
-      pEdit->GetSel(m_State.nStart, m_State.nEnd);
+      pEdit->GetSelection(m_State.nStart, m_State.nEnd);
       m_State.sValue = pEdit->GetText();
     }
   }
@@ -222,33 +219,12 @@
     } else {
       if (CPWL_Edit* pEdit = pComboBox->GetEdit()) {
         pEdit->SetText(m_State.sValue);
-        pEdit->SetSel(m_State.nStart, m_State.nEnd);
+        pEdit->SetSelection(m_State.nStart, m_State.nEnd);
       }
     }
   }
 }
 
-CPWL_Wnd* CFFL_ComboBox::ResetPDFWindow(CPDFSDK_PageView* pPageView,
-                                        bool bRestoreValue) {
-  if (bRestoreValue)
-    SaveState(pPageView);
-
-  DestroyPDFWindow(pPageView);
-
-  CPWL_Wnd* pRet = nullptr;
-
-  if (bRestoreValue) {
-    RestoreState(pPageView);
-    pRet = GetPDFWindow(pPageView, false);
-  } else {
-    pRet = GetPDFWindow(pPageView, true);
-  }
-
-  m_pWidget->UpdateField();
-
-  return pRet;
-}
-
 #ifdef PDF_ENABLE_XFA
 bool CFFL_ComboBox::IsFieldFull(CPDFSDK_PageView* pPageView) {
   if (CPWL_ComboBox* pComboBox =
@@ -260,25 +236,19 @@
 }
 #endif  // PDF_ENABLE_XFA
 
-void CFFL_ComboBox::OnSetFocus(CPWL_Wnd* pWnd) {
-  ASSERT(m_pFormFillEnv);
+void CFFL_ComboBox::OnSetFocus(CPWL_Edit* pEdit) {
+  pEdit->SetCharSet(FX_CHARSET_ChineseSimplified);
+  pEdit->SetReadyToInput();
 
-  if (pWnd->GetClassName() == PWL_CLASSNAME_EDIT) {
-    CPWL_Edit* pEdit = (CPWL_Edit*)pWnd;
-    pEdit->SetCharSet(FXFONT_GB2312_CHARSET);
-    pEdit->SetCodePage(936);
-
-    pEdit->SetReadyToInput();
-    CFX_WideString wsText = pEdit->GetText();
-    int nCharacters = wsText.GetLength();
-    CFX_ByteString bsUTFText = wsText.UTF16LE_Encode();
-    unsigned short* pBuffer = (unsigned short*)bsUTFText.c_str();
-    m_pFormFillEnv->OnSetFieldInputFocus(pBuffer, nCharacters, true);
-  }
+  WideString wsText = pEdit->GetText();
+  int nCharacters = wsText.GetLength();
+  ByteString bsUTFText = wsText.UTF16LE_Encode();
+  auto* pBuffer = reinterpret_cast<const unsigned short*>(bsUTFText.c_str());
+  m_pFormFillEnv->OnSetFieldInputFocus(pBuffer, nCharacters, true);
 }
 
-CFX_WideString CFFL_ComboBox::GetSelectExportText() {
-  CFX_WideString swRet;
+WideString CFFL_ComboBox::GetSelectExportText() {
+  WideString swRet;
 
   int nExport = -1;
   CPDFSDK_PageView* pPageView = GetCurPageView(true);
diff --git a/fpdfsdk/formfiller/cffl_combobox.h b/fpdfsdk/formfiller/cffl_combobox.h
index aab10b9..bdc0934 100644
--- a/fpdfsdk/formfiller/cffl_combobox.h
+++ b/fpdfsdk/formfiller/cffl_combobox.h
@@ -8,7 +8,7 @@
 #define FPDFSDK_FORMFILLER_CFFL_COMBOBOX_H_
 
 #include "core/fxcrt/fx_string.h"
-#include "fpdfsdk/formfiller/cffl_formfiller.h"
+#include "fpdfsdk/formfiller/cffl_textobject.h"
 
 class CBA_FontMap;
 
@@ -16,18 +16,18 @@
   int nIndex;
   int nStart;
   int nEnd;
-  CFX_WideString sValue;
+  WideString sValue;
 };
 
-class CFFL_ComboBox : public CFFL_FormFiller, public IPWL_FocusHandler {
+class CFFL_ComboBox : public CFFL_TextObject,
+                      public CPWL_Wnd::FocusHandlerIface {
  public:
-  CFFL_ComboBox(CPDFSDK_FormFillEnvironment* pApp, CPDFSDK_Annot* pWidget);
+  CFFL_ComboBox(CPDFSDK_FormFillEnvironment* pApp, CPDFSDK_Widget* pWidget);
   ~CFFL_ComboBox() override;
 
-  // CFFL_FormFiller:
-  PWL_CREATEPARAM GetCreateParam() override;
-  CPWL_Wnd* NewPDFWindow(const PWL_CREATEPARAM& cp,
-                         CPDFSDK_PageView* pPageView) override;
+  // CFFL_TextObject:
+  CPWL_Wnd::CreateParams GetCreateParam() override;
+  CPWL_Wnd* NewPDFWindow(const CPWL_Wnd::CreateParams& cp) override;
   bool OnChar(CPDFSDK_Annot* pAnnot, uint32_t nChar, uint32_t nFlags) override;
   bool IsDataChanged(CPDFSDK_PageView* pPageView) override;
   void SaveData(CPDFSDK_PageView* pPageView) override;
@@ -42,21 +42,16 @@
                            const PDFSDK_FieldAction& faNew) override;
   void SaveState(CPDFSDK_PageView* pPageView) override;
   void RestoreState(CPDFSDK_PageView* pPageView) override;
-  CPWL_Wnd* ResetPDFWindow(CPDFSDK_PageView* pPageView,
-                           bool bRestoreValue) override;
-
-  // IPWL_FocusHandler:
-  void OnSetFocus(CPWL_Wnd* pWnd) override;
-
 #ifdef PDF_ENABLE_XFA
-  // CFFL_FormFiller:
   bool IsFieldFull(CPDFSDK_PageView* pPageView) override;
-#endif  // PDF_ENABLE_XFA
+#endif
+
+  // CPWL_Wnd::FocusHandlerIface:
+  void OnSetFocus(CPWL_Edit* pEdit) override;
 
  private:
-  CFX_WideString GetSelectExportText();
+  WideString GetSelectExportText();
 
-  CBA_FontMap* m_pFontMap;
   FFL_ComboBoxState m_State;
 };
 
diff --git a/fpdfsdk/formfiller/cffl_formfiller.cpp b/fpdfsdk/formfiller/cffl_formfiller.cpp
index da6f920..d3aa37e 100644
--- a/fpdfsdk/formfiller/cffl_formfiller.cpp
+++ b/fpdfsdk/formfiller/cffl_formfiller.cpp
@@ -6,6 +6,8 @@
 
 #include "fpdfsdk/formfiller/cffl_formfiller.h"
 
+#include <utility>
+
 #include "core/fpdfapi/page/cpdf_page.h"
 #include "core/fxge/cfx_renderdevice.h"
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
@@ -13,18 +15,19 @@
 #include "fpdfsdk/cpdfsdk_widget.h"
 #include "fpdfsdk/formfiller/cba_fontmap.h"
 #include "fpdfsdk/fsdk_common.h"
-#include "fpdfsdk/pdfwindow/PWL_Utils.h"
 
-#define GetRed(rgb) ((uint8_t)(rgb))
-#define GetGreen(rgb) ((uint8_t)(((uint16_t)(rgb)) >> 8))
-#define GetBlue(rgb) ((uint8_t)((rgb) >> 16))
+namespace {
 
-#define FFL_HINT_ELAPSE 800
+CPDFSDK_Widget* CPDFSDKAnnotToWidget(CPDFSDK_Annot* annot) {
+  return static_cast<CPDFSDK_Widget*>(annot);
+}
+
+}  // namespace
 
 CFFL_FormFiller::CFFL_FormFiller(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                 CPDFSDK_Annot* pAnnot)
-    : m_pFormFillEnv(pFormFillEnv), m_pAnnot(pAnnot), m_bValid(false) {
-  m_pWidget = static_cast<CPDFSDK_Widget*>(pAnnot);
+                                 CPDFSDK_Widget* pWidget)
+    : m_pFormFillEnv(pFormFillEnv), m_pWidget(pWidget), m_bValid(false) {
+  ASSERT(m_pFormFillEnv);
 }
 
 CFFL_FormFiller::~CFFL_FormFiller() {
@@ -34,7 +37,7 @@
 void CFFL_FormFiller::DestroyWindows() {
   for (const auto& it : m_Maps) {
     CPWL_Wnd* pWnd = it.second;
-    CFFL_PrivateData* pData = (CFFL_PrivateData*)pWnd->GetAttachedData();
+    auto* pData = static_cast<CFFL_PrivateData*>(pWnd->GetAttachedData());
     pWnd->InvalidateProvider(this);
     pWnd->Destroy();
     delete pWnd;
@@ -43,68 +46,53 @@
   m_Maps.clear();
 }
 
-void CFFL_FormFiller::SetWindowRect(CPDFSDK_PageView* pPageView,
-                                    const CFX_FloatRect& rcWindow) {
-  if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false)) {
-    pWnd->Move(CFX_FloatRect(rcWindow), true, false);
-  }
-}
-
-CFX_FloatRect CFFL_FormFiller::GetWindowRect(CPDFSDK_PageView* pPageView) {
-  if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false)) {
-    return pWnd->GetWindowRect();
-  }
-
-  return CFX_FloatRect(0, 0, 0, 0);
-}
-
 FX_RECT CFFL_FormFiller::GetViewBBox(CPDFSDK_PageView* pPageView,
                                      CPDFSDK_Annot* pAnnot) {
   ASSERT(pPageView);
   ASSERT(pAnnot);
 
   CFX_FloatRect rcAnnot = m_pWidget->GetRect();
-
-  if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false)) {
-    CFX_FloatRect rcWindow = pWnd->GetWindowRect();
-    rcAnnot = PWLtoFFL(rcWindow);
-  }
+  if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false))
+    rcAnnot = PWLtoFFL(pWnd->GetWindowRect());
 
   CFX_FloatRect rcWin = rcAnnot;
-
   CFX_FloatRect rcFocus = GetFocusBox(pPageView);
   if (!rcFocus.IsEmpty())
     rcWin.Union(rcFocus);
 
-  CFX_FloatRect rect = CPWL_Utils::InflateRect(rcWin, 1);
-
-  return rect.GetOuterRect();
+  if (!rcWin.IsEmpty()) {
+    rcWin.Inflate(1, 1);
+    rcWin.Normalize();
+  }
+  return rcWin.GetOuterRect();
 }
 
 void CFFL_FormFiller::OnDraw(CPDFSDK_PageView* pPageView,
                              CPDFSDK_Annot* pAnnot,
                              CFX_RenderDevice* pDevice,
-                             CFX_Matrix* pUser2Device) {
+                             const CFX_Matrix& mtUser2Device) {
   ASSERT(pAnnot->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
 
   if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false)) {
     CFX_Matrix mt = GetCurMatrix();
-    mt.Concat(*pUser2Device);
-    pWnd->DrawAppearance(pDevice, &mt);
-  } else {
-    CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)pAnnot;
-    if (CFFL_InteractiveFormFiller::IsVisible(pWidget))
-      pWidget->DrawAppearance(pDevice, pUser2Device, CPDF_Annot::Normal,
-                              nullptr);
+    mt.Concat(mtUser2Device);
+    pWnd->DrawAppearance(pDevice, mt);
+    return;
   }
+
+  CPDFSDK_Widget* pWidget = CPDFSDKAnnotToWidget(pAnnot);
+  if (!CFFL_InteractiveFormFiller::IsVisible(pWidget))
+    return;
+
+  pWidget->DrawAppearance(pDevice, mtUser2Device, CPDF_Annot::Normal, nullptr);
 }
 
 void CFFL_FormFiller::OnDrawDeactive(CPDFSDK_PageView* pPageView,
                                      CPDFSDK_Annot* pAnnot,
                                      CFX_RenderDevice* pDevice,
-                                     CFX_Matrix* pUser2Device) {
-  CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)pAnnot;
-  pWidget->DrawAppearance(pDevice, pUser2Device, CPDF_Annot::Normal, nullptr);
+                                     const CFX_Matrix& mtUser2Device) {
+  CPDFSDKAnnotToWidget(pAnnot)->DrawAppearance(pDevice, mtUser2Device,
+                                               CPDF_Annot::Normal, nullptr);
 }
 
 void CFFL_FormFiller::OnMouseEnter(CPDFSDK_PageView* pPageView,
@@ -120,17 +108,16 @@
                                     CPDFSDK_Annot* pAnnot,
                                     uint32_t nFlags,
                                     const CFX_PointF& point) {
-  if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, true)) {
-    m_bValid = true;
-    FX_RECT rect = GetViewBBox(pPageView, pAnnot);
-    InvalidateRect(rect);
-    if (!rect.Contains(static_cast<int>(point.x), static_cast<int>(point.y)))
-      return false;
+  CPWL_Wnd* pWnd = GetPDFWindow(pPageView, true);
+  if (!pWnd)
+    return false;
 
-    return pWnd->OnLButtonDown(WndtoPWL(pPageView, point), nFlags);
-  }
-
-  return false;
+  m_bValid = true;
+  FX_RECT rect = GetViewBBox(pPageView, pAnnot);
+  InvalidateRect(rect);
+  if (!rect.Contains(static_cast<int>(point.x), static_cast<int>(point.y)))
+    return false;
+  return pWnd->OnLButtonDown(WndtoPWL(pPageView, point), nFlags);
 }
 
 bool CFFL_FormFiller::OnLButtonUp(CPDFSDK_PageView* pPageView,
@@ -162,9 +149,6 @@
                                   CPDFSDK_Annot* pAnnot,
                                   uint32_t nFlags,
                                   const CFX_PointF& point) {
-  if (m_ptOldPos != point)
-    m_ptOldPos = point;
-
   CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false);
   if (!pWnd)
     return false;
@@ -212,31 +196,53 @@
 bool CFFL_FormFiller::OnKeyDown(CPDFSDK_Annot* pAnnot,
                                 uint32_t nKeyCode,
                                 uint32_t nFlags) {
-  if (IsValid()) {
-    CPDFSDK_PageView* pPageView = GetCurPageView(true);
-    ASSERT(pPageView);
+  if (!IsValid())
+    return false;
 
-    if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false)) {
-      return pWnd->OnKeyDown(nKeyCode, nFlags);
-    }
-  }
+  CPDFSDK_PageView* pPageView = GetCurPageView(true);
+  ASSERT(pPageView);
 
-  return false;
+  CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false);
+  return pWnd && pWnd->OnKeyDown(nKeyCode, nFlags);
 }
 
 bool CFFL_FormFiller::OnChar(CPDFSDK_Annot* pAnnot,
                              uint32_t nChar,
                              uint32_t nFlags) {
-  if (IsValid()) {
-    CPDFSDK_PageView* pPageView = GetCurPageView(true);
-    ASSERT(pPageView);
+  if (!IsValid())
+    return false;
 
-    if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false)) {
-      return pWnd->OnChar(nChar, nFlags);
-    }
-  }
+  CPDFSDK_PageView* pPageView = GetCurPageView(true);
+  ASSERT(pPageView);
 
-  return false;
+  CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false);
+  return pWnd && pWnd->OnChar(nChar, nFlags);
+}
+
+WideString CFFL_FormFiller::GetSelectedText(CPDFSDK_Annot* pAnnot) {
+  if (!IsValid())
+    return WideString();
+
+  CPDFSDK_PageView* pPageView = GetCurPageView(true);
+  ASSERT(pPageView);
+
+  CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false);
+  return pWnd ? pWnd->GetSelectedText() : WideString();
+}
+
+void CFFL_FormFiller::ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                                       const WideString& text) {
+  if (!IsValid())
+    return;
+
+  CPDFSDK_PageView* pPageView = GetCurPageView(true);
+  ASSERT(pPageView);
+
+  CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false);
+  if (!pWnd)
+    return;
+
+  pWnd->ReplaceSelection(text);
 }
 
 void CFFL_FormFiller::SetFocusForAnnot(CPDFSDK_Annot* pAnnot, uint32_t nFlag) {
@@ -255,19 +261,16 @@
     return;
 
   CPDFSDK_PageView* pPageView = GetCurPageView(false);
-  if (!pPageView)
+  if (!pPageView || !CommitData(pPageView, nFlag))
     return;
-
-  CommitData(pPageView, nFlag);
-
   if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false))
     pWnd->KillFocus();
 
   bool bDestroyPDFWindow;
   switch (m_pWidget->GetFieldType()) {
-    case FIELDTYPE_PUSHBUTTON:
-    case FIELDTYPE_CHECKBOX:
-    case FIELDTYPE_RADIOBUTTON:
+    case FormFieldType::kPushButton:
+    case FormFieldType::kCheckBox:
+    case FormFieldType::kRadioButton:
       bDestroyPDFWindow = true;
       break;
     default:
@@ -281,36 +284,27 @@
   return m_bValid;
 }
 
-PWL_CREATEPARAM CFFL_FormFiller::GetCreateParam() {
-  ASSERT(m_pFormFillEnv);
-
-  PWL_CREATEPARAM cp;
+CPWL_Wnd::CreateParams CFFL_FormFiller::GetCreateParam() {
+  CPWL_Wnd::CreateParams cp;
   cp.pParentWnd = nullptr;
   cp.pProvider.Reset(this);
   cp.rcRectWnd = GetPDFWindowRect();
 
   uint32_t dwCreateFlags = PWS_BORDER | PWS_BACKGROUND | PWS_VISIBLE;
   uint32_t dwFieldFlag = m_pWidget->GetFieldFlags();
-  if (dwFieldFlag & FIELDFLAG_READONLY) {
+  if (dwFieldFlag & FIELDFLAG_READONLY)
     dwCreateFlags |= PWS_READONLY;
-  }
 
   FX_COLORREF color;
-  if (m_pWidget->GetFillColor(color)) {
-    cp.sBackgroundColor =
-        CPWL_Color(GetRed(color), GetGreen(color), GetBlue(color));
-  }
+  if (m_pWidget->GetFillColor(color))
+    cp.sBackgroundColor = CFX_Color(color);
+  if (m_pWidget->GetBorderColor(color))
+    cp.sBorderColor = CFX_Color(color);
 
-  if (m_pWidget->GetBorderColor(color)) {
-    cp.sBorderColor =
-        CPWL_Color(GetRed(color), GetGreen(color), GetBlue(color));
-  }
+  cp.sTextColor = CFX_Color(CFX_Color::kGray, 0);
 
-  cp.sTextColor = CPWL_Color(COLORTYPE_GRAY, 0);
-
-  if (m_pWidget->GetTextColor(color)) {
-    cp.sTextColor = CPWL_Color(GetRed(color), GetGreen(color), GetBlue(color));
-  }
+  if (m_pWidget->GetTextColor(color))
+    cp.sTextColor = CFX_Color(color);
 
   cp.fFontSize = m_pWidget->GetFontSize();
   cp.dwBorderWidth = m_pWidget->GetBorderWidth();
@@ -321,8 +315,6 @@
       cp.sDash = CPWL_Dash(3, 3, 0);
       break;
     case BorderStyle::BEVELED:
-      cp.dwBorderWidth *= 2;
-      break;
     case BorderStyle::INSET:
       cp.dwBorderWidth *= 2;
       break;
@@ -348,29 +340,27 @@
   if (!bNew)
     return pWnd;
 
-  if (found) {
-    CFFL_PrivateData* pPrivateData = (CFFL_PrivateData*)pWnd->GetAttachedData();
-    if (pPrivateData->nWidgetAge != m_pWidget->GetAppearanceAge()) {
-      return ResetPDFWindow(
-          pPageView, m_pWidget->GetValueAge() == pPrivateData->nValueAge);
-    }
-  } else {
-    PWL_CREATEPARAM cp = GetCreateParam();
-    cp.pAttachedWidget.Reset(m_pWidget);
+  if (!found) {
+    CPWL_Wnd::CreateParams cp = GetCreateParam();
+    cp.pAttachedWidget.Reset(m_pWidget.Get());
 
-    CFFL_PrivateData* pPrivateData = new CFFL_PrivateData;
-    pPrivateData->pWidget = m_pWidget;
+    auto* pPrivateData = new CFFL_PrivateData;
+    pPrivateData->pWidget = m_pWidget.Get();
     pPrivateData->pPageView = pPageView;
-    pPrivateData->nWidgetAge = m_pWidget->GetAppearanceAge();
-    pPrivateData->nValueAge = 0;
-
+    pPrivateData->nWidgetAppearanceAge = m_pWidget->GetAppearanceAge();
+    pPrivateData->nWidgetValueAge = 0;
     cp.pAttachedData = pPrivateData;
-
-    pWnd = NewPDFWindow(cp, pPageView);
-    m_Maps[pPageView] = pWnd;
+    CPWL_Wnd* pNewWnd = NewPDFWindow(cp);
+    m_Maps[pPageView] = pNewWnd;
+    return pNewWnd;
   }
 
-  return pWnd;
+  auto* pPrivateData = static_cast<CFFL_PrivateData*>(pWnd->GetAttachedData());
+  if (pPrivateData->nWidgetAppearanceAge == m_pWidget->GetAppearanceAge())
+    return pWnd;
+
+  return ResetPDFWindow(
+      pPageView, pPrivateData->nWidgetValueAge == m_pWidget->GetValueAge());
 }
 
 void CFFL_FormFiller::DestroyPDFWindow(CPDFSDK_PageView* pPageView) {
@@ -379,39 +369,30 @@
     return;
 
   CPWL_Wnd* pWnd = it->second;
-  CFFL_PrivateData* pData = (CFFL_PrivateData*)pWnd->GetAttachedData();
+  auto* pData = static_cast<CFFL_PrivateData*>(pWnd->GetAttachedData());
   pWnd->Destroy();
   delete pWnd;
   delete pData;
-
   m_Maps.erase(it);
 }
 
-CFX_Matrix CFFL_FormFiller::GetWindowMatrix(void* pAttachedData) {
-  if (CFFL_PrivateData* pPrivateData = (CFFL_PrivateData*)pAttachedData) {
-    if (pPrivateData->pPageView) {
-      CFX_Matrix mtPageView;
-      pPrivateData->pPageView->GetCurrentMatrix(mtPageView);
+CFX_Matrix CFFL_FormFiller::GetWindowMatrix(CPWL_Wnd::PrivateData* pAttached) {
+  CFX_Matrix mt;
+  auto* pPrivateData = static_cast<CFFL_PrivateData*>(pAttached);
+  if (!pPrivateData || !pPrivateData->pPageView)
+    return mt;
 
-      CFX_Matrix mt = GetCurMatrix();
-      mt.Concat(mtPageView);
-
-      return mt;
-    }
-  }
-  return CFX_Matrix(1, 0, 0, 1, 0, 0);
+  CFX_Matrix mtPageView;
+  pPrivateData->pPageView->GetCurrentMatrix(mtPageView);
+  mt = GetCurMatrix();
+  mt.Concat(mtPageView);
+  return mt;
 }
 
 CFX_Matrix CFFL_FormFiller::GetCurMatrix() {
   CFX_Matrix mt;
-
   CFX_FloatRect rcDA = m_pWidget->GetPDFAnnot()->GetRect();
-
   switch (m_pWidget->GetRotate()) {
-    default:
-    case 0:
-      mt = CFX_Matrix(1, 0, 0, 1, 0, 0);
-      break;
     case 90:
       mt = CFX_Matrix(0, 1, -1, 0, rcDA.right - rcDA.left, 0);
       break;
@@ -422,6 +403,9 @@
     case 270:
       mt = CFX_Matrix(0, -1, 1, 0, 0, rcDA.top - rcDA.bottom);
       break;
+    case 0:
+    default:
+      break;
   }
   mt.e += rcDA.left;
   mt.f += rcDA.bottom;
@@ -429,61 +413,42 @@
   return mt;
 }
 
-CFX_WideString CFFL_FormFiller::LoadPopupMenuString(int nIndex) {
-  ASSERT(m_pFormFillEnv);
-
-  return L"";
-}
-
 CFX_FloatRect CFFL_FormFiller::GetPDFWindowRect() const {
   CFX_FloatRect rectAnnot = m_pWidget->GetPDFAnnot()->GetRect();
 
-  FX_FLOAT fWidth = rectAnnot.right - rectAnnot.left;
-  FX_FLOAT fHeight = rectAnnot.top - rectAnnot.bottom;
+  float fWidth = rectAnnot.right - rectAnnot.left;
+  float fHeight = rectAnnot.top - rectAnnot.bottom;
   if ((m_pWidget->GetRotate() / 90) & 0x01)
-    return CFX_FloatRect(0, 0, fHeight, fWidth);
-
+    std::swap(fWidth, fHeight);
   return CFX_FloatRect(0, 0, fWidth, fHeight);
 }
 
 CPDFSDK_PageView* CFFL_FormFiller::GetCurPageView(bool renew) {
-  UnderlyingPageType* pPage = m_pAnnot->GetUnderlyingPage();
-  return m_pFormFillEnv ? m_pFormFillEnv->GetPageView(pPage, renew) : nullptr;
+  UnderlyingPageType* pPage = m_pWidget->GetUnderlyingPage();
+  return m_pFormFillEnv->GetPageView(pPage, renew);
 }
 
 CFX_FloatRect CFFL_FormFiller::GetFocusBox(CPDFSDK_PageView* pPageView) {
-  if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false)) {
-    CFX_FloatRect rcFocus = FFLtoWnd(pPageView, PWLtoFFL(pWnd->GetFocusRect()));
-    CFX_FloatRect rcPage = pPageView->GetPDFPage()->GetPageBBox();
-    if (rcPage.Contains(rcFocus))
-      return rcFocus;
-  }
-  return CFX_FloatRect(0, 0, 0, 0);
+  CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false);
+  if (!pWnd)
+    return CFX_FloatRect();
+
+  CFX_FloatRect rcFocus = FFLtoWnd(pPageView, PWLtoFFL(pWnd->GetFocusRect()));
+  return pPageView->GetPDFPage()->GetPageBBox().Contains(rcFocus)
+             ? rcFocus
+             : CFX_FloatRect();
 }
 
 CFX_FloatRect CFFL_FormFiller::FFLtoPWL(const CFX_FloatRect& rect) {
-  CFX_Matrix mt;
-  mt.SetReverse(GetCurMatrix());
-
-  CFX_FloatRect temp = rect;
-  mt.TransformRect(temp);
-
-  return temp;
+  return GetCurMatrix().GetInverse().TransformRect(rect);
 }
 
 CFX_FloatRect CFFL_FormFiller::PWLtoFFL(const CFX_FloatRect& rect) {
-  CFX_Matrix mt = GetCurMatrix();
-
-  CFX_FloatRect temp = rect;
-  mt.TransformRect(temp);
-
-  return temp;
+  return GetCurMatrix().TransformRect(rect);
 }
 
 CFX_PointF CFFL_FormFiller::FFLtoPWL(const CFX_PointF& point) {
-  CFX_Matrix mt;
-  mt.SetReverse(GetCurMatrix());
-  return mt.Transform(point);
+  return GetCurMatrix().GetInverse().Transform(point);
 }
 
 CFX_PointF CFFL_FormFiller::PWLtoFFL(const CFX_PointF& point) {
@@ -501,33 +466,43 @@
 }
 
 bool CFFL_FormFiller::CommitData(CPDFSDK_PageView* pPageView, uint32_t nFlag) {
-  if (IsDataChanged(pPageView)) {
-    bool bRC = true;
-    bool bExit = false;
-    CFFL_InteractiveFormFiller* pFormFiller =
-        m_pFormFillEnv->GetInteractiveFormFiller();
-    CPDFSDK_Annot::ObservedPtr pObserved(m_pWidget);
-    pFormFiller->OnKeyStrokeCommit(&pObserved, pPageView, bRC, bExit, nFlag);
-    if (!pObserved || bExit)
-      return true;
-    if (!bRC) {
-      ResetPDFWindow(pPageView, false);
-      return true;
-    }
-    pFormFiller->OnValidate(&pObserved, pPageView, bRC, bExit, nFlag);
-    if (!pObserved || bExit)
-      return true;
-    if (!bRC) {
-      ResetPDFWindow(pPageView, false);
-      return true;
-    }
-    SaveData(pPageView);
-    pFormFiller->OnCalculate(m_pWidget, pPageView, bExit, nFlag);
-    if (bExit)
-      return true;
+  if (!IsDataChanged(pPageView))
+    return true;
 
-    pFormFiller->OnFormat(m_pWidget, pPageView, bExit, nFlag);
+  CFFL_InteractiveFormFiller* pFormFiller =
+      m_pFormFillEnv->GetInteractiveFormFiller();
+  CPDFSDK_Annot::ObservedPtr pObserved(m_pWidget.Get());
+
+  if (!pFormFiller->OnKeyStrokeCommit(&pObserved, pPageView, nFlag)) {
+    if (!pObserved)
+      return false;
+    ResetPDFWindow(pPageView, false);
+    return true;
   }
+  if (!pObserved)
+    return false;
+
+  if (!pFormFiller->OnValidate(&pObserved, pPageView, nFlag)) {
+    if (!pObserved)
+      return false;
+    ResetPDFWindow(pPageView, false);
+    return true;
+  }
+  if (!pObserved)
+    return false;
+
+  SaveData(pPageView); // may invoking JS to delete this widget.
+  if (!pObserved)
+    return false;
+
+  pFormFiller->OnCalculate(&pObserved, pPageView, nFlag);
+  if (!pObserved)
+    return false;
+
+  pFormFiller->OnFormat(&pObserved, pPageView, nFlag);
+  if (!pObserved)
+    return false;
+
   return true;
 }
 
@@ -582,7 +557,7 @@
                                    bool bDestroyPDFWindow) {
   m_bValid = false;
 
-  InvalidateRect(GetViewBBox(pPageView, m_pWidget));
+  InvalidateRect(GetViewBBox(pPageView, m_pWidget.Get()));
   if (bDestroyPDFWindow)
     DestroyPDFWindow(pPageView);
 }
@@ -590,98 +565,3 @@
 void CFFL_FormFiller::InvalidateRect(const FX_RECT& rect) {
   m_pFormFillEnv->Invalidate(m_pWidget->GetUnderlyingPage(), rect);
 }
-
-CFFL_Button::CFFL_Button(CPDFSDK_FormFillEnvironment* pApp,
-                         CPDFSDK_Annot* pWidget)
-    : CFFL_FormFiller(pApp, pWidget), m_bMouseIn(false), m_bMouseDown(false) {}
-
-CFFL_Button::~CFFL_Button() {}
-
-void CFFL_Button::OnMouseEnter(CPDFSDK_PageView* pPageView,
-                               CPDFSDK_Annot* pAnnot) {
-  m_bMouseIn = true;
-  InvalidateRect(GetViewBBox(pPageView, pAnnot));
-}
-
-void CFFL_Button::OnMouseExit(CPDFSDK_PageView* pPageView,
-                              CPDFSDK_Annot* pAnnot) {
-  m_bMouseIn = false;
-
-  InvalidateRect(GetViewBBox(pPageView, pAnnot));
-  EndTimer();
-  ASSERT(m_pWidget);
-}
-
-bool CFFL_Button::OnLButtonDown(CPDFSDK_PageView* pPageView,
-                                CPDFSDK_Annot* pAnnot,
-                                uint32_t nFlags,
-                                const CFX_PointF& point) {
-  if (!pAnnot->GetRect().Contains(point))
-    return false;
-
-  m_bMouseDown = true;
-  m_bValid = true;
-  InvalidateRect(GetViewBBox(pPageView, pAnnot));
-  return true;
-}
-
-bool CFFL_Button::OnLButtonUp(CPDFSDK_PageView* pPageView,
-                              CPDFSDK_Annot* pAnnot,
-                              uint32_t nFlags,
-                              const CFX_PointF& point) {
-  if (!pAnnot->GetRect().Contains(point))
-    return false;
-
-  m_bMouseDown = false;
-  m_pWidget->GetPDFPage();
-
-  InvalidateRect(GetViewBBox(pPageView, pAnnot));
-  return true;
-}
-
-bool CFFL_Button::OnMouseMove(CPDFSDK_PageView* pPageView,
-                              CPDFSDK_Annot* pAnnot,
-                              uint32_t nFlags,
-                              const CFX_PointF& point) {
-  ASSERT(m_pFormFillEnv);
-  return true;
-}
-
-void CFFL_Button::OnDraw(CPDFSDK_PageView* pPageView,
-                         CPDFSDK_Annot* pAnnot,
-                         CFX_RenderDevice* pDevice,
-                         CFX_Matrix* pUser2Device) {
-  ASSERT(pPageView);
-  CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)pAnnot;
-  CPDF_FormControl* pCtrl = pWidget->GetFormControl();
-  CPDF_FormControl::HighlightingMode eHM = pCtrl->GetHighlightingMode();
-
-  if (eHM != CPDF_FormControl::Push) {
-    pWidget->DrawAppearance(pDevice, pUser2Device, CPDF_Annot::Normal, nullptr);
-    return;
-  }
-
-  if (m_bMouseDown) {
-    if (pWidget->IsWidgetAppearanceValid(CPDF_Annot::Down))
-      pWidget->DrawAppearance(pDevice, pUser2Device, CPDF_Annot::Down, nullptr);
-    else
-      pWidget->DrawAppearance(pDevice, pUser2Device, CPDF_Annot::Normal,
-                              nullptr);
-  } else if (m_bMouseIn) {
-    if (pWidget->IsWidgetAppearanceValid(CPDF_Annot::Rollover))
-      pWidget->DrawAppearance(pDevice, pUser2Device, CPDF_Annot::Rollover,
-                              nullptr);
-    else
-      pWidget->DrawAppearance(pDevice, pUser2Device, CPDF_Annot::Normal,
-                              nullptr);
-  } else {
-    pWidget->DrawAppearance(pDevice, pUser2Device, CPDF_Annot::Normal, nullptr);
-  }
-}
-
-void CFFL_Button::OnDrawDeactive(CPDFSDK_PageView* pPageView,
-                                 CPDFSDK_Annot* pAnnot,
-                                 CFX_RenderDevice* pDevice,
-                                 CFX_Matrix* pUser2Device) {
-  OnDraw(pPageView, pAnnot, pDevice, pUser2Device);
-}
diff --git a/fpdfsdk/formfiller/cffl_formfiller.h b/fpdfsdk/formfiller/cffl_formfiller.h
index c6b1e59..11a2f8c 100644
--- a/fpdfsdk/formfiller/cffl_formfiller.h
+++ b/fpdfsdk/formfiller/cffl_formfiller.h
@@ -9,6 +9,7 @@
 
 #include <map>
 
+#include "core/fxcrt/unowned_ptr.h"
 #include "fpdfsdk/formfiller/cba_fontmap.h"
 #include "fpdfsdk/formfiller/cffl_interactiveformfiller.h"
 #include "fpdfsdk/pdfsdk_fieldaction.h"
@@ -18,10 +19,11 @@
 class CPDFSDK_PageView;
 class CPDFSDK_Widget;
 
-class CFFL_FormFiller : public IPWL_Provider, public CPWL_TimerHandler {
+class CFFL_FormFiller : public CPWL_Wnd::ProviderIface,
+                        public CPWL_TimerHandler {
  public:
   CFFL_FormFiller(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                  CPDFSDK_Annot* pAnnot);
+                  CPDFSDK_Widget* pWidget);
   ~CFFL_FormFiller() override;
 
   virtual FX_RECT GetViewBBox(CPDFSDK_PageView* pPageView,
@@ -29,11 +31,11 @@
   virtual void OnDraw(CPDFSDK_PageView* pPageView,
                       CPDFSDK_Annot* pAnnot,
                       CFX_RenderDevice* pDevice,
-                      CFX_Matrix* pUser2Device);
+                      const CFX_Matrix& mtUser2Device);
   virtual void OnDrawDeactive(CPDFSDK_PageView* pPageView,
                               CPDFSDK_Annot* pAnnot,
                               CFX_RenderDevice* pDevice,
-                              CFX_Matrix* pUser2Device);
+                              const CFX_Matrix& mtUser2Device);
 
   virtual void OnMouseEnter(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot);
   virtual void OnMouseExit(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot);
@@ -73,6 +75,9 @@
                          uint32_t nFlags);
   virtual bool OnChar(CPDFSDK_Annot* pAnnot, uint32_t nChar, uint32_t nFlags);
 
+  WideString GetSelectedText(CPDFSDK_Annot* pAnnot);
+  void ReplaceSelection(CPDFSDK_Annot* pAnnot, const WideString& text);
+
   void SetFocusForAnnot(CPDFSDK_Annot* pAnnot, uint32_t nFlag);
   void KillFocusForAnnot(CPDFSDK_Annot* pAnnot, uint32_t nFlag);
 
@@ -80,9 +85,8 @@
   void TimerProc() override;
   CFX_SystemHandler* GetSystemHandler() const override;
 
-  // IPWL_Provider
-  CFX_Matrix GetWindowMatrix(void* pAttachedData) override;
-  CFX_WideString LoadPopupMenuString(int nIndex) override;
+  // CPWL_Wnd::ProviderIface:
+  CFX_Matrix GetWindowMatrix(CPWL_Wnd::PrivateData* pAttached) override;
 
   virtual void GetActionData(CPDFSDK_PageView* pPageView,
                              CPDF_AAction::AActionType type,
@@ -111,10 +115,6 @@
   CFX_FloatRect FFLtoWnd(CPDFSDK_PageView* pPageView,
                          const CFX_FloatRect& rect);
 
-  void SetWindowRect(CPDFSDK_PageView* pPageView,
-                     const CFX_FloatRect& rcWindow);
-  CFX_FloatRect GetWindowRect(CPDFSDK_PageView* pPageView);
-
   bool CommitData(CPDFSDK_PageView* pPageView, uint32_t nFlag);
   virtual bool IsDataChanged(CPDFSDK_PageView* pPageView);
   virtual void SaveData(CPDFSDK_PageView* pPageView);
@@ -127,9 +127,8 @@
   void DestroyPDFWindow(CPDFSDK_PageView* pPageView);
   void EscapeFiller(CPDFSDK_PageView* pPageView, bool bDestroyPDFWindow);
 
-  virtual PWL_CREATEPARAM GetCreateParam();
-  virtual CPWL_Wnd* NewPDFWindow(const PWL_CREATEPARAM& cp,
-                                 CPDFSDK_PageView* pPageView) = 0;
+  virtual CPWL_Wnd::CreateParams GetCreateParam();
+  virtual CPWL_Wnd* NewPDFWindow(const CPWL_Wnd::CreateParams& cp) = 0;
   virtual CFX_FloatRect GetFocusBox(CPDFSDK_PageView* pPageView);
 
   bool IsValid() const;
@@ -138,8 +137,7 @@
   CPDFSDK_PageView* GetCurPageView(bool renew);
   void SetChangeMark();
 
-  virtual void InvalidateRect(const FX_RECT& rect);
-  CPDFSDK_Annot* GetSDKAnnot() { return m_pAnnot; }
+  CPDFSDK_Annot* GetSDKAnnot() { return m_pWidget.Get(); }
 
  protected:
   using CFFL_PageView2PDFWindow = std::map<CPDFSDK_PageView*, CPWL_Wnd*>;
@@ -152,48 +150,12 @@
   // until the PWL_Edit is done with it. pdfium:566
   void DestroyWindows();
 
-  CPDFSDK_FormFillEnvironment* m_pFormFillEnv;
-  CPDFSDK_Widget* m_pWidget;
-  CPDFSDK_Annot* m_pAnnot;
+  void InvalidateRect(const FX_RECT& rect);
+
+  UnownedPtr<CPDFSDK_FormFillEnvironment> const m_pFormFillEnv;
+  UnownedPtr<CPDFSDK_Widget> m_pWidget;
   bool m_bValid;
   CFFL_PageView2PDFWindow m_Maps;
-  CFX_PointF m_ptOldPos;
-};
-
-class CFFL_Button : public CFFL_FormFiller {
- public:
-  CFFL_Button(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-              CPDFSDK_Annot* pWidget);
-  ~CFFL_Button() override;
-
-  // CFFL_FormFiller
-  void OnMouseEnter(CPDFSDK_PageView* pPageView,
-                    CPDFSDK_Annot* pAnnot) override;
-  void OnMouseExit(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot) override;
-  bool OnLButtonDown(CPDFSDK_PageView* pPageView,
-                     CPDFSDK_Annot* pAnnot,
-                     uint32_t nFlags,
-                     const CFX_PointF& point) override;
-  bool OnLButtonUp(CPDFSDK_PageView* pPageView,
-                   CPDFSDK_Annot* pAnnot,
-                   uint32_t nFlags,
-                   const CFX_PointF& point) override;
-  bool OnMouseMove(CPDFSDK_PageView* pPageView,
-                   CPDFSDK_Annot* pAnnot,
-                   uint32_t nFlags,
-                   const CFX_PointF& point) override;
-  void OnDraw(CPDFSDK_PageView* pPageView,
-              CPDFSDK_Annot* pAnnot,
-              CFX_RenderDevice* pDevice,
-              CFX_Matrix* pUser2Device) override;
-  void OnDrawDeactive(CPDFSDK_PageView* pPageView,
-                      CPDFSDK_Annot* pAnnot,
-                      CFX_RenderDevice* pDevice,
-                      CFX_Matrix* pUser2Device) override;
-
- protected:
-  bool m_bMouseIn;
-  bool m_bMouseDown;
 };
 
 #endif  // FPDFSDK_FORMFILLER_CFFL_FORMFILLER_H_
diff --git a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
index a830d52..e74f902 100644
--- a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
+++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
@@ -8,6 +8,7 @@
 
 #include "core/fpdfapi/page/cpdf_page.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
+#include "core/fxcrt/autorestorer.h"
 #include "core/fxge/cfx_graphstatedata.h"
 #include "core/fxge/cfx_pathdata.h"
 #include "core/fxge/cfx_renderdevice.h"
@@ -22,9 +23,7 @@
 #include "fpdfsdk/formfiller/cffl_pushbutton.h"
 #include "fpdfsdk/formfiller/cffl_radiobutton.h"
 #include "fpdfsdk/formfiller/cffl_textfield.h"
-#include "fpdfsdk/pdfwindow/PWL_Utils.h"
-
-#define FFL_MAXLISTBOXHEIGHT 140.0f
+#include "third_party/base/stl_util.h"
 
 CFFL_InteractiveFormFiller::CFFL_InteractiveFormFiller(
     CPDFSDK_FormFillEnvironment* pFormFillEnv)
@@ -46,7 +45,11 @@
   ASSERT(pPageView);
 
   CPDF_Annot* pPDFAnnot = pAnnot->GetPDFAnnot();
-  CFX_FloatRect rcWin = CPWL_Utils::InflateRect(pPDFAnnot->GetRect(), 1);
+  CFX_FloatRect rcWin = pPDFAnnot->GetRect();
+  if (!rcWin.IsEmpty()) {
+    rcWin.Inflate(1, 1);
+    rcWin.Normalize();
+  }
   return rcWin.GetOuterRect();
 }
 
@@ -55,48 +58,50 @@
                                         CFX_RenderDevice* pDevice,
                                         CFX_Matrix* pUser2Device) {
   ASSERT(pPageView);
-  CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)pAnnot;
-
+  CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot);
   if (!IsVisible(pWidget))
     return;
 
-  if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false)) {
-    if (pFormFiller->IsValid()) {
-      pFormFiller->OnDraw(pPageView, pAnnot, pDevice, pUser2Device);
-      pAnnot->GetPDFPage();
+  CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false);
+  if (pFormFiller && pFormFiller->IsValid()) {
+    pFormFiller->OnDraw(pPageView, pAnnot, pDevice, *pUser2Device);
+    pAnnot->GetPDFPage();
 
-      if (m_pFormFillEnv->GetFocusAnnot() == pAnnot) {
-        CFX_FloatRect rcFocus = pFormFiller->GetFocusBox(pPageView);
-        if (!rcFocus.IsEmpty()) {
-          CFX_PathData path;
-          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);
-          gsd.m_DashArray[0] = 1.0f;
-          gsd.m_DashPhase = 0;
-          gsd.m_LineWidth = 1.0f;
-          pDevice->DrawPath(&path, pUser2Device, &gsd, 0,
-                            ArgbEncode(255, 0, 0, 0), FXFILL_ALTERNATE);
-        }
-      }
+    if (m_pFormFillEnv->GetFocusAnnot() != pAnnot)
       return;
-    }
+
+    CFX_FloatRect rcFocus = pFormFiller->GetFocusBox(pPageView);
+    if (rcFocus.IsEmpty())
+      return;
+
+    CFX_PathData path;
+    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);
+    gsd.m_DashArray[0] = 1.0f;
+    gsd.m_DashPhase = 0;
+    gsd.m_LineWidth = 1.0f;
+    pDevice->DrawPath(&path, pUser2Device, &gsd, 0, ArgbEncode(255, 0, 0, 0),
+                      FXFILL_ALTERNATE);
+    return;
   }
 
-  if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false)) {
-    pFormFiller->OnDrawDeactive(pPageView, pAnnot, pDevice, pUser2Device);
+  pFormFiller = GetFormFiller(pAnnot, false);
+  if (pFormFiller) {
+    pFormFiller->OnDrawDeactive(pPageView, pAnnot, pDevice, *pUser2Device);
   } else {
-    pWidget->DrawAppearance(pDevice, pUser2Device, CPDF_Annot::Normal, nullptr);
+    pWidget->DrawAppearance(pDevice, *pUser2Device, CPDF_Annot::Normal,
+                            nullptr);
   }
 
   if (!IsReadOnly(pWidget) && IsFillingAllowed(pWidget))
@@ -117,13 +122,13 @@
     if (pWidget->GetAAction(CPDF_AAction::CursorEnter).GetDict()) {
       m_bNotifying = true;
 
-      int nValueAge = pWidget->GetValueAge();
+      uint32_t nValueAge = pWidget->GetValueAge();
       pWidget->ClearAppModified();
       ASSERT(pPageView);
 
       PDFSDK_FieldAction fa;
-      fa.bModifier = m_pFormFillEnv->IsCTRLKeyDown(nFlag);
-      fa.bShift = m_pFormFillEnv->IsSHIFTKeyDown(nFlag);
+      fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
+      fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
       pWidget->OnAAction(CPDF_AAction::CursorEnter, fa, pPageView);
       m_bNotifying = false;
       if (!(*pAnnot))
@@ -149,15 +154,14 @@
     CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
     if (pWidget->GetAAction(CPDF_AAction::CursorExit).GetDict()) {
       m_bNotifying = true;
-      pWidget->GetAppearanceAge();
 
-      int nValueAge = pWidget->GetValueAge();
+      uint32_t nValueAge = pWidget->GetValueAge();
       pWidget->ClearAppModified();
       ASSERT(pPageView);
 
       PDFSDK_FieldAction fa;
-      fa.bModifier = m_pFormFillEnv->IsCTRLKeyDown(nFlag);
-      fa.bShift = m_pFormFillEnv->IsSHIFTKeyDown(nFlag);
+      fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
+      fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
       pWidget->OnAAction(CPDF_AAction::CursorExit, fa, pPageView);
       m_bNotifying = false;
       if (!(*pAnnot))
@@ -186,15 +190,14 @@
     if (Annot_HitTest(pPageView, pAnnot->Get(), point) &&
         pWidget->GetAAction(CPDF_AAction::ButtonDown).GetDict()) {
       m_bNotifying = true;
-      pWidget->GetAppearanceAge();
 
-      int nValueAge = pWidget->GetValueAge();
+      uint32_t nValueAge = pWidget->GetValueAge();
       pWidget->ClearAppModified();
       ASSERT(pPageView);
 
       PDFSDK_FieldAction fa;
-      fa.bModifier = m_pFormFillEnv->IsCTRLKeyDown(nFlags);
-      fa.bShift = m_pFormFillEnv->IsSHIFTKeyDown(nFlags);
+      fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlags);
+      fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlags);
       pWidget->OnAAction(CPDF_AAction::ButtonDown, fa, pPageView);
       m_bNotifying = false;
       if (!(*pAnnot))
@@ -211,10 +214,9 @@
       }
     }
   }
-  if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false))
-    return pFormFiller->OnLButtonDown(pPageView, pAnnot->Get(), nFlags, point);
-
-  return false;
+  CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false);
+  return pFormFiller &&
+         pFormFiller->OnLButtonDown(pPageView, pAnnot->Get(), nFlags, point);
 }
 
 bool CFFL_InteractiveFormFiller::OnLButtonUp(CPDFSDK_PageView* pPageView,
@@ -224,70 +226,67 @@
   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
   CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
 
+  bool bSetFocus;
   switch (pWidget->GetFieldType()) {
-    case FIELDTYPE_PUSHBUTTON:
-    case FIELDTYPE_CHECKBOX:
-    case FIELDTYPE_RADIOBUTTON:
-      if (GetViewBBox(pPageView, pAnnot->Get())
-              .Contains((int)point.x, (int)point.y))
-        m_pFormFillEnv->SetFocusAnnot(pAnnot);
+    case FormFieldType::kPushButton:
+    case FormFieldType::kCheckBox:
+    case FormFieldType::kRadioButton: {
+      FX_RECT bbox = GetViewBBox(pPageView, pAnnot->Get());
+      bSetFocus =
+          bbox.Contains(static_cast<int>(point.x), static_cast<int>(point.y));
       break;
+    }
     default:
-      m_pFormFillEnv->SetFocusAnnot(pAnnot);
+      bSetFocus = true;
       break;
   }
+  if (bSetFocus)
+    m_pFormFillEnv->SetFocusAnnot(pAnnot);
 
-  bool bRet = false;
-  if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false))
-    bRet = pFormFiller->OnLButtonUp(pPageView, pAnnot->Get(), nFlags, point);
-
-  if (m_pFormFillEnv->GetFocusAnnot() == pAnnot->Get()) {
-    bool bExit = false;
-    bool bReset = false;
-    OnButtonUp(pAnnot, pPageView, bReset, bExit, nFlags);
-    if (!pAnnot || bExit)
-      return true;
+  CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false);
+  bool bRet = pFormFiller &&
+              pFormFiller->OnLButtonUp(pPageView, pAnnot->Get(), nFlags, point);
+  if (m_pFormFillEnv->GetFocusAnnot() != pAnnot->Get())
+    return bRet;
+  if (OnButtonUp(pAnnot, pPageView, nFlags) || !pAnnot)
+    return true;
 #ifdef PDF_ENABLE_XFA
-    OnClick(pWidget, pPageView, bReset, bExit, nFlags);
-    if (!pAnnot || bExit)
-      return true;
+  if (OnClick(pAnnot, pPageView, nFlags) || !pAnnot)
+    return true;
 #endif  // PDF_ENABLE_XFA
-  }
   return bRet;
 }
 
-void CFFL_InteractiveFormFiller::OnButtonUp(CPDFSDK_Annot::ObservedPtr* pAnnot,
+bool CFFL_InteractiveFormFiller::OnButtonUp(CPDFSDK_Annot::ObservedPtr* pAnnot,
                                             CPDFSDK_PageView* pPageView,
-                                            bool& bReset,
-                                            bool& bExit,
                                             uint32_t nFlag) {
-  if (!m_bNotifying) {
-    CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
-    if (pWidget->GetAAction(CPDF_AAction::ButtonUp).GetDict()) {
-      m_bNotifying = true;
+  if (m_bNotifying)
+    return false;
 
-      int nAge = pWidget->GetAppearanceAge();
-      int nValueAge = pWidget->GetValueAge();
-      ASSERT(pPageView);
+  CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
+  if (!pWidget->GetAAction(CPDF_AAction::ButtonUp).GetDict())
+    return false;
 
-      PDFSDK_FieldAction fa;
-      fa.bModifier = m_pFormFillEnv->IsCTRLKeyDown(nFlag);
-      fa.bShift = m_pFormFillEnv->IsSHIFTKeyDown(nFlag);
-      pWidget->OnAAction(CPDF_AAction::ButtonUp, fa, pPageView);
-      m_bNotifying = false;
-      if (!(*pAnnot) || !IsValidAnnot(pPageView, pWidget)) {
-        bExit = true;
-        return;
-      }
-      if (nAge != pWidget->GetAppearanceAge()) {
-        if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false)) {
-          pFormFiller->ResetPDFWindow(pPageView,
-                                      nValueAge == pWidget->GetValueAge());
-        }
-        bReset = true;
-      }
-    }
-  }
+  m_bNotifying = true;
+
+  uint32_t nAge = pWidget->GetAppearanceAge();
+  uint32_t nValueAge = pWidget->GetValueAge();
+  ASSERT(pPageView);
+
+  PDFSDK_FieldAction fa;
+  fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
+  fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
+  pWidget->OnAAction(CPDF_AAction::ButtonUp, fa, pPageView);
+  m_bNotifying = false;
+  if (!(*pAnnot) || !IsValidAnnot(pPageView, pWidget))
+    return true;
+  if (nAge == pWidget->GetAppearanceAge())
+    return false;
+
+  CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false);
+  if (pFormFiller)
+    pFormFiller->ResetPDFWindow(pPageView, nValueAge == pWidget->GetValueAge());
+  return true;
 }
 
 bool CFFL_InteractiveFormFiller::OnLButtonDblClk(
@@ -350,11 +349,8 @@
                                            uint32_t nFlags) {
   ASSERT(pAnnot->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
 
-  if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false)) {
-    return pFormFiller->OnKeyDown(pAnnot, nKeyCode, nFlags);
-  }
-
-  return false;
+  CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false);
+  return pFormFiller && pFormFiller->OnKeyDown(pAnnot, nKeyCode, nFlags);
 }
 
 bool CFFL_InteractiveFormFiller::OnChar(CPDFSDK_Annot* pAnnot,
@@ -364,10 +360,8 @@
   if (nChar == FWL_VKEY_Tab)
     return true;
 
-  if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false))
-    return pFormFiller->OnChar(pAnnot, nChar, nFlags);
-
-  return false;
+  CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false);
+  return pFormFiller && pFormFiller->OnChar(pAnnot, nChar, nFlags);
 }
 
 bool CFFL_InteractiveFormFiller::OnSetFocus(CPDFSDK_Annot::ObservedPtr* pAnnot,
@@ -380,9 +374,8 @@
     CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
     if (pWidget->GetAAction(CPDF_AAction::GetFocus).GetDict()) {
       m_bNotifying = true;
-      pWidget->GetAppearanceAge();
 
-      int nValueAge = pWidget->GetValueAge();
+      uint32_t nValueAge = pWidget->GetValueAge();
       pWidget->ClearAppModified();
 
       CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, true);
@@ -393,8 +386,8 @@
       ASSERT(pPageView);
 
       PDFSDK_FieldAction fa;
-      fa.bModifier = m_pFormFillEnv->IsCTRLKeyDown(nFlag);
-      fa.bShift = m_pFormFillEnv->IsSHIFTKeyDown(nFlag);
+      fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
+      fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
       pFormFiller->GetActionData(pPageView, CPDF_AAction::GetFocus, fa);
       pWidget->OnAAction(CPDF_AAction::GetFocus, fa, pPageView);
       m_bNotifying = false;
@@ -422,29 +415,34 @@
     return false;
 
   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
-  if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false)) {
-    pFormFiller->KillFocusForAnnot(pAnnot->Get(), nFlag);
-    if (!m_bNotifying) {
-      CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
-      if (pWidget->GetAAction(CPDF_AAction::LoseFocus).GetDict()) {
-        m_bNotifying = true;
-        pWidget->ClearAppModified();
+  CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false);
+  if (!pFormFiller)
+    return true;
 
-        CPDFSDK_PageView* pPageView = pWidget->GetPageView();
-        ASSERT(pPageView);
+  pFormFiller->KillFocusForAnnot(pAnnot->Get(), nFlag);
+  if (!(*pAnnot))
+    return false;
 
-        PDFSDK_FieldAction fa;
-        fa.bModifier = m_pFormFillEnv->IsCTRLKeyDown(nFlag);
-        fa.bShift = m_pFormFillEnv->IsSHIFTKeyDown(nFlag);
-        pFormFiller->GetActionData(pPageView, CPDF_AAction::LoseFocus, fa);
-        pWidget->OnAAction(CPDF_AAction::LoseFocus, fa, pPageView);
-        m_bNotifying = false;
-        if (!(*pAnnot))
-          return false;
-      }
-    }
-  }
-  return true;
+  if (m_bNotifying)
+    return true;
+
+  CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
+  if (!pWidget->GetAAction(CPDF_AAction::LoseFocus).GetDict())
+    return true;
+
+  m_bNotifying = true;
+  pWidget->ClearAppModified();
+
+  CPDFSDK_PageView* pPageView = pWidget->GetPageView();
+  ASSERT(pPageView);
+
+  PDFSDK_FieldAction fa;
+  fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
+  fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
+  pFormFiller->GetActionData(pPageView, CPDF_AAction::LoseFocus, fa);
+  pWidget->OnAAction(CPDF_AAction::LoseFocus, fa, pPageView);
+  m_bNotifying = false;
+  return !!(*pAnnot);
 }
 
 bool CFFL_InteractiveFormFiller::IsVisible(CPDFSDK_Widget* pWidget) {
@@ -457,12 +455,11 @@
 }
 
 bool CFFL_InteractiveFormFiller::IsFillingAllowed(CPDFSDK_Widget* pWidget) {
-  if (pWidget->GetFieldType() == FIELDTYPE_PUSHBUTTON)
-    return true;
+  if (pWidget->GetFieldType() == FormFieldType::kPushButton)
+    return false;
 
   CPDF_Page* pPage = pWidget->GetPDFPage();
-  CPDF_Document* pDocument = pPage->m_pDocument;
-  uint32_t dwPermissions = pDocument->GetUserPermissions();
+  uint32_t dwPermissions = pPage->m_pDocument->GetUserPermissions();
   return (dwPermissions & FPDFPERM_FILL_FORM) ||
          (dwPermissions & FPDFPERM_ANNOT_FORM) ||
          (dwPermissions & FPDFPERM_MODIFY);
@@ -478,29 +475,30 @@
   if (!bRegister)
     return nullptr;
 
-  CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)pAnnot;
-  int nFieldType = pWidget->GetFieldType();
+  // TODO(thestig): How do we know |pAnnot| is a CPDFSDK_Widget?
+  CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot);
+  FormFieldType fieldType = pWidget->GetFieldType();
   CFFL_FormFiller* pFormFiller;
-  switch (nFieldType) {
-    case FIELDTYPE_PUSHBUTTON:
-      pFormFiller = new CFFL_PushButton(m_pFormFillEnv, pWidget);
+  switch (fieldType) {
+    case FormFieldType::kPushButton:
+      pFormFiller = new CFFL_PushButton(m_pFormFillEnv.Get(), pWidget);
       break;
-    case FIELDTYPE_CHECKBOX:
-      pFormFiller = new CFFL_CheckBox(m_pFormFillEnv, pWidget);
+    case FormFieldType::kCheckBox:
+      pFormFiller = new CFFL_CheckBox(m_pFormFillEnv.Get(), pWidget);
       break;
-    case FIELDTYPE_RADIOBUTTON:
-      pFormFiller = new CFFL_RadioButton(m_pFormFillEnv, pWidget);
+    case FormFieldType::kRadioButton:
+      pFormFiller = new CFFL_RadioButton(m_pFormFillEnv.Get(), pWidget);
       break;
-    case FIELDTYPE_TEXTFIELD:
-      pFormFiller = new CFFL_TextField(m_pFormFillEnv, pWidget);
+    case FormFieldType::kTextField:
+      pFormFiller = new CFFL_TextField(m_pFormFillEnv.Get(), pWidget);
       break;
-    case FIELDTYPE_LISTBOX:
-      pFormFiller = new CFFL_ListBox(m_pFormFillEnv, pWidget);
+    case FormFieldType::kListBox:
+      pFormFiller = new CFFL_ListBox(m_pFormFillEnv.Get(), pWidget);
       break;
-    case FIELDTYPE_COMBOBOX:
-      pFormFiller = new CFFL_ComboBox(m_pFormFillEnv, pWidget);
+    case FormFieldType::kComboBox:
+      pFormFiller = new CFFL_ComboBox(m_pFormFillEnv.Get(), pWidget);
       break;
-    case FIELDTYPE_UNKNOWN:
+    case FormFieldType::kUnknown:
     default:
       pFormFiller = nullptr;
       break;
@@ -513,9 +511,20 @@
   return pFormFiller;
 }
 
-void CFFL_InteractiveFormFiller::RemoveFormFiller(CPDFSDK_Annot* pAnnot) {
-  if (pAnnot)
-    UnRegisterFormFiller(pAnnot);
+WideString CFFL_InteractiveFormFiller::GetSelectedText(CPDFSDK_Annot* pAnnot) {
+  ASSERT(pAnnot->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
+  CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false);
+  return pFormFiller ? pFormFiller->GetSelectedText(pAnnot) : WideString();
+}
+
+void CFFL_InteractiveFormFiller::ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                                                  const WideString& text) {
+  ASSERT(pAnnot->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
+  CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false);
+  if (!pFormFiller)
+    return;
+
+  pFormFiller->ReplaceSelection(pAnnot, text);
 }
 
 void CFFL_InteractiveFormFiller::UnRegisterFormFiller(CPDFSDK_Annot* pAnnot) {
@@ -526,24 +535,22 @@
   m_Maps.erase(it);
 }
 
-void CFFL_InteractiveFormFiller::QueryWherePopup(void* pPrivateData,
-                                                 FX_FLOAT fPopupMin,
-                                                 FX_FLOAT fPopupMax,
-                                                 int32_t& nRet,
-                                                 FX_FLOAT& fPopupRet) {
-  CFFL_PrivateData* pData = (CFFL_PrivateData*)pPrivateData;
+void CFFL_InteractiveFormFiller::QueryWherePopup(
+    CPWL_Wnd::PrivateData* pAttached,
+    float fPopupMin,
+    float fPopupMax,
+    bool* bBottom,
+    float* fPopupRet) {
+  auto* pData = static_cast<CFFL_PrivateData*>(pAttached);
+  CPDFSDK_Widget* pWidget = pData->pWidget;
+  CPDF_Page* pPage = pWidget->GetPDFPage();
 
-  CFX_FloatRect rcPageView(0, 0, 0, 0);
-  rcPageView.right = pData->pWidget->GetPDFPage()->GetPageWidth();
-  rcPageView.bottom = pData->pWidget->GetPDFPage()->GetPageHeight();
+  CFX_FloatRect rcPageView(0, pPage->GetPageHeight(), pPage->GetPageWidth(), 0);
   rcPageView.Normalize();
 
-  CFX_FloatRect rcAnnot = pData->pWidget->GetRect();
-
-  FX_FLOAT fTop = 0.0f;
-  FX_FLOAT fBottom = 0.0f;
-
-  CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)pData->pWidget;
+  CFX_FloatRect rcAnnot = pWidget->GetRect();
+  float fTop = 0.0f;
+  float fBottom = 0.0f;
   switch (pWidget->GetRotate() / 90) {
     default:
     case 0:
@@ -564,308 +571,276 @@
       break;
   }
 
-  FX_FLOAT fFactHeight = 0;
-  bool bBottom = true;
-  FX_FLOAT fMaxListBoxHeight = 0;
-  if (fPopupMax > FFL_MAXLISTBOXHEIGHT) {
-    if (fPopupMin > FFL_MAXLISTBOXHEIGHT) {
-      fMaxListBoxHeight = fPopupMin;
-    } else {
-      fMaxListBoxHeight = FFL_MAXLISTBOXHEIGHT;
-    }
-  } else {
-    fMaxListBoxHeight = fPopupMax;
-  }
+  constexpr float kMaxListBoxHeight = 140;
+  const float fMaxListBoxHeight =
+      pdfium::clamp(kMaxListBoxHeight, fPopupMin, fPopupMax);
 
   if (fBottom > fMaxListBoxHeight) {
-    fFactHeight = fMaxListBoxHeight;
-    bBottom = true;
-  } else {
-    if (fTop > fMaxListBoxHeight) {
-      fFactHeight = fMaxListBoxHeight;
-      bBottom = false;
-    } else {
-      if (fTop > fBottom) {
-        fFactHeight = fTop;
-        bBottom = false;
-      } else {
-        fFactHeight = fBottom;
-        bBottom = true;
-      }
-    }
+    *fPopupRet = fMaxListBoxHeight;
+    *bBottom = true;
+    return;
   }
 
-  nRet = bBottom ? 0 : 1;
-  fPopupRet = fFactHeight;
+  if (fTop > fMaxListBoxHeight) {
+    *fPopupRet = fMaxListBoxHeight;
+    *bBottom = false;
+    return;
+  }
+
+  if (fTop > fBottom) {
+    *fPopupRet = fTop;
+    *bBottom = false;
+  } else {
+    *fPopupRet = fBottom;
+    *bBottom = true;
+  }
 }
 
-void CFFL_InteractiveFormFiller::OnKeyStrokeCommit(
+bool CFFL_InteractiveFormFiller::OnKeyStrokeCommit(
     CPDFSDK_Annot::ObservedPtr* pAnnot,
     CPDFSDK_PageView* pPageView,
-    bool& bRC,
-    bool& bExit,
     uint32_t nFlag) {
-  if (!m_bNotifying) {
-    CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
-    if (pWidget->GetAAction(CPDF_AAction::KeyStroke).GetDict()) {
-      ASSERT(pPageView);
-      m_bNotifying = true;
-      pWidget->ClearAppModified();
+  if (m_bNotifying)
+    return true;
 
-      PDFSDK_FieldAction fa;
-      fa.bModifier = m_pFormFillEnv->IsCTRLKeyDown(nFlag);
-      fa.bShift = m_pFormFillEnv->IsSHIFTKeyDown(nFlag);
-      fa.bWillCommit = true;
-      fa.bKeyDown = true;
-      fa.bRC = true;
+  CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
+  if (!pWidget->GetAAction(CPDF_AAction::KeyStroke).GetDict())
+    return true;
 
-      CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false);
-      pFormFiller->GetActionData(pPageView, CPDF_AAction::KeyStroke, fa);
-      pFormFiller->SaveState(pPageView);
-      pWidget->OnAAction(CPDF_AAction::KeyStroke, fa, pPageView);
-      if (!(*pAnnot))
-        return;
+  ASSERT(pPageView);
+  m_bNotifying = true;
+  pWidget->ClearAppModified();
 
-      bRC = fa.bRC;
-      m_bNotifying = false;
-    }
-  }
+  PDFSDK_FieldAction fa;
+  fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
+  fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
+  fa.bWillCommit = true;
+  fa.bKeyDown = true;
+  fa.bRC = true;
+
+  CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false);
+  pFormFiller->GetActionData(pPageView, CPDF_AAction::KeyStroke, fa);
+  pFormFiller->SaveState(pPageView);
+  pWidget->OnAAction(CPDF_AAction::KeyStroke, fa, pPageView);
+  if (!(*pAnnot))
+    return true;
+
+  m_bNotifying = false;
+  return fa.bRC;
 }
 
-void CFFL_InteractiveFormFiller::OnValidate(CPDFSDK_Annot::ObservedPtr* pAnnot,
+bool CFFL_InteractiveFormFiller::OnValidate(CPDFSDK_Annot::ObservedPtr* pAnnot,
                                             CPDFSDK_PageView* pPageView,
-                                            bool& bRC,
-                                            bool& bExit,
                                             uint32_t nFlag) {
-  if (!m_bNotifying) {
-    CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
-    if (pWidget->GetAAction(CPDF_AAction::Validate).GetDict()) {
-      ASSERT(pPageView);
-      m_bNotifying = true;
-      pWidget->ClearAppModified();
+  if (m_bNotifying)
+    return true;
 
-      PDFSDK_FieldAction fa;
-      fa.bModifier = m_pFormFillEnv->IsCTRLKeyDown(nFlag);
-      fa.bShift = m_pFormFillEnv->IsSHIFTKeyDown(nFlag);
-      fa.bKeyDown = true;
-      fa.bRC = true;
+  CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
+  if (!pWidget->GetAAction(CPDF_AAction::Validate).GetDict())
+    return true;
 
-      CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false);
-      pFormFiller->GetActionData(pPageView, CPDF_AAction::Validate, fa);
-      pFormFiller->SaveState(pPageView);
-      pWidget->OnAAction(CPDF_AAction::Validate, fa, pPageView);
-      if (!(*pAnnot))
-        return;
+  ASSERT(pPageView);
+  m_bNotifying = true;
+  pWidget->ClearAppModified();
 
-      bRC = fa.bRC;
-      m_bNotifying = false;
-    }
-  }
+  PDFSDK_FieldAction fa;
+  fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
+  fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
+  fa.bKeyDown = true;
+  fa.bRC = true;
+
+  CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false);
+  pFormFiller->GetActionData(pPageView, CPDF_AAction::Validate, fa);
+  pFormFiller->SaveState(pPageView);
+  pWidget->OnAAction(CPDF_AAction::Validate, fa, pPageView);
+  if (!(*pAnnot))
+    return true;
+
+  m_bNotifying = false;
+  return fa.bRC;
 }
 
-void CFFL_InteractiveFormFiller::OnCalculate(CPDFSDK_Widget* pWidget,
+void CFFL_InteractiveFormFiller::OnCalculate(CPDFSDK_Annot::ObservedPtr* pAnnot,
                                              CPDFSDK_PageView* pPageView,
-                                             bool& bExit,
                                              uint32_t nFlag) {
-  if (!m_bNotifying) {
-    ASSERT(pWidget);
+  if (m_bNotifying)
+    return;
+
+  CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
+  if (pWidget) {
     CPDFSDK_InterForm* pInterForm = pPageView->GetFormFillEnv()->GetInterForm();
     pInterForm->OnCalculate(pWidget->GetFormField());
-    m_bNotifying = false;
   }
+  m_bNotifying = false;
 }
 
-void CFFL_InteractiveFormFiller::OnFormat(CPDFSDK_Widget* pWidget,
+void CFFL_InteractiveFormFiller::OnFormat(CPDFSDK_Annot::ObservedPtr* pAnnot,
                                           CPDFSDK_PageView* pPageView,
-                                          bool& bExit,
                                           uint32_t nFlag) {
-  if (!m_bNotifying) {
-    ASSERT(pWidget);
-    CPDFSDK_InterForm* pInterForm = pPageView->GetFormFillEnv()->GetInterForm();
+  if (m_bNotifying)
+    return;
 
-    bool bFormatted = false;
-    CFX_WideString sValue =
-        pInterForm->OnFormat(pWidget->GetFormField(), bFormatted);
+  CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
+  ASSERT(pWidget);
+  CPDFSDK_InterForm* pInterForm = pPageView->GetFormFillEnv()->GetInterForm();
 
-    if (bExit)
-      return;
+  bool bFormatted = false;
+  WideString sValue = pInterForm->OnFormat(pWidget->GetFormField(), bFormatted);
+  if (!(*pAnnot))
+    return;
 
-    if (bFormatted) {
-      pInterForm->ResetFieldAppearance(pWidget->GetFormField(), &sValue, true);
-      pInterForm->UpdateField(pWidget->GetFormField());
-    }
-
-    m_bNotifying = false;
+  if (bFormatted) {
+    pInterForm->ResetFieldAppearance(pWidget->GetFormField(), &sValue, true);
+    pInterForm->UpdateField(pWidget->GetFormField());
   }
+
+  m_bNotifying = false;
 }
 
 #ifdef PDF_ENABLE_XFA
-void CFFL_InteractiveFormFiller::OnClick(CPDFSDK_Widget* pWidget,
+bool CFFL_InteractiveFormFiller::OnClick(CPDFSDK_Annot::ObservedPtr* pAnnot,
                                          CPDFSDK_PageView* pPageView,
-                                         bool& bReset,
-                                         bool& bExit,
                                          uint32_t nFlag) {
-  if (!m_bNotifying) {
-    if (pWidget->HasXFAAAction(PDFSDK_XFA_Click)) {
-      m_bNotifying = true;
-      int nAge = pWidget->GetAppearanceAge();
-      int nValueAge = pWidget->GetValueAge();
+  if (m_bNotifying)
+    return false;
 
-      PDFSDK_FieldAction fa;
-      fa.bModifier = m_pFormFillEnv->IsCTRLKeyDown(nFlag);
-      fa.bShift = m_pFormFillEnv->IsSHIFTKeyDown(nFlag);
+  CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
+  if (!pWidget->HasXFAAAction(PDFSDK_XFA_Click))
+    return false;
 
-      pWidget->OnXFAAAction(PDFSDK_XFA_Click, fa, pPageView);
-      m_bNotifying = false;
+  m_bNotifying = true;
+  uint32_t nAge = pWidget->GetAppearanceAge();
+  uint32_t nValueAge = pWidget->GetValueAge();
 
-      if (!IsValidAnnot(pPageView, pWidget)) {
-        bExit = true;
-        return;
-      }
+  PDFSDK_FieldAction fa;
+  fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
+  fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
 
-      if (nAge != pWidget->GetAppearanceAge()) {
-        if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false)) {
-          pFormFiller->ResetPDFWindow(pPageView,
-                                      nValueAge == pWidget->GetValueAge());
-        }
+  pWidget->OnXFAAAction(PDFSDK_XFA_Click, fa, pPageView);
+  m_bNotifying = false;
+  if (!(*pAnnot) || !IsValidAnnot(pPageView, pWidget))
+    return true;
+  if (nAge == pWidget->GetAppearanceAge())
+    return false;
 
-        bReset = true;
-      }
-    }
-  }
+  if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false))
+    pFormFiller->ResetPDFWindow(pPageView, nValueAge == pWidget->GetValueAge());
+  return false;
 }
 
-void CFFL_InteractiveFormFiller::OnFull(CPDFSDK_Widget* pWidget,
+bool CFFL_InteractiveFormFiller::OnFull(CPDFSDK_Annot::ObservedPtr* pAnnot,
                                         CPDFSDK_PageView* pPageView,
-                                        bool& bReset,
-                                        bool& bExit,
                                         uint32_t nFlag) {
-  if (!m_bNotifying) {
-    if (pWidget->HasXFAAAction(PDFSDK_XFA_Full)) {
-      m_bNotifying = true;
-      int nAge = pWidget->GetAppearanceAge();
-      int nValueAge = pWidget->GetValueAge();
+  if (m_bNotifying)
+    return false;
 
-      PDFSDK_FieldAction fa;
-      fa.bModifier = m_pFormFillEnv->IsCTRLKeyDown(nFlag);
-      fa.bShift = m_pFormFillEnv->IsSHIFTKeyDown(nFlag);
+  CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
+  if (!pWidget->HasXFAAAction(PDFSDK_XFA_Full))
+    return false;
 
-      pWidget->OnXFAAAction(PDFSDK_XFA_Full, fa, pPageView);
-      m_bNotifying = false;
+  m_bNotifying = true;
+  uint32_t nAge = pWidget->GetAppearanceAge();
+  uint32_t nValueAge = pWidget->GetValueAge();
 
-      if (!IsValidAnnot(pPageView, pWidget)) {
-        bExit = true;
-        return;
-      }
+  PDFSDK_FieldAction fa;
+  fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
+  fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
 
-      if (nAge != pWidget->GetAppearanceAge()) {
-        if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false)) {
-          pFormFiller->ResetPDFWindow(pPageView,
-                                      nValueAge == pWidget->GetValueAge());
-        }
+  pWidget->OnXFAAAction(PDFSDK_XFA_Full, fa, pPageView);
+  m_bNotifying = false;
+  if (!(*pAnnot) || !IsValidAnnot(pPageView, pWidget))
+    return true;
+  if (nAge == pWidget->GetAppearanceAge())
+    return false;
 
-        bReset = true;
-      }
-    }
-  }
+  if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false))
+    pFormFiller->ResetPDFWindow(pPageView, nValueAge == pWidget->GetValueAge());
+
+  return true;
 }
 
-void CFFL_InteractiveFormFiller::OnPopupPreOpen(void* pPrivateData,
-                                                bool& bExit,
-                                                uint32_t nFlag) {
-  CFFL_PrivateData* pData = (CFFL_PrivateData*)pPrivateData;
+bool CFFL_InteractiveFormFiller::OnPopupPreOpen(
+    CPWL_Wnd::PrivateData* pAttached,
+    uint32_t nFlag) {
+  auto* pData = static_cast<CFFL_PrivateData*>(pAttached);
   ASSERT(pData);
   ASSERT(pData->pWidget);
 
-  bool bTempReset = false;
-  bool bTempExit = false;
-  OnPreOpen(pData->pWidget, pData->pPageView, bTempReset, bTempExit, nFlag);
-  if (bTempReset || bTempExit)
-    bExit = true;
+  CPDFSDK_Annot::ObservedPtr pObserved(pData->pWidget);
+  return OnPreOpen(&pObserved, pData->pPageView, nFlag) || !pObserved;
 }
 
-void CFFL_InteractiveFormFiller::OnPopupPostOpen(void* pPrivateData,
-                                                 bool& bExit,
-                                                 uint32_t nFlag) {
-  CFFL_PrivateData* pData = (CFFL_PrivateData*)pPrivateData;
+bool CFFL_InteractiveFormFiller::OnPopupPostOpen(
+    CPWL_Wnd::PrivateData* pAttached,
+    uint32_t nFlag) {
+  auto* pData = static_cast<CFFL_PrivateData*>(pAttached);
   ASSERT(pData);
   ASSERT(pData->pWidget);
 
-  bool bTempReset = false;
-  bool bTempExit = false;
-  OnPostOpen(pData->pWidget, pData->pPageView, bTempReset, bTempExit, nFlag);
-  if (bTempReset || bTempExit)
-    bExit = true;
+  CPDFSDK_Annot::ObservedPtr pObserved(pData->pWidget);
+  return OnPostOpen(&pObserved, pData->pPageView, nFlag) || !pObserved;
 }
 
-void CFFL_InteractiveFormFiller::OnPreOpen(CPDFSDK_Widget* pWidget,
+bool CFFL_InteractiveFormFiller::OnPreOpen(CPDFSDK_Annot::ObservedPtr* pAnnot,
                                            CPDFSDK_PageView* pPageView,
-                                           bool& bReset,
-                                           bool& bExit,
                                            uint32_t nFlag) {
-  if (!m_bNotifying) {
-    if (pWidget->HasXFAAAction(PDFSDK_XFA_PreOpen)) {
-      m_bNotifying = true;
-      int nAge = pWidget->GetAppearanceAge();
-      int nValueAge = pWidget->GetValueAge();
+  if (m_bNotifying)
+    return false;
 
-      PDFSDK_FieldAction fa;
-      fa.bModifier = m_pFormFillEnv->IsCTRLKeyDown(nFlag);
-      fa.bShift = m_pFormFillEnv->IsSHIFTKeyDown(nFlag);
+  CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
+  if (!pWidget->HasXFAAAction(PDFSDK_XFA_PreOpen))
+    return false;
 
-      pWidget->OnXFAAAction(PDFSDK_XFA_PreOpen, fa, pPageView);
-      m_bNotifying = false;
+  m_bNotifying = true;
+  uint32_t nAge = pWidget->GetAppearanceAge();
+  uint32_t nValueAge = pWidget->GetValueAge();
 
-      if (!IsValidAnnot(pPageView, pWidget)) {
-        bExit = true;
-        return;
-      }
+  PDFSDK_FieldAction fa;
+  fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
+  fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
 
-      if (nAge != pWidget->GetAppearanceAge()) {
-        if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false)) {
-          pFormFiller->ResetPDFWindow(pPageView,
-                                      nValueAge == pWidget->GetValueAge());
-        }
+  pWidget->OnXFAAAction(PDFSDK_XFA_PreOpen, fa, pPageView);
+  m_bNotifying = false;
+  if (!(*pAnnot) || !IsValidAnnot(pPageView, pWidget))
+    return true;
+  if (nAge == pWidget->GetAppearanceAge())
+    return false;
 
-        bReset = true;
-      }
-    }
-  }
+  if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false))
+    pFormFiller->ResetPDFWindow(pPageView, nValueAge == pWidget->GetValueAge());
+
+  return true;
 }
 
-void CFFL_InteractiveFormFiller::OnPostOpen(CPDFSDK_Widget* pWidget,
+bool CFFL_InteractiveFormFiller::OnPostOpen(CPDFSDK_Annot::ObservedPtr* pAnnot,
                                             CPDFSDK_PageView* pPageView,
-                                            bool& bReset,
-                                            bool& bExit,
                                             uint32_t nFlag) {
-  if (!m_bNotifying) {
-    if (pWidget->HasXFAAAction(PDFSDK_XFA_PostOpen)) {
-      m_bNotifying = true;
-      int nAge = pWidget->GetAppearanceAge();
-      int nValueAge = pWidget->GetValueAge();
+  if (m_bNotifying)
+    return false;
 
-      PDFSDK_FieldAction fa;
-      fa.bModifier = m_pFormFillEnv->IsCTRLKeyDown(nFlag);
-      fa.bShift = m_pFormFillEnv->IsSHIFTKeyDown(nFlag);
+  CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
+  if (!pWidget->HasXFAAAction(PDFSDK_XFA_PostOpen))
+    return false;
 
-      pWidget->OnXFAAAction(PDFSDK_XFA_PostOpen, fa, pPageView);
-      m_bNotifying = false;
+  m_bNotifying = true;
+  uint32_t nAge = pWidget->GetAppearanceAge();
+  uint32_t nValueAge = pWidget->GetValueAge();
 
-      if (!IsValidAnnot(pPageView, pWidget)) {
-        bExit = true;
-        return;
-      }
+  PDFSDK_FieldAction fa;
+  fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
+  fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
 
-      if (nAge != pWidget->GetAppearanceAge()) {
-        if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false)) {
-          pFormFiller->ResetPDFWindow(pPageView,
-                                      nValueAge == pWidget->GetValueAge());
-        }
+  pWidget->OnXFAAAction(PDFSDK_XFA_PostOpen, fa, pPageView);
+  m_bNotifying = false;
+  if (!(*pAnnot) || !IsValidAnnot(pPageView, pWidget))
+    return true;
+  if (nAge == pWidget->GetAppearanceAge())
+    return false;
 
-        bReset = true;
-      }
-    }
-  }
+  if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false))
+    pFormFiller->ResetPDFWindow(pPageView, nValueAge == pWidget->GetValueAge());
+
+  return true;
 }
 #endif  // PDF_ENABLE_XFA
 
@@ -874,95 +849,83 @@
   return pPageView && pPageView->IsValidAnnot(pAnnot->GetPDFAnnot());
 }
 
-void CFFL_InteractiveFormFiller::OnBeforeKeyStroke(
-    void* pPrivateData,
-    CFX_WideString& strChange,
-    const CFX_WideString& strChangeEx,
+std::pair<bool, bool> CFFL_InteractiveFormFiller::OnBeforeKeyStroke(
+    CPWL_Wnd::PrivateData* pAttached,
+    WideString& strChange,
+    const WideString& strChangeEx,
     int nSelStart,
     int nSelEnd,
     bool bKeyDown,
-    bool& bRC,
-    bool& bExit,
     uint32_t nFlag) {
-  CFFL_PrivateData* pData = (CFFL_PrivateData*)pPrivateData;
-  ASSERT(pData->pWidget);
+  // Copy the private data since the window owning it may not survive.
+  CFFL_PrivateData privateData = *static_cast<CFFL_PrivateData*>(pAttached);
+  ASSERT(privateData.pWidget);
 
-  CFFL_FormFiller* pFormFiller = GetFormFiller(pData->pWidget, false);
+  CFFL_FormFiller* pFormFiller = GetFormFiller(privateData.pWidget, false);
 
 #ifdef PDF_ENABLE_XFA
-  if (pFormFiller->IsFieldFull(pData->pPageView)) {
-    bool bFullExit = false;
-    bool bFullReset = false;
-    OnFull(pData->pWidget, pData->pPageView, bFullReset, bFullExit, nFlag);
-
-    if (bFullReset || bFullExit) {
-      bExit = true;
-      return;
-    }
+  if (pFormFiller->IsFieldFull(privateData.pPageView)) {
+    CPDFSDK_Annot::ObservedPtr pObserved(privateData.pWidget);
+    if (OnFull(&pObserved, privateData.pPageView, nFlag) || !pObserved)
+      return {true, true};
   }
 #endif  // PDF_ENABLE_XFA
 
-  if (!m_bNotifying) {
-    if (pData->pWidget->GetAAction(CPDF_AAction::KeyStroke).GetDict()) {
-      m_bNotifying = true;
-      int nAge = pData->pWidget->GetAppearanceAge();
-      int nValueAge = pData->pWidget->GetValueAge();
-
-      CPDFSDK_FormFillEnvironment* pFormFillEnv =
-          pData->pPageView->GetFormFillEnv();
-
-      PDFSDK_FieldAction fa;
-      fa.bModifier = m_pFormFillEnv->IsCTRLKeyDown(nFlag);
-      fa.bShift = m_pFormFillEnv->IsSHIFTKeyDown(nFlag);
-      fa.sChange = strChange;
-      fa.sChangeEx = strChangeEx;
-      fa.bKeyDown = bKeyDown;
-      fa.bWillCommit = false;
-      fa.bRC = true;
-      fa.nSelStart = nSelStart;
-      fa.nSelEnd = nSelEnd;
-
-      pFormFiller->GetActionData(pData->pPageView, CPDF_AAction::KeyStroke, fa);
-      pFormFiller->SaveState(pData->pPageView);
-
-      CPDFSDK_Annot::ObservedPtr pObserved(pData->pWidget);
-      if (pData->pWidget->OnAAction(CPDF_AAction::KeyStroke, fa,
-                                    pData->pPageView)) {
-        if (!pObserved || !IsValidAnnot(pData->pPageView, pData->pWidget)) {
-          bExit = true;
-          m_bNotifying = false;
-          return;
-        }
-
-        if (nAge != pData->pWidget->GetAppearanceAge()) {
-          CPWL_Wnd* pWnd = pFormFiller->ResetPDFWindow(
-              pData->pPageView, nValueAge == pData->pWidget->GetValueAge());
-          pData = (CFFL_PrivateData*)pWnd->GetAttachedData();
-          bExit = true;
-        }
-
-        if (fa.bRC) {
-          pFormFiller->SetActionData(pData->pPageView, CPDF_AAction::KeyStroke,
-                                     fa);
-          bRC = false;
-        } else {
-          pFormFiller->RestoreState(pData->pPageView);
-          bRC = false;
-        }
-
-        if (pFormFillEnv->GetFocusAnnot() != pData->pWidget) {
-          pFormFiller->CommitData(pData->pPageView, nFlag);
-          bExit = true;
-        }
-      } else {
-        if (!IsValidAnnot(pData->pPageView, pData->pWidget)) {
-          bExit = true;
-          m_bNotifying = false;
-          return;
-        }
-      }
-
-      m_bNotifying = false;
-    }
+  if (m_bNotifying ||
+      !privateData.pWidget->GetAAction(CPDF_AAction::KeyStroke).GetDict()) {
+    return {true, false};
   }
+
+  AutoRestorer<bool> restorer(&m_bNotifying);
+  m_bNotifying = true;
+
+  uint32_t nAge = privateData.pWidget->GetAppearanceAge();
+  uint32_t nValueAge = privateData.pWidget->GetValueAge();
+  CPDFSDK_FormFillEnvironment* pFormFillEnv =
+      privateData.pPageView->GetFormFillEnv();
+
+  PDFSDK_FieldAction fa;
+  fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
+  fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
+  fa.sChange = strChange;
+  fa.sChangeEx = strChangeEx;
+  fa.bKeyDown = bKeyDown;
+  fa.bWillCommit = false;
+  fa.bRC = true;
+  fa.nSelStart = nSelStart;
+  fa.nSelEnd = nSelEnd;
+  pFormFiller->GetActionData(privateData.pPageView, CPDF_AAction::KeyStroke,
+                             fa);
+  pFormFiller->SaveState(privateData.pPageView);
+
+  CPDFSDK_Annot::ObservedPtr pObserved(privateData.pWidget);
+  bool action_status = privateData.pWidget->OnAAction(
+      CPDF_AAction::KeyStroke, fa, privateData.pPageView);
+
+  if (!pObserved || !IsValidAnnot(privateData.pPageView, privateData.pWidget))
+    return {true, true};
+
+  if (!action_status)
+    return {true, false};
+
+  bool bExit = false;
+  if (nAge != privateData.pWidget->GetAppearanceAge()) {
+    CPWL_Wnd* pWnd = pFormFiller->ResetPDFWindow(
+        privateData.pPageView, nValueAge == privateData.pWidget->GetValueAge());
+    if (!pWnd)
+      return {true, true};
+    privateData = *static_cast<CFFL_PrivateData*>(pWnd->GetAttachedData());
+    bExit = true;
+  }
+  if (fa.bRC) {
+    pFormFiller->SetActionData(privateData.pPageView, CPDF_AAction::KeyStroke,
+                               fa);
+  } else {
+    pFormFiller->RestoreState(privateData.pPageView);
+  }
+  if (pFormFillEnv->GetFocusAnnot() == privateData.pWidget)
+    return {false, bExit};
+
+  pFormFiller->CommitData(privateData.pPageView, nFlag);
+  return {false, true};
 }
diff --git a/fpdfsdk/formfiller/cffl_interactiveformfiller.h b/fpdfsdk/formfiller/cffl_interactiveformfiller.h
index 90fd98c..0192752 100644
--- a/fpdfsdk/formfiller/cffl_interactiveformfiller.h
+++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.h
@@ -9,10 +9,12 @@
 
 #include <map>
 #include <memory>
+#include <utility>
 
+#include "core/fxcrt/unowned_ptr.h"
 #include "fpdfsdk/cpdfsdk_annot.h"
 #include "fpdfsdk/fsdk_define.h"
-#include "fpdfsdk/pdfwindow/PWL_Edit.h"
+#include "fpdfsdk/pwl/cpwl_edit.h"
 
 class CFFL_FormFiller;
 class CPDFSDK_FormFillEnvironment;
@@ -79,57 +81,42 @@
   bool OnKillFocus(CPDFSDK_Annot::ObservedPtr* pAnnot, uint32_t nFlag);
 
   CFFL_FormFiller* GetFormFiller(CPDFSDK_Annot* pAnnot, bool bRegister);
-  void RemoveFormFiller(CPDFSDK_Annot* pAnnot);
+
+  WideString GetSelectedText(CPDFSDK_Annot* pAnnot);
+  void ReplaceSelection(CPDFSDK_Annot* pAnnot, const WideString& text);
 
   static bool IsVisible(CPDFSDK_Widget* pWidget);
   static bool IsReadOnly(CPDFSDK_Widget* pWidget);
   static bool IsFillingAllowed(CPDFSDK_Widget* pWidget);
   static bool IsValidAnnot(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot);
 
-  void OnKeyStrokeCommit(CPDFSDK_Annot::ObservedPtr* pWidget,
+  bool OnKeyStrokeCommit(CPDFSDK_Annot::ObservedPtr* pWidget,
                          CPDFSDK_PageView* pPageView,
-                         bool& bRC,
-                         bool& bExit,
                          uint32_t nFlag);
-  void OnValidate(CPDFSDK_Annot::ObservedPtr* pWidget,
+  bool OnValidate(CPDFSDK_Annot::ObservedPtr* pAnnot,
                   CPDFSDK_PageView* pPageView,
-                  bool& bRC,
-                  bool& bExit,
                   uint32_t nFlag);
-
-  void OnCalculate(CPDFSDK_Widget* pWidget,
+  void OnCalculate(CPDFSDK_Annot::ObservedPtr* pAnnot,
                    CPDFSDK_PageView* pPageView,
-                   bool& bExit,
                    uint32_t nFlag);
-  void OnFormat(CPDFSDK_Widget* pWidget,
+  void OnFormat(CPDFSDK_Annot::ObservedPtr* pAnnot,
                 CPDFSDK_PageView* pPageView,
-                bool& bExit,
                 uint32_t nFlag);
-  void OnButtonUp(CPDFSDK_Annot::ObservedPtr* pWidget,
+  bool OnButtonUp(CPDFSDK_Annot::ObservedPtr* pAnnot,
                   CPDFSDK_PageView* pPageView,
-                  bool& bReset,
-                  bool& bExit,
                   uint32_t nFlag);
 #ifdef PDF_ENABLE_XFA
-  void OnClick(CPDFSDK_Widget* pWidget,
+  bool OnClick(CPDFSDK_Annot::ObservedPtr* pAnnot,
                CPDFSDK_PageView* pPageView,
-               bool& bReset,
-               bool& bExit,
                uint32_t nFlag);
-  void OnFull(CPDFSDK_Widget* pWidget,
+  bool OnFull(CPDFSDK_Annot::ObservedPtr* pAnnot,
               CPDFSDK_PageView* pPageView,
-              bool& bReset,
-              bool& bExit,
               uint32_t nFlag);
-  void OnPreOpen(CPDFSDK_Widget* pWidget,
+  bool OnPreOpen(CPDFSDK_Annot::ObservedPtr* pAnnot,
                  CPDFSDK_PageView* pPageView,
-                 bool& bReset,
-                 bool& bExit,
                  uint32_t nFlag);
-  void OnPostOpen(CPDFSDK_Widget* pWidget,
+  bool OnPostOpen(CPDFSDK_Annot::ObservedPtr* pAnnot,
                   CPDFSDK_PageView* pPageView,
-                  bool& bReset,
-                  bool& bExit,
                   uint32_t nFlag);
 #endif  // PDF_ENABLE_XFA
 
@@ -138,40 +125,39 @@
       std::map<CPDFSDK_Annot*, std::unique_ptr<CFFL_FormFiller>>;
 
   // IPWL_Filler_Notify:
-  void QueryWherePopup(void* pPrivateData,
-                       FX_FLOAT fPopupMin,
-                       FX_FLOAT fPopupMax,
-                       int32_t& nRet,
-                       FX_FLOAT& fPopupRet) override;
-  void OnBeforeKeyStroke(void* pPrivateData,
-                         CFX_WideString& strChange,
-                         const CFX_WideString& strChangeEx,
-                         int nSelStart,
-                         int nSelEnd,
-                         bool bKeyDown,
-                         bool& bRC,
-                         bool& bExit,
-                         uint32_t nFlag) override;
+  void QueryWherePopup(CPWL_Wnd::PrivateData* pAttached,
+                       float fPopupMin,
+                       float fPopupMax,
+                       bool* bBottom,
+                       float* fPopupRet) override;
+  // Returns {bRC, bExit}.
+  std::pair<bool, bool> OnBeforeKeyStroke(CPWL_Wnd::PrivateData* pAttached,
+                                          WideString& strChange,
+                                          const WideString& strChangeEx,
+                                          int nSelStart,
+                                          int nSelEnd,
+                                          bool bKeyDown,
+                                          uint32_t nFlag) override;
 #ifdef PDF_ENABLE_XFA
-  void OnPopupPreOpen(void* pPrivateData, bool& bExit, uint32_t nFlag) override;
-  void OnPopupPostOpen(void* pPrivateData,
-                       bool& bExit,
+  bool OnPopupPreOpen(CPWL_Wnd::PrivateData* pAttached,
+                      uint32_t nFlag) override;
+  bool OnPopupPostOpen(CPWL_Wnd::PrivateData* pAttached,
                        uint32_t nFlag) override;
   void SetFocusAnnotTab(CPDFSDK_Annot* pWidget, bool bSameField, bool bNext);
 #endif  // PDF_ENABLE_XFA
   void UnRegisterFormFiller(CPDFSDK_Annot* pAnnot);
 
-  CPDFSDK_FormFillEnvironment* const m_pFormFillEnv;
+  UnownedPtr<CPDFSDK_FormFillEnvironment> const m_pFormFillEnv;
   CFFL_Widget2Filler m_Maps;
   bool m_bNotifying;
 };
 
-class CFFL_PrivateData {
+class CFFL_PrivateData : public CPWL_Wnd::PrivateData {
  public:
   CPDFSDK_Widget* pWidget;
   CPDFSDK_PageView* pPageView;
-  int nWidgetAge;
-  int nValueAge;
+  uint32_t nWidgetAppearanceAge;
+  uint32_t nWidgetValueAge;
 };
 
 #endif  // FPDFSDK_FORMFILLER_CFFL_INTERACTIVEFORMFILLER_H_
diff --git a/fpdfsdk/formfiller/cffl_listbox.cpp b/fpdfsdk/formfiller/cffl_listbox.cpp
index 556e0e1..e628e59 100644
--- a/fpdfsdk/formfiller/cffl_listbox.cpp
+++ b/fpdfsdk/formfiller/cffl_listbox.cpp
@@ -9,46 +9,36 @@
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 #include "fpdfsdk/cpdfsdk_widget.h"
 #include "fpdfsdk/formfiller/cba_fontmap.h"
-#include "fpdfsdk/formfiller/cffl_formfiller.h"
 #include "fpdfsdk/formfiller/cffl_interactiveformfiller.h"
 #include "fpdfsdk/fsdk_common.h"
-#include "fpdfsdk/pdfwindow/PWL_ListBox.h"
+#include "fpdfsdk/pwl/cpwl_list_box.h"
 #include "third_party/base/ptr_util.h"
 
 #define FFL_DEFAULTLISTBOXFONTSIZE 12.0f
 
 CFFL_ListBox::CFFL_ListBox(CPDFSDK_FormFillEnvironment* pApp,
-                           CPDFSDK_Annot* pWidget)
-    : CFFL_FormFiller(pApp, pWidget) {}
+                           CPDFSDK_Widget* pWidget)
+    : CFFL_TextObject(pApp, pWidget) {}
 
 CFFL_ListBox::~CFFL_ListBox() {}
 
-PWL_CREATEPARAM CFFL_ListBox::GetCreateParam() {
-  PWL_CREATEPARAM cp = CFFL_FormFiller::GetCreateParam();
-
+CPWL_Wnd::CreateParams CFFL_ListBox::GetCreateParam() {
+  CPWL_Wnd::CreateParams cp = CFFL_TextObject::GetCreateParam();
   uint32_t dwFieldFlag = m_pWidget->GetFieldFlags();
-
-  if (dwFieldFlag & FIELDFLAG_MULTISELECT) {
+  if (dwFieldFlag & FIELDFLAG_MULTISELECT)
     cp.dwFlags |= PLBS_MULTIPLESEL;
-  }
 
   cp.dwFlags |= PWS_VSCROLL;
 
   if (cp.dwFlags & PWS_AUTOFONTSIZE)
     cp.fFontSize = FFL_DEFAULTLISTBOXFONTSIZE;
 
-  if (!m_pFontMap) {
-    m_pFontMap = pdfium::MakeUnique<CBA_FontMap>(
-        m_pWidget, m_pFormFillEnv->GetSysHandler());
-  }
-  cp.pFontMap = m_pFontMap.get();
-
+  cp.pFontMap = MaybeCreateFontMap();
   return cp;
 }
 
-CPWL_Wnd* CFFL_ListBox::NewPDFWindow(const PWL_CREATEPARAM& cp,
-                                     CPDFSDK_PageView* pPageView) {
-  CPWL_ListBox* pWnd = new CPWL_ListBox();
+CPWL_Wnd* CFFL_ListBox::NewPDFWindow(const CPWL_Wnd::CreateParams& cp) {
+  auto* pWnd = new CPWL_ListBox();
   pWnd->AttachFFLData(this);
   pWnd->Create(cp);
   pWnd->SetFillerNotify(m_pFormFillEnv->GetInteractiveFormFiller());
@@ -87,7 +77,7 @@
 bool CFFL_ListBox::OnChar(CPDFSDK_Annot* pAnnot,
                           uint32_t nChar,
                           uint32_t nFlags) {
-  return CFFL_FormFiller::OnChar(pAnnot, nChar, nFlags);
+  return CFFL_TextObject::OnChar(pAnnot, nChar, nFlags);
 }
 
 bool CFFL_ListBox::IsDataChanged(CPDFSDK_PageView* pPageView) {
@@ -127,9 +117,18 @@
   } else {
     m_pWidget->SetOptionSelection(pListBox->GetCurSel(), true, false);
   }
+  CPDFSDK_Widget::ObservedPtr observed_widget(m_pWidget.Get());
+  CFFL_ListBox::ObservedPtr observed_this(this);
+
   m_pWidget->SetTopVisibleIndex(nNewTopIndex);
+  if (!observed_widget)
+    return;
   m_pWidget->ResetFieldAppearance(true);
+  if (!observed_widget)
+    return;
   m_pWidget->UpdateField();
+  if (!observed_widget || !observed_this)
+    return;
   SetChangeMark();
 }
 
@@ -187,24 +186,3 @@
   for (const auto& item : m_State)
     pListBox->Select(item);
 }
-
-CPWL_Wnd* CFFL_ListBox::ResetPDFWindow(CPDFSDK_PageView* pPageView,
-                                       bool bRestoreValue) {
-  if (bRestoreValue)
-    SaveState(pPageView);
-
-  DestroyPDFWindow(pPageView);
-
-  CPWL_Wnd* pRet = nullptr;
-
-  if (bRestoreValue) {
-    RestoreState(pPageView);
-    pRet = GetPDFWindow(pPageView, false);
-  } else {
-    pRet = GetPDFWindow(pPageView, true);
-  }
-
-  m_pWidget->UpdateField();
-
-  return pRet;
-}
diff --git a/fpdfsdk/formfiller/cffl_listbox.h b/fpdfsdk/formfiller/cffl_listbox.h
index 609f2c4..014865d 100644
--- a/fpdfsdk/formfiller/cffl_listbox.h
+++ b/fpdfsdk/formfiller/cffl_listbox.h
@@ -7,23 +7,21 @@
 #ifndef FPDFSDK_FORMFILLER_CFFL_LISTBOX_H_
 #define FPDFSDK_FORMFILLER_CFFL_LISTBOX_H_
 
-#include <memory>
 #include <set>
 #include <vector>
 
-#include "fpdfsdk/formfiller/cffl_formfiller.h"
+#include "fpdfsdk/formfiller/cffl_textobject.h"
 
 class CBA_FontMap;
 
-class CFFL_ListBox : public CFFL_FormFiller {
+class CFFL_ListBox : public CFFL_TextObject {
  public:
-  CFFL_ListBox(CPDFSDK_FormFillEnvironment* pApp, CPDFSDK_Annot* pWidget);
+  CFFL_ListBox(CPDFSDK_FormFillEnvironment* pApp, CPDFSDK_Widget* pWidget);
   ~CFFL_ListBox() override;
 
-  // CFFL_FormFiller
-  PWL_CREATEPARAM GetCreateParam() override;
-  CPWL_Wnd* NewPDFWindow(const PWL_CREATEPARAM& cp,
-                         CPDFSDK_PageView* pPageView) override;
+  // CFFL_TextObject:
+  CPWL_Wnd::CreateParams GetCreateParam() override;
+  CPWL_Wnd* NewPDFWindow(const CPWL_Wnd::CreateParams& cp) override;
   bool OnChar(CPDFSDK_Annot* pAnnot, uint32_t nChar, uint32_t nFlags) override;
   bool IsDataChanged(CPDFSDK_PageView* pPageView) override;
   void SaveData(CPDFSDK_PageView* pPageView) override;
@@ -32,11 +30,8 @@
                      PDFSDK_FieldAction& fa) override;
   void SaveState(CPDFSDK_PageView* pPageView) override;
   void RestoreState(CPDFSDK_PageView* pPageView) override;
-  CPWL_Wnd* ResetPDFWindow(CPDFSDK_PageView* pPageView,
-                           bool bRestoreValue) override;
 
  private:
-  std::unique_ptr<CBA_FontMap> m_pFontMap;
   std::set<int> m_OriginSelections;
   std::vector<int> m_State;
 };
diff --git a/fpdfsdk/formfiller/cffl_pushbutton.cpp b/fpdfsdk/formfiller/cffl_pushbutton.cpp
index 9b4121a..7310da6 100644
--- a/fpdfsdk/formfiller/cffl_pushbutton.cpp
+++ b/fpdfsdk/formfiller/cffl_pushbutton.cpp
@@ -7,31 +7,16 @@
 #include "fpdfsdk/formfiller/cffl_pushbutton.h"
 
 #include "fpdfsdk/formfiller/cffl_formfiller.h"
-#include "fpdfsdk/pdfwindow/PWL_SpecialButton.h"
+#include "fpdfsdk/pwl/cpwl_special_button.h"
 
 CFFL_PushButton::CFFL_PushButton(CPDFSDK_FormFillEnvironment* pApp,
-                                 CPDFSDK_Annot* pAnnot)
-    : CFFL_Button(pApp, pAnnot) {}
+                                 CPDFSDK_Widget* pWidget)
+    : CFFL_Button(pApp, pWidget) {}
 
 CFFL_PushButton::~CFFL_PushButton() {}
 
-CPWL_Wnd* CFFL_PushButton::NewPDFWindow(const PWL_CREATEPARAM& cp,
-                                        CPDFSDK_PageView* pPageView) {
-  CPWL_PushButton* pWnd = new CPWL_PushButton();
+CPWL_Wnd* CFFL_PushButton::NewPDFWindow(const CPWL_Wnd::CreateParams& cp) {
+  auto* pWnd = new CPWL_PushButton();
   pWnd->Create(cp);
-
   return pWnd;
 }
-
-bool CFFL_PushButton::OnChar(CPDFSDK_Annot* pAnnot,
-                             uint32_t nChar,
-                             uint32_t nFlags) {
-  return CFFL_FormFiller::OnChar(pAnnot, nChar, nFlags);
-}
-
-void CFFL_PushButton::OnDraw(CPDFSDK_PageView* pPageView,
-                             CPDFSDK_Annot* pAnnot,
-                             CFX_RenderDevice* pDevice,
-                             CFX_Matrix* pUser2Device) {
-  CFFL_Button::OnDraw(pPageView, pAnnot, pDevice, pUser2Device);
-}
diff --git a/fpdfsdk/formfiller/cffl_pushbutton.h b/fpdfsdk/formfiller/cffl_pushbutton.h
index 1d50595..7ee0767 100644
--- a/fpdfsdk/formfiller/cffl_pushbutton.h
+++ b/fpdfsdk/formfiller/cffl_pushbutton.h
@@ -7,21 +7,15 @@
 #ifndef FPDFSDK_FORMFILLER_CFFL_PUSHBUTTON_H_
 #define FPDFSDK_FORMFILLER_CFFL_PUSHBUTTON_H_
 
-#include "fpdfsdk/formfiller/cffl_formfiller.h"
+#include "fpdfsdk/formfiller/cffl_button.h"
 
 class CFFL_PushButton : public CFFL_Button {
  public:
-  CFFL_PushButton(CPDFSDK_FormFillEnvironment* pApp, CPDFSDK_Annot* pAnnot);
+  CFFL_PushButton(CPDFSDK_FormFillEnvironment* pApp, CPDFSDK_Widget* pWidget);
   ~CFFL_PushButton() override;
 
-  // CFFL_Button
-  CPWL_Wnd* NewPDFWindow(const PWL_CREATEPARAM& cp,
-                         CPDFSDK_PageView* pPageView) override;
-  bool OnChar(CPDFSDK_Annot* pAnnot, uint32_t nChar, uint32_t nFlags) override;
-  void OnDraw(CPDFSDK_PageView* pPageView,
-              CPDFSDK_Annot* pAnnot,
-              CFX_RenderDevice* pDevice,
-              CFX_Matrix* pUser2Device) override;
+  // CFFL_Button:
+  CPWL_Wnd* NewPDFWindow(const CPWL_Wnd::CreateParams& cp) override;
 };
 
 #endif  // FPDFSDK_FORMFILLER_CFFL_PUSHBUTTON_H_
diff --git a/fpdfsdk/formfiller/cffl_radiobutton.cpp b/fpdfsdk/formfiller/cffl_radiobutton.cpp
index e78160e..73ac44d 100644
--- a/fpdfsdk/formfiller/cffl_radiobutton.cpp
+++ b/fpdfsdk/formfiller/cffl_radiobutton.cpp
@@ -9,22 +9,19 @@
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 #include "fpdfsdk/cpdfsdk_widget.h"
 #include "fpdfsdk/formfiller/cffl_formfiller.h"
-#include "fpdfsdk/pdfwindow/PWL_SpecialButton.h"
+#include "fpdfsdk/pwl/cpwl_special_button.h"
 #include "public/fpdf_fwlevent.h"
 
 CFFL_RadioButton::CFFL_RadioButton(CPDFSDK_FormFillEnvironment* pApp,
-                                   CPDFSDK_Annot* pWidget)
+                                   CPDFSDK_Widget* pWidget)
     : CFFL_Button(pApp, pWidget) {}
 
 CFFL_RadioButton::~CFFL_RadioButton() {}
 
-CPWL_Wnd* CFFL_RadioButton::NewPDFWindow(const PWL_CREATEPARAM& cp,
-                                         CPDFSDK_PageView* pPageView) {
-  CPWL_RadioButton* pWnd = new CPWL_RadioButton();
+CPWL_Wnd* CFFL_RadioButton::NewPDFWindow(const CPWL_Wnd::CreateParams& cp) {
+  auto* pWnd = new CPWL_RadioButton();
   pWnd->Create(cp);
-
   pWnd->SetCheck(m_pWidget->IsChecked());
-
   return pWnd;
 }
 
@@ -49,20 +46,18 @@
       CPDFSDK_PageView* pPageView = pAnnot->GetPageView();
       ASSERT(pPageView);
 
-      bool bReset = false;
-      bool bExit = false;
-      CPDFSDK_Annot::ObservedPtr pObserved(m_pWidget);
-      m_pFormFillEnv->GetInteractiveFormFiller()->OnButtonUp(
-          &pObserved, pPageView, bReset, bExit, nFlags);
-      if (!pObserved || bReset || bExit)
+      CPDFSDK_Annot::ObservedPtr pObserved(m_pWidget.Get());
+      if (m_pFormFillEnv->GetInteractiveFormFiller()->OnButtonUp(
+              &pObserved, pPageView, nFlags) ||
+          !pObserved) {
         return true;
+      }
 
       CFFL_FormFiller::OnChar(pAnnot, nChar, nFlags);
-      if (CPWL_RadioButton* pWnd =
-              (CPWL_RadioButton*)GetPDFWindow(pPageView, true))
+      CPWL_RadioButton* pWnd = GetRadioButton(pPageView, true);
+      if (pWnd)
         pWnd->SetCheck(true);
-      CommitData(pPageView, nFlags);
-      return true;
+      return CommitData(pPageView, nFlags);
     }
     default:
       return CFFL_FormFiller::OnChar(pAnnot, nChar, nFlags);
@@ -75,45 +70,51 @@
                                    const CFX_PointF& point) {
   CFFL_Button::OnLButtonUp(pPageView, pAnnot, nFlags, point);
 
-  if (IsValid()) {
-    if (CPWL_RadioButton* pWnd =
-            (CPWL_RadioButton*)GetPDFWindow(pPageView, true))
-      pWnd->SetCheck(true);
+  if (!IsValid())
+    return true;
 
-    if (!CommitData(pPageView, nFlags))
-      return false;
-  }
+  CPWL_RadioButton* pWnd = GetRadioButton(pPageView, true);
+  if (pWnd)
+    pWnd->SetCheck(true);
 
-  return true;
+  return CommitData(pPageView, nFlags);
 }
 
 bool CFFL_RadioButton::IsDataChanged(CPDFSDK_PageView* pPageView) {
-  if (CPWL_RadioButton* pWnd =
-          (CPWL_RadioButton*)GetPDFWindow(pPageView, false)) {
-    return pWnd->IsChecked() != m_pWidget->IsChecked();
-  }
-
-  return false;
+  CPWL_RadioButton* pWnd = GetRadioButton(pPageView, false);
+  return pWnd && pWnd->IsChecked() != m_pWidget->IsChecked();
 }
 
 void CFFL_RadioButton::SaveData(CPDFSDK_PageView* pPageView) {
-  if (CPWL_RadioButton* pWnd =
-          (CPWL_RadioButton*)GetPDFWindow(pPageView, false)) {
-    bool bNewChecked = pWnd->IsChecked();
+  CPWL_RadioButton* pWnd = GetRadioButton(pPageView, false);
+  if (!pWnd)
+    return;
 
-    if (bNewChecked) {
-      CPDF_FormField* pField = m_pWidget->GetFormField();
-      for (int32_t i = 0, sz = pField->CountControls(); i < sz; i++) {
-        if (CPDF_FormControl* pCtrl = pField->GetControl(i)) {
-          if (pCtrl->IsChecked()) {
-            break;
-          }
+  bool bNewChecked = pWnd->IsChecked();
+
+  if (bNewChecked) {
+    CPDF_FormField* pField = m_pWidget->GetFormField();
+    for (int32_t i = 0, sz = pField->CountControls(); i < sz; i++) {
+      if (CPDF_FormControl* pCtrl = pField->GetControl(i)) {
+        if (pCtrl->IsChecked()) {
+          break;
         }
       }
     }
-
-    m_pWidget->SetCheck(bNewChecked, false);
-    m_pWidget->UpdateField();
-    SetChangeMark();
   }
+  CPDFSDK_Widget::ObservedPtr observed_widget(m_pWidget.Get());
+  CFFL_RadioButton::ObservedPtr observed_this(this);
+
+  m_pWidget->SetCheck(bNewChecked, false);
+  if (!observed_widget)
+    return;
+  m_pWidget->UpdateField();
+  if (!observed_widget || !observed_this)
+    return;
+  SetChangeMark();
+}
+
+CPWL_RadioButton* CFFL_RadioButton::GetRadioButton(CPDFSDK_PageView* pPageView,
+                                                   bool bNew) {
+  return static_cast<CPWL_RadioButton*>(GetPDFWindow(pPageView, bNew));
 }
diff --git a/fpdfsdk/formfiller/cffl_radiobutton.h b/fpdfsdk/formfiller/cffl_radiobutton.h
index 10ac37d..2838254 100644
--- a/fpdfsdk/formfiller/cffl_radiobutton.h
+++ b/fpdfsdk/formfiller/cffl_radiobutton.h
@@ -7,16 +7,17 @@
 #ifndef FPDFSDK_FORMFILLER_CFFL_RADIOBUTTON_H_
 #define FPDFSDK_FORMFILLER_CFFL_RADIOBUTTON_H_
 
-#include "fpdfsdk/formfiller/cffl_formfiller.h"
+#include "fpdfsdk/formfiller/cffl_button.h"
+
+class CPWL_RadioButton;
 
 class CFFL_RadioButton : public CFFL_Button {
  public:
-  CFFL_RadioButton(CPDFSDK_FormFillEnvironment* pApp, CPDFSDK_Annot* pAnnot);
+  CFFL_RadioButton(CPDFSDK_FormFillEnvironment* pApp, CPDFSDK_Widget* pWidget);
   ~CFFL_RadioButton() override;
 
-  // CFFL_Button
-  CPWL_Wnd* NewPDFWindow(const PWL_CREATEPARAM& cp,
-                         CPDFSDK_PageView* pPageView) override;
+  // CFFL_Button:
+  CPWL_Wnd* NewPDFWindow(const CPWL_Wnd::CreateParams& cp) override;
   bool OnKeyDown(CPDFSDK_Annot* pAnnot,
                  uint32_t nKeyCode,
                  uint32_t nFlags) override;
@@ -27,6 +28,9 @@
                    const CFX_PointF& point) override;
   bool IsDataChanged(CPDFSDK_PageView* pPageView) override;
   void SaveData(CPDFSDK_PageView* pPageView) override;
+
+ private:
+  CPWL_RadioButton* GetRadioButton(CPDFSDK_PageView* pPageView, bool bNew);
 };
 
 #endif  // FPDFSDK_FORMFILLER_CFFL_RADIOBUTTON_H_
diff --git a/fpdfsdk/formfiller/cffl_textfield.cpp b/fpdfsdk/formfiller/cffl_textfield.cpp
index 91db095..ad8d27c 100644
--- a/fpdfsdk/formfiller/cffl_textfield.cpp
+++ b/fpdfsdk/formfiller/cffl_textfield.cpp
@@ -13,8 +13,8 @@
 #include "third_party/base/ptr_util.h"
 
 CFFL_TextField::CFFL_TextField(CPDFSDK_FormFillEnvironment* pApp,
-                               CPDFSDK_Annot* pAnnot)
-    : CFFL_FormFiller(pApp, pAnnot) {}
+                               CPDFSDK_Widget* pWidget)
+    : CFFL_TextObject(pApp, pWidget) {}
 
 CFFL_TextField::~CFFL_TextField() {
   for (const auto& it : m_Maps)
@@ -26,36 +26,27 @@
   DestroyWindows();
 }
 
-PWL_CREATEPARAM CFFL_TextField::GetCreateParam() {
-  PWL_CREATEPARAM cp = CFFL_FormFiller::GetCreateParam();
-
+CPWL_Wnd::CreateParams CFFL_TextField::GetCreateParam() {
+  CPWL_Wnd::CreateParams cp = CFFL_TextObject::GetCreateParam();
   int nFlags = m_pWidget->GetFieldFlags();
-
-  if (nFlags & FIELDFLAG_PASSWORD) {
+  if (nFlags & FIELDFLAG_PASSWORD)
     cp.dwFlags |= PES_PASSWORD;
-  }
 
   if (nFlags & FIELDFLAG_MULTILINE) {
     cp.dwFlags |= PES_MULTILINE | PES_AUTORETURN | PES_TOP;
-
-    if (!(nFlags & FIELDFLAG_DONOTSCROLL)) {
+    if (!(nFlags & FIELDFLAG_DONOTSCROLL))
       cp.dwFlags |= PWS_VSCROLL | PES_AUTOSCROLL;
-    }
   } else {
     cp.dwFlags |= PES_CENTER;
-
-    if (!(nFlags & FIELDFLAG_DONOTSCROLL)) {
+    if (!(nFlags & FIELDFLAG_DONOTSCROLL))
       cp.dwFlags |= PES_AUTOSCROLL;
-    }
   }
 
-  if (nFlags & FIELDFLAG_COMB) {
+  if (nFlags & FIELDFLAG_COMB)
     cp.dwFlags |= PES_CHARARRAY;
-  }
 
-  if (nFlags & FIELDFLAG_RICHTEXT) {
+  if (nFlags & FIELDFLAG_RICHTEXT)
     cp.dwFlags |= PES_RICH;
-  }
 
   cp.dwFlags |= PES_UNDO;
 
@@ -71,26 +62,19 @@
       cp.dwFlags |= PES_RIGHT;
       break;
   }
-
-  if (!m_pFontMap) {
-    m_pFontMap = pdfium::MakeUnique<CBA_FontMap>(
-        m_pWidget, m_pFormFillEnv->GetSysHandler());
-  }
-  cp.pFontMap = m_pFontMap.get();
+  cp.pFontMap = MaybeCreateFontMap();
   cp.pFocusHandler = this;
-
   return cp;
 }
 
-CPWL_Wnd* CFFL_TextField::NewPDFWindow(const PWL_CREATEPARAM& cp,
-                                       CPDFSDK_PageView* pPageView) {
-  CPWL_Edit* pWnd = new CPWL_Edit();
+CPWL_Wnd* CFFL_TextField::NewPDFWindow(const CPWL_Wnd::CreateParams& cp) {
+  auto* pWnd = new CPWL_Edit();
   pWnd->AttachFFLData(this);
   pWnd->Create(cp);
   pWnd->SetFillerNotify(m_pFormFillEnv->GetInteractiveFormFiller());
 
   int32_t nMaxLen = m_pWidget->GetMaxLen();
-  CFX_WideString swValue = m_pWidget->GetValue();
+  WideString swValue = m_pWidget->GetValue();
 
   if (nMaxLen > 0) {
     if (pWnd->HasFlag(PES_CHARARRAY)) {
@@ -109,26 +93,28 @@
                             uint32_t nChar,
                             uint32_t nFlags) {
   switch (nChar) {
-    case FWL_VKEY_Return:
-      if (!(m_pWidget->GetFieldFlags() & FIELDFLAG_MULTILINE)) {
-        CPDFSDK_PageView* pPageView = GetCurPageView(true);
-        ASSERT(pPageView);
-        m_bValid = !m_bValid;
-        m_pFormFillEnv->Invalidate(pAnnot->GetUnderlyingPage(),
-                                   pAnnot->GetRect().ToFxRect());
+    case FWL_VKEY_Return: {
+      if (m_pWidget->GetFieldFlags() & FIELDFLAG_MULTILINE)
+        break;
 
-        if (m_bValid) {
-          if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, true))
-            pWnd->SetFocus();
-        } else {
-          if (CommitData(pPageView, nFlags)) {
-            DestroyPDFWindow(pPageView);
-            return true;
-          }
-          return false;
-        }
+      CPDFSDK_PageView* pPageView = GetCurPageView(true);
+      ASSERT(pPageView);
+      m_bValid = !m_bValid;
+      m_pFormFillEnv->Invalidate(pAnnot->GetUnderlyingPage(),
+                                 pAnnot->GetRect().GetOuterRect());
+
+      if (m_bValid) {
+        if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, true))
+          pWnd->SetFocus();
+        break;
       }
-      break;
+
+      if (!CommitData(pPageView, nFlags))
+        return false;
+
+      DestroyPDFWindow(pPageView);
+      return true;
+    }
     case FWL_VKEY_Escape: {
       CPDFSDK_PageView* pPageView = GetCurPageView(true);
       ASSERT(pPageView);
@@ -137,26 +123,35 @@
     }
   }
 
-  return CFFL_FormFiller::OnChar(pAnnot, nChar, nFlags);
+  return CFFL_TextObject::OnChar(pAnnot, nChar, nFlags);
 }
 
 bool CFFL_TextField::IsDataChanged(CPDFSDK_PageView* pPageView) {
-  if (CPWL_Edit* pEdit = (CPWL_Edit*)GetPDFWindow(pPageView, false))
-    return pEdit->GetText() != m_pWidget->GetValue();
-
-  return false;
+  CPWL_Edit* pEdit = GetEdit(pPageView, false);
+  return pEdit && pEdit->GetText() != m_pWidget->GetValue();
 }
 
 void CFFL_TextField::SaveData(CPDFSDK_PageView* pPageView) {
-  if (CPWL_Edit* pWnd = (CPWL_Edit*)GetPDFWindow(pPageView, false)) {
-    CFX_WideString sOldValue = m_pWidget->GetValue();
-    CFX_WideString sNewValue = pWnd->GetText();
+  CPWL_Edit* pWnd = GetEdit(pPageView, false);
+  if (!pWnd)
+    return;
 
-    m_pWidget->SetValue(sNewValue, false);
-    m_pWidget->ResetFieldAppearance(true);
-    m_pWidget->UpdateField();
-    SetChangeMark();
-  }
+  WideString sOldValue = m_pWidget->GetValue();
+  WideString sNewValue = pWnd->GetText();
+
+  CPDFSDK_Widget::ObservedPtr observed_widget(m_pWidget.Get());
+  CFFL_TextField::ObservedPtr observed_this(this);
+
+  m_pWidget->SetValue(sNewValue, false);
+  if (!observed_widget)
+    return;
+  m_pWidget->ResetFieldAppearance(true);
+  if (!observed_widget)
+    return;
+  m_pWidget->UpdateField();
+  if (!observed_widget || !observed_this)
+    return;
+  SetChangeMark();
 }
 
 void CFFL_TextField::GetActionData(CPDFSDK_PageView* pPageView,
@@ -164,7 +159,7 @@
                                    PDFSDK_FieldAction& fa) {
   switch (type) {
     case CPDF_AAction::KeyStroke:
-      if (CPWL_Edit* pWnd = (CPWL_Edit*)GetPDFWindow(pPageView, false)) {
+      if (CPWL_Edit* pWnd = GetEdit(pPageView, false)) {
         fa.bFieldFull = pWnd->IsTextFull();
 
         fa.sValue = pWnd->GetText();
@@ -176,7 +171,7 @@
       }
       break;
     case CPDF_AAction::Validate:
-      if (CPWL_Edit* pWnd = (CPWL_Edit*)GetPDFWindow(pPageView, false)) {
+      if (CPWL_Edit* pWnd = GetEdit(pPageView, false)) {
         fa.sValue = pWnd->GetText();
       }
       break;
@@ -194,9 +189,9 @@
                                    const PDFSDK_FieldAction& fa) {
   switch (type) {
     case CPDF_AAction::KeyStroke:
-      if (CPWL_Edit* pEdit = (CPWL_Edit*)GetPDFWindow(pPageView, false)) {
+      if (CPWL_Edit* pEdit = GetEdit(pPageView, false)) {
         pEdit->SetFocus();
-        pEdit->SetSel(fa.nSelStart, fa.nSelEnd);
+        pEdit->SetSelection(fa.nSelStart, fa.nSelEnd);
         pEdit->ReplaceSel(fa.sChange);
       }
       break;
@@ -223,64 +218,43 @@
 void CFFL_TextField::SaveState(CPDFSDK_PageView* pPageView) {
   ASSERT(pPageView);
 
-  if (CPWL_Edit* pWnd = (CPWL_Edit*)GetPDFWindow(pPageView, false)) {
-    pWnd->GetSel(m_State.nStart, m_State.nEnd);
-    m_State.sValue = pWnd->GetText();
-  }
+  CPWL_Edit* pWnd = GetEdit(pPageView, false);
+  if (!pWnd)
+    return;
+
+  pWnd->GetSelection(m_State.nStart, m_State.nEnd);
+  m_State.sValue = pWnd->GetText();
 }
 
 void CFFL_TextField::RestoreState(CPDFSDK_PageView* pPageView) {
   ASSERT(pPageView);
 
-  if (CPWL_Edit* pWnd = (CPWL_Edit*)GetPDFWindow(pPageView, true)) {
-    pWnd->SetText(m_State.sValue);
-    pWnd->SetSel(m_State.nStart, m_State.nEnd);
-  }
-}
+  CPWL_Edit* pWnd = GetEdit(pPageView, true);
+  if (!pWnd)
+    return;
 
-CPWL_Wnd* CFFL_TextField::ResetPDFWindow(CPDFSDK_PageView* pPageView,
-                                         bool bRestoreValue) {
-  if (bRestoreValue)
-    SaveState(pPageView);
-
-  DestroyPDFWindow(pPageView);
-
-  CPWL_Wnd* pRet = nullptr;
-
-  if (bRestoreValue) {
-    RestoreState(pPageView);
-    pRet = GetPDFWindow(pPageView, false);
-  } else {
-    pRet = GetPDFWindow(pPageView, true);
-  }
-
-  m_pWidget->UpdateField();
-
-  return pRet;
+  pWnd->SetText(m_State.sValue);
+  pWnd->SetSelection(m_State.nStart, m_State.nEnd);
 }
 
 #ifdef PDF_ENABLE_XFA
 bool CFFL_TextField::IsFieldFull(CPDFSDK_PageView* pPageView) {
-  if (CPWL_Edit* pWnd = (CPWL_Edit*)GetPDFWindow(pPageView, false)) {
-    return pWnd->IsTextFull();
-  }
-
-  return false;
+  CPWL_Edit* pWnd = GetEdit(pPageView, false);
+  return pWnd && pWnd->IsTextFull();
 }
 #endif  // PDF_ENABLE_XFA
 
-void CFFL_TextField::OnSetFocus(CPWL_Wnd* pWnd) {
-  ASSERT(m_pFormFillEnv);
-  if (pWnd->GetClassName() == PWL_CLASSNAME_EDIT) {
-    CPWL_Edit* pEdit = (CPWL_Edit*)pWnd;
-    pEdit->SetCharSet(FXFONT_GB2312_CHARSET);
-    pEdit->SetCodePage(936);
+void CFFL_TextField::OnSetFocus(CPWL_Edit* pEdit) {
+  pEdit->SetCharSet(FX_CHARSET_ChineseSimplified);
+  pEdit->SetReadyToInput();
 
-    pEdit->SetReadyToInput();
-    CFX_WideString wsText = pEdit->GetText();
-    int nCharacters = wsText.GetLength();
-    CFX_ByteString bsUTFText = wsText.UTF16LE_Encode();
-    unsigned short* pBuffer = (unsigned short*)bsUTFText.c_str();
-    m_pFormFillEnv->OnSetFieldInputFocus(pBuffer, nCharacters, true);
-  }
+  WideString wsText = pEdit->GetText();
+  int nCharacters = wsText.GetLength();
+  ByteString bsUTFText = wsText.UTF16LE_Encode();
+  auto* pBuffer = reinterpret_cast<const unsigned short*>(bsUTFText.c_str());
+  m_pFormFillEnv->OnSetFieldInputFocus(pBuffer, nCharacters, true);
+}
+
+CPWL_Edit* CFFL_TextField::GetEdit(CPDFSDK_PageView* pPageView, bool bNew) {
+  return static_cast<CPWL_Edit*>(GetPDFWindow(pPageView, bNew));
 }
diff --git a/fpdfsdk/formfiller/cffl_textfield.h b/fpdfsdk/formfiller/cffl_textfield.h
index 29579f7..49ffc0f 100644
--- a/fpdfsdk/formfiller/cffl_textfield.h
+++ b/fpdfsdk/formfiller/cffl_textfield.h
@@ -7,33 +7,32 @@
 #ifndef FPDFSDK_FORMFILLER_CFFL_TEXTFIELD_H_
 #define FPDFSDK_FORMFILLER_CFFL_TEXTFIELD_H_
 
-#include <memory>
-
-#include "fpdfsdk/formfiller/cffl_formfiller.h"
+#include "fpdfsdk/formfiller/cffl_textobject.h"
 
 #define BF_ALIGN_LEFT 0
 #define BF_ALIGN_MIDDLE 1
 #define BF_ALIGN_RIGHT 2
 
 class CBA_FontMap;
+class CPWL_Edit;
 
 struct FFL_TextFieldState {
   FFL_TextFieldState() : nStart(0), nEnd(0) {}
 
   int nStart;
   int nEnd;
-  CFX_WideString sValue;
+  WideString sValue;
 };
 
-class CFFL_TextField : public CFFL_FormFiller, public IPWL_FocusHandler {
+class CFFL_TextField : public CFFL_TextObject,
+                       public CPWL_Wnd::FocusHandlerIface {
  public:
-  CFFL_TextField(CPDFSDK_FormFillEnvironment* pApp, CPDFSDK_Annot* pAnnot);
+  CFFL_TextField(CPDFSDK_FormFillEnvironment* pApp, CPDFSDK_Widget* pWidget);
   ~CFFL_TextField() override;
 
-  // CFFL_FormFiller:
-  PWL_CREATEPARAM GetCreateParam() override;
-  CPWL_Wnd* NewPDFWindow(const PWL_CREATEPARAM& cp,
-                         CPDFSDK_PageView* pPageView) override;
+  // CFFL_TextObject:
+  CPWL_Wnd::CreateParams GetCreateParam() override;
+  CPWL_Wnd* NewPDFWindow(const CPWL_Wnd::CreateParams& cp) override;
   bool OnChar(CPDFSDK_Annot* pAnnot, uint32_t nChar, uint32_t nFlags) override;
   bool IsDataChanged(CPDFSDK_PageView* pPageView) override;
   void SaveData(CPDFSDK_PageView* pPageView) override;
@@ -48,19 +47,16 @@
                            const PDFSDK_FieldAction& faNew) override;
   void SaveState(CPDFSDK_PageView* pPageView) override;
   void RestoreState(CPDFSDK_PageView* pPageView) override;
-  CPWL_Wnd* ResetPDFWindow(CPDFSDK_PageView* pPageView,
-                           bool bRestoreValue) override;
-
-  // IPWL_FocusHandler:
-  void OnSetFocus(CPWL_Wnd* pWnd) override;
-
 #ifdef PDF_ENABLE_XFA
-  // CFFL_FormFiller:
   bool IsFieldFull(CPDFSDK_PageView* pPageView) override;
-#endif  // PDF_ENABLE_XFA
+#endif
+
+  // CPWL_Wnd::FocusHandlerIface:
+  void OnSetFocus(CPWL_Edit* pEdit) override;
 
  private:
-  std::unique_ptr<CBA_FontMap> m_pFontMap;
+  CPWL_Edit* GetEdit(CPDFSDK_PageView* pPageView, bool bNew);
+
   FFL_TextFieldState m_State;
 };
 
diff --git a/fpdfsdk/formfiller/cffl_textobject.cpp b/fpdfsdk/formfiller/cffl_textobject.cpp
new file mode 100644
index 0000000..df2f5e5
--- /dev/null
+++ b/fpdfsdk/formfiller/cffl_textobject.cpp
@@ -0,0 +1,39 @@
+// 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/formfiller/cffl_textobject.h"
+
+CPWL_Wnd* CFFL_TextObject::ResetPDFWindow(CPDFSDK_PageView* pPageView,
+                                          bool bRestoreValue) {
+  if (bRestoreValue)
+    SaveState(pPageView);
+
+  DestroyPDFWindow(pPageView);
+  if (bRestoreValue)
+    RestoreState(pPageView);
+
+  CPWL_Wnd::ObservedPtr pRet(GetPDFWindow(pPageView, !bRestoreValue));
+  m_pWidget->UpdateField();  // May invoke JS, invalidating |pRet|.
+  return pRet.Get();
+}
+
+CFFL_TextObject::CFFL_TextObject(CPDFSDK_FormFillEnvironment* pApp,
+                                 CPDFSDK_Widget* pWidget)
+    : CFFL_FormFiller(pApp, pWidget) {}
+
+CFFL_TextObject::~CFFL_TextObject() {
+  // Destroy view classes before this object's members are destroyed since
+  // the view classes have pointers to m_pFontMap that would be left dangling.
+  DestroyWindows();
+}
+
+CBA_FontMap* CFFL_TextObject::MaybeCreateFontMap() {
+  if (!m_pFontMap) {
+    m_pFontMap =
+        pdfium::MakeUnique<CBA_FontMap>(m_pWidget.Get(), GetSystemHandler());
+  }
+  return m_pFontMap.get();
+}
diff --git a/fpdfsdk/formfiller/cffl_textobject.h b/fpdfsdk/formfiller/cffl_textobject.h
new file mode 100644
index 0000000..fcb3c1b
--- /dev/null
+++ b/fpdfsdk/formfiller/cffl_textobject.h
@@ -0,0 +1,32 @@
+// 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_FORMFILLER_CFFL_TEXTOBJECT_H_
+#define FPDFSDK_FORMFILLER_CFFL_TEXTOBJECT_H_
+
+#include <memory>
+
+#include "fpdfsdk/formfiller/cffl_formfiller.h"
+
+// Class to implement common functionality for CFFL_FormFiller sub-classes with
+// text fields.
+class CFFL_TextObject : public CFFL_FormFiller {
+ public:
+  // CFFL_FormFiller:
+  CPWL_Wnd* ResetPDFWindow(CPDFSDK_PageView* pPageView,
+                           bool bRestoreValue) override;
+
+ protected:
+  CFFL_TextObject(CPDFSDK_FormFillEnvironment* pApp, CPDFSDK_Widget* pWidget);
+  ~CFFL_TextObject() override;
+
+  CBA_FontMap* MaybeCreateFontMap();
+
+ private:
+  std::unique_ptr<CBA_FontMap> m_pFontMap;
+};
+
+#endif  // FPDFSDK_FORMFILLER_CFFL_TEXTOBJECT_H_
diff --git a/fpdfsdk/fpdf_dataavail.cpp b/fpdfsdk/fpdf_dataavail.cpp
index b1bc1e3..b1a134d 100644
--- a/fpdfsdk/fpdf_dataavail.cpp
+++ b/fpdfsdk/fpdf_dataavail.cpp
@@ -11,7 +11,8 @@
 
 #include "core/fpdfapi/parser/cpdf_data_avail.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
-#include "core/fxcrt/cfx_retain_ptr.h"
+#include "core/fxcrt/fx_stream.h"
+#include "core/fxcrt/retain_ptr.h"
 #include "fpdfsdk/fsdk_define.h"
 #include "public/fpdf_formfill.h"
 #include "third_party/base/ptr_util.h"
@@ -42,15 +43,15 @@
 
 namespace {
 
-class CFPDF_FileAvailWrap : public CPDF_DataAvail::FileAvail {
+class FPDF_FileAvailContext : public CPDF_DataAvail::FileAvail {
  public:
-  CFPDF_FileAvailWrap() : m_pfileAvail(nullptr) {}
-  ~CFPDF_FileAvailWrap() override {}
+  FPDF_FileAvailContext() : m_pfileAvail(nullptr) {}
+  ~FPDF_FileAvailContext() override {}
 
   void Set(FX_FILEAVAIL* pfileAvail) { m_pfileAvail = pfileAvail; }
 
   // CPDF_DataAvail::FileAvail:
-  bool IsDataAvail(FX_FILESIZE offset, uint32_t size) override {
+  bool IsDataAvail(FX_FILESIZE offset, size_t size) override {
     return !!m_pfileAvail->IsDataAvail(m_pfileAvail, offset, size);
   }
 
@@ -58,12 +59,12 @@
   FX_FILEAVAIL* m_pfileAvail;
 };
 
-class CFPDF_FileAccessWrap : public IFX_SeekableReadStream {
+class FPDF_FileAccessContext : public IFX_SeekableReadStream {
  public:
-  static CFX_RetainPtr<CFPDF_FileAccessWrap> Create() {
-    return CFX_RetainPtr<CFPDF_FileAccessWrap>(new CFPDF_FileAccessWrap());
-  }
-  ~CFPDF_FileAccessWrap() override {}
+  template <typename T, typename... Args>
+  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
+
+  ~FPDF_FileAccessContext() override {}
 
   void Set(FPDF_FILEACCESS* pFile) { m_pFileAccess = pFile; }
 
@@ -76,119 +77,115 @@
   }
 
  private:
-  CFPDF_FileAccessWrap() : m_pFileAccess(nullptr) {}
+  FPDF_FileAccessContext() : m_pFileAccess(nullptr) {}
 
   FPDF_FILEACCESS* m_pFileAccess;
 };
 
-class CFPDF_DownloadHintsWrap : public CPDF_DataAvail::DownloadHints {
+class FPDF_DownloadHintsContext : public CPDF_DataAvail::DownloadHints {
  public:
-  explicit CFPDF_DownloadHintsWrap(FX_DOWNLOADHINTS* pDownloadHints) {
+  explicit FPDF_DownloadHintsContext(FX_DOWNLOADHINTS* pDownloadHints) {
     m_pDownloadHints = pDownloadHints;
   }
-  ~CFPDF_DownloadHintsWrap() override {}
+  ~FPDF_DownloadHintsContext() override {}
 
  public:
   // IFX_DownloadHints
-  void AddSegment(FX_FILESIZE offset, uint32_t size) override {
-    m_pDownloadHints->AddSegment(m_pDownloadHints, offset, size);
+  void AddSegment(FX_FILESIZE offset, size_t size) override {
+    if (m_pDownloadHints)
+      m_pDownloadHints->AddSegment(m_pDownloadHints, offset, size);
   }
 
  private:
   FX_DOWNLOADHINTS* m_pDownloadHints;
 };
 
-class CFPDF_DataAvail {
+class FPDF_AvailContext {
  public:
-  CFPDF_DataAvail()
-      : m_FileAvail(new CFPDF_FileAvailWrap),
-        m_FileRead(CFPDF_FileAccessWrap::Create()) {}
-  ~CFPDF_DataAvail() {}
+  FPDF_AvailContext()
+      : m_FileAvail(pdfium::MakeUnique<FPDF_FileAvailContext>()),
+        m_FileRead(pdfium::MakeRetain<FPDF_FileAccessContext>()) {}
+  ~FPDF_AvailContext() {}
 
+  std::unique_ptr<FPDF_FileAvailContext> m_FileAvail;
+  RetainPtr<FPDF_FileAccessContext> m_FileRead;
   std::unique_ptr<CPDF_DataAvail> m_pDataAvail;
-  std::unique_ptr<CFPDF_FileAvailWrap> m_FileAvail;
-  CFX_RetainPtr<CFPDF_FileAccessWrap> m_FileRead;
 };
 
-CFPDF_DataAvail* CFPDFDataAvailFromFPDFAvail(FPDF_AVAIL avail) {
-  return static_cast<CFPDF_DataAvail*>(avail);
+FPDF_AvailContext* FPDFAvailContextFromFPDFAvail(FPDF_AVAIL avail) {
+  return static_cast<FPDF_AvailContext*>(avail);
 }
 
 }  // namespace
 
-DLLEXPORT FPDF_AVAIL STDCALL FPDFAvail_Create(FX_FILEAVAIL* file_avail,
-                                              FPDF_FILEACCESS* file) {
-  CFPDF_DataAvail* pAvail = new CFPDF_DataAvail;
+FPDF_EXPORT FPDF_AVAIL FPDF_CALLCONV FPDFAvail_Create(FX_FILEAVAIL* file_avail,
+                                                      FPDF_FILEACCESS* file) {
+  auto pAvail = pdfium::MakeUnique<FPDF_AvailContext>();
   pAvail->m_FileAvail->Set(file_avail);
   pAvail->m_FileRead->Set(file);
   pAvail->m_pDataAvail = pdfium::MakeUnique<CPDF_DataAvail>(
       pAvail->m_FileAvail.get(), pAvail->m_FileRead, true);
-  return pAvail;
+  return pAvail.release();  // Caller takes ownership.
 }
 
-DLLEXPORT void STDCALL FPDFAvail_Destroy(FPDF_AVAIL avail) {
-  delete (CFPDF_DataAvail*)avail;
+FPDF_EXPORT void FPDF_CALLCONV FPDFAvail_Destroy(FPDF_AVAIL avail) {
+  // Take ownership back from caller and destroy.
+  std::unique_ptr<FPDF_AvailContext>(FPDFAvailContextFromFPDFAvail(avail));
 }
 
-DLLEXPORT int STDCALL FPDFAvail_IsDocAvail(FPDF_AVAIL avail,
-                                           FX_DOWNLOADHINTS* hints) {
-  if (!avail || !hints)
+FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsDocAvail(FPDF_AVAIL avail,
+                                                   FX_DOWNLOADHINTS* hints) {
+  if (!avail)
     return PDF_DATA_ERROR;
-  CFPDF_DownloadHintsWrap hints_wrap(hints);
-  return CFPDFDataAvailFromFPDFAvail(avail)->m_pDataAvail->IsDocAvail(
-      &hints_wrap);
+  FPDF_DownloadHintsContext hints_context(hints);
+  return FPDFAvailContextFromFPDFAvail(avail)->m_pDataAvail->IsDocAvail(
+      &hints_context);
 }
 
-DLLEXPORT FPDF_DOCUMENT STDCALL
+FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
 FPDFAvail_GetDocument(FPDF_AVAIL avail, FPDF_BYTESTRING password) {
-  CFPDF_DataAvail* pDataAvail = static_cast<CFPDF_DataAvail*>(avail);
+  auto* pDataAvail = FPDFAvailContextFromFPDFAvail(avail);
   if (!pDataAvail)
     return nullptr;
-
-  std::unique_ptr<CPDF_Parser> pParser(new CPDF_Parser);
-  pParser->SetPassword(password);
-
-  std::unique_ptr<CPDF_Document> pDocument(
-      new CPDF_Document(std::move(pParser)));
-  CPDF_Parser::Error error = pDocument->GetParser()->StartLinearizedParse(
-      pDataAvail->m_pDataAvail->GetFileRead(), pDocument.get());
+  CPDF_Parser::Error error;
+  std::unique_ptr<CPDF_Document> document;
+  std::tie(error, document) = pDataAvail->m_pDataAvail->ParseDocument(password);
   if (error != CPDF_Parser::SUCCESS) {
     ProcessParseError(error);
     return nullptr;
   }
-  pDataAvail->m_pDataAvail->SetDocument(pDocument.get());
-  CheckUnSupportError(pDocument.get(), FPDF_ERR_SUCCESS);
-  return FPDFDocumentFromCPDFDocument(pDocument.release());
+  CheckUnSupportError(document.get(), FPDF_ERR_SUCCESS);
+  return FPDFDocumentFromCPDFDocument(document.release());
 }
 
-DLLEXPORT int STDCALL FPDFAvail_GetFirstPageNum(FPDF_DOCUMENT doc) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_GetFirstPageNum(FPDF_DOCUMENT doc) {
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(doc);
   return pDoc ? pDoc->GetParser()->GetFirstPageNo() : 0;
 }
 
-DLLEXPORT int STDCALL FPDFAvail_IsPageAvail(FPDF_AVAIL avail,
-                                            int page_index,
-                                            FX_DOWNLOADHINTS* hints) {
-  if (!avail || !hints)
+FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsPageAvail(FPDF_AVAIL avail,
+                                                    int page_index,
+                                                    FX_DOWNLOADHINTS* hints) {
+  if (!avail)
     return PDF_DATA_ERROR;
   if (page_index < 0)
     return PDF_DATA_NOTAVAIL;
-  CFPDF_DownloadHintsWrap hints_wrap(hints);
-  return CFPDFDataAvailFromFPDFAvail(avail)->m_pDataAvail->IsPageAvail(
-      page_index, &hints_wrap);
+  FPDF_DownloadHintsContext hints_context(hints);
+  return FPDFAvailContextFromFPDFAvail(avail)->m_pDataAvail->IsPageAvail(
+      page_index, &hints_context);
 }
 
-DLLEXPORT int STDCALL FPDFAvail_IsFormAvail(FPDF_AVAIL avail,
-                                            FX_DOWNLOADHINTS* hints) {
-  if (!avail || !hints)
+FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsFormAvail(FPDF_AVAIL avail,
+                                                    FX_DOWNLOADHINTS* hints) {
+  if (!avail)
     return PDF_FORM_ERROR;
-  CFPDF_DownloadHintsWrap hints_wrap(hints);
-  return CFPDFDataAvailFromFPDFAvail(avail)->m_pDataAvail->IsFormAvail(
-      &hints_wrap);
+  FPDF_DownloadHintsContext hints_context(hints);
+  return FPDFAvailContextFromFPDFAvail(avail)->m_pDataAvail->IsFormAvail(
+      &hints_context);
 }
 
-DLLEXPORT int STDCALL FPDFAvail_IsLinearized(FPDF_AVAIL avail) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsLinearized(FPDF_AVAIL avail) {
   if (!avail)
     return PDF_LINEARIZATION_UNKNOWN;
-  return CFPDFDataAvailFromFPDFAvail(avail)->m_pDataAvail->IsLinearizedPDF();
+  return FPDFAvailContextFromFPDFAvail(avail)->m_pDataAvail->IsLinearizedPDF();
 }
diff --git a/fpdfsdk/fpdf_dataavail_embeddertest.cpp b/fpdfsdk/fpdf_dataavail_embeddertest.cpp
index c226a31..2084153 100644
--- a/fpdfsdk/fpdf_dataavail_embeddertest.cpp
+++ b/fpdfsdk/fpdf_dataavail_embeddertest.cpp
@@ -12,10 +12,25 @@
 #include "public/fpdfview.h"
 #include "testing/embedder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "testing/range_set.h"
 #include "testing/test_support.h"
 #include "testing/utils/path_service.h"
 
 namespace {
+
+class MockDownloadHints : public FX_DOWNLOADHINTS {
+ public:
+  static void SAddSegment(FX_DOWNLOADHINTS* pThis, size_t offset, size_t size) {
+  }
+
+  MockDownloadHints() {
+    FX_DOWNLOADHINTS::version = 1;
+    FX_DOWNLOADHINTS::AddSegment = SAddSegment;
+  }
+
+  ~MockDownloadHints() {}
+};
+
 class TestAsyncLoader : public FX_DOWNLOADHINTS, FX_FILEAVAIL {
  public:
   explicit TestAsyncLoader(const std::string& file_name) {
@@ -60,50 +75,25 @@
   }
 
   size_t max_already_available_bound() const {
-    return available_ranges_.empty() ? 0 : available_ranges_.rbegin()->second;
+    return available_ranges_.IsEmpty()
+               ? 0
+               : available_ranges_.ranges().rbegin()->second;
+  }
+
+  void FlushRequestedData() {
+    for (const auto& it : requested_segments_) {
+      SetDataAvailable(it.first, it.second);
+    }
+    ClearRequestedSegments();
   }
 
  private:
   void SetDataAvailable(size_t start, size_t size) {
-    if (size == 0)
-      return;
-    const auto range = std::make_pair(start, start + size);
-    if (available_ranges_.empty()) {
-      available_ranges_.insert(range);
-      return;
-    }
-    auto start_it = available_ranges_.upper_bound(range);
-    if (start_it != available_ranges_.begin())
-      --start_it;  // start now points to the key equal or lower than offset.
-    if (start_it->second < range.first)
-      ++start_it;  // start element is entirely before current range, skip it.
-
-    auto end_it = available_ranges_.upper_bound(
-        std::make_pair(range.second, range.second));
-    if (start_it == end_it) {  // No ranges to merge.
-      available_ranges_.insert(range);
-      return;
-    }
-
-    --end_it;
-
-    size_t new_start = std::min<size_t>(start_it->first, range.first);
-    size_t new_end = std::max(end_it->second, range.second);
-
-    available_ranges_.erase(start_it, ++end_it);
-    available_ranges_.insert(std::make_pair(new_start, new_end));
+    available_ranges_.Union(RangeSet::Range(start, start + size));
   }
 
   bool CheckDataAlreadyAvailable(size_t start, size_t size) const {
-    if (size == 0)
-      return false;
-    const auto range = std::make_pair(start, start + size);
-    auto it = available_ranges_.upper_bound(range);
-    if (it == available_ranges_.begin())
-      return false;  // No ranges includes range.start().
-
-    --it;  // Now it starts equal or before range.start().
-    return it->second >= range.second;
+    return available_ranges_.Contains(RangeSet::Range(start, start + size));
   }
 
   int GetBlockImpl(unsigned long pos, unsigned char* pBuf, unsigned long size) {
@@ -158,14 +148,7 @@
   size_t max_requested_bound_ = 0;
   bool is_new_data_available_ = true;
 
-  using Range = std::pair<size_t, size_t>;
-  struct range_compare {
-    bool operator()(const Range& lval, const Range& rval) const {
-      return lval.first < rval.first;
-    }
-  };
-  using RangesContainer = std::set<Range, range_compare>;
-  RangesContainer available_ranges_;
+  RangeSet available_ranges_;
 };
 
 }  // namespace
@@ -175,13 +158,15 @@
 TEST_F(FPDFDataAvailEmbeddertest, TrailerUnterminated) {
   // Document must load without crashing but is too malformed to be available.
   EXPECT_FALSE(OpenDocument("trailer_unterminated.pdf"));
-  EXPECT_FALSE(FPDFAvail_IsDocAvail(avail_, &hints_));
+  MockDownloadHints hints;
+  EXPECT_FALSE(FPDFAvail_IsDocAvail(avail_, &hints));
 }
 
 TEST_F(FPDFDataAvailEmbeddertest, TrailerAsHexstring) {
   // Document must load without crashing but is too malformed to be available.
   EXPECT_FALSE(OpenDocument("trailer_as_hexstring.pdf"));
-  EXPECT_FALSE(FPDFAvail_IsDocAvail(avail_, &hints_));
+  MockDownloadHints hints;
+  EXPECT_FALSE(FPDFAvail_IsDocAvail(avail_, &hints));
 }
 
 TEST_F(FPDFDataAvailEmbeddertest, LoadUsingHintTables) {
@@ -194,9 +179,29 @@
 
   // No new data available, to prevent load "Pages" node.
   loader.set_is_new_data_available(false);
-  FPDF_PAGE page = LoadPage(1);
+  FPDF_PAGE page = FPDF_LoadPage(document(), 1);
   EXPECT_TRUE(page);
-  UnloadPage(page);
+  FPDF_ClosePage(page);
+}
+
+TEST_F(FPDFDataAvailEmbeddertest, CheckFormAvailIfLinearized) {
+  TestAsyncLoader loader("feature_linearized_loading.pdf");
+  avail_ = FPDFAvail_Create(loader.file_avail(), loader.file_access());
+  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsDocAvail(avail_, loader.hints()));
+  document_ = FPDFAvail_GetDocument(avail_, nullptr);
+  ASSERT_TRUE(document_);
+
+  // Prevent access to non requested data to coerce the parser to send new
+  // request for non available (non requested before) data.
+  loader.set_is_new_data_available(false);
+  loader.ClearRequestedSegments();
+
+  int status = PDF_FORM_NOTAVAIL;
+  while (status == PDF_FORM_NOTAVAIL) {
+    loader.FlushRequestedData();
+    status = FPDFAvail_IsFormAvail(avail_, loader.hints());
+  }
+  EXPECT_NE(PDF_FORM_ERROR, status);
 }
 
 TEST_F(FPDFDataAvailEmbeddertest,
@@ -234,7 +239,35 @@
 
   // Prevent loading data, while page loading.
   loader.set_is_new_data_available(false);
-  FPDF_PAGE page = LoadPage(first_page_num);
+  FPDF_PAGE page = FPDF_LoadPage(document(), first_page_num);
   EXPECT_TRUE(page);
-  UnloadPage(page);
+  FPDF_ClosePage(page);
+}
+
+TEST_F(FPDFDataAvailEmbeddertest, LoadSecondPageIfLinearizedWithHints) {
+  TestAsyncLoader loader("feature_linearized_loading.pdf");
+  avail_ = FPDFAvail_Create(loader.file_avail(), loader.file_access());
+  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsDocAvail(avail_, loader.hints()));
+  document_ = FPDFAvail_GetDocument(avail_, nullptr);
+  ASSERT_TRUE(document_);
+
+  static constexpr uint32_t kSecondPageNum = 1;
+
+  // Prevent access to non requested data to coerce the parser to send new
+  // request for non available (non requested before) data.
+  loader.set_is_new_data_available(false);
+  loader.ClearRequestedSegments();
+
+  int status = PDF_DATA_NOTAVAIL;
+  while (status == PDF_DATA_NOTAVAIL) {
+    loader.FlushRequestedData();
+    status = FPDFAvail_IsPageAvail(avail_, kSecondPageNum, loader.hints());
+  }
+  EXPECT_EQ(PDF_DATA_AVAIL, status);
+
+  // Prevent loading data, while page loading.
+  loader.set_is_new_data_available(false);
+  FPDF_PAGE page = FPDF_LoadPage(document(), kSecondPageNum);
+  EXPECT_TRUE(page);
+  FPDF_ClosePage(page);
 }
diff --git a/fpdfsdk/fpdf_ext.cpp b/fpdfsdk/fpdf_ext.cpp
index 3bcb0c0..87605cf 100644
--- a/fpdfsdk/fpdf_ext.cpp
+++ b/fpdfsdk/fpdf_ext.cpp
@@ -14,9 +14,9 @@
 #include "core/fpdfdoc/cpdf_annot.h"
 #include "core/fpdfdoc/cpdf_interform.h"
 #include "core/fpdfdoc/cpdf_metadata.h"
-#include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_memory.h"
-#include "core/fxcrt/fx_xml.h"
+#include "core/fxcrt/xml/cxml_content.h"
+#include "core/fxcrt/xml/cxml_element.h"
 #include "fpdfsdk/fsdk_define.h"
 #include "third_party/base/ptr_util.h"
 
@@ -36,7 +36,7 @@
   return true;
 }
 
-DLLEXPORT FPDF_BOOL STDCALL
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
 FSDK_SetUnSpObjProcessHandler(UNSUPPORT_INFO* unsp_info) {
   if (!unsp_info || unsp_info->version != 1)
     return false;
@@ -52,7 +52,7 @@
     FPDF_UnSupportError(FPDF_UNSP_ANNOT_3DANNOT);
   } else if (nAnnotSubtype == CPDF_Annot::Subtype::SCREEN) {
     const CPDF_Dictionary* pAnnotDict = pPDFAnnot->GetAnnotDict();
-    CFX_ByteString cbString;
+    ByteString cbString;
     if (pAnnotDict->KeyExist("IT"))
       cbString = pAnnotDict->GetStringFor("IT");
     if (cbString.Compare("Img") != 0)
@@ -67,7 +67,7 @@
     FPDF_UnSupportError(FPDF_UNSP_ANNOT_ATTACHMENT);
   } else if (nAnnotSubtype == CPDF_Annot::Subtype::WIDGET) {
     const CPDF_Dictionary* pAnnotDict = pPDFAnnot->GetAnnotDict();
-    CFX_ByteString cbString;
+    ByteString cbString;
     if (pAnnotDict->KeyExist("FT"))
       cbString = pAnnotDict->GetStringFor("FT");
     if (cbString.Compare("Sig") == 0)
@@ -75,22 +75,23 @@
   }
 }
 
-bool CheckSharedForm(const CXML_Element* pElement, CFX_ByteString cbName) {
-  int count = pElement->CountAttrs();
-  int i = 0;
-  for (i = 0; i < count; i++) {
-    CFX_ByteString space, name;
-    CFX_WideString value;
-    pElement->GetAttrByIndex(i, space, name, value);
+bool CheckSharedForm(const CXML_Element* pElement, ByteString cbName) {
+  size_t count = pElement->CountAttrs();
+  for (size_t i = 0; i < count; ++i) {
+    ByteString space;
+    ByteString name;
+    WideString value;
+    pElement->GetAttrByIndex(i, &space, &name, &value);
     if (space == "xmlns" && name == "adhocwf" &&
         value == L"http://ns.adobe.com/AcrobatAdhocWorkflow/1.0/") {
       CXML_Element* pVersion =
-          pElement->GetElement("adhocwf", cbName.AsStringC());
+          pElement->GetElement("adhocwf", cbName.AsStringView(), 0);
       if (!pVersion)
         continue;
-      CFX_WideString wsContent = pVersion->GetContent(0);
-      int nType = wsContent.GetInteger();
-      switch (nType) {
+      CXML_Content* pContent = ToContent(pVersion->GetChild(0));
+      if (!pContent)
+        continue;
+      switch (pContent->m_Content.GetInteger()) {
         case 1:
           FPDF_UnSupportError(FPDF_UNSP_DOC_SHAREDFORM_ACROBAT);
           break;
@@ -104,14 +105,11 @@
     }
   }
 
-  uint32_t nCount = pElement->CountChildren();
-  for (i = 0; i < (int)nCount; i++) {
-    CXML_Element::ChildType childType = pElement->GetChildType(i);
-    if (childType == CXML_Element::Element) {
-      CXML_Element* pChild = pElement->GetElement(i);
-      if (CheckSharedForm(pChild, cbName))
-        return true;
-    }
+  size_t nCount = pElement->CountChildren();
+  for (size_t i = 0; i < nCount; ++i) {
+    CXML_Element* pChild = ToElement(pElement->GetChild(i));
+    if (pChild && CheckSharedForm(pChild, cbName))
+      return true;
   }
   return false;
 }
@@ -126,9 +124,9 @@
     return;
 
   // Portfolios and Packages
-  CPDF_Dictionary* pRootDict = pDoc->GetRoot();
+  const CPDF_Dictionary* pRootDict = pDoc->GetRoot();
   if (pRootDict) {
-    CFX_ByteString cbString;
+    ByteString cbString;
     if (pRootDict->KeyExist("Collection")) {
       FPDF_UnSupportError(FPDF_UNSP_DOC_PORTABLECOLLECTION);
       return;
@@ -144,7 +142,7 @@
         CPDF_Array* pArray = pJSDict ? pJSDict->GetArrayFor("Names") : nullptr;
         if (pArray) {
           for (size_t i = 0; i < pArray->GetCount(); i++) {
-            CFX_ByteString cbStr = pArray->GetStringAt(i);
+            ByteString cbStr = pArray->GetStringAt(i);
             if (cbStr.Compare("com.adobe.acrobat.SharedReview.Register") == 0) {
               FPDF_UnSupportError(FPDF_UNSP_DOC_SHAREDREVIEW);
               return;
@@ -169,12 +167,12 @@
 #endif  // PDF_ENABLE_XFA
 }
 
-DLLEXPORT int STDCALL FPDFDoc_GetPageMode(FPDF_DOCUMENT document) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetPageMode(FPDF_DOCUMENT document) {
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
   if (!pDoc)
     return PAGEMODE_UNKNOWN;
 
-  CPDF_Dictionary* pRoot = pDoc->GetRoot();
+  const CPDF_Dictionary* pRoot = pDoc->GetRoot();
   if (!pRoot)
     return PAGEMODE_UNKNOWN;
 
@@ -182,7 +180,7 @@
   if (!pName)
     return PAGEMODE_USENONE;
 
-  CFX_ByteString strPageMode = pName->GetString();
+  ByteString strPageMode = pName->GetString();
   if (strPageMode.IsEmpty() || strPageMode.EqualNoCase("UseNone"))
     return PAGEMODE_USENONE;
   if (strPageMode.EqualNoCase("UseOutlines"))
diff --git a/fpdfsdk/fpdf_flatten.cpp b/fpdfsdk/fpdf_flatten.cpp
index e649bac..4d06693 100644
--- a/fpdfsdk/fpdf_flatten.cpp
+++ b/fpdfsdk/fpdf_flatten.cpp
@@ -29,29 +29,25 @@
 
 namespace {
 
-bool IsValiableRect(CFX_FloatRect rect, CFX_FloatRect rcPage) {
-  if (rect.left - rect.right > 0.000001f || rect.bottom - rect.top > 0.000001f)
+bool IsValidRect(const CFX_FloatRect& rect, const CFX_FloatRect& rcPage) {
+  constexpr float kMinSize = 0.000001f;
+  if (rect.IsEmpty() || rect.Width() < kMinSize || rect.Height() < kMinSize)
     return false;
 
-  if (rect.left == 0.0f && rect.top == 0.0f && rect.right == 0.0f &&
-      rect.bottom == 0.0f)
-    return false;
+  if (rcPage.IsEmpty())
+    return true;
 
-  if (!rcPage.IsEmpty()) {
-    if (rect.left - rcPage.left < -10.000001f ||
-        rect.right - rcPage.right > 10.000001f ||
-        rect.top - rcPage.top > 10.000001f ||
-        rect.bottom - rcPage.bottom < -10.000001f)
-      return false;
-  }
-
-  return true;
+  constexpr float kMinBorderSize = 10.000001f;
+  return rect.left - rcPage.left >= -kMinBorderSize &&
+         rect.right - rcPage.right <= kMinBorderSize &&
+         rect.top - rcPage.top <= kMinBorderSize &&
+         rect.bottom - rcPage.bottom >= -kMinBorderSize;
 }
 
 void GetContentsRect(CPDF_Document* pDoc,
                      CPDF_Dictionary* pDict,
                      std::vector<CFX_FloatRect>* pRectArray) {
-  std::unique_ptr<CPDF_Page> pPDFPage(new CPDF_Page(pDoc, pDict, false));
+  auto pPDFPage = pdfium::MakeUnique<CPDF_Page>(pDoc, pDict, false);
   pPDFPage->ParseContent();
 
   for (const auto& pPageObject : *pPDFPage->GetPageObjectList()) {
@@ -60,7 +56,7 @@
     rc.right = pPageObject->m_Right;
     rc.bottom = pPageObject->m_Bottom;
     rc.top = pPageObject->m_Top;
-    if (IsValiableRect(rc, pDict->GetRectFor("MediaBox")))
+    if (IsValidRect(rc, pDict->GetRectFor("MediaBox")))
       pRectArray->push_back(rc);
   }
 }
@@ -77,7 +73,7 @@
   else if (pStream->KeyExist("BBox"))
     rect = pStream->GetRectFor("BBox");
 
-  if (IsValiableRect(rect, pPageDic->GetRectFor("MediaBox")))
+  if (IsValidRect(rect, pPageDic->GetRectFor("MediaBox")))
     pRectArray->push_back(rect);
 
   pObjectArray->push_back(pStream);
@@ -96,13 +92,12 @@
   if (!pAnnots)
     return FLATTEN_NOTHINGTODO;
 
-  uint32_t dwSize = pAnnots->GetCount();
-  for (int i = 0; i < (int)dwSize; i++) {
-    CPDF_Dictionary* pAnnotDic = ToDictionary(pAnnots->GetDirectObjectAt(i));
+  for (const auto& pAnnot : *pAnnots) {
+    CPDF_Dictionary* pAnnotDic = ToDictionary(pAnnot->GetDirect());
     if (!pAnnotDic)
       continue;
 
-    CFX_ByteString sSubtype = pAnnotDic->GetStringFor("Subtype");
+    ByteString sSubtype = pAnnotDic->GetStringFor("Subtype");
     if (sSubtype == "Popup")
       continue;
 
@@ -110,27 +105,25 @@
     if (nAnnotFlag & ANNOTFLAG_HIDDEN)
       continue;
 
-    if (nUsage == FLAT_NORMALDISPLAY) {
-      if (nAnnotFlag & ANNOTFLAG_INVISIBLE)
-        continue;
-
+    bool bParseStream;
+    if (nUsage == FLAT_NORMALDISPLAY)
+      bParseStream = !(nAnnotFlag & ANNOTFLAG_INVISIBLE);
+    else
+      bParseStream = !!(nAnnotFlag & ANNOTFLAG_PRINT);
+    if (bParseStream)
       ParserStream(pPageDic, pAnnotDic, pRectArray, pObjectArray);
-    } else {
-      if (nAnnotFlag & ANNOTFLAG_PRINT)
-        ParserStream(pPageDic, pAnnotDic, pRectArray, pObjectArray);
-    }
   }
   return FLATTEN_SUCCESS;
 }
 
-FX_FLOAT GetMinMaxValue(const std::vector<CFX_FloatRect>& array,
-                        FPDF_TYPE type,
-                        FPDF_VALUE value) {
-  size_t nRects = array.size();
-  if (nRects <= 0)
+float GetMinMaxValue(const std::vector<CFX_FloatRect>& array,
+                     FPDF_TYPE type,
+                     FPDF_VALUE value) {
+  if (array.empty())
     return 0.0f;
 
-  std::vector<FX_FLOAT> pArray(nRects);
+  size_t nRects = array.size();
+  std::vector<float> pArray(nRects);
   switch (value) {
     case LEFT:
       for (size_t i = 0; i < nRects; i++)
@@ -149,11 +142,11 @@
         pArray[i] = array[i].bottom;
       break;
     default:
-      // Not reachable.
+      NOTREACHED();
       return 0.0f;
   }
 
-  FX_FLOAT fRet = pArray[0];
+  float fRet = pArray[0];
   if (type == MAX) {
     for (size_t i = 1; i < nRects; i++)
       fRet = std::max(fRet, pArray[i]);
@@ -175,18 +168,18 @@
   return rcRet;
 }
 
-uint32_t NewIndirectContentsStream(const CFX_ByteString& key,
+uint32_t NewIndirectContentsStream(const ByteString& key,
                                    CPDF_Document* pDocument) {
   CPDF_Stream* pNewContents = pDocument->NewIndirect<CPDF_Stream>(
       nullptr, 0,
       pdfium::MakeUnique<CPDF_Dictionary>(pDocument->GetByteStringPool()));
-  CFX_ByteString sStream;
-  sStream.Format("q 1 0 0 1 0 0 cm /%s Do Q", key.c_str());
+  ByteString sStream =
+      ByteString::Format("q 1 0 0 1 0 0 cm /%s Do Q", key.c_str());
   pNewContents->SetData(sStream.raw_str(), sStream.GetLength());
   return pNewContents->GetObjNum();
 }
 
-void SetPageContents(const CFX_ByteString& key,
+void SetPageContents(const ByteString& key,
                      CPDF_Dictionary* pPage,
                      CPDF_Document* pDocument) {
   CPDF_Array* pContentsArray = nullptr;
@@ -204,13 +197,13 @@
   pPage->ConvertToIndirectObjectFor("Contents", pDocument);
   if (!pContentsArray) {
     pContentsArray = pDocument->NewIndirect<CPDF_Array>();
-    CPDF_StreamAcc acc;
-    acc.LoadAllData(pContentsStream);
-    CFX_ByteString sStream = "q\n";
-    CFX_ByteString sBody =
-        CFX_ByteString((const FX_CHAR*)acc.GetData(), acc.GetSize());
+    auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pContentsStream);
+    pAcc->LoadAllDataFiltered();
+    ByteString sStream = "q\n";
+    ByteString sBody = ByteString(pAcc->GetData(), pAcc->GetSize());
     sStream = sStream + sBody + "\nQ";
-    pContentsStream->SetData(sStream.raw_str(), sStream.GetLength());
+    pContentsStream->SetDataAndRemoveFilter(sStream.raw_str(),
+                                            sStream.GetLength());
     pContentsArray->AddNew<CPDF_Reference>(pDocument,
                                            pContentsStream->GetObjNum());
     pPage->SetNewFor<CPDF_Reference>("Contents", pDocument,
@@ -228,26 +221,26 @@
   if (rcStream.IsEmpty())
     return CFX_Matrix();
 
-  matrix.TransformRect(rcStream);
+  rcStream = matrix.TransformRect(rcStream);
   rcStream.Normalize();
 
-  FX_FLOAT a = rcAnnot.Width() / rcStream.Width();
-  FX_FLOAT d = rcAnnot.Height() / rcStream.Height();
+  float a = rcAnnot.Width() / rcStream.Width();
+  float d = rcAnnot.Height() / rcStream.Height();
 
-  FX_FLOAT e = rcAnnot.left - rcStream.left * a;
-  FX_FLOAT f = rcAnnot.bottom - rcStream.bottom * d;
+  float e = rcAnnot.left - rcStream.left * a;
+  float f = rcAnnot.bottom - rcStream.bottom * d;
   return CFX_Matrix(a, 0, 0, d, e, f);
 }
 
 }  // namespace
 
-DLLEXPORT int STDCALL FPDFPage_Flatten(FPDF_PAGE page, int nFlag) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFPage_Flatten(FPDF_PAGE page, int nFlag) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!page)
     return FLATTEN_FAIL;
 
-  CPDF_Document* pDocument = pPage->m_pDocument;
-  CPDF_Dictionary* pPageDict = pPage->m_pFormDict;
+  CPDF_Document* pDocument = pPage->m_pDocument.Get();
+  CPDF_Dictionary* pPageDict = pPage->m_pFormDict.Get();
   if (!pDocument || !pPageDict)
     return FLATTEN_FAIL;
 
@@ -305,15 +298,16 @@
   if (!pPageXObject)
     pPageXObject = pRes->SetNewFor<CPDF_Dictionary>("XObject");
 
-  CFX_ByteString key = "";
-  int nStreams = pdfium::CollectionSize<int>(ObjectArray);
-  if (nStreams > 0) {
-    for (int iKey = 0; /*iKey < 100*/; iKey++) {
-      char sExtend[5] = {};
-      FXSYS_itoa(iKey, sExtend, 10);
-      key = CFX_ByteString("FFT") + CFX_ByteString(sExtend);
-      if (!pPageXObject->KeyExist(key))
+  ByteString key;
+  if (!ObjectArray.empty()) {
+    int i = 0;
+    while (i < INT_MAX) {
+      ByteString sKey = ByteString::Format("FFT%d", i);
+      if (!pPageXObject->KeyExist(sKey)) {
+        key = sKey;
         break;
+      }
+      ++i;
     }
   }
 
@@ -327,12 +321,11 @@
     pNewOXbjectDic->SetNewFor<CPDF_Name>("Type", "XObject");
     pNewOXbjectDic->SetNewFor<CPDF_Name>("Subtype", "Form");
     pNewOXbjectDic->SetNewFor<CPDF_Number>("FormType", 1);
-    pNewOXbjectDic->SetNewFor<CPDF_Name>("Name", "FRM");
     CFX_FloatRect rcBBox = pPageDict->GetRectFor("ArtBox");
     pNewOXbjectDic->SetRectFor("BBox", rcBBox);
   }
 
-  for (int i = 0; i < nStreams; i++) {
+  for (size_t i = 0; i < ObjectArray.size(); ++i) {
     CPDF_Dictionary* pAnnotDic = ObjectArray[i];
     if (!pAnnotDic)
       continue;
@@ -340,7 +333,7 @@
     CFX_FloatRect rcAnnot = pAnnotDic->GetRectFor("Rect");
     rcAnnot.Normalize();
 
-    CFX_ByteString sAnnotState = pAnnotDic->GetStringFor("AS");
+    ByteString sAnnotState = pAnnotDic->GetStringFor("AS");
     CPDF_Dictionary* pAnnotAP = pAnnotDic->GetDictFor("AP");
     if (!pAnnotAP)
       continue;
@@ -354,9 +347,8 @@
       if (!sAnnotState.IsEmpty()) {
         pAPStream = pAPDic->GetStreamFor(sAnnotState);
       } else {
-        auto it = pAPDic->begin();
-        if (it != pAPDic->end()) {
-          CPDF_Object* pFirstObj = it->second.get();
+        if (pAPDic->GetCount() > 0) {
+          CPDF_Object* pFirstObj = pAPDic->begin()->second.get();
           if (pFirstObj) {
             if (pFirstObj->IsReference())
               pFirstObj = pFirstObj->GetDirect();
@@ -397,32 +389,18 @@
     if (!pXObject)
       pXObject = pNewXORes->SetNewFor<CPDF_Dictionary>("XObject");
 
-    CFX_ByteString sFormName;
-    sFormName.Format("F%d", i);
+    ByteString sFormName = ByteString::Format("F%d", i);
     pXObject->SetNewFor<CPDF_Reference>(sFormName, pDocument,
                                         pObj->GetObjNum());
 
-    CPDF_StreamAcc acc;
-    acc.LoadAllData(pNewXObject);
-
-    const uint8_t* pData = acc.GetData();
-    CFX_ByteString sStream(pData, acc.GetSize());
+    auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pNewXObject);
+    pAcc->LoadAllDataFiltered();
+    ByteString sStream(pAcc->GetData(), pAcc->GetSize());
     CFX_Matrix matrix = pAPDic->GetMatrixFor("Matrix");
-    if (matrix.IsIdentity()) {
-      matrix.a = 1.0f;
-      matrix.b = 0.0f;
-      matrix.c = 0.0f;
-      matrix.d = 1.0f;
-      matrix.e = 0.0f;
-      matrix.f = 0.0f;
-    }
-
-    CFX_ByteString sTemp;
     CFX_Matrix m = GetMatrix(rcAnnot, rcStream, matrix);
-    sTemp.Format("q %f 0 0 %f %f %f cm /%s Do Q\n", m.a, m.d, m.e, m.f,
-                 sFormName.c_str());
-    sStream += sTemp;
-    pNewXObject->SetData(sStream.raw_str(), sStream.GetLength());
+    sStream += ByteString::Format("q %f 0 0 %f %f %f cm /%s Do Q\n", m.a, m.d,
+                                  m.e, m.f, sFormName.c_str());
+    pNewXObject->SetDataAndRemoveFilter(sStream.raw_str(), sStream.GetLength());
   }
   pPageDict->RemoveFor("Annots");
   return FLATTEN_SUCCESS;
diff --git a/fpdfsdk/fpdf_flatten_embeddertest.cpp b/fpdfsdk/fpdf_flatten_embeddertest.cpp
index d709f59..a8915fe 100644
--- a/fpdfsdk/fpdf_flatten_embeddertest.cpp
+++ b/fpdfsdk/fpdf_flatten_embeddertest.cpp
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/fxcrt/fx_basic.h"
 #include "public/fpdf_flatten.h"
 #include "public/fpdfview.h"
 #include "testing/embedder_test.h"
diff --git a/fpdfsdk/fpdf_progressive.cpp b/fpdfsdk/fpdf_progressive.cpp
index cc09d07..730ba48 100644
--- a/fpdfsdk/fpdf_progressive.cpp
+++ b/fpdfsdk/fpdf_progressive.cpp
@@ -6,11 +6,13 @@
 
 #include "public/fpdf_progressive.h"
 
+#include <utility>
+
 #include "core/fpdfapi/cpdf_pagerendercontext.h"
 #include "core/fpdfapi/page/cpdf_page.h"
 #include "core/fpdfapi/render/cpdf_progressiverenderer.h"
 #include "core/fxcrt/fx_memory.h"
-#include "core/fxge/cfx_fxgedevice.h"
+#include "core/fxge/cfx_defaultrenderdevice.h"
 #include "core/fxge/cfx_renderdevice.h"
 #include "fpdfsdk/fsdk_define.h"
 #include "fpdfsdk/fsdk_pauseadapter.h"
@@ -18,25 +20,25 @@
 #include "third_party/base/ptr_util.h"
 
 // These checks are here because core/ and public/ cannot depend on each other.
-static_assert(CPDF_ProgressiveRenderer::Ready == FPDF_RENDER_READER,
+static_assert(CPDF_ProgressiveRenderer::Ready == FPDF_RENDER_READY,
               "CPDF_ProgressiveRenderer::Ready value mismatch");
 static_assert(CPDF_ProgressiveRenderer::ToBeContinued ==
-                  FPDF_RENDER_TOBECOUNTINUED,
+                  FPDF_RENDER_TOBECONTINUED,
               "CPDF_ProgressiveRenderer::ToBeContinued value mismatch");
 static_assert(CPDF_ProgressiveRenderer::Done == FPDF_RENDER_DONE,
               "CPDF_ProgressiveRenderer::Done value mismatch");
 static_assert(CPDF_ProgressiveRenderer::Failed == FPDF_RENDER_FAILED,
               "CPDF_ProgressiveRenderer::Failed value mismatch");
 
-DLLEXPORT int STDCALL FPDF_RenderPageBitmap_Start(FPDF_BITMAP bitmap,
-                                                  FPDF_PAGE page,
-                                                  int start_x,
-                                                  int start_y,
-                                                  int size_x,
-                                                  int size_y,
-                                                  int rotate,
-                                                  int flags,
-                                                  IFSDK_PAUSE* pause) {
+FPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPageBitmap_Start(FPDF_BITMAP bitmap,
+                                                          FPDF_PAGE page,
+                                                          int start_x,
+                                                          int start_y,
+                                                          int size_x,
+                                                          int size_y,
+                                                          int rotate,
+                                                          int flags,
+                                                          IFSDK_PAUSE* pause) {
   if (!bitmap || !pause || pause->version != 1)
     return FPDF_RENDER_FAILED;
 
@@ -44,17 +46,24 @@
   if (!pPage)
     return FPDF_RENDER_FAILED;
 
-  CPDF_PageRenderContext* pContext = new CPDF_PageRenderContext;
-  pPage->SetRenderContext(pdfium::WrapUnique(pContext));
-  CFX_FxgeDevice* pDevice = new CFX_FxgeDevice;
-  pContext->m_pDevice.reset(pDevice);
-  CFX_DIBitmap* pBitmap = CFXBitmapFromFPDFBitmap(bitmap);
+  auto pOwnedContext = pdfium::MakeUnique<CPDF_PageRenderContext>();
+  CPDF_PageRenderContext* pContext = pOwnedContext.get();
+  pPage->SetRenderContext(std::move(pOwnedContext));
+
+  RetainPtr<CFX_DIBitmap> pBitmap(CFXBitmapFromFPDFBitmap(bitmap));
+  auto pOwnedDevice = pdfium::MakeUnique<CFX_DefaultRenderDevice>();
+  CFX_DefaultRenderDevice* pDevice = pOwnedDevice.get();
+  pContext->m_pDevice = std::move(pOwnedDevice);
   pDevice->Attach(pBitmap, !!(flags & FPDF_REVERSE_BYTE_ORDER), nullptr, false);
 
   IFSDK_PAUSE_Adapter IPauseAdapter(pause);
   FPDF_RenderPage_Retail(pContext, page, start_x, start_y, size_x, size_y,
                          rotate, flags, false, &IPauseAdapter);
 
+#ifdef _SKIA_SUPPORT_PATHS_
+  pDevice->Flush(false);
+  pBitmap->UnPreMultiply();
+#endif
   if (pContext->m_pRenderer) {
     return CPDF_ProgressiveRenderer::ToFPDFStatus(
         pContext->m_pRenderer->GetStatus());
@@ -62,8 +71,8 @@
   return FPDF_RENDER_FAILED;
 }
 
-DLLEXPORT int STDCALL FPDF_RenderPage_Continue(FPDF_PAGE page,
-                                               IFSDK_PAUSE* pause) {
+FPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPage_Continue(FPDF_PAGE page,
+                                                       IFSDK_PAUSE* pause) {
   if (!pause || pause->version != 1)
     return FPDF_RENDER_FAILED;
 
@@ -75,21 +84,28 @@
   if (pContext && pContext->m_pRenderer) {
     IFSDK_PAUSE_Adapter IPauseAdapter(pause);
     pContext->m_pRenderer->Continue(&IPauseAdapter);
+#ifdef _SKIA_SUPPORT_PATHS_
+    CFX_RenderDevice* pDevice = pContext->m_pDevice.get();
+    pDevice->Flush(false);
+    pDevice->GetBitmap()->UnPreMultiply();
+#endif
     return CPDF_ProgressiveRenderer::ToFPDFStatus(
         pContext->m_pRenderer->GetStatus());
   }
   return FPDF_RENDER_FAILED;
 }
 
-DLLEXPORT void STDCALL FPDF_RenderPage_Close(FPDF_PAGE page) {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPage_Close(FPDF_PAGE page) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
-  if (!pPage)
-    return;
-
-  CPDF_PageRenderContext* pContext = pPage->GetRenderContext();
-  if (!pContext)
-    return;
-
-  pContext->m_pDevice->RestoreState(false);
-  pPage->SetRenderContext(nullptr);
+  if (pPage) {
+#ifdef _SKIA_SUPPORT_PATHS_
+    CPDF_PageRenderContext* pContext = pPage->GetRenderContext();
+    if (pContext && pContext->m_pRenderer) {
+      CFX_RenderDevice* pDevice = pContext->m_pDevice.get();
+      pDevice->Flush(true);
+      pDevice->GetBitmap()->UnPreMultiply();
+    }
+#endif
+    pPage->SetRenderContext(nullptr);
+  }
 }
diff --git a/fpdfsdk/fpdf_searchex.cpp b/fpdfsdk/fpdf_searchex.cpp
index f82db37..9d48ceb 100644
--- a/fpdfsdk/fpdf_searchex.cpp
+++ b/fpdfsdk/fpdf_searchex.cpp
@@ -8,10 +8,18 @@
 
 #include "core/fpdftext/cpdf_textpage.h"
 
-DLLEXPORT int STDCALL
+FPDF_EXPORT int FPDF_CALLCONV
 FPDFText_GetCharIndexFromTextIndex(FPDF_TEXTPAGE text_page, int nTextIndex) {
   if (!text_page)
     return -1;
   return static_cast<CPDF_TextPage*>(text_page)
       ->CharIndexFromTextIndex(nTextIndex);
 }
+
+FPDF_EXPORT int FPDF_CALLCONV
+FPDFText_GetTextIndexFromCharIndex(FPDF_TEXTPAGE text_page, int nCharIndex) {
+  if (!text_page)
+    return -1;
+  return static_cast<CPDF_TextPage*>(text_page)->TextIndexFromCharIndex(
+      nCharIndex);
+}
diff --git a/fpdfsdk/fpdf_structtree.cpp b/fpdfsdk/fpdf_structtree.cpp
index 5a922a1..676824e 100644
--- a/fpdfsdk/fpdf_structtree.cpp
+++ b/fpdfsdk/fpdf_structtree.cpp
@@ -8,82 +8,124 @@
 
 #include "core/fpdfapi/page/cpdf_page.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
-#include "core/fpdfdoc/fpdf_tagged.h"
+#include "core/fpdfdoc/cpdf_structelement.h"
+#include "core/fpdfdoc/cpdf_structtree.h"
 #include "fpdfsdk/fsdk_define.h"
 
 namespace {
 
-IPDF_StructTree* ToStructTree(FPDF_STRUCTTREE struct_tree) {
-  return reinterpret_cast<IPDF_StructTree*>(struct_tree);
+CPDF_StructTree* ToStructTree(FPDF_STRUCTTREE struct_tree) {
+  return static_cast<CPDF_StructTree*>(struct_tree);
 }
 
-IPDF_StructElement* ToStructTreeElement(FPDF_STRUCTELEMENT struct_element) {
-  return reinterpret_cast<IPDF_StructElement*>(struct_element);
+CPDF_StructElement* ToStructTreeElement(FPDF_STRUCTELEMENT struct_element) {
+  return static_cast<CPDF_StructElement*>(struct_element);
+}
+
+unsigned long WideStringToBuffer(const WideString& str,
+                                 void* buffer,
+                                 unsigned long buflen) {
+  if (str.IsEmpty())
+    return 0;
+
+  ByteString encodedStr = str.UTF16LE_Encode();
+  const unsigned long len = encodedStr.GetLength();
+  if (buffer && len <= buflen)
+    memcpy(buffer, encodedStr.c_str(), len);
+  return len;
 }
 
 }  // namespace
 
-DLLEXPORT FPDF_STRUCTTREE STDCALL FPDF_StructTree_GetForPage(FPDF_PAGE page) {
+FPDF_EXPORT FPDF_STRUCTTREE FPDF_CALLCONV
+FPDF_StructTree_GetForPage(FPDF_PAGE page) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!pPage)
     return nullptr;
-  return IPDF_StructTree::LoadPage(pPage->m_pDocument, pPage->m_pFormDict)
+  return CPDF_StructTree::LoadPage(pPage->m_pDocument.Get(),
+                                   pPage->m_pFormDict.Get())
       .release();
 }
 
-DLLEXPORT void STDCALL FPDF_StructTree_Close(FPDF_STRUCTTREE struct_tree) {
-  std::unique_ptr<IPDF_StructTree>(ToStructTree(struct_tree));
+FPDF_EXPORT void FPDF_CALLCONV
+FPDF_StructTree_Close(FPDF_STRUCTTREE struct_tree) {
+  std::unique_ptr<CPDF_StructTree>(ToStructTree(struct_tree));
 }
 
-DLLEXPORT int STDCALL
+FPDF_EXPORT int FPDF_CALLCONV
 FPDF_StructTree_CountChildren(FPDF_STRUCTTREE struct_tree) {
-  IPDF_StructTree* tree = ToStructTree(struct_tree);
-  return tree ? tree->CountTopElements() : -1;
+  CPDF_StructTree* tree = ToStructTree(struct_tree);
+  if (!tree)
+    return -1;
+
+  pdfium::base::CheckedNumeric<int> tmp_size = tree->CountTopElements();
+  return tmp_size.ValueOrDefault(-1);
 }
 
-DLLEXPORT FPDF_STRUCTELEMENT STDCALL
+FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV
 FPDF_StructTree_GetChildAtIndex(FPDF_STRUCTTREE struct_tree, int index) {
-  IPDF_StructTree* tree = ToStructTree(struct_tree);
-  if (!tree || index < 0 || index >= tree->CountTopElements())
+  CPDF_StructTree* tree = ToStructTree(struct_tree);
+  if (!tree || index < 0 ||
+      static_cast<size_t>(index) >= tree->CountTopElements()) {
     return nullptr;
-  return tree->GetTopElement(index);
+  }
+  return tree->GetTopElement(static_cast<size_t>(index));
 }
 
-DLLEXPORT unsigned long STDCALL
+FPDF_EXPORT unsigned long FPDF_CALLCONV
 FPDF_StructElement_GetAltText(FPDF_STRUCTELEMENT struct_element,
                               void* buffer,
                               unsigned long buflen) {
-  IPDF_StructElement* elem = ToStructTreeElement(struct_element);
-  if (!elem)
-    return 0;
-
-  CPDF_Dictionary* dict = elem->GetDict();
-  if (!dict)
-    return 0;
-
-  CFX_WideString str = elem->GetDict()->GetUnicodeTextFor("Alt");
-  if (str.IsEmpty())
-    return 0;
-
-  CFX_ByteString encodedStr = str.UTF16LE_Encode();
-  const unsigned long len = encodedStr.GetLength();
-  if (buffer && len <= buflen)
-    FXSYS_memcpy(buffer, encodedStr.c_str(), len);
-  return len;
+  CPDF_StructElement* elem = ToStructTreeElement(struct_element);
+  return (elem && elem->GetDict())
+             ? WideStringToBuffer(elem->GetDict()->GetUnicodeTextFor("Alt"),
+                                  buffer, buflen)
+             : 0;
 }
 
-DLLEXPORT int STDCALL
+FPDF_EXPORT int FPDF_CALLCONV
+FPDF_StructElement_GetMarkedContentID(FPDF_STRUCTELEMENT struct_element) {
+  CPDF_StructElement* elem = ToStructTreeElement(struct_element);
+  CPDF_Object* p =
+      (elem && elem->GetDict()) ? elem->GetDict()->GetObjectFor("K") : nullptr;
+  return p && p->IsNumber() ? p->GetInteger() : -1;
+}
+
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDF_StructElement_GetType(FPDF_STRUCTELEMENT struct_element,
+                           void* buffer,
+                           unsigned long buflen) {
+  CPDF_StructElement* elem = ToStructTreeElement(struct_element);
+  return elem ? WideStringToBuffer(elem->GetType().UTF8Decode(), buffer, buflen)
+              : 0;
+}
+
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDF_StructElement_GetTitle(FPDF_STRUCTELEMENT struct_element,
+                            void* buffer,
+                            unsigned long buflen) {
+  CPDF_StructElement* elem = ToStructTreeElement(struct_element);
+  return elem
+             ? WideStringToBuffer(elem->GetTitle().UTF8Decode(), buffer, buflen)
+             : 0;
+}
+
+FPDF_EXPORT int FPDF_CALLCONV
 FPDF_StructElement_CountChildren(FPDF_STRUCTELEMENT struct_element) {
-  IPDF_StructElement* elem = ToStructTreeElement(struct_element);
-  return elem ? elem->CountKids() : -1;
+  CPDF_StructElement* elem = ToStructTreeElement(struct_element);
+  if (!elem)
+    return -1;
+
+  pdfium::base::CheckedNumeric<int> tmp_size = elem->CountKids();
+  return tmp_size.ValueOrDefault(-1);
 }
 
-DLLEXPORT FPDF_STRUCTELEMENT STDCALL
+FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV
 FPDF_StructElement_GetChildAtIndex(FPDF_STRUCTELEMENT struct_element,
                                    int index) {
-  IPDF_StructElement* elem = ToStructTreeElement(struct_element);
-  if (!elem || index < 0 || index >= elem->CountKids())
+  CPDF_StructElement* elem = ToStructTreeElement(struct_element);
+  if (!elem || index < 0 || static_cast<size_t>(index) >= elem->CountKids())
     return nullptr;
 
-  return elem->GetKidIfElement(index);
+  return elem->GetKidIfElement(static_cast<size_t>(index));
 }
diff --git a/fpdfsdk/fpdf_structtree_embeddertest.cpp b/fpdfsdk/fpdf_structtree_embeddertest.cpp
index 58b3172..7ca81f7 100644
--- a/fpdfsdk/fpdf_structtree_embeddertest.cpp
+++ b/fpdfsdk/fpdf_structtree_embeddertest.cpp
@@ -6,8 +6,9 @@
 #include "public/fpdf_structtree.h"
 #include "testing/embedder_test.h"
 #include "testing/test_support.h"
+#include "third_party/base/optional.h"
 
-class FPDFStructTreeEmbeddertest : public EmbedderTest, public TestSaver {};
+class FPDFStructTreeEmbeddertest : public EmbedderTest {};
 
 TEST_F(FPDFStructTreeEmbeddertest, GetAltText) {
   ASSERT_TRUE(OpenDocument("tagged_alt_text.pdf"));
@@ -24,6 +25,7 @@
   EXPECT_EQ(nullptr, element);
   element = FPDF_StructTree_GetChildAtIndex(struct_tree, 0);
   ASSERT_NE(nullptr, element);
+  EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(element));
   EXPECT_EQ(0U, FPDF_StructElement_GetAltText(element, nullptr, 0));
 
   ASSERT_EQ(1, FPDF_StructElement_CountChildren(element));
@@ -34,6 +36,7 @@
   EXPECT_EQ(nullptr, child_element);
   child_element = FPDF_StructElement_GetChildAtIndex(element, 0);
   ASSERT_NE(nullptr, child_element);
+  EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(child_element));
   EXPECT_EQ(0U, FPDF_StructElement_GetAltText(child_element, nullptr, 0));
 
   ASSERT_EQ(1, FPDF_StructElement_CountChildren(child_element));
@@ -44,6 +47,7 @@
   EXPECT_EQ(nullptr, gchild_element);
   gchild_element = FPDF_StructElement_GetChildAtIndex(child_element, 0);
   ASSERT_NE(nullptr, gchild_element);
+  EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(gchild_element));
   ASSERT_EQ(24U, FPDF_StructElement_GetAltText(gchild_element, nullptr, 0));
 
   unsigned short buffer[12];
@@ -54,11 +58,12 @@
   for (size_t i = 0; i < FX_ArraySize(buffer); ++i)
     EXPECT_EQ(0U, buffer[i]);
 
+  EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(gchild_element));
   ASSERT_EQ(24U, FPDF_StructElement_GetAltText(gchild_element, buffer,
                                                sizeof(buffer)));
-  const FX_WCHAR kExpected[] = L"Black Image";
-  EXPECT_EQ(CFX_WideString(kExpected),
-            CFX_WideString::FromUTF16LE(buffer, FXSYS_len(kExpected)));
+  const wchar_t kExpected[] = L"Black Image";
+  EXPECT_EQ(WideString(kExpected),
+            WideString::FromUTF16LE(buffer, FXSYS_len(kExpected)));
 
   ASSERT_EQ(1, FPDF_StructElement_CountChildren(gchild_element));
   FPDF_STRUCTELEMENT ggchild_element =
@@ -68,3 +73,48 @@
   FPDF_StructTree_Close(struct_tree);
   FPDF_ClosePage(page);
 }
+
+TEST_F(FPDFStructTreeEmbeddertest, GetMarkedContentID) {
+  ASSERT_TRUE(OpenDocument("marked_content_id.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  FPDF_STRUCTTREE struct_tree = FPDF_StructTree_GetForPage(page);
+  ASSERT_TRUE(struct_tree);
+  ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree));
+
+  FPDF_STRUCTELEMENT element = FPDF_StructTree_GetChildAtIndex(struct_tree, 0);
+  EXPECT_EQ(0, FPDF_StructElement_GetMarkedContentID(element));
+
+  FPDF_StructTree_Close(struct_tree);
+  FPDF_ClosePage(page);
+}
+
+TEST_F(FPDFStructTreeEmbeddertest, GetType) {
+  ASSERT_TRUE(OpenDocument("tagged_alt_text.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  FPDF_STRUCTTREE struct_tree = FPDF_StructTree_GetForPage(page);
+  ASSERT_TRUE(struct_tree);
+  ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree));
+
+  FPDF_STRUCTELEMENT element = FPDF_StructTree_GetChildAtIndex(struct_tree, 0);
+  ASSERT_NE(nullptr, element);
+
+  unsigned short buffer[12];
+  memset(buffer, 0, sizeof(buffer));
+  // Deliberately pass in a small buffer size to make sure |buffer| remains
+  // untouched.
+  ASSERT_EQ(18U, FPDF_StructElement_GetType(element, buffer, 1));
+  for (size_t i = 0; i < FX_ArraySize(buffer); ++i)
+    EXPECT_EQ(0U, buffer[i]);
+
+  ASSERT_EQ(18U, FPDF_StructElement_GetType(element, buffer, sizeof(buffer)));
+  const wchar_t kExpected[] = L"Document";
+  EXPECT_EQ(WideString(kExpected),
+            WideString::FromUTF16LE(buffer, FXSYS_len(kExpected)));
+
+  FPDF_StructTree_Close(struct_tree);
+  FPDF_ClosePage(page);
+}
diff --git a/fpdfsdk/fpdf_sysfontinfo.cpp b/fpdfsdk/fpdf_sysfontinfo.cpp
index 1b62dc4..97d02e8 100644
--- a/fpdfsdk/fpdf_sysfontinfo.cpp
+++ b/fpdfsdk/fpdf_sysfontinfo.cpp
@@ -8,12 +8,28 @@
 
 #include <memory>
 
+#include "core/fxcrt/fx_codepage.h"
 #include "core/fxge/cfx_fontmapper.h"
+#include "core/fxge/cfx_fontmgr.h"
 #include "core/fxge/cfx_gemodule.h"
 #include "core/fxge/fx_font.h"
 #include "core/fxge/ifx_systemfontinfo.h"
 #include "fpdfsdk/fsdk_define.h"
-#include "fpdfsdk/pdfwindow/PWL_FontMap.h"
+#include "fpdfsdk/pwl/cpwl_font_map.h"
+#include "third_party/base/ptr_util.h"
+
+static_assert(FXFONT_ANSI_CHARSET == FX_CHARSET_ANSI, "Charset must match");
+static_assert(FXFONT_DEFAULT_CHARSET == FX_CHARSET_Default,
+              "Charset must match");
+static_assert(FXFONT_SYMBOL_CHARSET == FX_CHARSET_Symbol, "Charset must match");
+static_assert(FXFONT_SHIFTJIS_CHARSET == FX_CHARSET_ShiftJIS,
+              "Charset must match");
+static_assert(FXFONT_HANGEUL_CHARSET == FX_CHARSET_Hangul,
+              "Charset must match");
+static_assert(FXFONT_GB2312_CHARSET == FX_CHARSET_ChineseSimplified,
+              "Charset must match");
+static_assert(FXFONT_CHINESEBIG5_CHARSET == FX_CHARSET_ChineseTraditional,
+              "Charset must match");
 
 class CFX_ExternalFontInfo final : public IFX_SystemFontInfo {
  public:
@@ -35,15 +51,16 @@
                 bool bItalic,
                 int charset,
                 int pitch_family,
-                const FX_CHAR* family,
-                int& iExact) override {
+                const char* family) override {
     if (!m_pInfo->MapFont)
       return nullptr;
+
+    int iExact;
     return m_pInfo->MapFont(m_pInfo, weight, bItalic, charset, pitch_family,
                             family, &iExact);
   }
 
-  void* GetFont(const FX_CHAR* family) override {
+  void* GetFont(const char* family) override {
     if (!m_pInfo->GetFont)
       return nullptr;
     return m_pInfo->GetFont(m_pInfo, family);
@@ -58,7 +75,7 @@
     return m_pInfo->GetFontData(m_pInfo, hFont, table, buffer, size);
   }
 
-  bool GetFaceName(void* hFont, CFX_ByteString& name) override {
+  bool GetFaceName(void* hFont, ByteString* name) override {
     if (!m_pInfo->GetFaceName)
       return false;
     uint32_t size = m_pInfo->GetFaceName(m_pInfo, hFont, nullptr, 0);
@@ -66,16 +83,16 @@
       return false;
     char* buffer = FX_Alloc(char, size);
     size = m_pInfo->GetFaceName(m_pInfo, hFont, buffer, size);
-    name = CFX_ByteString(buffer, size);
+    *name = ByteString(buffer, size);
     FX_Free(buffer);
     return true;
   }
 
-  bool GetFontCharset(void* hFont, int& charset) override {
+  bool GetFontCharset(void* hFont, int* charset) override {
     if (!m_pInfo->GetFontCharset)
       return false;
 
-    charset = m_pInfo->GetFontCharset(m_pInfo, hFont);
+    *charset = m_pInfo->GetFontCharset(m_pInfo, hFont);
     return true;
   }
 
@@ -88,34 +105,33 @@
   FPDF_SYSFONTINFO* const m_pInfo;
 };
 
-DLLEXPORT void STDCALL FPDF_AddInstalledFont(void* mapper,
-                                             const char* name,
-                                             int charset) {
-  CFX_FontMapper* pMapper = reinterpret_cast<CFX_FontMapper*>(mapper);
+FPDF_EXPORT void FPDF_CALLCONV FPDF_AddInstalledFont(void* mapper,
+                                                     const char* name,
+                                                     int charset) {
+  CFX_FontMapper* pMapper = static_cast<CFX_FontMapper*>(mapper);
   pMapper->AddInstalledFont(name, charset);
 }
 
-DLLEXPORT void STDCALL FPDF_SetSystemFontInfo(FPDF_SYSFONTINFO* pFontInfoExt) {
+FPDF_EXPORT void FPDF_CALLCONV
+FPDF_SetSystemFontInfo(FPDF_SYSFONTINFO* pFontInfoExt) {
   if (pFontInfoExt->version != 1)
     return;
 
   CFX_GEModule::Get()->GetFontMgr()->SetSystemFontInfo(
-      std::unique_ptr<IFX_SystemFontInfo>(
-          new CFX_ExternalFontInfo(pFontInfoExt)));
+      pdfium::MakeUnique<CFX_ExternalFontInfo>(pFontInfoExt));
 }
 
-DLLEXPORT const FPDF_CharsetFontMap* STDCALL FPDF_GetDefaultTTFMap() {
+FPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV FPDF_GetDefaultTTFMap() {
   return CPWL_FontMap::defaultTTFMap;
 }
 
 struct FPDF_SYSFONTINFO_DEFAULT : public FPDF_SYSFONTINFO {
-  IFX_SystemFontInfo* m_pFontInfo;
+  UnownedPtr<IFX_SystemFontInfo> m_pFontInfo;
 };
 
 static void DefaultRelease(struct _FPDF_SYSFONTINFO* pThis) {
   auto* pDefault = static_cast<FPDF_SYSFONTINFO_DEFAULT*>(pThis);
-  // TODO(thestig): Should this be set to nullptr too?
-  delete pDefault->m_pFontInfo;
+  delete pDefault->m_pFontInfo.Release();
 }
 
 static void DefaultEnumFonts(struct _FPDF_SYSFONTINFO* pThis, void* pMapper) {
@@ -132,7 +148,7 @@
                             int* bExact) {
   auto* pDefault = static_cast<FPDF_SYSFONTINFO_DEFAULT*>(pThis);
   return pDefault->m_pFontInfo->MapFont(weight, !!bItalic, charset,
-                                        pitch_family, family, *bExact);
+                                        pitch_family, family);
 }
 
 void* DefaultGetFont(struct _FPDF_SYSFONTINFO* pThis, const char* family) {
@@ -153,20 +169,22 @@
                                         void* hFont,
                                         char* buffer,
                                         unsigned long buf_size) {
-  CFX_ByteString name;
+  ByteString name;
   auto* pDefault = static_cast<FPDF_SYSFONTINFO_DEFAULT*>(pThis);
-  if (!pDefault->m_pFontInfo->GetFaceName(hFont, name))
+  if (!pDefault->m_pFontInfo->GetFaceName(hFont, &name))
     return 0;
-  if (name.GetLength() >= (long)buf_size)
+  if (name.GetLength() >= static_cast<size_t>(buf_size))
     return name.GetLength() + 1;
-  FXSYS_strcpy(buffer, name.c_str());
+
+  strncpy(buffer, name.c_str(),
+          (name.GetLength() + 1) * sizeof(ByteString::CharType));
   return name.GetLength() + 1;
 }
 
 static int DefaultGetFontCharset(struct _FPDF_SYSFONTINFO* pThis, void* hFont) {
   int charset;
   auto* pDefault = static_cast<FPDF_SYSFONTINFO_DEFAULT*>(pThis);
-  if (!pDefault->m_pFontInfo->GetFontCharset(hFont, charset))
+  if (!pDefault->m_pFontInfo->GetFontCharset(hFont, &charset))
     return 0;
   return charset;
 }
@@ -176,7 +194,7 @@
   pDefault->m_pFontInfo->DeleteFont(hFont);
 }
 
-DLLEXPORT FPDF_SYSFONTINFO* STDCALL FPDF_GetDefaultSystemFontInfo() {
+FPDF_EXPORT FPDF_SYSFONTINFO* FPDF_CALLCONV FPDF_GetDefaultSystemFontInfo() {
   std::unique_ptr<IFX_SystemFontInfo> pFontInfo =
       IFX_SystemFontInfo::CreateDefault(nullptr);
   if (!pFontInfo)
@@ -197,7 +215,7 @@
   return pFontInfoExt;
 }
 
-DLLEXPORT void FPDF_FreeDefaultSystemFontInfo(
-    FPDF_SYSFONTINFO* pDefaultFontInfo) {
+FPDF_EXPORT void FPDF_CALLCONV
+FPDF_FreeDefaultSystemFontInfo(FPDF_SYSFONTINFO* pDefaultFontInfo) {
   FX_Free(static_cast<FPDF_SYSFONTINFO_DEFAULT*>(pDefaultFontInfo));
 }
diff --git a/fpdfsdk/fpdf_transformpage.cpp b/fpdfsdk/fpdf_transformpage.cpp
index 3427f4e..565d90b 100644
--- a/fpdfsdk/fpdf_transformpage.cpp
+++ b/fpdfsdk/fpdf_transformpage.cpp
@@ -6,6 +6,8 @@
 
 #include "public/fpdf_transformpage.h"
 
+#include <memory>
+#include <sstream>
 #include <vector>
 
 #include "core/fpdfapi/page/cpdf_clippath.h"
@@ -23,7 +25,7 @@
 namespace {
 
 void SetBoundingBox(CPDF_Page* page,
-                    const CFX_ByteString& key,
+                    const ByteString& key,
                     float left,
                     float bottom,
                     float right,
@@ -36,7 +38,7 @@
 }
 
 bool GetBoundingBox(CPDF_Page* page,
-                    const CFX_ByteString& key,
+                    const ByteString& key,
                     float* left,
                     float* bottom,
                     float* right,
@@ -52,13 +54,17 @@
   return true;
 }
 
+CPDF_Object* GetPageContent(CPDF_Dictionary* pPageDict) {
+  return pPageDict ? pPageDict->GetDirectObjectFor("Contents") : nullptr;
+}
+
 }  // namespace
 
-DLLEXPORT void STDCALL FPDFPage_SetMediaBox(FPDF_PAGE page,
-                                            float left,
-                                            float bottom,
-                                            float right,
-                                            float top) {
+FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetMediaBox(FPDF_PAGE page,
+                                                    float left,
+                                                    float bottom,
+                                                    float right,
+                                                    float top) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!pPage)
     return;
@@ -66,11 +72,11 @@
   SetBoundingBox(pPage, "MediaBox", left, bottom, right, top);
 }
 
-DLLEXPORT void STDCALL FPDFPage_SetCropBox(FPDF_PAGE page,
-                                           float left,
-                                           float bottom,
-                                           float right,
-                                           float top) {
+FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetCropBox(FPDF_PAGE page,
+                                                   float left,
+                                                   float bottom,
+                                                   float right,
+                                                   float top) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!pPage)
     return;
@@ -78,96 +84,83 @@
   SetBoundingBox(pPage, "CropBox", left, bottom, right, top);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDFPage_GetMediaBox(FPDF_PAGE page,
-                                                 float* left,
-                                                 float* bottom,
-                                                 float* right,
-                                                 float* top) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetMediaBox(FPDF_PAGE page,
+                                                         float* left,
+                                                         float* bottom,
+                                                         float* right,
+                                                         float* top) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   return pPage && GetBoundingBox(pPage, "MediaBox", left, bottom, right, top);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDFPage_GetCropBox(FPDF_PAGE page,
-                                                float* left,
-                                                float* bottom,
-                                                float* right,
-                                                float* top) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetCropBox(FPDF_PAGE page,
+                                                        float* left,
+                                                        float* bottom,
+                                                        float* right,
+                                                        float* top) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   return pPage && GetBoundingBox(pPage, "CropBox", left, bottom, right, top);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDFPage_TransFormWithClip(FPDF_PAGE page,
-                                                       FS_MATRIX* matrix,
-                                                       FS_RECTF* clipRect) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPage_TransFormWithClip(FPDF_PAGE page,
+                           FS_MATRIX* matrix,
+                           FS_RECTF* clipRect) {
+  if (!matrix && !clipRect)
+    return false;
+
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!pPage)
     return false;
 
-  CFX_ByteTextBuf textBuf;
+  std::ostringstream textBuf;
   textBuf << "q ";
-  CFX_FloatRect rect(clipRect->left, clipRect->bottom, clipRect->right,
-                     clipRect->top);
-  rect.Normalize();
-  CFX_ByteString bsClipping;
-  bsClipping.Format("%f %f %f %f re W* n ", rect.left, rect.bottom,
-                    rect.Width(), rect.Height());
-  textBuf << bsClipping;
 
-  CFX_ByteString bsMatix;
-  bsMatix.Format("%f %f %f %f %f %f cm ", matrix->a, matrix->b, matrix->c,
-                 matrix->d, matrix->e, matrix->f);
-  textBuf << bsMatix;
+  if (clipRect) {
+    CFX_FloatRect rect = CFXFloatRectFromFSRECTF(*clipRect);
+    rect.Normalize();
 
-  CPDF_Dictionary* pPageDic = pPage->m_pFormDict;
-  CPDF_Object* pContentObj =
-      pPageDic ? pPageDic->GetObjectFor("Contents") : nullptr;
-  if (!pContentObj)
-    pContentObj = pPageDic ? pPageDic->GetArrayFor("Contents") : nullptr;
+    textBuf << ByteString::Format("%f %f %f %f re W* n ", rect.left,
+                                  rect.bottom, rect.Width(), rect.Height());
+  }
+  if (matrix) {
+    textBuf << ByteString::Format("%f %f %f %f %f %f cm ", matrix->a, matrix->b,
+                                  matrix->c, matrix->d, matrix->e, matrix->f);
+  }
+
+  CPDF_Dictionary* pPageDict = pPage->m_pFormDict.Get();
+  CPDF_Object* pContentObj = GetPageContent(pPageDict);
   if (!pContentObj)
     return false;
 
-  CPDF_Document* pDoc = pPage->m_pDocument;
+  CPDF_Document* pDoc = pPage->m_pDocument.Get();
   if (!pDoc)
     return false;
 
   CPDF_Stream* pStream = pDoc->NewIndirect<CPDF_Stream>(
       nullptr, 0,
       pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool()));
-  pStream->SetData(textBuf.GetBuffer(), textBuf.GetSize());
+  pStream->SetData(&textBuf);
 
   CPDF_Stream* pEndStream = pDoc->NewIndirect<CPDF_Stream>(
       nullptr, 0,
       pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool()));
   pEndStream->SetData((const uint8_t*)" Q", 2);
 
-  CPDF_Array* pContentArray = nullptr;
-  CPDF_Array* pArray = ToArray(pContentObj);
-  if (pArray) {
-    pContentArray = pArray;
+  if (CPDF_Array* pContentArray = ToArray(pContentObj)) {
     pContentArray->InsertNewAt<CPDF_Reference>(0, pDoc, pStream->GetObjNum());
     pContentArray->AddNew<CPDF_Reference>(pDoc, pEndStream->GetObjNum());
-  } else if (CPDF_Reference* pReference = ToReference(pContentObj)) {
-    CPDF_Object* pDirectObj = pReference->GetDirect();
-    if (pDirectObj) {
-      CPDF_Array* pObjArray = pDirectObj->AsArray();
-      if (pObjArray) {
-        pContentArray = pObjArray;
-        pContentArray->InsertNewAt<CPDF_Reference>(0, pDoc,
-                                                   pStream->GetObjNum());
-        pContentArray->AddNew<CPDF_Reference>(pDoc, pEndStream->GetObjNum());
-      } else if (pDirectObj->IsStream()) {
-        pContentArray = pDoc->NewIndirect<CPDF_Array>();
-        pContentArray->AddNew<CPDF_Reference>(pDoc, pStream->GetObjNum());
-        pContentArray->AddNew<CPDF_Reference>(pDoc, pDirectObj->GetObjNum());
-        pContentArray->AddNew<CPDF_Reference>(pDoc, pEndStream->GetObjNum());
-        pPageDic->SetNewFor<CPDF_Reference>("Contents", pDoc,
-                                            pContentArray->GetObjNum());
-      }
-    }
+  } else if (pContentObj->IsStream() && !pContentObj->IsInline()) {
+    CPDF_Array* pContentArray = pDoc->NewIndirect<CPDF_Array>();
+    pContentArray->AddNew<CPDF_Reference>(pDoc, pStream->GetObjNum());
+    pContentArray->AddNew<CPDF_Reference>(pDoc, pContentObj->GetObjNum());
+    pContentArray->AddNew<CPDF_Reference>(pDoc, pEndStream->GetObjNum());
+    pPageDict->SetNewFor<CPDF_Reference>("Contents", pDoc,
+                                         pContentArray->GetObjNum());
   }
 
   // Need to transform the patterns as well.
-  CPDF_Dictionary* pRes = pPageDic->GetDictFor("Resources");
+  CPDF_Dictionary* pRes = pPageDict->GetDictFor("Resources");
   if (pRes) {
     CPDF_Dictionary* pPattenDict = pRes->GetDictFor("Pattern");
     if (pPattenDict) {
@@ -195,7 +188,7 @@
   return true;
 }
 
-DLLEXPORT void STDCALL
+FPDF_EXPORT void FPDF_CALLCONV
 FPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object,
                               double a,
                               double b,
@@ -206,8 +199,7 @@
   CPDF_PageObject* pPageObj = (CPDF_PageObject*)page_object;
   if (!pPageObj)
     return;
-  CFX_Matrix matrix((FX_FLOAT)a, (FX_FLOAT)b, (FX_FLOAT)c, (FX_FLOAT)d,
-                    (FX_FLOAT)e, (FX_FLOAT)f);
+  CFX_Matrix matrix((float)a, (float)b, (float)c, (float)d, (float)e, (float)f);
 
   // Special treatment to shading object, because the ClipPath for shading
   // object is already transformed.
@@ -216,23 +208,24 @@
   pPageObj->TransformGeneralState(matrix);
 }
 
-DLLEXPORT FPDF_CLIPPATH STDCALL FPDF_CreateClipPath(float left,
-                                                    float bottom,
-                                                    float right,
-                                                    float top) {
+FPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDF_CreateClipPath(float left,
+                                                            float bottom,
+                                                            float right,
+                                                            float top) {
   CPDF_Path Path;
   Path.AppendRect(left, bottom, right, top);
 
-  CPDF_ClipPath* pNewClipPath = new CPDF_ClipPath();
+  auto pNewClipPath = pdfium::MakeUnique<CPDF_ClipPath>();
   pNewClipPath->AppendPath(Path, FXFILL_ALTERNATE, false);
-  return pNewClipPath;
+  return pNewClipPath.release();  // Caller takes ownership.
 }
 
-DLLEXPORT void STDCALL FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath) {
-  delete (CPDF_ClipPath*)clipPath;
+FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath) {
+  // Take ownership back from caller and destroy.
+  std::unique_ptr<CPDF_ClipPath>(static_cast<CPDF_ClipPath*>(clipPath));
 }
 
-void OutputPath(CFX_ByteTextBuf& buf, CPDF_Path path) {
+void OutputPath(std::ostringstream& buf, CPDF_Path path) {
   const CFX_PathData* pPathData = path.GetObject();
   if (!pPathData)
     return;
@@ -245,7 +238,7 @@
     return;
   }
 
-  CFX_ByteString temp;
+  ByteString temp;
   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;
@@ -269,69 +262,48 @@
   }
 }
 
-DLLEXPORT void STDCALL FPDFPage_InsertClipPath(FPDF_PAGE page,
-                                               FPDF_CLIPPATH clipPath) {
+FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertClipPath(FPDF_PAGE page,
+                                                       FPDF_CLIPPATH clipPath) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!pPage)
     return;
 
-  CPDF_Dictionary* pPageDic = pPage->m_pFormDict;
-  CPDF_Object* pContentObj =
-      pPageDic ? pPageDic->GetObjectFor("Contents") : nullptr;
-  if (!pContentObj)
-    pContentObj = pPageDic ? pPageDic->GetArrayFor("Contents") : nullptr;
+  CPDF_Dictionary* pPageDict = pPage->m_pFormDict.Get();
+  CPDF_Object* pContentObj = GetPageContent(pPageDict);
   if (!pContentObj)
     return;
 
-  CFX_ByteTextBuf strClip;
+  std::ostringstream strClip;
   CPDF_ClipPath* pClipPath = (CPDF_ClipPath*)clipPath;
-  uint32_t i;
-  for (i = 0; i < pClipPath->GetPathCount(); i++) {
+  for (size_t i = 0; i < pClipPath->GetPathCount(); ++i) {
     CPDF_Path path = pClipPath->GetPath(i);
-    int iClipType = pClipPath->GetClipType(i);
     if (path.GetPoints().empty()) {
       // Empty clipping (totally clipped out)
       strClip << "0 0 m W n ";
     } else {
       OutputPath(strClip, path);
-      if (iClipType == FXFILL_WINDING)
+      if (pClipPath->GetClipType(i) == FXFILL_WINDING)
         strClip << "W n\n";
       else
         strClip << "W* n\n";
     }
   }
-  CPDF_Document* pDoc = pPage->m_pDocument;
+  CPDF_Document* pDoc = pPage->m_pDocument.Get();
   if (!pDoc)
     return;
 
   CPDF_Stream* pStream = pDoc->NewIndirect<CPDF_Stream>(
       nullptr, 0,
       pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool()));
-  pStream->SetData(strClip.GetBuffer(), strClip.GetSize());
+  pStream->SetData(&strClip);
 
-  CPDF_Array* pArray = ToArray(pContentObj);
-  if (pArray) {
+  if (CPDF_Array* pArray = ToArray(pContentObj)) {
     pArray->InsertNewAt<CPDF_Reference>(0, pDoc, pStream->GetObjNum());
-    return;
-  }
-  CPDF_Reference* pReference = ToReference(pContentObj);
-  if (!pReference)
-    return;
-
-  CPDF_Object* pDirectObj = pReference->GetDirect();
-  if (!pDirectObj)
-    return;
-
-  CPDF_Array* pObjArray = pDirectObj->AsArray();
-  if (pObjArray) {
-    pObjArray->InsertNewAt<CPDF_Reference>(0, pDoc, pStream->GetObjNum());
-    return;
-  }
-  if (pDirectObj->IsStream()) {
+  } else if (pContentObj->IsStream() && !pContentObj->IsInline()) {
     CPDF_Array* pContentArray = pDoc->NewIndirect<CPDF_Array>();
     pContentArray->AddNew<CPDF_Reference>(pDoc, pStream->GetObjNum());
-    pContentArray->AddNew<CPDF_Reference>(pDoc, pDirectObj->GetObjNum());
-    pPageDic->SetNewFor<CPDF_Reference>("Contents", pDoc,
-                                        pContentArray->GetObjNum());
+    pContentArray->AddNew<CPDF_Reference>(pDoc, pContentObj->GetObjNum());
+    pPageDict->SetNewFor<CPDF_Reference>("Contents", pDoc,
+                                         pContentArray->GetObjNum());
   }
 }
diff --git a/fpdfsdk/fpdfannot.cpp b/fpdfsdk/fpdfannot.cpp
new file mode 100644
index 0000000..9b0cb39
--- /dev/null
+++ b/fpdfsdk/fpdfannot.cpp
@@ -0,0 +1,890 @@
+// 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_annot.h"
+
+#include <memory>
+#include <utility>
+
+#include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h"
+#include "core/fpdfapi/page/cpdf_form.h"
+#include "core/fpdfapi/page/cpdf_page.h"
+#include "core/fpdfapi/page/cpdf_pageobject.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_string.h"
+#include "core/fpdfdoc/cpdf_annot.h"
+#include "core/fpdfdoc/cpdf_formfield.h"
+#include "core/fpdfdoc/cpdf_interform.h"
+#include "core/fpdfdoc/cpvt_generateap.h"
+#include "core/fxge/cfx_color.h"
+#include "fpdfsdk/fsdk_define.h"
+
+namespace {
+
+// These checks ensure the consistency of annotation subtype values across core/
+// and public.
+static_assert(static_cast<int>(CPDF_Annot::Subtype::UNKNOWN) ==
+                  FPDF_ANNOT_UNKNOWN,
+              "CPDF_Annot::UNKNOWN value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::TEXT) == FPDF_ANNOT_TEXT,
+              "CPDF_Annot::TEXT value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::LINK) == FPDF_ANNOT_LINK,
+              "CPDF_Annot::LINK value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::FREETEXT) ==
+                  FPDF_ANNOT_FREETEXT,
+              "CPDF_Annot::FREETEXT value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::LINE) == FPDF_ANNOT_LINE,
+              "CPDF_Annot::LINE value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::SQUARE) ==
+                  FPDF_ANNOT_SQUARE,
+              "CPDF_Annot::SQUARE value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::CIRCLE) ==
+                  FPDF_ANNOT_CIRCLE,
+              "CPDF_Annot::CIRCLE value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::POLYGON) ==
+                  FPDF_ANNOT_POLYGON,
+              "CPDF_Annot::POLYGON value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::POLYLINE) ==
+                  FPDF_ANNOT_POLYLINE,
+              "CPDF_Annot::POLYLINE value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::HIGHLIGHT) ==
+                  FPDF_ANNOT_HIGHLIGHT,
+              "CPDF_Annot::HIGHLIGHT value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::UNDERLINE) ==
+                  FPDF_ANNOT_UNDERLINE,
+              "CPDF_Annot::UNDERLINE value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::SQUIGGLY) ==
+                  FPDF_ANNOT_SQUIGGLY,
+              "CPDF_Annot::SQUIGGLY value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::STRIKEOUT) ==
+                  FPDF_ANNOT_STRIKEOUT,
+              "CPDF_Annot::STRIKEOUT value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::STAMP) == FPDF_ANNOT_STAMP,
+              "CPDF_Annot::STAMP value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::CARET) == FPDF_ANNOT_CARET,
+              "CPDF_Annot::CARET value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::INK) == FPDF_ANNOT_INK,
+              "CPDF_Annot::INK value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::POPUP) == FPDF_ANNOT_POPUP,
+              "CPDF_Annot::POPUP value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::FILEATTACHMENT) ==
+                  FPDF_ANNOT_FILEATTACHMENT,
+              "CPDF_Annot::FILEATTACHMENT value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::SOUND) == FPDF_ANNOT_SOUND,
+              "CPDF_Annot::SOUND value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::MOVIE) == FPDF_ANNOT_MOVIE,
+              "CPDF_Annot::MOVIE value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::WIDGET) ==
+                  FPDF_ANNOT_WIDGET,
+              "CPDF_Annot::WIDGET value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::SCREEN) ==
+                  FPDF_ANNOT_SCREEN,
+              "CPDF_Annot::SCREEN value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::PRINTERMARK) ==
+                  FPDF_ANNOT_PRINTERMARK,
+              "CPDF_Annot::PRINTERMARK value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::TRAPNET) ==
+                  FPDF_ANNOT_TRAPNET,
+              "CPDF_Annot::TRAPNET value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::WATERMARK) ==
+                  FPDF_ANNOT_WATERMARK,
+              "CPDF_Annot::WATERMARK value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::THREED) ==
+                  FPDF_ANNOT_THREED,
+              "CPDF_Annot::THREED value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::RICHMEDIA) ==
+                  FPDF_ANNOT_RICHMEDIA,
+              "CPDF_Annot::RICHMEDIA value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::Subtype::XFAWIDGET) ==
+                  FPDF_ANNOT_XFAWIDGET,
+              "CPDF_Annot::XFAWIDGET value mismatch");
+
+// These checks ensure the consistency of annotation appearance mode values
+// across core/ and public.
+static_assert(static_cast<int>(CPDF_Annot::AppearanceMode::Normal) ==
+                  FPDF_ANNOT_APPEARANCEMODE_NORMAL,
+              "CPDF_Annot::AppearanceMode::Normal value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::AppearanceMode::Rollover) ==
+                  FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
+              "CPDF_Annot::AppearanceMode::Rollover value mismatch");
+static_assert(static_cast<int>(CPDF_Annot::AppearanceMode::Down) ==
+                  FPDF_ANNOT_APPEARANCEMODE_DOWN,
+              "CPDF_Annot::AppearanceMode::Down value mismatch");
+
+// These checks ensure the consistency of dictionary value types across core/
+// and public/.
+static_assert(static_cast<int>(CPDF_Object::Type::BOOLEAN) ==
+                  FPDF_OBJECT_BOOLEAN,
+              "CPDF_Object::BOOLEAN value mismatch");
+static_assert(static_cast<int>(CPDF_Object::Type::NUMBER) == FPDF_OBJECT_NUMBER,
+              "CPDF_Object::NUMBER value mismatch");
+static_assert(static_cast<int>(CPDF_Object::Type::STRING) == FPDF_OBJECT_STRING,
+              "CPDF_Object::STRING value mismatch");
+static_assert(static_cast<int>(CPDF_Object::Type::NAME) == FPDF_OBJECT_NAME,
+              "CPDF_Object::NAME value mismatch");
+static_assert(static_cast<int>(CPDF_Object::Type::ARRAY) == FPDF_OBJECT_ARRAY,
+              "CPDF_Object::ARRAY value mismatch");
+static_assert(static_cast<int>(CPDF_Object::Type::DICTIONARY) ==
+                  FPDF_OBJECT_DICTIONARY,
+              "CPDF_Object::DICTIONARY value mismatch");
+static_assert(static_cast<int>(CPDF_Object::Type::STREAM) == FPDF_OBJECT_STREAM,
+              "CPDF_Object::STREAM value mismatch");
+static_assert(static_cast<int>(CPDF_Object::Type::NULLOBJ) ==
+                  FPDF_OBJECT_NULLOBJ,
+              "CPDF_Object::NULLOBJ value mismatch");
+static_assert(static_cast<int>(CPDF_Object::Type::REFERENCE) ==
+                  FPDF_OBJECT_REFERENCE,
+              "CPDF_Object::REFERENCE value mismatch");
+
+class CPDF_AnnotContext {
+ public:
+  CPDF_AnnotContext(CPDF_Dictionary* pAnnotDict,
+                    CPDF_Page* pPage,
+                    CPDF_Stream* pStream)
+      : m_pAnnotDict(pAnnotDict), m_pPage(pPage) {
+    SetForm(pStream);
+  }
+  ~CPDF_AnnotContext() {}
+
+  bool HasForm() const { return !!m_pAnnotForm; }
+
+  void SetForm(CPDF_Stream* pStream) {
+    if (!pStream)
+      return;
+
+    // Reset the annotation matrix to be the identity matrix, since the
+    // appearance stream already takes matrix into account.
+    pStream->GetDict()->SetMatrixFor("Matrix", CFX_Matrix());
+
+    m_pAnnotForm = pdfium::MakeUnique<CPDF_Form>(
+        m_pPage->m_pDocument.Get(), m_pPage->m_pResources.Get(), pStream);
+    m_pAnnotForm->ParseContent();
+  }
+
+  CPDF_Form* GetForm() const { return m_pAnnotForm.get(); }
+  CPDF_Dictionary* GetAnnotDict() const { return m_pAnnotDict.Get(); }
+  CPDF_Page* GetPage() const { return m_pPage.Get(); }
+
+ private:
+  std::unique_ptr<CPDF_Form> m_pAnnotForm;
+  UnownedPtr<CPDF_Dictionary> m_pAnnotDict;
+  UnownedPtr<CPDF_Page> m_pPage;
+};
+
+CPDF_AnnotContext* CPDFAnnotContextFromFPDFAnnotation(FPDF_ANNOTATION annot) {
+  return static_cast<CPDF_AnnotContext*>(annot);
+}
+
+bool HasAPStream(const CPDF_Dictionary* pAnnotDict) {
+  return !!FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
+}
+
+void UpdateContentStream(CPDF_Form* pForm, CPDF_Stream* pStream) {
+  ASSERT(pForm);
+  ASSERT(pStream);
+
+  CPDF_PageContentGenerator generator(pForm);
+  std::ostringstream buf;
+  generator.ProcessPageObjects(&buf);
+  pStream->SetDataAndRemoveFilter(&buf);
+}
+
+}  // namespace
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAnnot_IsSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype) {
+  // The supported subtypes must also be communicated in the user doc.
+  return subtype == FPDF_ANNOT_CIRCLE || subtype == FPDF_ANNOT_HIGHLIGHT ||
+         subtype == FPDF_ANNOT_INK || subtype == FPDF_ANNOT_POPUP ||
+         subtype == FPDF_ANNOT_SQUARE || subtype == FPDF_ANNOT_SQUIGGLY ||
+         subtype == FPDF_ANNOT_STAMP || subtype == FPDF_ANNOT_STRIKEOUT ||
+         subtype == FPDF_ANNOT_TEXT || subtype == FPDF_ANNOT_UNDERLINE;
+}
+
+FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV
+FPDFPage_CreateAnnot(FPDF_PAGE page, FPDF_ANNOTATION_SUBTYPE subtype) {
+  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
+  if (!pPage || !FPDFAnnot_IsSupportedSubtype(subtype))
+    return nullptr;
+
+  auto pDict = pdfium::MakeUnique<CPDF_Dictionary>(
+      pPage->m_pDocument->GetByteStringPool());
+  pDict->SetNewFor<CPDF_Name>("Type", "Annot");
+  pDict->SetNewFor<CPDF_Name>("Subtype",
+                              CPDF_Annot::AnnotSubtypeToString(
+                                  static_cast<CPDF_Annot::Subtype>(subtype)));
+  auto pNewAnnot =
+      pdfium::MakeUnique<CPDF_AnnotContext>(pDict.get(), pPage, nullptr);
+
+  CPDF_Array* pAnnotList = pPage->m_pFormDict->GetArrayFor("Annots");
+  if (!pAnnotList)
+    pAnnotList = pPage->m_pFormDict->SetNewFor<CPDF_Array>("Annots");
+
+  pAnnotList->Add(std::move(pDict));
+  return pNewAnnot.release();
+}
+
+FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotCount(FPDF_PAGE page) {
+  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
+  if (!pPage || !pPage->m_pFormDict)
+    return 0;
+
+  CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots");
+  return pAnnots ? pAnnots->GetCount() : 0;
+}
+
+FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_GetAnnot(FPDF_PAGE page,
+                                                            int index) {
+  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
+  if (!pPage || !pPage->m_pFormDict || index < 0)
+    return nullptr;
+
+  CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots");
+  if (!pAnnots || static_cast<size_t>(index) >= pAnnots->GetCount())
+    return nullptr;
+
+  CPDF_Dictionary* pDict = ToDictionary(pAnnots->GetDirectObjectAt(index));
+  auto pNewAnnot = pdfium::MakeUnique<CPDF_AnnotContext>(pDict, pPage, nullptr);
+  return pNewAnnot.release();
+}
+
+FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotIndex(FPDF_PAGE page,
+                                                     FPDF_ANNOTATION annot) {
+  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
+  CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
+  if (!pPage || !pPage->m_pFormDict || !pAnnot || !pAnnot->GetAnnotDict())
+    return -1;
+
+  CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots");
+  if (!pAnnots)
+    return -1;
+
+  CPDF_Dictionary* pDict = pAnnot->GetAnnotDict();
+  auto it =
+      std::find_if(pAnnots->begin(), pAnnots->end(),
+                   [pDict](const std::unique_ptr<CPDF_Object>& candidate) {
+                     return candidate->GetDirect() == pDict;
+                   });
+
+  if (it == pAnnots->end())
+    return -1;
+
+  return it - pAnnots->begin();
+}
+
+FPDF_EXPORT void FPDF_CALLCONV FPDFPage_CloseAnnot(FPDF_ANNOTATION annot) {
+  delete CPDFAnnotContextFromFPDFAnnotation(annot);
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveAnnot(FPDF_PAGE page,
+                                                         int index) {
+  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
+  if (!pPage || !pPage->m_pFormDict || index < 0)
+    return false;
+
+  CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots");
+  if (!pAnnots || static_cast<size_t>(index) >= pAnnots->GetCount())
+    return false;
+
+  pAnnots->RemoveAt(index);
+  return true;
+}
+
+FPDF_EXPORT FPDF_ANNOTATION_SUBTYPE FPDF_CALLCONV
+FPDFAnnot_GetSubtype(FPDF_ANNOTATION annot) {
+  if (!annot)
+    return FPDF_ANNOT_UNKNOWN;
+
+  CPDF_Dictionary* pAnnotDict =
+      CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
+  if (!pAnnotDict)
+    return FPDF_ANNOT_UNKNOWN;
+
+  return static_cast<FPDF_ANNOTATION_SUBTYPE>(
+      CPDF_Annot::StringToAnnotSubtype(pAnnotDict->GetStringFor("Subtype")));
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype) {
+  // The supported subtypes must also be communicated in the user doc.
+  return subtype == FPDF_ANNOT_INK || subtype == FPDF_ANNOT_STAMP;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAnnot_UpdateObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj) {
+  CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
+  CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(obj);
+  if (!pAnnot || !pAnnot->GetAnnotDict() || !pAnnot->HasForm() || !pObj)
+    return false;
+
+  // Check that the annotation type is supported by this method.
+  if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
+    return false;
+
+  // Check that the annotation already has an appearance stream, since an
+  // existing object is to be updated.
+  CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(pAnnot->GetAnnotDict(),
+                                            CPDF_Annot::AppearanceMode::Normal);
+  if (!pStream)
+    return false;
+
+  // Check that the object is already in this annotation's object list.
+  CPDF_Form* pForm = pAnnot->GetForm();
+  CPDF_PageObjectList* pObjList = pForm->GetPageObjectList();
+  auto it =
+      std::find_if(pObjList->begin(), pObjList->end(),
+                   [pObj](const std::unique_ptr<CPDF_PageObject>& candidate) {
+                     return candidate.get() == pObj;
+                   });
+  if (it == pObjList->end())
+    return false;
+
+  // Update the content stream data in the annotation's AP stream.
+  UpdateContentStream(pForm, pStream);
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAnnot_AppendObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj) {
+  CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
+  CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(obj);
+  if (!pAnnot || !pObj)
+    return false;
+
+  CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict();
+  CPDF_Page* pPage = pAnnot->GetPage();
+  if (!pAnnotDict || !pPage)
+    return false;
+
+  // Check that the annotation type is supported by this method.
+  if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
+    return false;
+
+  // If the annotation does not have an AP stream yet, generate and set it.
+  CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(pAnnot->GetAnnotDict(),
+                                            CPDF_Annot::AppearanceMode::Normal);
+  if (!pStream) {
+    CPVT_GenerateAP::GenerateEmptyAP(pPage->m_pDocument.Get(), pAnnotDict);
+    pStream =
+        FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
+    if (!pStream)
+      return false;
+  }
+
+  // Get the annotation's corresponding form object for parsing its AP stream.
+  if (!pAnnot->HasForm())
+    pAnnot->SetForm(pStream);
+
+  // Check that the object did not come from the same annotation. If this check
+  // succeeds, then it is assumed that the object came from
+  // FPDFPageObj_CreateNew{Path|Rect}() or FPDFPageObj_New{Text|Image}Obj().
+  // Note that an object that came from a different annotation must not be
+  // passed here, since an object cannot belong to more than one annotation.
+  CPDF_Form* pForm = pAnnot->GetForm();
+  CPDF_PageObjectList* pObjList = pForm->GetPageObjectList();
+  auto it =
+      std::find_if(pObjList->begin(), pObjList->end(),
+                   [pObj](const std::unique_ptr<CPDF_PageObject>& candidate) {
+                     return candidate.get() == pObj;
+                   });
+  if (it != pObjList->end())
+    return false;
+
+  // Append the object to the object list.
+  std::unique_ptr<CPDF_PageObject> pPageObjHolder(pObj);
+  pObjList->push_back(std::move(pPageObjHolder));
+
+  // Set the content stream data in the annotation's AP stream.
+  UpdateContentStream(pForm, pStream);
+  return true;
+}
+
+FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetObjectCount(FPDF_ANNOTATION annot) {
+  CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
+  if (!pAnnot || !pAnnot->GetAnnotDict())
+    return 0;
+
+  if (!pAnnot->HasForm()) {
+    CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(
+        pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal);
+    if (!pStream)
+      return 0;
+
+    pAnnot->SetForm(pStream);
+  }
+  return pdfium::CollectionSize<int>(*pAnnot->GetForm()->GetPageObjectList());
+}
+
+FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
+FPDFAnnot_GetObject(FPDF_ANNOTATION annot, int index) {
+  CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
+  if (!pAnnot || !pAnnot->GetAnnotDict() || index < 0)
+    return nullptr;
+
+  if (!pAnnot->HasForm()) {
+    CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(
+        pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal);
+    if (!pStream)
+      return nullptr;
+
+    pAnnot->SetForm(pStream);
+  }
+
+  return pAnnot->GetForm()->GetPageObjectList()->GetPageObjectByIndex(index);
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAnnot_RemoveObject(FPDF_ANNOTATION annot, int index) {
+  CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
+  if (!pAnnot || !pAnnot->GetAnnotDict() || !pAnnot->HasForm() || index < 0)
+    return false;
+
+  // Check that the annotation type is supported by this method.
+  if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
+    return false;
+
+  // Check that the annotation already has an appearance stream, since an
+  // existing object is to be deleted.
+  CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(pAnnot->GetAnnotDict(),
+                                            CPDF_Annot::AppearanceMode::Normal);
+  if (!pStream)
+    return false;
+
+  CPDF_PageObjectList* pObjList = pAnnot->GetForm()->GetPageObjectList();
+  if (static_cast<size_t>(index) >= pObjList->size())
+    return false;
+
+  pObjList->erase(pObjList->begin() + index);
+  UpdateContentStream(pAnnot->GetForm(), pStream);
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetColor(FPDF_ANNOTATION annot,
+                                                       FPDFANNOT_COLORTYPE type,
+                                                       unsigned int R,
+                                                       unsigned int G,
+                                                       unsigned int B,
+                                                       unsigned int A) {
+  if (!annot || R > 255 || G > 255 || B > 255 || A > 255)
+    return false;
+
+  CPDF_Dictionary* pAnnotDict =
+      CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
+  if (!pAnnotDict)
+    return false;
+
+  // For annotations with their appearance streams already defined, the path
+  // stream's own color definitions take priority over the annotation color
+  // definitions set by this method, hence this method will simply fail.
+  if (HasAPStream(pAnnotDict))
+    return false;
+
+  // Set the opacity of the annotation.
+  pAnnotDict->SetNewFor<CPDF_Number>("CA", A / 255.f);
+
+  // Set the color of the annotation.
+  ByteString key = type == FPDFANNOT_COLORTYPE_InteriorColor ? "IC" : "C";
+  CPDF_Array* pColor = pAnnotDict->GetArrayFor(key);
+  if (pColor)
+    pColor->Clear();
+  else
+    pColor = pAnnotDict->SetNewFor<CPDF_Array>(key);
+
+  pColor->AddNew<CPDF_Number>(R / 255.f);
+  pColor->AddNew<CPDF_Number>(G / 255.f);
+  pColor->AddNew<CPDF_Number>(B / 255.f);
+
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetColor(FPDF_ANNOTATION annot,
+                                                       FPDFANNOT_COLORTYPE type,
+                                                       unsigned int* R,
+                                                       unsigned int* G,
+                                                       unsigned int* B,
+                                                       unsigned int* A) {
+  if (!annot || !R || !G || !B || !A)
+    return false;
+
+  CPDF_Dictionary* pAnnotDict =
+      CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
+  if (!pAnnotDict)
+    return false;
+
+  // For annotations with their appearance streams already defined, the path
+  // stream's own color definitions take priority over the annotation color
+  // definitions retrieved by this method, hence this method will simply fail.
+  if (HasAPStream(pAnnotDict))
+    return false;
+
+  CPDF_Array* pColor = pAnnotDict->GetArrayFor(
+      type == FPDFANNOT_COLORTYPE_InteriorColor ? "IC" : "C");
+  *A =
+      (pAnnotDict->KeyExist("CA") ? pAnnotDict->GetNumberFor("CA") : 1) * 255.f;
+  if (!pColor) {
+    // Use default color. The default colors must be consistent with the ones
+    // used to generate AP. See calls to GetColorStringWithDefault() in
+    // CPVT_GenerateAP::Generate*AP().
+    if (pAnnotDict->GetStringFor("Subtype") == "Highlight") {
+      *R = 255;
+      *G = 255;
+      *B = 0;
+    } else {
+      *R = 0;
+      *G = 0;
+      *B = 0;
+    }
+    return true;
+  }
+
+  CFX_Color color = CFX_Color::ParseColor(*pColor);
+  switch (color.nColorType) {
+    case CFX_Color::kRGB:
+      *R = color.fColor1 * 255.f;
+      *G = color.fColor2 * 255.f;
+      *B = color.fColor3 * 255.f;
+      break;
+    case CFX_Color::kGray:
+      *R = 255.f * color.fColor1;
+      *G = 255.f * color.fColor1;
+      *B = 255.f * color.fColor1;
+      break;
+    case CFX_Color::kCMYK:
+      *R = 255.f * (1 - color.fColor1) * (1 - color.fColor4);
+      *G = 255.f * (1 - color.fColor2) * (1 - color.fColor4);
+      *B = 255.f * (1 - color.fColor3) * (1 - color.fColor4);
+      break;
+    case CFX_Color::kTransparent:
+      *R = 0;
+      *G = 0;
+      *B = 0;
+      break;
+  }
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot) {
+  if (!annot)
+    return false;
+
+  FPDF_ANNOTATION_SUBTYPE subtype = FPDFAnnot_GetSubtype(annot);
+  return subtype == FPDF_ANNOT_LINK || subtype == FPDF_ANNOT_HIGHLIGHT ||
+         subtype == FPDF_ANNOT_UNDERLINE || subtype == FPDF_ANNOT_SQUIGGLY ||
+         subtype == FPDF_ANNOT_STRIKEOUT;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot,
+                              const FS_QUADPOINTSF* quadPoints) {
+  if (!annot || !quadPoints || !FPDFAnnot_HasAttachmentPoints(annot))
+    return false;
+
+  CPDF_Dictionary* pAnnotDict =
+      CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
+  if (!pAnnotDict)
+    return false;
+
+  // Update the "QuadPoints" entry in the annotation dictionary.
+  CPDF_Array* pQuadPoints = pAnnotDict->GetArrayFor("QuadPoints");
+  if (pQuadPoints)
+    pQuadPoints->Clear();
+  else
+    pQuadPoints = pAnnotDict->SetNewFor<CPDF_Array>("QuadPoints");
+
+  pQuadPoints->AddNew<CPDF_Number>(quadPoints->x1);
+  pQuadPoints->AddNew<CPDF_Number>(quadPoints->y1);
+  pQuadPoints->AddNew<CPDF_Number>(quadPoints->x2);
+  pQuadPoints->AddNew<CPDF_Number>(quadPoints->y2);
+  pQuadPoints->AddNew<CPDF_Number>(quadPoints->x3);
+  pQuadPoints->AddNew<CPDF_Number>(quadPoints->y3);
+  pQuadPoints->AddNew<CPDF_Number>(quadPoints->x4);
+  pQuadPoints->AddNew<CPDF_Number>(quadPoints->y4);
+
+  // If the annotation's appearance stream is defined, and the new quadpoints
+  // defines a bigger bounding box than the appearance stream currently
+  // specifies, then update the "BBox" entry in the AP dictionary too, since it
+  // comes from annotation dictionary's "QuadPoints" entry.
+  CPDF_Stream* pStream =
+      FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
+  if (pStream) {
+    CFX_FloatRect newRect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
+    if (newRect.Contains(pStream->GetDict()->GetRectFor("BBox")))
+      pStream->GetDict()->SetRectFor("BBox", newRect);
+  }
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot,
+                              FS_QUADPOINTSF* quadPoints) {
+  if (!annot || !FPDFAnnot_HasAttachmentPoints(annot) || !quadPoints)
+    return false;
+
+  CPDF_Dictionary* pAnnotDict =
+      CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
+  if (!pAnnotDict)
+    return false;
+
+  CPDF_Array* pArray = pAnnotDict->GetArrayFor("QuadPoints");
+  if (!pArray)
+    return false;
+
+  quadPoints->x1 = pArray->GetNumberAt(0);
+  quadPoints->y1 = pArray->GetNumberAt(1);
+  quadPoints->x2 = pArray->GetNumberAt(2);
+  quadPoints->y2 = pArray->GetNumberAt(3);
+  quadPoints->x3 = pArray->GetNumberAt(4);
+  quadPoints->y3 = pArray->GetNumberAt(5);
+  quadPoints->x4 = pArray->GetNumberAt(6);
+  quadPoints->y4 = pArray->GetNumberAt(7);
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetRect(FPDF_ANNOTATION annot,
+                                                      const FS_RECTF* rect) {
+  if (!annot || !rect)
+    return false;
+
+  CPDF_Dictionary* pAnnotDict =
+      CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
+  if (!pAnnotDict)
+    return false;
+
+  CFX_FloatRect newRect = CFXFloatRectFromFSRECTF(*rect);
+
+  // Update the "Rect" entry in the annotation dictionary.
+  pAnnotDict->SetRectFor("Rect", newRect);
+
+  // If the annotation's appearance stream is defined, the annotation is of a
+  // type that does not have quadpoints, and the new rectangle is bigger than
+  // the current bounding box, then update the "BBox" entry in the AP
+  // dictionary too, since its "BBox" entry comes from annotation dictionary's
+  // "Rect" entry.
+  if (FPDFAnnot_HasAttachmentPoints(annot))
+    return true;
+
+  CPDF_Stream* pStream =
+      FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
+  if (pStream && newRect.Contains(pStream->GetDict()->GetRectFor("BBox")))
+    pStream->GetDict()->SetRectFor("BBox", newRect);
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetRect(FPDF_ANNOTATION annot,
+                                                      FS_RECTF* rect) {
+  if (!annot || !rect)
+    return false;
+
+  CPDF_Dictionary* pAnnotDict =
+      CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
+  if (!pAnnotDict)
+    return false;
+
+  FSRECTFFromCFXFloatRect(pAnnotDict->GetRectFor("Rect"), rect);
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasKey(FPDF_ANNOTATION annot,
+                                                     FPDF_BYTESTRING key) {
+  if (!annot)
+    return false;
+
+  CPDF_Dictionary* pAnnotDict =
+      CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
+  if (!pAnnotDict)
+    return false;
+
+  return pAnnotDict->KeyExist(key);
+}
+
+FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV
+FPDFAnnot_GetValueType(FPDF_ANNOTATION annot, FPDF_BYTESTRING key) {
+  if (!FPDFAnnot_HasKey(annot, key))
+    return FPDF_OBJECT_UNKNOWN;
+
+  auto* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
+  CPDF_Object* pObj = pAnnot->GetAnnotDict()->GetObjectFor(key);
+  return pObj ? pObj->GetType() : FPDF_OBJECT_UNKNOWN;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAnnot_SetStringValue(FPDF_ANNOTATION annot,
+                         FPDF_BYTESTRING key,
+                         FPDF_WIDESTRING value) {
+  if (!annot)
+    return false;
+
+  CPDF_Dictionary* pAnnotDict =
+      CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
+  if (!pAnnotDict)
+    return false;
+
+  pAnnotDict->SetNewFor<CPDF_String>(
+      key, CFXByteStringFromFPDFWideString(value), false);
+  return true;
+}
+
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDFAnnot_GetStringValue(FPDF_ANNOTATION annot,
+                         FPDF_BYTESTRING key,
+                         void* buffer,
+                         unsigned long buflen) {
+  if (!annot)
+    return 0;
+
+  CPDF_Dictionary* pAnnotDict =
+      CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
+  if (!pAnnotDict)
+    return 0;
+
+  return Utf16EncodeMaybeCopyAndReturnLength(pAnnotDict->GetUnicodeTextFor(key),
+                                             buffer, buflen);
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAnnot_SetAP(FPDF_ANNOTATION annot,
+                FPDF_ANNOT_APPEARANCEMODE appearanceMode,
+                FPDF_WIDESTRING value) {
+  if (appearanceMode < 0 || appearanceMode >= FPDF_ANNOT_APPEARANCEMODE_COUNT)
+    return false;
+
+  if (!annot)
+    return false;
+
+  CPDF_Dictionary* pAnnotDict =
+      CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
+  if (!pAnnotDict)
+    return false;
+
+  constexpr const char* modeKeyForMode[] = {"N", "R", "D"};
+  static_assert(FX_ArraySize(modeKeyForMode) == FPDF_ANNOT_APPEARANCEMODE_COUNT,
+                "length of modeKeyForMode should be equal to "
+                "FPDF_ANNOT_APPEARANCEMODE_COUNT");
+  const char* modeKey = modeKeyForMode[appearanceMode];
+
+  CPDF_Dictionary* pApDict = pAnnotDict->GetDictFor("AP");
+
+  // If value is null, we're in remove mode. Otherwise, we're in add/update
+  // mode.
+  if (value) {
+    if (!pApDict)
+      pApDict = pAnnotDict->SetNewFor<CPDF_Dictionary>("AP");
+
+    ByteString newValue = CFXByteStringFromFPDFWideString(value);
+    auto pNewApStream = pdfium::MakeUnique<CPDF_Stream>();
+    pNewApStream->SetData(newValue.raw_str(), newValue.GetLength());
+    pApDict->SetFor(modeKey, std::move(pNewApStream));
+  } else {
+    if (pApDict) {
+      if (appearanceMode == FPDF_ANNOT_APPEARANCEMODE_NORMAL)
+        pAnnotDict->RemoveFor("AP");
+      else
+        pApDict->RemoveFor(modeKey);
+    }
+  }
+
+  return true;
+}
+
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDFAnnot_GetAP(FPDF_ANNOTATION annot,
+                FPDF_ANNOT_APPEARANCEMODE appearanceMode,
+                void* buffer,
+                unsigned long buflen) {
+  if (appearanceMode < 0 || appearanceMode >= FPDF_ANNOT_APPEARANCEMODE_COUNT)
+    return 0;
+
+  if (!annot)
+    return 0;
+
+  CPDF_Dictionary* pAnnotDict =
+      CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
+  if (!pAnnotDict)
+    return 0;
+
+  CPDF_Annot::AppearanceMode mode =
+      static_cast<CPDF_Annot::AppearanceMode>(appearanceMode);
+
+  CPDF_Stream* pStream = FPDFDOC_GetAnnotAPNoFallback(pAnnotDict, mode);
+  return Utf16EncodeMaybeCopyAndReturnLength(
+      pStream ? pStream->GetUnicodeText() : L"", buffer, buflen);
+}
+
+FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV
+FPDFAnnot_GetLinkedAnnot(FPDF_ANNOTATION annot, FPDF_BYTESTRING key) {
+  CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
+  if (!pAnnot || !pAnnot->GetAnnotDict())
+    return nullptr;
+
+  CPDF_Dictionary* pLinkedDict = pAnnot->GetAnnotDict()->GetDictFor(key);
+  if (!pLinkedDict || pLinkedDict->GetStringFor("Type") != "Annot")
+    return nullptr;
+
+  auto pLinkedAnnot = pdfium::MakeUnique<CPDF_AnnotContext>(
+      pLinkedDict, pAnnot->GetPage(), nullptr);
+  return pLinkedAnnot.release();
+}
+
+FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFlags(FPDF_ANNOTATION annot) {
+  if (!annot)
+    return FPDF_ANNOT_FLAG_NONE;
+
+  CPDF_Dictionary* pAnnotDict =
+      CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
+  return pAnnotDict ? pAnnotDict->GetIntegerFor("F") : FPDF_ANNOT_FLAG_NONE;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFlags(FPDF_ANNOTATION annot,
+                                                       int flags) {
+  if (!annot)
+    return false;
+
+  CPDF_Dictionary* pAnnotDict =
+      CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
+  if (!pAnnotDict)
+    return false;
+
+  pAnnotDict->SetNewFor<CPDF_Number>("F", flags);
+  return true;
+}
+
+FPDF_EXPORT int FPDF_CALLCONV
+FPDFAnnot_GetFormFieldFlags(FPDF_PAGE page, FPDF_ANNOTATION annot) {
+  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
+  if (!pPage || !annot)
+    return FPDF_FORMFLAG_NONE;
+
+  CPDF_Dictionary* pAnnotDict =
+      CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
+  if (!pAnnotDict)
+    return FPDF_FORMFLAG_NONE;
+
+  CPDF_InterForm interform(pPage->m_pDocument.Get());
+  CPDF_FormField* pFormField = interform.GetFieldByDict(pAnnotDict);
+  return pFormField ? pFormField->GetFieldFlags() : FPDF_FORMFLAG_NONE;
+}
+
+FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV
+FPDFAnnot_GetFormFieldAtPoint(FPDF_FORMHANDLE hHandle,
+                              FPDF_PAGE page,
+                              double page_x,
+                              double page_y) {
+  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
+  if (!hHandle || !pPage)
+    return nullptr;
+
+  CPDF_InterForm interform(pPage->m_pDocument.Get());
+  int annot_index = -1;
+  CPDF_FormControl* pFormCtrl = interform.GetControlAtPoint(
+      pPage, CFX_PointF(static_cast<float>(page_x), static_cast<float>(page_y)),
+      &annot_index);
+  if (!pFormCtrl || annot_index == -1)
+    return nullptr;
+  return FPDFPage_GetAnnot(page, annot_index);
+}
diff --git a/fpdfsdk/fpdfannot_embeddertest.cpp b/fpdfsdk/fpdfannot_embeddertest.cpp
new file mode 100644
index 0000000..b38bd87
--- /dev/null
+++ b/fpdfsdk/fpdfannot_embeddertest.cpp
@@ -0,0 +1,1267 @@
+// 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 <cwchar>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "core/fxcrt/fx_system.h"
+#include "public/fpdf_annot.h"
+#include "public/fpdf_edit.h"
+#include "public/fpdfview.h"
+#include "testing/embedder_test.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+static constexpr char kContentsKey[] = "Contents";
+
+class FPDFAnnotEmbeddertest : public EmbedderTest {};
+
+std::wstring BufferToWString(const std::vector<char>& buf) {
+  return GetPlatformWString(reinterpret_cast<FPDF_WIDESTRING>(buf.data()));
+}
+
+std::string BufferToString(const std::vector<char>& buf) {
+  return GetPlatformString(reinterpret_cast<FPDF_WIDESTRING>(buf.data()));
+}
+
+TEST_F(FPDFAnnotEmbeddertest, RenderAnnotWithOnlyRolloverAP) {
+  // Open a file with one annotation and load its first page.
+  ASSERT_TRUE(OpenDocument("annotation_highlight_rollover_ap.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+
+  // This annotation has a malformed appearance stream, which does not have its
+  // normal appearance defined, only its rollover appearance. In this case, its
+  // normal appearance should be generated, allowing the highlight annotation to
+  // still display.
+  FPDF_BITMAP bitmap = RenderPageWithFlags(page, form_handle(), FPDF_ANNOT);
+  CompareBitmap(bitmap, 612, 792, "dc98f06da047bd8aabfa99562d2cbd1e");
+  FPDFBitmap_Destroy(bitmap);
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, ExtractHighlightLongContent) {
+  // Open a file with one annotation and load its first page.
+  ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+
+  // Check that there is a total of 1 annotation on its first page.
+  EXPECT_EQ(1, FPDFPage_GetAnnotCount(page));
+
+  // Check that the annotation is of type "highlight".
+  FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
+  ASSERT_TRUE(annot);
+  EXPECT_EQ(FPDF_ANNOT_HIGHLIGHT, FPDFAnnot_GetSubtype(annot));
+
+  // Check that the annotation color is yellow.
+  unsigned int R;
+  unsigned int G;
+  unsigned int B;
+  unsigned int A;
+  EXPECT_TRUE(
+      FPDFAnnot_GetColor(annot, FPDFANNOT_COLORTYPE_Color, &R, &G, &B, &A));
+  EXPECT_EQ(255u, R);
+  EXPECT_EQ(255u, G);
+  EXPECT_EQ(0u, B);
+  EXPECT_EQ(255u, A);
+
+  // Check that the author is correct.
+  static constexpr char kAuthorKey[] = "T";
+  EXPECT_EQ(FPDF_OBJECT_STRING, FPDFAnnot_GetValueType(annot, kAuthorKey));
+  unsigned long len = FPDFAnnot_GetStringValue(annot, kAuthorKey, nullptr, 0);
+  std::vector<char> buf(len);
+  EXPECT_EQ(28u, FPDFAnnot_GetStringValue(annot, kAuthorKey, buf.data(), len));
+  EXPECT_STREQ(L"Jae Hyun Park", BufferToWString(buf).c_str());
+
+  // Check that the content is correct.
+  EXPECT_EQ(FPDF_OBJECT_STRING, FPDFAnnot_GetValueType(annot, kContentsKey));
+  len = FPDFAnnot_GetStringValue(annot, kContentsKey, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  EXPECT_EQ(2690u,
+            FPDFAnnot_GetStringValue(annot, kContentsKey, buf.data(), len));
+  const wchar_t contents[] =
+      L"This is a note for that highlight annotation. Very long highlight "
+      "annotation. Long long long Long long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long longLong long longLong long longLong long longLong long "
+      "longLong long long. END";
+  EXPECT_STREQ(contents, BufferToWString(buf).c_str());
+
+  // Check that the quadpoints are correct.
+  FS_QUADPOINTSF quadpoints;
+  ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot, &quadpoints));
+  EXPECT_EQ(115.802643f, quadpoints.x1);
+  EXPECT_EQ(718.913940f, quadpoints.y1);
+  EXPECT_EQ(157.211182f, quadpoints.x4);
+  EXPECT_EQ(706.264465f, quadpoints.y4);
+
+  FPDFPage_CloseAnnot(annot);
+  UnloadPage(page);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, ExtractInkMultiple) {
+  // Open a file with three annotations and load its first page.
+  ASSERT_TRUE(OpenDocument("annotation_ink_multiple.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+
+  // Check that there is a total of 3 annotation on its first page.
+  EXPECT_EQ(3, FPDFPage_GetAnnotCount(page));
+
+  // Check that the third annotation is of type "ink".
+  FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 2);
+  ASSERT_TRUE(annot);
+  EXPECT_EQ(FPDF_ANNOT_INK, FPDFAnnot_GetSubtype(annot));
+
+  // Check that the annotation color is blue with opacity.
+  unsigned int R;
+  unsigned int G;
+  unsigned int B;
+  unsigned int A;
+  EXPECT_TRUE(
+      FPDFAnnot_GetColor(annot, FPDFANNOT_COLORTYPE_Color, &R, &G, &B, &A));
+  EXPECT_EQ(0u, R);
+  EXPECT_EQ(0u, G);
+  EXPECT_EQ(255u, B);
+  EXPECT_EQ(76u, A);
+
+  // Check that there is no content.
+  EXPECT_EQ(2u, FPDFAnnot_GetStringValue(annot, kContentsKey, nullptr, 0));
+
+  // Check that the rectange coordinates are correct.
+  // Note that upon rendering, the rectangle coordinates will be adjusted.
+  FS_RECTF rect;
+  ASSERT_TRUE(FPDFAnnot_GetRect(annot, &rect));
+  EXPECT_EQ(351.820404f, rect.left);
+  EXPECT_EQ(583.830688f, rect.bottom);
+  EXPECT_EQ(475.336090f, rect.right);
+  EXPECT_EQ(681.535034f, rect.top);
+
+  FPDFPage_CloseAnnot(annot);
+  UnloadPage(page);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, AddIllegalSubtypeAnnotation) {
+  // Open a file with one annotation and load its first page.
+  ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+
+  // Add an annotation with an illegal subtype.
+  ASSERT_FALSE(FPDFPage_CreateAnnot(page, -1));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, AddFirstTextAnnotation) {
+  // Open a file with no annotation and load its first page.
+  ASSERT_TRUE(OpenDocument("hello_world.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+  EXPECT_EQ(0, FPDFPage_GetAnnotCount(page));
+
+  // Add a text annotation to the page.
+  FPDF_ANNOTATION annot = FPDFPage_CreateAnnot(page, FPDF_ANNOT_TEXT);
+  ASSERT_TRUE(annot);
+
+  // Check that there is now 1 annotations on this page.
+  EXPECT_EQ(1, FPDFPage_GetAnnotCount(page));
+
+  // Check that the subtype of the annotation is correct.
+  EXPECT_EQ(FPDF_ANNOT_TEXT, FPDFAnnot_GetSubtype(annot));
+  FPDFPage_CloseAnnot(annot);
+
+  annot = FPDFPage_GetAnnot(page, 0);
+  ASSERT_TRUE(annot);
+  EXPECT_EQ(FPDF_ANNOT_TEXT, FPDFAnnot_GetSubtype(annot));
+
+  // Set the color of the annotation.
+  ASSERT_TRUE(
+      FPDFAnnot_SetColor(annot, FPDFANNOT_COLORTYPE_Color, 51, 102, 153, 204));
+  // Check that the color has been set correctly.
+  unsigned int R;
+  unsigned int G;
+  unsigned int B;
+  unsigned int A;
+  EXPECT_TRUE(
+      FPDFAnnot_GetColor(annot, FPDFANNOT_COLORTYPE_Color, &R, &G, &B, &A));
+  EXPECT_EQ(51u, R);
+  EXPECT_EQ(102u, G);
+  EXPECT_EQ(153u, B);
+  EXPECT_EQ(204u, A);
+
+  // Change the color of the annotation.
+  ASSERT_TRUE(
+      FPDFAnnot_SetColor(annot, FPDFANNOT_COLORTYPE_Color, 204, 153, 102, 51));
+  // Check that the color has been set correctly.
+  EXPECT_TRUE(
+      FPDFAnnot_GetColor(annot, FPDFANNOT_COLORTYPE_Color, &R, &G, &B, &A));
+  EXPECT_EQ(204u, R);
+  EXPECT_EQ(153u, G);
+  EXPECT_EQ(102u, B);
+  EXPECT_EQ(51u, A);
+
+  // Set the annotation rectangle.
+  FS_RECTF rect;
+  ASSERT_TRUE(FPDFAnnot_GetRect(annot, &rect));
+  EXPECT_EQ(0.f, rect.left);
+  EXPECT_EQ(0.f, rect.right);
+  rect.left = 35;
+  rect.bottom = 150;
+  rect.right = 53;
+  rect.top = 165;
+  ASSERT_TRUE(FPDFAnnot_SetRect(annot, &rect));
+  // Check that the annotation rectangle has been set correctly.
+  ASSERT_TRUE(FPDFAnnot_GetRect(annot, &rect));
+  EXPECT_EQ(35.f, rect.left);
+  EXPECT_EQ(150.f, rect.bottom);
+  EXPECT_EQ(53.f, rect.right);
+  EXPECT_EQ(165.f, rect.top);
+
+  // Set the content of the annotation.
+  static constexpr wchar_t contents[] = L"Hello! This is a customized content.";
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
+      GetFPDFWideString(contents);
+  ASSERT_TRUE(FPDFAnnot_SetStringValue(annot, kContentsKey, text.get()));
+  // Check that the content has been set correctly.
+  unsigned long len = FPDFAnnot_GetStringValue(annot, kContentsKey, nullptr, 0);
+  std::vector<char> buf(len);
+  EXPECT_EQ(74u,
+            FPDFAnnot_GetStringValue(annot, kContentsKey, buf.data(), len));
+  EXPECT_STREQ(contents, BufferToWString(buf).c_str());
+
+  FPDFPage_CloseAnnot(annot);
+  UnloadPage(page);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, AddAndSaveUnderlineAnnotation) {
+  // Open a file with one annotation and load its first page.
+  ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+
+  // Check that there is a total of one annotation on its first page, and verify
+  // its quadpoints.
+  EXPECT_EQ(1, FPDFPage_GetAnnotCount(page));
+  FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
+  ASSERT_TRUE(annot);
+  FS_QUADPOINTSF quadpoints;
+  ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot, &quadpoints));
+  EXPECT_EQ(115.802643f, quadpoints.x1);
+  EXPECT_EQ(718.913940f, quadpoints.y1);
+  EXPECT_EQ(157.211182f, quadpoints.x4);
+  EXPECT_EQ(706.264465f, quadpoints.y4);
+  FPDFPage_CloseAnnot(annot);
+
+  // Add an underline annotation to the page and set its quadpoints.
+  annot = FPDFPage_CreateAnnot(page, FPDF_ANNOT_UNDERLINE);
+  ASSERT_TRUE(annot);
+  quadpoints.x1 = 140.802643f;
+  quadpoints.x3 = 140.802643f;
+  ASSERT_TRUE(FPDFAnnot_SetAttachmentPoints(annot, &quadpoints));
+  FPDFPage_CloseAnnot(annot);
+
+  // Save the document, closing the page and document.
+  EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+  FPDF_ClosePage(page);
+
+  // Open the saved document.
+  const char md5[] = "dba153419f67b7c0c0e3d22d3e8910d5";
+
+  OpenSavedDocument();
+  page = LoadSavedPage(0);
+  VerifySavedRendering(page, 612, 792, md5);
+
+  // Check that the saved document has 2 annotations on the first page
+  EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
+
+  // Check that the second annotation is an underline annotation and verify
+  // its quadpoints.
+  FPDF_ANNOTATION new_annot = FPDFPage_GetAnnot(page, 1);
+  ASSERT_TRUE(new_annot);
+  EXPECT_EQ(FPDF_ANNOT_UNDERLINE, FPDFAnnot_GetSubtype(new_annot));
+  FS_QUADPOINTSF new_quadpoints;
+  ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(new_annot, &new_quadpoints));
+  EXPECT_NEAR(quadpoints.x1, new_quadpoints.x1, 0.001f);
+  EXPECT_NEAR(quadpoints.y1, new_quadpoints.y1, 0.001f);
+  EXPECT_NEAR(quadpoints.x4, new_quadpoints.x4, 0.001f);
+  EXPECT_NEAR(quadpoints.y4, new_quadpoints.y4, 0.001f);
+
+  FPDFPage_CloseAnnot(new_annot);
+
+  CloseSavedPage(page);
+  CloseSavedDocument();
+}
+
+TEST_F(FPDFAnnotEmbeddertest, ModifyRectQuadpointsWithAP) {
+#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+  const char md5_original[] = "63af8432fab95a67cdebb7cd0e514941";
+  const char md5_modified_highlight[] = "aec26075011349dec9bace891856b5f2";
+  const char md5_modified_square[] = "057f57a32be95975775e5ec513fdcb56";
+#elif _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+  const char md5_original[] = "0e27376094f11490f74c65f3dc3a42c5";
+  const char md5_modified_highlight[] = "66f3caef3a7d488a4fa1ad37fc06310e";
+  const char md5_modified_square[] = "a456dad0bc6801ee2d6408a4394af563";
+#else
+  const char md5_original[] = "0e27376094f11490f74c65f3dc3a42c5";
+  const char md5_modified_highlight[] = "66f3caef3a7d488a4fa1ad37fc06310e";
+  const char md5_modified_square[] = "a456dad0bc6801ee2d6408a4394af563";
+#endif
+
+  // Open a file with four annotations and load its first page.
+  ASSERT_TRUE(OpenDocument("annotation_highlight_square_with_ap.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+  EXPECT_EQ(4, FPDFPage_GetAnnotCount(page));
+
+  // Check that the original file renders correctly.
+  FPDF_BITMAP bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 612, 792, md5_original);
+  FPDFBitmap_Destroy(bitmap);
+
+  // Retrieve the highlight annotation which has its AP stream already defined.
+  FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
+  ASSERT_TRUE(annot);
+  EXPECT_EQ(FPDF_ANNOT_HIGHLIGHT, FPDFAnnot_GetSubtype(annot));
+
+  // Check that color cannot be set when an AP stream is defined already.
+  EXPECT_FALSE(
+      FPDFAnnot_SetColor(annot, FPDFANNOT_COLORTYPE_Color, 51, 102, 153, 204));
+
+  // Verify its attachment points.
+  FS_QUADPOINTSF quadpoints;
+  ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot, &quadpoints));
+  EXPECT_NEAR(72.0000f, quadpoints.x1, 0.001f);
+  EXPECT_NEAR(720.792f, quadpoints.y1, 0.001f);
+  EXPECT_NEAR(132.055f, quadpoints.x4, 0.001f);
+  EXPECT_NEAR(704.796f, quadpoints.y4, 0.001f);
+
+  // Check that updating the attachment points would succeed.
+  quadpoints.x1 -= 50.f;
+  quadpoints.x2 -= 50.f;
+  quadpoints.x3 -= 50.f;
+  quadpoints.x4 -= 50.f;
+  ASSERT_TRUE(FPDFAnnot_SetAttachmentPoints(annot, &quadpoints));
+  FS_QUADPOINTSF new_quadpoints;
+  ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot, &new_quadpoints));
+  EXPECT_EQ(quadpoints.x1, new_quadpoints.x1);
+  EXPECT_EQ(quadpoints.y1, new_quadpoints.y1);
+  EXPECT_EQ(quadpoints.x4, new_quadpoints.x4);
+  EXPECT_EQ(quadpoints.y4, new_quadpoints.y4);
+
+  // Check that updating quadpoints does not change the annotation's position.
+  bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 612, 792, md5_original);
+  FPDFBitmap_Destroy(bitmap);
+
+  // Verify its annotation rectangle.
+  FS_RECTF rect;
+  ASSERT_TRUE(FPDFAnnot_GetRect(annot, &rect));
+  EXPECT_NEAR(67.7299f, rect.left, 0.001f);
+  EXPECT_NEAR(704.296f, rect.bottom, 0.001f);
+  EXPECT_NEAR(136.325f, rect.right, 0.001f);
+  EXPECT_NEAR(721.292f, rect.top, 0.001f);
+
+  // Check that updating the rectangle would succeed.
+  rect.left -= 60.f;
+  rect.right -= 60.f;
+  ASSERT_TRUE(FPDFAnnot_SetRect(annot, &rect));
+  FS_RECTF new_rect;
+  ASSERT_TRUE(FPDFAnnot_GetRect(annot, &new_rect));
+  EXPECT_EQ(rect.right, new_rect.right);
+  FPDFPage_CloseAnnot(annot);
+
+  // Check that updating the rectangle changes the annotation's position.
+  bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 612, 792, md5_modified_highlight);
+  FPDFBitmap_Destroy(bitmap);
+
+  // Retrieve the square annotation which has its AP stream already defined.
+  annot = FPDFPage_GetAnnot(page, 2);
+  ASSERT_TRUE(annot);
+  EXPECT_EQ(FPDF_ANNOT_SQUARE, FPDFAnnot_GetSubtype(annot));
+
+  // Check that updating the rectangle would succeed.
+  ASSERT_TRUE(FPDFAnnot_GetRect(annot, &rect));
+  rect.left += 70.f;
+  rect.right += 70.f;
+  ASSERT_TRUE(FPDFAnnot_SetRect(annot, &rect));
+  ASSERT_TRUE(FPDFAnnot_GetRect(annot, &new_rect));
+  EXPECT_EQ(rect.right, new_rect.right);
+
+  // Check that updating the rectangle changes the square annotation's position.
+  bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 612, 792, md5_modified_square);
+  FPDFBitmap_Destroy(bitmap);
+
+  FPDFPage_CloseAnnot(annot);
+  UnloadPage(page);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, RemoveAnnotation) {
+  // Open a file with 3 annotations on its first page.
+  ASSERT_TRUE(OpenDocument("annotation_ink_multiple.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+  EXPECT_EQ(3, FPDFPage_GetAnnotCount(page));
+
+  // Check that the annotations have the expected rectangle coordinates.
+  FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
+  FS_RECTF rect;
+  ASSERT_TRUE(FPDFAnnot_GetRect(annot, &rect));
+  EXPECT_NEAR(86.1971f, rect.left, 0.001f);
+  FPDFPage_CloseAnnot(annot);
+
+  annot = FPDFPage_GetAnnot(page, 1);
+  ASSERT_TRUE(FPDFAnnot_GetRect(annot, &rect));
+  EXPECT_NEAR(149.8127f, rect.left, 0.001f);
+  FPDFPage_CloseAnnot(annot);
+
+  annot = FPDFPage_GetAnnot(page, 2);
+  ASSERT_TRUE(FPDFAnnot_GetRect(annot, &rect));
+  EXPECT_NEAR(351.8204f, rect.left, 0.001f);
+  FPDFPage_CloseAnnot(annot);
+
+  // Check that nothing happens when attempting to remove an annotation with an
+  // out-of-bound index.
+  EXPECT_FALSE(FPDFPage_RemoveAnnot(page, 4));
+  EXPECT_FALSE(FPDFPage_RemoveAnnot(page, -1));
+  EXPECT_EQ(3, FPDFPage_GetAnnotCount(page));
+
+  // Remove the second annotation.
+  EXPECT_TRUE(FPDFPage_RemoveAnnot(page, 1));
+  EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
+  EXPECT_FALSE(FPDFPage_GetAnnot(page, 2));
+
+  // Save the document, closing the page and document.
+  EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+  FPDF_ClosePage(page);
+
+  // TODO(npm): VerifySavedRendering changes annot rect dimensions by 1??
+  // Open the saved document.
+  std::string new_file = GetString();
+  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_TRUE(new_doc);
+  FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
+  ASSERT_TRUE(new_page);
+
+  // Check that the saved document has 2 annotations on the first page.
+  EXPECT_EQ(2, FPDFPage_GetAnnotCount(new_page));
+
+  // Check that the remaining 2 annotations are the original 1st and 3rd ones by
+  // verifying their rectangle coordinates.
+  annot = FPDFPage_GetAnnot(new_page, 0);
+  ASSERT_TRUE(FPDFAnnot_GetRect(annot, &rect));
+  EXPECT_NEAR(86.1971f, rect.left, 0.001f);
+  FPDFPage_CloseAnnot(annot);
+
+  annot = FPDFPage_GetAnnot(new_page, 1);
+  ASSERT_TRUE(FPDFAnnot_GetRect(annot, &rect));
+  EXPECT_NEAR(351.8204f, rect.left, 0.001f);
+  FPDFPage_CloseAnnot(annot);
+  FPDF_ClosePage(new_page);
+  FPDF_CloseDocument(new_doc);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, AddAndModifyPath) {
+#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+  const char md5_original[] = "c35408717759562d1f8bf33d317483d2";
+  const char md5_modified_path[] = "cf3cea74bd46497520ff6c4d1ea228c8";
+  const char md5_two_paths[] = "e8994452fc4385337bae5522354e10ff";
+  const char md5_new_annot[] = "ee5372b31fede117fc83b9384598aa25";
+#else
+  const char md5_original[] = "964f89bbe8911e540a465cf1a64b7f7e";
+  const char md5_modified_path[] = "3f77b88ce6048e08e636c9a03921b2e5";
+  const char md5_two_paths[] = "bffbf5ecd15862b9fe553c795400ff8e";
+  const char md5_new_annot[] = "e020534c7eeea76be537c70d6e359a40";
+#endif
+
+  // Open a file with two annotations and load its first page.
+  ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+  EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
+
+  // Check that the page renders correctly.
+  FPDF_BITMAP bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 595, 842, md5_original);
+  FPDFBitmap_Destroy(bitmap);
+
+  // Retrieve the stamp annotation which has its AP stream already defined.
+  FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
+  ASSERT_TRUE(annot);
+
+  // Check that this annotation has one path object and retrieve it.
+  EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot));
+  FPDF_PAGEOBJECT path = FPDFAnnot_GetObject(annot, 1);
+  EXPECT_FALSE(path);
+  path = FPDFAnnot_GetObject(annot, 0);
+  EXPECT_EQ(FPDF_PAGEOBJ_PATH, FPDFPageObj_GetType(path));
+  EXPECT_TRUE(path);
+
+  // Modify the color of the path object.
+  EXPECT_TRUE(FPDFPath_SetStrokeColor(path, 0, 0, 0, 255));
+  EXPECT_TRUE(FPDFAnnot_UpdateObject(annot, path));
+
+  // Check that the page with the modified annotation renders correctly.
+  bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 595, 842, md5_modified_path);
+  FPDFBitmap_Destroy(bitmap);
+
+  // Add a second path object to the same annotation.
+  FPDF_PAGEOBJECT dot = FPDFPageObj_CreateNewPath(7, 84);
+  EXPECT_TRUE(FPDFPath_BezierTo(dot, 9, 86, 10, 87, 11, 88));
+  EXPECT_TRUE(FPDFPath_SetStrokeColor(dot, 255, 0, 0, 100));
+  EXPECT_TRUE(FPDFPath_SetStrokeWidth(dot, 14));
+  EXPECT_TRUE(FPDFPath_SetDrawMode(dot, 0, 1));
+  EXPECT_TRUE(FPDFAnnot_AppendObject(annot, dot));
+  EXPECT_EQ(2, FPDFAnnot_GetObjectCount(annot));
+
+  // Check that the page with an annotation with two paths renders correctly.
+  bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 595, 842, md5_two_paths);
+  FPDFBitmap_Destroy(bitmap);
+
+  // Delete the newly added path object.
+  EXPECT_TRUE(FPDFAnnot_RemoveObject(annot, 1));
+  EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot));
+  FPDFPage_CloseAnnot(annot);
+
+  // Check that the page renders the same as before.
+  bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 595, 842, md5_modified_path);
+  FPDFBitmap_Destroy(bitmap);
+
+  // Create another stamp annotation and set its annotation rectangle.
+  annot = FPDFPage_CreateAnnot(page, FPDF_ANNOT_STAMP);
+  ASSERT_TRUE(annot);
+  FS_RECTF rect;
+  rect.left = 200.f;
+  rect.bottom = 400.f;
+  rect.right = 500.f;
+  rect.top = 600.f;
+  EXPECT_TRUE(FPDFAnnot_SetRect(annot, &rect));
+
+  // Add a new path to the annotation.
+  FPDF_PAGEOBJECT check = FPDFPageObj_CreateNewPath(200, 500);
+  EXPECT_TRUE(FPDFPath_LineTo(check, 300, 400));
+  EXPECT_TRUE(FPDFPath_LineTo(check, 500, 600));
+  EXPECT_TRUE(FPDFPath_MoveTo(check, 350, 550));
+  EXPECT_TRUE(FPDFPath_LineTo(check, 450, 450));
+  EXPECT_TRUE(FPDFPath_SetStrokeColor(check, 0, 255, 255, 180));
+  EXPECT_TRUE(FPDFPath_SetStrokeWidth(check, 8.35f));
+  EXPECT_TRUE(FPDFPath_SetDrawMode(check, 0, 1));
+  EXPECT_TRUE(FPDFAnnot_AppendObject(annot, check));
+  EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot));
+
+  // Check that the annotation's bounding box came from its rectangle.
+  FS_RECTF new_rect;
+  ASSERT_TRUE(FPDFAnnot_GetRect(annot, &new_rect));
+  EXPECT_EQ(rect.left, new_rect.left);
+  EXPECT_EQ(rect.bottom, new_rect.bottom);
+  EXPECT_EQ(rect.right, new_rect.right);
+  EXPECT_EQ(rect.top, new_rect.top);
+
+  // Save the document, closing the page and document.
+  FPDFPage_CloseAnnot(annot);
+  EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+  FPDF_ClosePage(page);
+
+  // Open the saved document.
+  OpenSavedDocument();
+  page = LoadSavedPage(0);
+  VerifySavedRendering(page, 595, 842, md5_new_annot);
+
+  // Check that the document has a correct count of annotations and objects.
+  EXPECT_EQ(3, FPDFPage_GetAnnotCount(page));
+  annot = FPDFPage_GetAnnot(page, 2);
+  ASSERT_TRUE(annot);
+  EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot));
+
+  // Check that the new annotation's rectangle is as defined.
+  ASSERT_TRUE(FPDFAnnot_GetRect(annot, &new_rect));
+  EXPECT_EQ(rect.left, new_rect.left);
+  EXPECT_EQ(rect.bottom, new_rect.bottom);
+  EXPECT_EQ(rect.right, new_rect.right);
+  EXPECT_EQ(rect.top, new_rect.top);
+
+  FPDFPage_CloseAnnot(annot);
+  CloseSavedPage(page);
+  CloseSavedDocument();
+}
+
+TEST_F(FPDFAnnotEmbeddertest, ModifyAnnotationFlags) {
+  // Open a file with an annotation and load its first page.
+  ASSERT_TRUE(OpenDocument("annotation_highlight_rollover_ap.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+
+  // Check that the page renders correctly.
+  FPDF_BITMAP bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 612, 792, "dc98f06da047bd8aabfa99562d2cbd1e");
+  FPDFBitmap_Destroy(bitmap);
+
+  // Retrieve the annotation.
+  FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
+  ASSERT_TRUE(annot);
+
+  // Check that the original flag values are as expected.
+  int flags = FPDFAnnot_GetFlags(annot);
+  EXPECT_FALSE(flags & FPDF_ANNOT_FLAG_HIDDEN);
+  EXPECT_TRUE(flags & FPDF_ANNOT_FLAG_PRINT);
+
+  // Set the HIDDEN flag.
+  flags |= FPDF_ANNOT_FLAG_HIDDEN;
+  EXPECT_TRUE(FPDFAnnot_SetFlags(annot, flags));
+  flags = FPDFAnnot_GetFlags(annot);
+  EXPECT_TRUE(flags & FPDF_ANNOT_FLAG_HIDDEN);
+  EXPECT_TRUE(flags & FPDF_ANNOT_FLAG_PRINT);
+
+  // Check that the page renders correctly without rendering the annotation.
+  bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 612, 792, "1940568c9ba33bac5d0b1ee9558c76b3");
+  FPDFBitmap_Destroy(bitmap);
+
+  // Unset the HIDDEN flag.
+  EXPECT_TRUE(FPDFAnnot_SetFlags(annot, FPDF_ANNOT_FLAG_NONE));
+  EXPECT_FALSE(FPDFAnnot_GetFlags(annot));
+  flags &= ~FPDF_ANNOT_FLAG_HIDDEN;
+  EXPECT_TRUE(FPDFAnnot_SetFlags(annot, flags));
+  flags = FPDFAnnot_GetFlags(annot);
+  EXPECT_FALSE(flags & FPDF_ANNOT_FLAG_HIDDEN);
+  EXPECT_TRUE(flags & FPDF_ANNOT_FLAG_PRINT);
+
+  // Check that the page renders correctly as before.
+  bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 612, 792, "dc98f06da047bd8aabfa99562d2cbd1e");
+  FPDFBitmap_Destroy(bitmap);
+
+  FPDFPage_CloseAnnot(annot);
+  UnloadPage(page);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, AddAndModifyImage) {
+#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+  const char md5_original[] = "c35408717759562d1f8bf33d317483d2";
+  const char md5_new_image[] = "ff012f5697436dfcaec25b32d1333596";
+  const char md5_modified_image[] = "86cf8cb2755a7a2046a543e66d9c1e61";
+#else
+  const char md5_original[] = "964f89bbe8911e540a465cf1a64b7f7e";
+  const char md5_new_image[] = "9ea8732dc9d579f68853f16892856208";
+  const char md5_modified_image[] = "74239d2a8c55c9de1dbb9cd8781895aa";
+#endif
+
+  // Open a file with two annotations and load its first page.
+  ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+  EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
+
+  // Check that the page renders correctly.
+  FPDF_BITMAP bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 595, 842, md5_original);
+  FPDFBitmap_Destroy(bitmap);
+
+  // Create a stamp annotation and set its annotation rectangle.
+  FPDF_ANNOTATION annot = FPDFPage_CreateAnnot(page, FPDF_ANNOT_STAMP);
+  ASSERT_TRUE(annot);
+  FS_RECTF rect;
+  rect.left = 200.f;
+  rect.bottom = 600.f;
+  rect.right = 400.f;
+  rect.top = 800.f;
+  EXPECT_TRUE(FPDFAnnot_SetRect(annot, &rect));
+
+  // Add a solid-color translucent image object to the new annotation.
+  constexpr int kBitmapSize = 200;
+  FPDF_BITMAP image_bitmap = FPDFBitmap_Create(kBitmapSize, kBitmapSize, 1);
+  FPDFBitmap_FillRect(image_bitmap, 0, 0, kBitmapSize, kBitmapSize, 0xeeeecccc);
+  EXPECT_EQ(kBitmapSize, FPDFBitmap_GetWidth(image_bitmap));
+  EXPECT_EQ(kBitmapSize, FPDFBitmap_GetHeight(image_bitmap));
+  FPDF_PAGEOBJECT image_object = FPDFPageObj_NewImageObj(document());
+  ASSERT_TRUE(FPDFImageObj_SetBitmap(&page, 0, image_object, image_bitmap));
+  ASSERT_TRUE(FPDFImageObj_SetMatrix(image_object, kBitmapSize, 0, 0,
+                                     kBitmapSize, 0, 0));
+  FPDFPageObj_Transform(image_object, 1, 0, 0, 1, 200, 600);
+  EXPECT_TRUE(FPDFAnnot_AppendObject(annot, image_object));
+  FPDFPage_CloseAnnot(annot);
+
+  // Check that the page renders correctly with the new image object.
+  bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 595, 842, md5_new_image);
+  FPDFBitmap_Destroy(bitmap);
+
+  // Retrieve the newly added stamp annotation and its image object.
+  annot = FPDFPage_GetAnnot(page, 2);
+  ASSERT_TRUE(annot);
+  EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot));
+  image_object = FPDFAnnot_GetObject(annot, 0);
+  EXPECT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(image_object));
+
+  // Modify the image in the new annotation.
+  FPDFBitmap_FillRect(image_bitmap, 0, 0, kBitmapSize, kBitmapSize, 0xff000000);
+  ASSERT_TRUE(FPDFImageObj_SetBitmap(&page, 0, image_object, image_bitmap));
+  EXPECT_TRUE(FPDFAnnot_UpdateObject(annot, image_object));
+  FPDFPage_CloseAnnot(annot);
+
+  // Save the document, closing the page and document.
+  EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+  FPDF_ClosePage(page);
+  FPDFBitmap_Destroy(image_bitmap);
+
+  // Test that the saved document renders the modified image object correctly.
+  VerifySavedDocument(595, 842, md5_modified_image);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, AddAndModifyText) {
+#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+  const char md5_original[] = "c35408717759562d1f8bf33d317483d2";
+  const char md5_new_text[] = "e5680ed048c2cfd9a1d27212cdf41286";
+  const char md5_modified_text[] = "79f5cfb0b07caaf936f65f6a7a57ce77";
+#else
+  const char md5_original[] = "964f89bbe8911e540a465cf1a64b7f7e";
+  const char md5_new_text[] = "00b14fa2dc1c90d1b0d034e1608efef5";
+  const char md5_modified_text[] = "076c8f24a09ddc0e49f7e758edead6f0";
+#endif
+
+  // Open a file with two annotations and load its first page.
+  ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+  EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
+
+  // Check that the page renders correctly.
+  FPDF_BITMAP bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 595, 842, md5_original);
+  FPDFBitmap_Destroy(bitmap);
+
+  // Create a stamp annotation and set its annotation rectangle.
+  FPDF_ANNOTATION annot = FPDFPage_CreateAnnot(page, FPDF_ANNOT_STAMP);
+  ASSERT_TRUE(annot);
+  FS_RECTF rect;
+  rect.left = 200.f;
+  rect.bottom = 550.f;
+  rect.right = 450.f;
+  rect.top = 650.f;
+  EXPECT_TRUE(FPDFAnnot_SetRect(annot, &rect));
+
+  // Add a translucent text object to the new annotation.
+  FPDF_PAGEOBJECT text_object =
+      FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
+  EXPECT_TRUE(text_object);
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
+      GetFPDFWideString(L"I'm a translucent text laying on other text.");
+  EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
+  EXPECT_TRUE(FPDFText_SetFillColor(text_object, 0, 0, 255, 150));
+  FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 200, 600);
+  EXPECT_TRUE(FPDFAnnot_AppendObject(annot, text_object));
+  FPDFPage_CloseAnnot(annot);
+
+  // Check that the page renders correctly with the new text object.
+  bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 595, 842, md5_new_text);
+  FPDFBitmap_Destroy(bitmap);
+
+  // Retrieve the newly added stamp annotation and its text object.
+  annot = FPDFPage_GetAnnot(page, 2);
+  ASSERT_TRUE(annot);
+  EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot));
+  text_object = FPDFAnnot_GetObject(annot, 0);
+  EXPECT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_object));
+
+  // Modify the text in the new annotation.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> new_text =
+      GetFPDFWideString(L"New text!");
+  EXPECT_TRUE(FPDFText_SetText(text_object, new_text.get()));
+  EXPECT_TRUE(FPDFAnnot_UpdateObject(annot, text_object));
+  FPDFPage_CloseAnnot(annot);
+
+  // Check that the page renders correctly with the modified text object.
+  bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 595, 842, md5_modified_text);
+  FPDFBitmap_Destroy(bitmap);
+
+  // Remove the new annotation, and check that the page renders as before.
+  EXPECT_TRUE(FPDFPage_RemoveAnnot(page, 2));
+  bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+  CompareBitmap(bitmap, 595, 842, md5_original);
+  FPDFBitmap_Destroy(bitmap);
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, GetSetStringValue) {
+  // Open a file with four annotations and load its first page.
+  ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+
+  // Retrieve the first annotation.
+  FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
+  ASSERT_TRUE(annot);
+
+  // Check that a non-existent key does not exist.
+  EXPECT_FALSE(FPDFAnnot_HasKey(annot, "none"));
+
+  // Check that the string value of a non-string dictionary entry is empty.
+  static constexpr char kApKey[] = "AP";
+  EXPECT_TRUE(FPDFAnnot_HasKey(annot, kApKey));
+  EXPECT_EQ(FPDF_OBJECT_REFERENCE, FPDFAnnot_GetValueType(annot, kApKey));
+  EXPECT_EQ(2u, FPDFAnnot_GetStringValue(annot, kApKey, nullptr, 0));
+
+  // Check that the string value of the hash is correct.
+  static constexpr char kHashKey[] = "AAPL:Hash";
+  EXPECT_EQ(FPDF_OBJECT_NAME, FPDFAnnot_GetValueType(annot, kHashKey));
+  unsigned long len = FPDFAnnot_GetStringValue(annot, kHashKey, nullptr, 0);
+  std::vector<char> buf(len);
+  EXPECT_EQ(66u, FPDFAnnot_GetStringValue(annot, kHashKey, buf.data(), len));
+  EXPECT_STREQ(L"395fbcb98d558681742f30683a62a2ad",
+               BufferToWString(buf).c_str());
+
+  // Check that the string value of the modified date is correct.
+  static constexpr char kDateKey[] = "M";
+  EXPECT_EQ(FPDF_OBJECT_NAME, FPDFAnnot_GetValueType(annot, kHashKey));
+  len = FPDFAnnot_GetStringValue(annot, kDateKey, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  EXPECT_EQ(44u, FPDFAnnot_GetStringValue(annot, kDateKey, buf.data(), len));
+  EXPECT_STREQ(L"D:201706071721Z00'00'", BufferToWString(buf).c_str());
+
+  // Update the date entry for the annotation.
+  const wchar_t new_date[] = L"D:201706282359Z00'00'";
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
+      GetFPDFWideString(new_date);
+  EXPECT_TRUE(FPDFAnnot_SetStringValue(annot, kDateKey, text.get()));
+
+  // Save the document, closing the page and document.
+  FPDFPage_CloseAnnot(annot);
+  EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+  FPDF_ClosePage(page);
+
+  // Open the saved annotation.
+#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+  const char md5[] = "4d64e61c9c0f8c60ab3cc3234bb73b1c";
+#else
+  const char md5[] = "c96ee1f316d7f5a1b154de9f9d467f01";
+#endif
+  OpenSavedDocument();
+  page = LoadSavedPage(0);
+  VerifySavedRendering(page, 595, 842, md5);
+  FPDF_ANNOTATION new_annot = FPDFPage_GetAnnot(page, 0);
+
+  // Check that the string value of the modified date is the newly-set value.
+  EXPECT_EQ(FPDF_OBJECT_STRING, FPDFAnnot_GetValueType(new_annot, kDateKey));
+  len = FPDFAnnot_GetStringValue(new_annot, kDateKey, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  EXPECT_EQ(44u,
+            FPDFAnnot_GetStringValue(new_annot, kDateKey, buf.data(), len));
+  EXPECT_STREQ(new_date, BufferToWString(buf).c_str());
+
+  FPDFPage_CloseAnnot(new_annot);
+  CloseSavedPage(page);
+  CloseSavedDocument();
+}
+
+TEST_F(FPDFAnnotEmbeddertest, GetSetAP) {
+  // Open a file with four annotations and load its first page.
+  ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+
+  // Retrieve the first annotation.
+  FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
+  ASSERT_TRUE(annot);
+
+  // Check that the string value of an AP returns the expected length.
+  unsigned long normal_len =
+      FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_NORMAL, nullptr, 0);
+  EXPECT_EQ(73970u, normal_len);
+
+  // Check that the string value of an AP is not returned if the buffer is too
+  // small. The result buffer should be overwritten with an empty string.
+  std::vector<char> buf(normal_len - 1);
+  // Write L"z" in the buffer to verify it's not overwritten.
+  wcscpy(reinterpret_cast<wchar_t*>(buf.data()), L"z");
+  EXPECT_EQ(73970u, FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_NORMAL,
+                                    buf.data(), buf.size()));
+  std::string ap = BufferToString(buf);
+  EXPECT_STREQ("z", ap.c_str());
+
+  // Check that the string value of an AP is returned through a buffer that is
+  // the right size.
+  buf.clear();
+  buf.resize(normal_len);
+  EXPECT_EQ(73970u, FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_NORMAL,
+                                    buf.data(), buf.size()));
+  ap = BufferToString(buf);
+  EXPECT_THAT(ap, testing::StartsWith("q Q q 7.442786 w 2 J"));
+  EXPECT_THAT(ap, testing::EndsWith("c 716.5381 327.7156 l S Q Q"));
+
+  // Check that the string value of an AP is returned through a buffer that is
+  // larger than necessary.
+  buf.clear();
+  buf.resize(normal_len + 1);
+  EXPECT_EQ(73970u, FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_NORMAL,
+                                    buf.data(), buf.size()));
+  ap = BufferToString(buf);
+  EXPECT_THAT(ap, testing::StartsWith("q Q q 7.442786 w 2 J"));
+  EXPECT_THAT(ap, testing::EndsWith("c 716.5381 327.7156 l S Q Q"));
+
+  // Check that getting an AP for a mode that does not have an AP returns an
+  // empty string.
+  unsigned long rollover_len =
+      FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_ROLLOVER, nullptr, 0);
+  EXPECT_EQ(2u, rollover_len);
+
+  buf.clear();
+  buf.resize(1000);
+  EXPECT_EQ(2u, FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
+                                buf.data(), buf.size()));
+  EXPECT_STREQ("", BufferToString(buf).c_str());
+
+  // Check that setting the AP for an invalid appearance mode fails.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> apText =
+      GetFPDFWideString(L"new test ap");
+  EXPECT_FALSE(FPDFAnnot_SetAP(annot, -1, apText.get()));
+  EXPECT_FALSE(
+      FPDFAnnot_SetAP(annot, FPDF_ANNOT_APPEARANCEMODE_COUNT, apText.get()));
+  EXPECT_FALSE(FPDFAnnot_SetAP(annot, FPDF_ANNOT_APPEARANCEMODE_COUNT + 1,
+                               apText.get()));
+
+  // Set the AP correctly now.
+  EXPECT_TRUE(
+      FPDFAnnot_SetAP(annot, FPDF_ANNOT_APPEARANCEMODE_ROLLOVER, apText.get()));
+
+  // Check that the new annotation value is equal to the value we just set.
+  rollover_len =
+      FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_ROLLOVER, nullptr, 0);
+  EXPECT_EQ(24u, rollover_len);
+  buf.clear();
+  buf.resize(rollover_len);
+  EXPECT_EQ(24u, FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
+                                 buf.data(), buf.size()));
+  EXPECT_STREQ(L"new test ap", BufferToWString(buf).c_str());
+
+  // Check that the Normal AP was not touched when the Rollover AP was set.
+  buf.clear();
+  buf.resize(normal_len);
+  EXPECT_EQ(73970u, FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_NORMAL,
+                                    buf.data(), buf.size()));
+  ap = BufferToString(buf);
+  EXPECT_THAT(ap, testing::StartsWith("q Q q 7.442786 w 2 J"));
+  EXPECT_THAT(ap, testing::EndsWith("c 716.5381 327.7156 l S Q Q"));
+
+  // Save the modified document, then reopen it.
+  FPDFPage_CloseAnnot(annot);
+  EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+  FPDF_ClosePage(page);
+
+  OpenSavedDocument();
+  page = LoadSavedPage(0);
+  FPDF_ANNOTATION new_annot = FPDFPage_GetAnnot(page, 0);
+
+  // Check that the new annotation value is equal to the value we set before
+  // saving.
+  rollover_len = FPDFAnnot_GetAP(new_annot, FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
+                                 nullptr, 0);
+  EXPECT_EQ(24u, rollover_len);
+  buf.clear();
+  buf.resize(rollover_len);
+  EXPECT_EQ(24u, FPDFAnnot_GetAP(new_annot, FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
+                                 buf.data(), buf.size()));
+  EXPECT_STREQ(L"new test ap", BufferToWString(buf).c_str());
+
+  // Close saved document.
+  FPDFPage_CloseAnnot(new_annot);
+  CloseSavedPage(page);
+  CloseSavedDocument();
+}
+
+TEST_F(FPDFAnnotEmbeddertest, RemoveOptionalAP) {
+  // Open a file with four annotations and load its first page.
+  ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+
+  // Retrieve the first annotation.
+  FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
+  ASSERT_TRUE(annot);
+
+  // Set Down AP. Normal AP is already set.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> apText =
+      GetFPDFWideString(L"new test ap");
+  EXPECT_TRUE(
+      FPDFAnnot_SetAP(annot, FPDF_ANNOT_APPEARANCEMODE_DOWN, apText.get()));
+  EXPECT_EQ(73970u, FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_NORMAL,
+                                    nullptr, 0));
+  EXPECT_EQ(24u,
+            FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_DOWN, nullptr, 0));
+
+  // Check that setting the Down AP to null removes the Down entry but keeps
+  // Normal intact.
+  EXPECT_TRUE(FPDFAnnot_SetAP(annot, FPDF_ANNOT_APPEARANCEMODE_DOWN, nullptr));
+  EXPECT_EQ(73970u, FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_NORMAL,
+                                    nullptr, 0));
+  EXPECT_EQ(2u,
+            FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_DOWN, nullptr, 0));
+
+  FPDFPage_CloseAnnot(annot);
+  FPDF_ClosePage(page);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, RemoveRequiredAP) {
+  // Open a file with four annotations and load its first page.
+  ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+
+  // Retrieve the first annotation.
+  FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
+  ASSERT_TRUE(annot);
+
+  // Set Down AP. Normal AP is already set.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> apText =
+      GetFPDFWideString(L"new test ap");
+  EXPECT_TRUE(
+      FPDFAnnot_SetAP(annot, FPDF_ANNOT_APPEARANCEMODE_DOWN, apText.get()));
+  EXPECT_EQ(73970u, FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_NORMAL,
+                                    nullptr, 0));
+  EXPECT_EQ(24u,
+            FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_DOWN, nullptr, 0));
+
+  // Check that setting the Normal AP to null removes the whole AP dictionary.
+  EXPECT_TRUE(
+      FPDFAnnot_SetAP(annot, FPDF_ANNOT_APPEARANCEMODE_NORMAL, nullptr));
+  EXPECT_EQ(
+      2u, FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_NORMAL, nullptr, 0));
+  EXPECT_EQ(2u,
+            FPDFAnnot_GetAP(annot, FPDF_ANNOT_APPEARANCEMODE_DOWN, nullptr, 0));
+
+  FPDFPage_CloseAnnot(annot);
+  FPDF_ClosePage(page);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, ExtractLinkedAnnotations) {
+  // Open a file with annotations and load its first page.
+  ASSERT_TRUE(OpenDocument("annotation_highlight_square_with_ap.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+  EXPECT_EQ(-1, FPDFPage_GetAnnotIndex(page, nullptr));
+
+  // Retrieve the highlight annotation which has its popup defined.
+  FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
+  ASSERT_TRUE(annot);
+  EXPECT_EQ(FPDF_ANNOT_HIGHLIGHT, FPDFAnnot_GetSubtype(annot));
+  EXPECT_EQ(0, FPDFPage_GetAnnotIndex(page, annot));
+  static constexpr char kPopupKey[] = "Popup";
+  ASSERT_TRUE(FPDFAnnot_HasKey(annot, kPopupKey));
+  ASSERT_EQ(FPDF_OBJECT_REFERENCE, FPDFAnnot_GetValueType(annot, kPopupKey));
+
+  // Retrieve and verify the popup of the highlight annotation.
+  FPDF_ANNOTATION popup = FPDFAnnot_GetLinkedAnnot(annot, kPopupKey);
+  ASSERT_TRUE(popup);
+  EXPECT_EQ(FPDF_ANNOT_POPUP, FPDFAnnot_GetSubtype(popup));
+  EXPECT_EQ(1, FPDFPage_GetAnnotIndex(page, popup));
+  FS_RECTF rect;
+  ASSERT_TRUE(FPDFAnnot_GetRect(popup, &rect));
+  EXPECT_NEAR(612.0f, rect.left, 0.001f);
+  EXPECT_NEAR(578.792, rect.bottom, 0.001f);
+
+  // Attempting to retrieve |annot|'s "IRT"-linked annotation would fail, since
+  // "IRT" is not a key in |annot|'s dictionary.
+  static constexpr char kIRTKey[] = "IRT";
+  ASSERT_FALSE(FPDFAnnot_HasKey(annot, kIRTKey));
+  EXPECT_FALSE(FPDFAnnot_GetLinkedAnnot(annot, kIRTKey));
+
+  // Attempting to retrieve |annot|'s parent dictionary as an annotation would
+  // fail, since its parent is not an annotation.
+  static constexpr char kPKey[] = "P";
+  ASSERT_TRUE(FPDFAnnot_HasKey(annot, kPKey));
+  EXPECT_EQ(FPDF_OBJECT_REFERENCE, FPDFAnnot_GetValueType(annot, kPKey));
+  EXPECT_FALSE(FPDFAnnot_GetLinkedAnnot(annot, kPKey));
+
+  FPDFPage_CloseAnnot(popup);
+  FPDFPage_CloseAnnot(annot);
+  UnloadPage(page);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, GetFormFieldFlagsTextField) {
+  // Open file with form text fields.
+  ASSERT_TRUE(OpenDocument("text_form_multiple.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+
+  // Retrieve the first annotation: user-editable text field.
+  FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
+  ASSERT_TRUE(annot);
+
+  // Check that the flag values are as expected.
+  int flags = FPDFAnnot_GetFormFieldFlags(page, annot);
+  EXPECT_FALSE(flags & FPDF_FORMFLAG_READONLY);
+  FPDFPage_CloseAnnot(annot);
+
+  // Retrieve the second annotation: read-only text field.
+  annot = FPDFPage_GetAnnot(page, 1);
+  ASSERT_TRUE(annot);
+
+  // Check that the flag values are as expected.
+  flags = FPDFAnnot_GetFormFieldFlags(page, annot);
+  EXPECT_TRUE(flags & FPDF_FORMFLAG_READONLY);
+  FPDFPage_CloseAnnot(annot);
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, GetFormFieldFlagsComboBox) {
+  // Open file with form text fields.
+  ASSERT_TRUE(OpenDocument("combobox_form.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+
+  // Retrieve the first annotation: user-editable combobox.
+  FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
+  ASSERT_TRUE(annot);
+
+  // Check that the flag values are as expected.
+  int flags = FPDFAnnot_GetFormFieldFlags(page, annot);
+  EXPECT_FALSE(flags & FPDF_FORMFLAG_READONLY);
+  EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_COMBO);
+  EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_EDIT);
+  FPDFPage_CloseAnnot(annot);
+
+  // Retrieve the second annotation: regular combobox.
+  annot = FPDFPage_GetAnnot(page, 1);
+  ASSERT_TRUE(annot);
+
+  // Check that the flag values are as expected.
+  flags = FPDFAnnot_GetFormFieldFlags(page, annot);
+  EXPECT_FALSE(flags & FPDF_FORMFLAG_READONLY);
+  EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_COMBO);
+  EXPECT_FALSE(flags & FPDF_FORMFLAG_CHOICE_EDIT);
+  FPDFPage_CloseAnnot(annot);
+
+  // Retrieve the third annotation: read-only combobox.
+  annot = FPDFPage_GetAnnot(page, 2);
+  ASSERT_TRUE(annot);
+
+  // Check that the flag values are as expected.
+  flags = FPDFAnnot_GetFormFieldFlags(page, annot);
+  EXPECT_TRUE(flags & FPDF_FORMFLAG_READONLY);
+  EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_COMBO);
+  EXPECT_FALSE(flags & FPDF_FORMFLAG_CHOICE_EDIT);
+  FPDFPage_CloseAnnot(annot);
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, GetFormAnnotNull) {
+  // Open file with form text fields.
+  EXPECT_TRUE(OpenDocument("text_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Attempt to get an annotation where no annotation exists on page.
+  FPDF_ANNOTATION annot =
+      FPDFAnnot_GetFormFieldAtPoint(form_handle(), page, 0, 0);
+  EXPECT_FALSE(annot);
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, GetFormAnnotAndCheckFlagsTextField) {
+  // Open file with form text fields.
+  EXPECT_TRUE(OpenDocument("text_form_multiple.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Retrieve user-editable text field annotation.
+  FPDF_ANNOTATION annot =
+      FPDFAnnot_GetFormFieldAtPoint(form_handle(), page, 105, 118);
+  ASSERT_TRUE(annot);
+
+  // Check that interactive form annotation flag values are as expected.
+  int flags = FPDFAnnot_GetFormFieldFlags(page, annot);
+  EXPECT_FALSE(flags & FPDF_FORMFLAG_READONLY);
+  FPDFPage_CloseAnnot(annot);
+
+  // Retrieve read-only text field annotation.
+  annot = FPDFAnnot_GetFormFieldAtPoint(form_handle(), page, 105, 202);
+  ASSERT_TRUE(annot);
+
+  // Check that interactive form annotation flag values are as expected.
+  flags = FPDFAnnot_GetFormFieldFlags(page, annot);
+  EXPECT_TRUE(flags & FPDF_FORMFLAG_READONLY);
+  FPDFPage_CloseAnnot(annot);
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFAnnotEmbeddertest, GetFormAnnotAndCheckFlagsComboBox) {
+  // Open file with form comboboxes.
+  EXPECT_TRUE(OpenDocument("combobox_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Retrieve user-editable combobox annotation.
+  FPDF_ANNOTATION annot =
+      FPDFAnnot_GetFormFieldAtPoint(form_handle(), page, 102, 63);
+  ASSERT_TRUE(annot);
+
+  // Check that interactive form annotation flag values are as expected.
+  int flags = FPDFAnnot_GetFormFieldFlags(page, annot);
+  EXPECT_FALSE(flags & FPDF_FORMFLAG_READONLY);
+  EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_COMBO);
+  EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_EDIT);
+  FPDFPage_CloseAnnot(annot);
+
+  // Retrieve regular combobox annotation.
+  annot = FPDFAnnot_GetFormFieldAtPoint(form_handle(), page, 102, 113);
+  ASSERT_TRUE(annot);
+
+  // Check that interactive form annotation flag values are as expected.
+  flags = FPDFAnnot_GetFormFieldFlags(page, annot);
+  EXPECT_FALSE(flags & FPDF_FORMFLAG_READONLY);
+  EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_COMBO);
+  EXPECT_FALSE(flags & FPDF_FORMFLAG_CHOICE_EDIT);
+  FPDFPage_CloseAnnot(annot);
+
+  // Retrieve read-only combobox annotation.
+  annot = FPDFAnnot_GetFormFieldAtPoint(form_handle(), page, 102, 213);
+  ASSERT_TRUE(annot);
+
+  // Check that interactive form annotation flag values are as expected.
+  flags = FPDFAnnot_GetFormFieldFlags(page, annot);
+  EXPECT_TRUE(flags & FPDF_FORMFLAG_READONLY);
+  EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_COMBO);
+  EXPECT_FALSE(flags & FPDF_FORMFLAG_CHOICE_EDIT);
+  FPDFPage_CloseAnnot(annot);
+
+  UnloadPage(page);
+}
diff --git a/fpdfsdk/fpdfattachment.cpp b/fpdfsdk/fpdfattachment.cpp
new file mode 100644
index 0000000..eb83534
--- /dev/null
+++ b/fpdfsdk/fpdfattachment.cpp
@@ -0,0 +1,271 @@
+// 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_attachment.h"
+
+#include <memory>
+#include <utility>
+
+#include "core/fdrm/crypto/fx_crypt.h"
+#include "core/fpdfapi/parser/cpdf_array.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_string.h"
+#include "core/fpdfapi/parser/fpdf_parser_decode.h"
+#include "core/fpdfdoc/cpdf_filespec.h"
+#include "core/fpdfdoc/cpdf_nametree.h"
+#include "core/fxcrt/cfx_datetime.h"
+#include "core/fxcrt/fx_extension.h"
+#include "fpdfsdk/fsdk_define.h"
+
+namespace {
+
+constexpr char kChecksumKey[] = "CheckSum";
+
+ByteString CFXByteStringHexDecode(const ByteString& bsHex) {
+  uint8_t* result = nullptr;
+  uint32_t size = 0;
+  HexDecode(bsHex.raw_str(), bsHex.GetLength(), &result, &size);
+  ByteString bsDecoded(result, size);
+  FX_Free(result);
+  return bsDecoded;
+}
+
+ByteString GenerateMD5Base16(const void* contents, const unsigned long len) {
+  uint8_t digest[16];
+  CRYPT_MD5Generate(reinterpret_cast<const uint8_t*>(contents), len, digest);
+  char buf[32];
+  for (int i = 0; i < 16; ++i)
+    FXSYS_IntToTwoHexChars(digest[i], &buf[i * 2]);
+
+  return ByteString(buf, 32);
+}
+
+}  // namespace
+
+FPDF_EXPORT int FPDF_CALLCONV
+FPDFDoc_GetAttachmentCount(FPDF_DOCUMENT document) {
+  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+  if (!pDoc)
+    return 0;
+
+  return CPDF_NameTree(pDoc, "EmbeddedFiles").GetCount();
+}
+
+FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV
+FPDFDoc_AddAttachment(FPDF_DOCUMENT document, FPDF_WIDESTRING name) {
+  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+  WideString wsName =
+      WideString::FromUTF16LE(name, WideString::WStringLength(name));
+  if (!pDoc || wsName.IsEmpty())
+    return nullptr;
+
+  CPDF_Dictionary* pRoot = pDoc->GetRoot();
+  if (!pRoot)
+    return nullptr;
+
+  // Retrieve the document's Names dictionary; create it if missing.
+  CPDF_Dictionary* pNames = pRoot->GetDictFor("Names");
+  if (!pNames) {
+    pNames = pDoc->NewIndirect<CPDF_Dictionary>();
+    pRoot->SetNewFor<CPDF_Reference>("Names", pDoc, pNames->GetObjNum());
+  }
+
+  // Create the EmbeddedFiles dictionary if missing.
+  if (!pNames->GetDictFor("EmbeddedFiles")) {
+    CPDF_Dictionary* pFiles = pDoc->NewIndirect<CPDF_Dictionary>();
+    pFiles->SetNewFor<CPDF_Array>("Names");
+    pNames->SetNewFor<CPDF_Reference>("EmbeddedFiles", pDoc,
+                                      pFiles->GetObjNum());
+  }
+
+  // Set up the basic entries in the filespec dictionary.
+  CPDF_Dictionary* pFile = pDoc->NewIndirect<CPDF_Dictionary>();
+  pFile->SetNewFor<CPDF_Name>("Type", "Filespec");
+  pFile->SetNewFor<CPDF_String>("UF", wsName);
+  pFile->SetNewFor<CPDF_String>("F", wsName);
+
+  // Add the new attachment name and filespec into the document's EmbeddedFiles.
+  CPDF_NameTree nameTree(pDoc, "EmbeddedFiles");
+  if (!nameTree.AddValueAndName(
+          pdfium::MakeUnique<CPDF_Reference>(pDoc, pFile->GetObjNum()),
+          wsName)) {
+    return nullptr;
+  }
+
+  return pFile;
+}
+
+FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV
+FPDFDoc_GetAttachment(FPDF_DOCUMENT document, int index) {
+  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+  if (!pDoc || index < 0)
+    return nullptr;
+
+  CPDF_NameTree nameTree(pDoc, "EmbeddedFiles");
+  if (static_cast<size_t>(index) >= nameTree.GetCount())
+    return nullptr;
+
+  WideString csName;
+  return nameTree.LookupValueAndName(index, &csName);
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFDoc_DeleteAttachment(FPDF_DOCUMENT document, int index) {
+  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+  if (!pDoc || index < 0)
+    return false;
+
+  CPDF_NameTree nameTree(pDoc, "EmbeddedFiles");
+  if (static_cast<size_t>(index) >= nameTree.GetCount())
+    return false;
+
+  return nameTree.DeleteValueAndName(index);
+}
+
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDFAttachment_GetName(FPDF_ATTACHMENT attachment,
+                       void* buffer,
+                       unsigned long buflen) {
+  CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
+  if (!pFile)
+    return 0;
+
+  return Utf16EncodeMaybeCopyAndReturnLength(CPDF_FileSpec(pFile).GetFileName(),
+                                             buffer, buflen);
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAttachment_HasKey(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key) {
+  CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
+  if (!pFile)
+    return 0;
+
+  CPDF_Dictionary* pParamsDict = CPDF_FileSpec(pFile).GetParamsDict();
+  return pParamsDict ? pParamsDict->KeyExist(key) : 0;
+}
+
+FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV
+FPDFAttachment_GetValueType(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key) {
+  if (!FPDFAttachment_HasKey(attachment, key))
+    return FPDF_OBJECT_UNKNOWN;
+
+  CPDF_FileSpec spec(CPDFObjectFromFPDFAttachment(attachment));
+  CPDF_Object* pObj = spec.GetParamsDict()->GetObjectFor(key);
+  return pObj ? pObj->GetType() : FPDF_OBJECT_UNKNOWN;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAttachment_SetStringValue(FPDF_ATTACHMENT attachment,
+                              FPDF_BYTESTRING key,
+                              FPDF_WIDESTRING value) {
+  CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
+  if (!pFile)
+    return false;
+
+  CPDF_Dictionary* pParamsDict = CPDF_FileSpec(pFile).GetParamsDict();
+  if (!pParamsDict)
+    return false;
+
+  ByteString bsKey = key;
+  ByteString bsValue = CFXByteStringFromFPDFWideString(value);
+  bool bEncodedAsHex = bsKey == kChecksumKey;
+  if (bEncodedAsHex)
+    bsValue = CFXByteStringHexDecode(bsValue);
+
+  pParamsDict->SetNewFor<CPDF_String>(bsKey, bsValue, bEncodedAsHex);
+  return true;
+}
+
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDFAttachment_GetStringValue(FPDF_ATTACHMENT attachment,
+                              FPDF_BYTESTRING key,
+                              void* buffer,
+                              unsigned long buflen) {
+  CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
+  if (!pFile)
+    return 0;
+
+  CPDF_Dictionary* pParamsDict = CPDF_FileSpec(pFile).GetParamsDict();
+  if (!pParamsDict)
+    return 0;
+
+  ByteString bsKey = key;
+  WideString value = pParamsDict->GetUnicodeTextFor(bsKey);
+  if (bsKey == kChecksumKey && !value.IsEmpty()) {
+    CPDF_String* stringValue = pParamsDict->GetObjectFor(bsKey)->AsString();
+    if (stringValue->IsHex()) {
+      ByteString encoded = PDF_EncodeString(stringValue->GetString(), true);
+      value = CPDF_String(nullptr, encoded, false).GetUnicodeText();
+    }
+  }
+
+  return Utf16EncodeMaybeCopyAndReturnLength(value, buffer, buflen);
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAttachment_SetFile(FPDF_ATTACHMENT attachment,
+                       FPDF_DOCUMENT document,
+                       const void* contents,
+                       const unsigned long len) {
+  CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
+  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+  if (!pFile || !pFile->IsDictionary() || !pDoc || len > INT_MAX)
+    return false;
+
+  // An empty content must have a zero length.
+  if (!contents && len != 0)
+    return false;
+
+  // Create a dictionary for the new embedded file stream.
+  auto pFileStreamDict = pdfium::MakeUnique<CPDF_Dictionary>();
+  CPDF_Dictionary* pParamsDict =
+      pFileStreamDict->SetNewFor<CPDF_Dictionary>("Params");
+
+  // Set the size of the new file in the dictionary.
+  pFileStreamDict->SetNewFor<CPDF_Number>("DL", static_cast<int>(len));
+  pParamsDict->SetNewFor<CPDF_Number>("Size", static_cast<int>(len));
+
+  // Set the creation date of the new attachment in the dictionary.
+  CFX_DateTime dateTime = CFX_DateTime::Now();
+  pParamsDict->SetNewFor<CPDF_String>(
+      "CreationDate",
+      ByteString::Format("D:%d%02d%02d%02d%02d%02d", dateTime.GetYear(),
+                         dateTime.GetMonth(), dateTime.GetDay(),
+                         dateTime.GetHour(), dateTime.GetMinute(),
+                         dateTime.GetSecond()),
+      false);
+
+  // Set the checksum of the new attachment in the dictionary.
+  pParamsDict->SetNewFor<CPDF_String>(
+      kChecksumKey, CFXByteStringHexDecode(GenerateMD5Base16(contents, len)),
+      true);
+
+  // Create the file stream and have the filespec dictionary link to it.
+  std::unique_ptr<uint8_t, FxFreeDeleter> stream(FX_Alloc(uint8_t, len));
+  memcpy(stream.get(), contents, len);
+  CPDF_Stream* pFileStream = pDoc->NewIndirect<CPDF_Stream>(
+      std::move(stream), len, std::move(pFileStreamDict));
+  CPDF_Dictionary* pEFDict =
+      pFile->AsDictionary()->SetNewFor<CPDF_Dictionary>("EF");
+  pEFDict->SetNewFor<CPDF_Reference>("F", pDoc, pFileStream->GetObjNum());
+  return true;
+}
+
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDFAttachment_GetFile(FPDF_ATTACHMENT attachment,
+                       void* buffer,
+                       unsigned long buflen) {
+  CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
+  if (!pFile)
+    return 0;
+
+  CPDF_Stream* pFileStream = CPDF_FileSpec(pFile).GetFileStream();
+  if (!pFileStream)
+    return 0;
+
+  return DecodeStreamMaybeCopyAndReturnLength(pFileStream, buffer, buflen);
+}
diff --git a/fpdfsdk/fpdfattachment_embeddertest.cpp b/fpdfsdk/fpdfattachment_embeddertest.cpp
new file mode 100644
index 0000000..dd9b5ae
--- /dev/null
+++ b/fpdfsdk/fpdfattachment_embeddertest.cpp
@@ -0,0 +1,260 @@
+// 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 <memory>
+#include <string>
+#include <vector>
+
+#include "public/fpdf_attachment.h"
+#include "public/fpdfview.h"
+#include "testing/embedder_test.h"
+
+static constexpr char kDateKey[] = "CreationDate";
+static constexpr char kChecksumKey[] = "CheckSum";
+
+class FPDFAttachmentEmbeddertest : public EmbedderTest {};
+
+TEST_F(FPDFAttachmentEmbeddertest, ExtractAttachments) {
+  // Open a file with two attachments.
+  ASSERT_TRUE(OpenDocument("embedded_attachments.pdf"));
+  EXPECT_EQ(2, FPDFDoc_GetAttachmentCount(document()));
+
+  // Retrieve the first attachment.
+  FPDF_ATTACHMENT attachment = FPDFDoc_GetAttachment(document(), 0);
+  ASSERT_TRUE(attachment);
+
+  // Check that the name of the first attachment is correct.
+  unsigned long len = FPDFAttachment_GetName(attachment, nullptr, 0);
+  std::vector<char> buf(len);
+  EXPECT_EQ(12u, FPDFAttachment_GetName(attachment, buf.data(), len));
+  EXPECT_STREQ(L"1.txt",
+               GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
+                   .c_str());
+
+  // Check that the content of the first attachment is correct.
+  len = FPDFAttachment_GetFile(attachment, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  ASSERT_EQ(4u, FPDFAttachment_GetFile(attachment, buf.data(), len));
+  EXPECT_EQ(std::string("test"), std::string(buf.data(), 4));
+
+  // Check that a non-existent key does not exist.
+  EXPECT_FALSE(FPDFAttachment_HasKey(attachment, "none"));
+
+  // Check that the string value of a non-string dictionary entry is empty.
+  static constexpr char kSizeKey[] = "Size";
+  EXPECT_EQ(FPDF_OBJECT_NUMBER,
+            FPDFAttachment_GetValueType(attachment, kSizeKey));
+  EXPECT_EQ(2u,
+            FPDFAttachment_GetStringValue(attachment, kSizeKey, nullptr, 0));
+
+  // Check that the creation date of the first attachment is correct.
+  len = FPDFAttachment_GetStringValue(attachment, kDateKey, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  EXPECT_EQ(48u, FPDFAttachment_GetStringValue(attachment, kDateKey, buf.data(),
+                                               len));
+  EXPECT_STREQ(L"D:20170712214438-07'00'",
+               GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
+                   .c_str());
+
+  // Retrieve the second attachment.
+  attachment = FPDFDoc_GetAttachment(document(), 1);
+  ASSERT_TRUE(attachment);
+
+  // Retrieve the second attachment file.
+  len = FPDFAttachment_GetFile(attachment, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  EXPECT_EQ(5869u, FPDFAttachment_GetFile(attachment, buf.data(), len));
+
+  // Check that the calculated checksum of the file data matches expectation.
+  const char kCheckSum[] = "72afcddedf554dda63c0c88e06f1ce18";
+  const wchar_t kCheckSumW[] = L"<72AFCDDEDF554DDA63C0C88E06F1CE18>";
+  const std::string generated_checksum =
+      GenerateMD5Base16(reinterpret_cast<uint8_t*>(buf.data()), len);
+  EXPECT_EQ(kCheckSum, generated_checksum);
+
+  // Check that the stored checksum matches expectation.
+  len = FPDFAttachment_GetStringValue(attachment, kChecksumKey, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  EXPECT_EQ(70u, FPDFAttachment_GetStringValue(attachment, kChecksumKey,
+                                               buf.data(), len));
+  EXPECT_EQ(kCheckSumW,
+            GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data())));
+}
+
+TEST_F(FPDFAttachmentEmbeddertest, AddAttachments) {
+  // Open a file with two attachments.
+  ASSERT_TRUE(OpenDocument("embedded_attachments.pdf"));
+  EXPECT_EQ(2, FPDFDoc_GetAttachmentCount(document()));
+
+  // Check that adding an attachment with an empty name would fail.
+  EXPECT_FALSE(FPDFDoc_AddAttachment(document(), nullptr));
+
+  // Add an attachment to the beginning of the embedded file list.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> file_name =
+      GetFPDFWideString(L"0.txt");
+  FPDF_ATTACHMENT attachment =
+      FPDFDoc_AddAttachment(document(), file_name.get());
+
+  // Check that writing to a file with nullptr but non-zero bytes would fail.
+  EXPECT_FALSE(FPDFAttachment_SetFile(attachment, document(), nullptr, 10));
+
+  // Set the new attachment's file.
+  constexpr char kContents1[] = "Hello!";
+  EXPECT_TRUE(FPDFAttachment_SetFile(attachment, document(), kContents1,
+                                     strlen(kContents1)));
+
+  // Verify the name of the new attachment (i.e. the first attachment).
+  attachment = FPDFDoc_GetAttachment(document(), 0);
+  ASSERT_TRUE(attachment);
+  unsigned long len = FPDFAttachment_GetName(attachment, nullptr, 0);
+  std::vector<char> buf(len);
+  EXPECT_EQ(12u, FPDFAttachment_GetName(attachment, buf.data(), len));
+  EXPECT_STREQ(L"0.txt",
+               GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
+                   .c_str());
+
+  // Verify the content of the new attachment (i.e. the first attachment).
+  len = FPDFAttachment_GetFile(attachment, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  ASSERT_EQ(6u, FPDFAttachment_GetFile(attachment, buf.data(), len));
+  EXPECT_EQ(std::string(kContents1), std::string(buf.data(), 6));
+
+  // Add an attachment to the end of the embedded file list and set its file.
+  file_name = GetFPDFWideString(L"z.txt");
+  attachment = FPDFDoc_AddAttachment(document(), file_name.get());
+  constexpr char kContents2[] = "World!";
+  EXPECT_TRUE(FPDFAttachment_SetFile(attachment, document(), kContents2,
+                                     strlen(kContents2)));
+  EXPECT_EQ(4, FPDFDoc_GetAttachmentCount(document()));
+
+  // Verify the name of the new attachment (i.e. the fourth attachment).
+  attachment = FPDFDoc_GetAttachment(document(), 3);
+  ASSERT_TRUE(attachment);
+  len = FPDFAttachment_GetName(attachment, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  EXPECT_EQ(12u, FPDFAttachment_GetName(attachment, buf.data(), len));
+  EXPECT_STREQ(L"z.txt",
+               GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
+                   .c_str());
+
+  // Verify the content of the new attachment (i.e. the fourth attachment).
+  len = FPDFAttachment_GetFile(attachment, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  ASSERT_EQ(6u, FPDFAttachment_GetFile(attachment, buf.data(), len));
+  EXPECT_EQ(std::string(kContents2), std::string(buf.data(), 6));
+}
+
+TEST_F(FPDFAttachmentEmbeddertest, AddAttachmentsWithParams) {
+  // Open a file with two attachments.
+  ASSERT_TRUE(OpenDocument("embedded_attachments.pdf"));
+  EXPECT_EQ(2, FPDFDoc_GetAttachmentCount(document()));
+
+  // Add an attachment to the embedded file list.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> file_name =
+      GetFPDFWideString(L"5.txt");
+  FPDF_ATTACHMENT attachment =
+      FPDFDoc_AddAttachment(document(), file_name.get());
+  constexpr char kContents[] = "Hello World!";
+  EXPECT_TRUE(FPDFAttachment_SetFile(attachment, document(), kContents,
+                                     strlen(kContents)));
+
+  // Set the date to be an arbitrary value.
+  constexpr wchar_t kDateW[] = L"D:20170720161527-04'00'";
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> ws_date =
+      GetFPDFWideString(kDateW);
+  EXPECT_TRUE(
+      FPDFAttachment_SetStringValue(attachment, kDateKey, ws_date.get()));
+
+  // Set the checksum to be an arbitrary value.
+  constexpr wchar_t kCheckSumW[] = L"<ABCDEF01234567899876543210FEDCBA>";
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> ws_checksum =
+      GetFPDFWideString(kCheckSumW);
+  EXPECT_TRUE(FPDFAttachment_SetStringValue(attachment, kChecksumKey,
+                                            ws_checksum.get()));
+
+  // Verify the name of the new attachment (i.e. the second attachment).
+  attachment = FPDFDoc_GetAttachment(document(), 1);
+  ASSERT_TRUE(attachment);
+  unsigned long len = FPDFAttachment_GetName(attachment, nullptr, 0);
+  std::vector<char> buf(len);
+  EXPECT_EQ(12u, FPDFAttachment_GetName(attachment, buf.data(), len));
+  EXPECT_STREQ(L"5.txt",
+               GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
+                   .c_str());
+
+  // Verify the content of the new attachment.
+  len = FPDFAttachment_GetFile(attachment, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  ASSERT_EQ(12u, FPDFAttachment_GetFile(attachment, buf.data(), len));
+  EXPECT_EQ(std::string(kContents), std::string(buf.data(), 12));
+
+  // Verify the creation date of the new attachment.
+  len = FPDFAttachment_GetStringValue(attachment, kDateKey, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  EXPECT_EQ(48u, FPDFAttachment_GetStringValue(attachment, kDateKey, buf.data(),
+                                               len));
+  EXPECT_STREQ(kDateW,
+               GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
+                   .c_str());
+
+  // Verify the checksum of the new attachment.
+  len = FPDFAttachment_GetStringValue(attachment, kChecksumKey, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  EXPECT_EQ(70u, FPDFAttachment_GetStringValue(attachment, kChecksumKey,
+                                               buf.data(), len));
+  EXPECT_STREQ(kCheckSumW,
+               GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
+                   .c_str());
+
+  // Overwrite the existing file with empty content, and check that the checksum
+  // gets updated to the correct value.
+  EXPECT_TRUE(FPDFAttachment_SetFile(attachment, document(), nullptr, 0));
+  EXPECT_EQ(0u, FPDFAttachment_GetFile(attachment, nullptr, 0));
+  len = FPDFAttachment_GetStringValue(attachment, kChecksumKey, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  EXPECT_EQ(70u, FPDFAttachment_GetStringValue(attachment, kChecksumKey,
+                                               buf.data(), len));
+  EXPECT_EQ(L"<D41D8CD98F00B204E9800998ECF8427E>",
+            GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data())));
+}
+
+TEST_F(FPDFAttachmentEmbeddertest, DeleteAttachment) {
+  // Open a file with two attachments.
+  ASSERT_TRUE(OpenDocument("embedded_attachments.pdf"));
+  EXPECT_EQ(2, FPDFDoc_GetAttachmentCount(document()));
+
+  // Verify the name of the first attachment.
+  FPDF_ATTACHMENT attachment = FPDFDoc_GetAttachment(document(), 0);
+  unsigned long len = FPDFAttachment_GetName(attachment, nullptr, 0);
+  std::vector<char> buf(len);
+  EXPECT_EQ(12u, FPDFAttachment_GetName(attachment, buf.data(), len));
+  EXPECT_STREQ(L"1.txt",
+               GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
+                   .c_str());
+
+  // Delete the first attachment.
+  EXPECT_TRUE(FPDFDoc_DeleteAttachment(document(), 0));
+  EXPECT_EQ(1, FPDFDoc_GetAttachmentCount(document()));
+
+  // Verify the name of the new first attachment.
+  attachment = FPDFDoc_GetAttachment(document(), 0);
+  len = FPDFAttachment_GetName(attachment, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  EXPECT_EQ(26u, FPDFAttachment_GetName(attachment, buf.data(), len));
+  EXPECT_STREQ(L"attached.pdf",
+               GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
+                   .c_str());
+}
diff --git a/fpdfsdk/fpdfcatalog.cpp b/fpdfsdk/fpdfcatalog.cpp
new file mode 100644
index 0000000..493e5ae
--- /dev/null
+++ b/fpdfsdk/fpdfcatalog.cpp
@@ -0,0 +1,22 @@
+// 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_catalog.h"
+
+#include "core/fpdfapi/parser/cpdf_document.h"
+#include "fpdfsdk/fsdk_define.h"
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFCatalog_IsTagged(FPDF_DOCUMENT document) {
+  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+  if (!pDoc)
+    return false;
+
+  const CPDF_Dictionary* pCatalog = pDoc->GetRoot();
+  if (!pCatalog)
+    return false;
+
+  const CPDF_Dictionary* pMarkInfo = pCatalog->GetDictFor("MarkInfo");
+  return pMarkInfo && pMarkInfo->GetIntegerFor("Marked") != 0;
+}
diff --git a/fpdfsdk/fpdfcatalog_unittest.cpp b/fpdfsdk/fpdfcatalog_unittest.cpp
new file mode 100644
index 0000000..13c0634
--- /dev/null
+++ b/fpdfsdk/fpdfcatalog_unittest.cpp
@@ -0,0 +1,95 @@
+// 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_catalog.h"
+
+#include "core/fpdfapi/cpdf_modulemgr.h"
+#include "core/fpdfapi/parser/cpdf_document.h"
+#include "core/fpdfapi/parser/cpdf_number.h"
+#include "core/fpdfapi/parser/cpdf_parser.h"
+#include "core/fpdfapi/parser/cpdf_string.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/test_support.h"
+
+#ifdef PDF_ENABLE_XFA
+#include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
+#endif  // PDF_ENABLE_XFA
+
+class CPDF_TestDocument : public CPDF_Document {
+ public:
+  CPDF_TestDocument() : CPDF_Document(nullptr) {}
+
+  void SetRoot(CPDF_Dictionary* root) {
+    m_pRootDict = root;
+    GetRoot();
+  }
+};
+
+#ifdef PDF_ENABLE_XFA
+class CPDF_TestXFAContext : public CPDFXFA_Context {
+ public:
+  CPDF_TestXFAContext()
+      : CPDFXFA_Context(pdfium::MakeUnique<CPDF_TestDocument>()) {}
+
+  void SetRoot(CPDF_Dictionary* root) {
+    reinterpret_cast<CPDF_TestDocument*>(GetPDFDoc())->SetRoot(root);
+  }
+
+  CPDF_IndirectObjectHolder* GetHolder() { return GetPDFDoc(); }
+};
+using CPDF_TestPdfDocument = CPDF_TestXFAContext;
+#else   // PDF_ENABLE_XFA
+using CPDF_TestPdfDocument = CPDF_TestDocument;
+#endif  // PDF_ENABLE_XFA
+
+class PDFCatalogTest : public testing::Test {
+ public:
+  void SetUp() override {
+    CPDF_ModuleMgr::Get()->Init();
+
+    m_pDoc = pdfium::MakeUnique<CPDF_TestPdfDocument>();
+
+    // Setup the root directory.
+    m_pRootObj = pdfium::MakeUnique<CPDF_Dictionary>();
+  }
+
+  void TearDown() override {
+    m_pDoc.reset();
+    CPDF_ModuleMgr::Destroy();
+  }
+
+ protected:
+  std::unique_ptr<CPDF_TestPdfDocument> m_pDoc;
+  std::unique_ptr<CPDF_Dictionary> m_pRootObj;
+};
+
+TEST_F(PDFCatalogTest, IsTagged) {
+  // Null doc
+  EXPECT_FALSE(FPDFCatalog_IsTagged(nullptr));
+
+  // No root
+  m_pDoc->SetRoot(nullptr);
+  EXPECT_FALSE(FPDFCatalog_IsTagged(m_pDoc.get()));
+
+  // Empty root
+  m_pDoc->SetRoot(m_pRootObj.get());
+  EXPECT_FALSE(FPDFCatalog_IsTagged(m_pDoc.get()));
+
+  // Root with other key
+  m_pRootObj->SetNewFor<CPDF_String>("OTHER_KEY", "other value", false);
+  EXPECT_FALSE(FPDFCatalog_IsTagged(m_pDoc.get()));
+
+  // Root with empty MarkInfo
+  CPDF_Dictionary* markInfoDict =
+      m_pRootObj->SetNewFor<CPDF_Dictionary>("MarkInfo");
+  EXPECT_FALSE(FPDFCatalog_IsTagged(m_pDoc.get()));
+
+  // MarkInfo present but Marked is 0
+  markInfoDict->SetNewFor<CPDF_Number>("Marked", 0);
+  EXPECT_FALSE(FPDFCatalog_IsTagged(m_pDoc.get()));
+
+  // MarkInfo present and Marked is 1, PDF is considered tagged.
+  markInfoDict->SetNewFor<CPDF_Number>("Marked", 1);
+  EXPECT_TRUE(FPDFCatalog_IsTagged(m_pDoc.get()));
+}
diff --git a/fpdfsdk/fpdfdoc.cpp b/fpdfsdk/fpdfdoc.cpp
index f7d94c2..47ecf42 100644
--- a/fpdfsdk/fpdfdoc.cpp
+++ b/fpdfsdk/fpdfdoc.cpp
@@ -24,7 +24,7 @@
 
 CPDF_Bookmark FindBookmark(const CPDF_BookmarkTree& tree,
                            CPDF_Bookmark bookmark,
-                           const CFX_WideString& title,
+                           const WideString& title,
                            std::set<CPDF_Dictionary*>* visited) {
   // Return if already checked to avoid circular calling.
   if (pdfium::ContainsKey(*visited, bookmark.GetDict()))
@@ -53,26 +53,16 @@
   if (!page)
     return nullptr;
 
-  CPDF_Document* pDoc = page->m_pDocument;
+  CPDF_Document* pDoc = page->m_pDocument.Get();
   std::unique_ptr<CPDF_LinkList>* pHolder = pDoc->LinksContext();
   if (!pHolder->get())
     *pHolder = pdfium::MakeUnique<CPDF_LinkList>();
   return pHolder->get();
 }
 
-unsigned long Utf16EncodeMaybeCopyAndReturnLength(const CFX_WideString& text,
-                                                  void* buffer,
-                                                  unsigned long buflen) {
-  CFX_ByteString encodedText = text.UTF16LE_Encode();
-  unsigned long len = encodedText.GetLength();
-  if (buffer && len <= buflen)
-    FXSYS_memcpy(buffer, encodedText.c_str(), len);
-  return len;
-}
-
 }  // namespace
 
-DLLEXPORT FPDF_BOOKMARK STDCALL
+FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV
 FPDFBookmark_GetFirstChild(FPDF_DOCUMENT document, FPDF_BOOKMARK pDict) {
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
   if (!pDoc)
@@ -83,7 +73,7 @@
   return tree.GetFirstChild(bookmark).GetDict();
 }
 
-DLLEXPORT FPDF_BOOKMARK STDCALL
+FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV
 FPDFBookmark_GetNextSibling(FPDF_DOCUMENT document, FPDF_BOOKMARK pDict) {
   if (!pDict)
     return nullptr;
@@ -96,32 +86,31 @@
   return tree.GetNextSibling(bookmark).GetDict();
 }
 
-DLLEXPORT unsigned long STDCALL FPDFBookmark_GetTitle(FPDF_BOOKMARK pDict,
-                                                      void* buffer,
-                                                      unsigned long buflen) {
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDFBookmark_GetTitle(FPDF_BOOKMARK pDict, void* buffer, unsigned long buflen) {
   if (!pDict)
     return 0;
   CPDF_Bookmark bookmark(ToDictionary(static_cast<CPDF_Object*>(pDict)));
-  CFX_WideString title = bookmark.GetTitle();
+  WideString title = bookmark.GetTitle();
   return Utf16EncodeMaybeCopyAndReturnLength(title, buffer, buflen);
 }
 
-DLLEXPORT FPDF_BOOKMARK STDCALL FPDFBookmark_Find(FPDF_DOCUMENT document,
-                                                  FPDF_WIDESTRING title) {
+FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV
+FPDFBookmark_Find(FPDF_DOCUMENT document, FPDF_WIDESTRING title) {
   if (!title || title[0] == 0)
     return nullptr;
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
   if (!pDoc)
     return nullptr;
   CPDF_BookmarkTree tree(pDoc);
-  FX_STRSIZE len = CFX_WideString::WStringLength(title);
-  CFX_WideString encodedTitle = CFX_WideString::FromUTF16LE(title, len);
+  size_t len = WideString::WStringLength(title);
+  WideString encodedTitle = WideString::FromUTF16LE(title, len);
   std::set<CPDF_Dictionary*> visited;
   return FindBookmark(tree, CPDF_Bookmark(), encodedTitle, &visited).GetDict();
 }
 
-DLLEXPORT FPDF_DEST STDCALL FPDFBookmark_GetDest(FPDF_DOCUMENT document,
-                                                 FPDF_BOOKMARK pDict) {
+FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFBookmark_GetDest(FPDF_DOCUMENT document,
+                                                         FPDF_BOOKMARK pDict) {
   if (!pDict)
     return nullptr;
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
@@ -139,14 +128,15 @@
   return action.GetDest(pDoc).GetObject();
 }
 
-DLLEXPORT FPDF_ACTION STDCALL FPDFBookmark_GetAction(FPDF_BOOKMARK pDict) {
+FPDF_EXPORT FPDF_ACTION FPDF_CALLCONV
+FPDFBookmark_GetAction(FPDF_BOOKMARK pDict) {
   if (!pDict)
     return nullptr;
   CPDF_Bookmark bookmark(ToDictionary(static_cast<CPDF_Object*>(pDict)));
   return bookmark.GetAction().GetDict();
 }
 
-DLLEXPORT unsigned long STDCALL FPDFAction_GetType(FPDF_ACTION pDict) {
+FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetType(FPDF_ACTION pDict) {
   if (!pDict)
     return PDFACTION_UNSUPPORTED;
 
@@ -166,8 +156,8 @@
   }
 }
 
-DLLEXPORT FPDF_DEST STDCALL FPDFAction_GetDest(FPDF_DOCUMENT document,
-                                               FPDF_ACTION pDict) {
+FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFAction_GetDest(FPDF_DOCUMENT document,
+                                                       FPDF_ACTION pDict) {
   if (!pDict)
     return nullptr;
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
@@ -177,40 +167,40 @@
   return action.GetDest(pDoc).GetObject();
 }
 
-DLLEXPORT unsigned long STDCALL FPDFAction_GetFilePath(FPDF_ACTION pDict,
-                                                       void* buffer,
-                                                       unsigned long buflen) {
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDFAction_GetFilePath(FPDF_ACTION pDict, void* buffer, unsigned long buflen) {
   unsigned long type = FPDFAction_GetType(pDict);
   if (type != PDFACTION_REMOTEGOTO && type != PDFACTION_LAUNCH)
     return 0;
 
   CPDF_Action action(ToDictionary(static_cast<CPDF_Object*>(pDict)));
-  CFX_ByteString path = action.GetFilePath().UTF8Encode();
+  ByteString path = action.GetFilePath().UTF8Encode();
   unsigned long len = path.GetLength() + 1;
   if (buffer && len <= buflen)
-    FXSYS_memcpy(buffer, path.c_str(), len);
+    memcpy(buffer, path.c_str(), len);
   return len;
 }
 
-DLLEXPORT unsigned long STDCALL FPDFAction_GetURIPath(FPDF_DOCUMENT document,
-                                                      FPDF_ACTION pDict,
-                                                      void* buffer,
-                                                      unsigned long buflen) {
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDFAction_GetURIPath(FPDF_DOCUMENT document,
+                      FPDF_ACTION pDict,
+                      void* buffer,
+                      unsigned long buflen) {
   if (!pDict)
     return 0;
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
   if (!pDoc)
     return 0;
   CPDF_Action action(ToDictionary(static_cast<CPDF_Object*>(pDict)));
-  CFX_ByteString path = action.GetURI(pDoc);
+  ByteString path = action.GetURI(pDoc);
   unsigned long len = path.GetLength() + 1;
   if (buffer && len <= buflen)
-    FXSYS_memcpy(buffer, path.c_str(), len);
+    memcpy(buffer, path.c_str(), len);
   return len;
 }
 
-DLLEXPORT unsigned long STDCALL FPDFDest_GetPageIndex(FPDF_DOCUMENT document,
-                                                      FPDF_DEST pDict) {
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDFDest_GetPageIndex(FPDF_DOCUMENT document, FPDF_DEST pDict) {
   if (!pDict)
     return 0;
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
@@ -220,18 +210,36 @@
   return dest.GetPageIndex(pDoc);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDFDest_GetLocationInPage(FPDF_DEST pDict,
-                                                       FPDF_BOOL* hasXVal,
-                                                       FPDF_BOOL* hasYVal,
-                                                       FPDF_BOOL* hasZoomVal,
-                                                       FS_FLOAT* x,
-                                                       FS_FLOAT* y,
-                                                       FS_FLOAT* zoom) {
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDFDest_GetView(FPDF_DEST pDict,
+                 unsigned long* pNumParams,
+                 FS_FLOAT* pParams) {
+  if (!pDict) {
+    *pNumParams = 0;
+    return 0;
+  }
+
+  CPDF_Dest dest(static_cast<CPDF_Array*>(pDict));
+  unsigned long nParams = dest.GetNumParams();
+  ASSERT(nParams <= 4);
+  *pNumParams = nParams;
+  for (unsigned long i = 0; i < nParams; ++i)
+    pParams[i] = dest.GetParam(i);
+  return dest.GetZoomMode();
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFDest_GetLocationInPage(FPDF_DEST pDict,
+                           FPDF_BOOL* hasXVal,
+                           FPDF_BOOL* hasYVal,
+                           FPDF_BOOL* hasZoomVal,
+                           FS_FLOAT* x,
+                           FS_FLOAT* y,
+                           FS_FLOAT* zoom) {
   if (!pDict)
     return false;
 
-  std::unique_ptr<CPDF_Dest> dest(
-      new CPDF_Dest(static_cast<CPDF_Object*>(pDict)));
+  auto dest = pdfium::MakeUnique<CPDF_Dest>(static_cast<CPDF_Object*>(pDict));
 
   // FPDF_BOOL is an int, GetXYZ expects bools.
   bool bHasX;
@@ -246,9 +254,9 @@
   return true;
 }
 
-DLLEXPORT FPDF_LINK STDCALL FPDFLink_GetLinkAtPoint(FPDF_PAGE page,
-                                                    double x,
-                                                    double y) {
+FPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFLink_GetLinkAtPoint(FPDF_PAGE page,
+                                                            double x,
+                                                            double y) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!pPage)
     return nullptr;
@@ -258,15 +266,15 @@
     return nullptr;
 
   return pLinkList
-      ->GetLinkAtPoint(
-          pPage, CFX_PointF(static_cast<FX_FLOAT>(x), static_cast<FX_FLOAT>(y)),
-          nullptr)
+      ->GetLinkAtPoint(pPage,
+                       CFX_PointF(static_cast<float>(x), static_cast<float>(y)),
+                       nullptr)
       .GetDict();
 }
 
-DLLEXPORT int STDCALL FPDFLink_GetLinkZOrderAtPoint(FPDF_PAGE page,
-                                                    double x,
-                                                    double y) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetLinkZOrderAtPoint(FPDF_PAGE page,
+                                                            double x,
+                                                            double y) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!pPage)
     return -1;
@@ -277,13 +285,13 @@
 
   int z_order = -1;
   pLinkList->GetLinkAtPoint(
-      pPage, CFX_PointF(static_cast<FX_FLOAT>(x), static_cast<FX_FLOAT>(y)),
+      pPage, CFX_PointF(static_cast<float>(x), static_cast<float>(y)),
       &z_order);
   return z_order;
 }
 
-DLLEXPORT FPDF_DEST STDCALL FPDFLink_GetDest(FPDF_DOCUMENT document,
-                                             FPDF_LINK pDict) {
+FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFLink_GetDest(FPDF_DOCUMENT document,
+                                                     FPDF_LINK pDict) {
   if (!pDict)
     return nullptr;
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
@@ -300,7 +308,7 @@
   return action.GetDest(pDoc).GetObject();
 }
 
-DLLEXPORT FPDF_ACTION STDCALL FPDFLink_GetAction(FPDF_LINK pDict) {
+FPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDFLink_GetAction(FPDF_LINK pDict) {
   if (!pDict)
     return nullptr;
 
@@ -308,9 +316,9 @@
   return link.GetAction().GetDict();
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDFLink_Enumerate(FPDF_PAGE page,
-                                               int* startPos,
-                                               FPDF_LINK* linkAnnot) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_Enumerate(FPDF_PAGE page,
+                                                       int* startPos,
+                                                       FPDF_LINK* linkAnnot) {
   if (!startPos || !linkAnnot)
     return false;
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
@@ -333,21 +341,17 @@
   return false;
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDFLink_GetAnnotRect(FPDF_LINK linkAnnot,
-                                                  FS_RECTF* rect) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetAnnotRect(FPDF_LINK linkAnnot,
+                                                          FS_RECTF* rect) {
   if (!linkAnnot || !rect)
     return false;
   CPDF_Dictionary* pAnnotDict =
       ToDictionary(static_cast<CPDF_Object*>(linkAnnot));
-  CFX_FloatRect rt = pAnnotDict->GetRectFor("Rect");
-  rect->left = rt.left;
-  rect->bottom = rt.bottom;
-  rect->right = rt.right;
-  rect->top = rt.top;
+  FSRECTFFromCFXFloatRect(pAnnotDict->GetRectFor("Rect"), rect);
   return true;
 }
 
-DLLEXPORT int STDCALL FPDFLink_CountQuadPoints(FPDF_LINK linkAnnot) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountQuadPoints(FPDF_LINK linkAnnot) {
   if (!linkAnnot)
     return 0;
   CPDF_Dictionary* pAnnotDict =
@@ -358,9 +362,10 @@
   return static_cast<int>(pArray->GetCount() / 8);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDFLink_GetQuadPoints(FPDF_LINK linkAnnot,
-                                                   int quadIndex,
-                                                   FS_QUADPOINTSF* quadPoints) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFLink_GetQuadPoints(FPDF_LINK linkAnnot,
+                       int quadIndex,
+                       FS_QUADPOINTSF* quadPoints) {
   if (!linkAnnot || !quadPoints)
     return false;
   CPDF_Dictionary* pAnnotDict =
@@ -386,33 +391,35 @@
   return true;
 }
 
-DLLEXPORT unsigned long STDCALL FPDF_GetMetaText(FPDF_DOCUMENT document,
-                                                 FPDF_BYTESTRING tag,
-                                                 void* buffer,
-                                                 unsigned long buflen) {
+FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetMetaText(FPDF_DOCUMENT document,
+                                                         FPDF_BYTESTRING tag,
+                                                         void* buffer,
+                                                         unsigned long buflen) {
   if (!tag)
     return 0;
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
   if (!pDoc)
     return 0;
-  CPDF_Dictionary* pInfo = pDoc->GetInfo();
+  pDoc->LoadDocumentInfo();
+  const CPDF_Dictionary* pInfo = pDoc->GetInfo();
   if (!pInfo)
     return 0;
-  CFX_WideString text = pInfo->GetUnicodeTextFor(tag);
+  WideString text = pInfo->GetUnicodeTextFor(tag);
   return Utf16EncodeMaybeCopyAndReturnLength(text, buffer, buflen);
 }
 
-DLLEXPORT unsigned long STDCALL FPDF_GetPageLabel(FPDF_DOCUMENT document,
-                                                  int page_index,
-                                                  void* buffer,
-                                                  unsigned long buflen) {
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDF_GetPageLabel(FPDF_DOCUMENT document,
+                  int page_index,
+                  void* buffer,
+                  unsigned long buflen) {
   if (page_index < 0)
     return 0;
 
   // CPDF_PageLabel can deal with NULL |document|.
   CPDF_PageLabel label(CPDFDocumentFromFPDFDocument(document));
-  CFX_WideString str;
-  if (!label.GetLabel(page_index, &str))
-    return 0;
-  return Utf16EncodeMaybeCopyAndReturnLength(str, buffer, buflen);
+  Optional<WideString> str = label.GetLabel(page_index);
+  return str.has_value()
+             ? Utf16EncodeMaybeCopyAndReturnLength(str.value(), buffer, buflen)
+             : 0;
 }
diff --git a/fpdfsdk/fpdfdoc_embeddertest.cpp b/fpdfsdk/fpdfdoc_embeddertest.cpp
index 3666687..d346330 100644
--- a/fpdfsdk/fpdfdoc_embeddertest.cpp
+++ b/fpdfsdk/fpdfdoc_embeddertest.cpp
@@ -10,7 +10,6 @@
 #include "public/fpdf_edit.h"
 #include "public/fpdfview.h"
 #include "testing/embedder_test.h"
-#include "testing/fx_string_testhelpers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/test_support.h"
 
@@ -43,6 +42,65 @@
   EXPECT_EQ(0U, FPDFDest_GetPageIndex(document(), dest));
 }
 
+TEST_F(FPDFDocEmbeddertest, DestGetView) {
+  EXPECT_TRUE(OpenDocument("named_dests.pdf"));
+
+  unsigned long numParams;
+  FS_FLOAT params[4];
+
+  numParams = 42;
+  std::fill_n(params, 4, 42.4242f);
+  EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_UNKNOWN_MODE),
+            FPDFDest_GetView(nullptr, &numParams, params));
+  EXPECT_EQ(0U, numParams);
+  EXPECT_FLOAT_EQ(42.4242f, params[0]);
+
+  numParams = 42;
+  std::fill_n(params, 4, 42.4242f);
+  FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
+  EXPECT_TRUE(dest);
+  EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_XYZ),
+            FPDFDest_GetView(dest, &numParams, params));
+  EXPECT_EQ(3U, numParams);
+  EXPECT_FLOAT_EQ(0, params[0]);
+  EXPECT_FLOAT_EQ(0, params[1]);
+  EXPECT_FLOAT_EQ(1, params[2]);
+  EXPECT_FLOAT_EQ(42.4242f, params[3]);
+
+  numParams = 42;
+  std::fill_n(params, 4, 42.4242f);
+  dest = FPDF_GetNamedDestByName(document(), "Next");
+  EXPECT_TRUE(dest);
+  EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_FIT),
+            FPDFDest_GetView(dest, &numParams, params));
+  EXPECT_EQ(0U, numParams);
+  EXPECT_FLOAT_EQ(42.4242f, params[0]);
+
+  numParams = 42;
+  std::fill_n(params, 4, 42.4242f);
+  dest = FPDF_GetNamedDestByName(document(), "FirstAlternate");
+  EXPECT_TRUE(dest);
+  EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_XYZ),
+            FPDFDest_GetView(dest, &numParams, params));
+  EXPECT_EQ(3U, numParams);
+  EXPECT_FLOAT_EQ(200, params[0]);
+  EXPECT_FLOAT_EQ(400, params[1]);
+  EXPECT_FLOAT_EQ(800, params[2]);
+  EXPECT_FLOAT_EQ(42.4242f, params[3]);
+
+  numParams = 42;
+  std::fill_n(params, 4, 42.4242f);
+  dest = FPDF_GetNamedDestByName(document(), "LastAlternate");
+  EXPECT_TRUE(dest);
+  EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_XYZ),
+            FPDFDest_GetView(dest, &numParams, params));
+  EXPECT_EQ(3U, numParams);
+  EXPECT_FLOAT_EQ(0, params[0]);
+  EXPECT_FLOAT_EQ(0, params[1]);
+  EXPECT_FLOAT_EQ(-200, params[2]);
+  EXPECT_FLOAT_EQ(42.4242f, params[3]);
+}
+
 TEST_F(FPDFDocEmbeddertest, DestGetLocationInPage) {
   EXPECT_TRUE(OpenDocument("named_dests.pdf"));
 
@@ -126,16 +184,14 @@
   FPDF_BOOKMARK child = FPDFBookmark_GetFirstChild(document(), nullptr);
   EXPECT_TRUE(child);
   EXPECT_EQ(34u, FPDFBookmark_GetTitle(child, buf, sizeof(buf)));
-  EXPECT_EQ(CFX_WideString(L"A Good Beginning"),
-            CFX_WideString::FromUTF16LE(buf, 16));
+  EXPECT_EQ(WideString(L"A Good Beginning"), WideString::FromUTF16LE(buf, 16));
 
   EXPECT_EQ(nullptr, FPDFBookmark_GetFirstChild(document(), child));
 
   FPDF_BOOKMARK sibling = FPDFBookmark_GetNextSibling(document(), child);
   EXPECT_TRUE(sibling);
   EXPECT_EQ(28u, FPDFBookmark_GetTitle(sibling, buf, sizeof(buf)));
-  EXPECT_EQ(CFX_WideString(L"A Good Ending"),
-            CFX_WideString::FromUTF16LE(buf, 13));
+  EXPECT_EQ(WideString(L"A Good Ending"), WideString::FromUTF16LE(buf, 13));
 
   EXPECT_EQ(nullptr, FPDFBookmark_GetNextSibling(document(), sibling));
 }
@@ -153,8 +209,7 @@
   // Check that the string matches.
   unsigned short buf[128];
   EXPECT_EQ(34u, FPDFBookmark_GetTitle(child, buf, sizeof(buf)));
-  EXPECT_EQ(CFX_WideString(L"A Good Beginning"),
-            CFX_WideString::FromUTF16LE(buf, 16));
+  EXPECT_EQ(WideString(L"A Good Beginning"), WideString::FromUTF16LE(buf, 16));
 
   // Check that it is them same as the one returned by GetFirstChild.
   EXPECT_EQ(child, FPDFBookmark_GetFirstChild(document(), nullptr));
@@ -183,6 +238,71 @@
   EXPECT_EQ(0, FPDF_GetPageCount(document()));
 }
 
+TEST_F(FPDFDocEmbeddertest, GetMetaText) {
+  ASSERT_TRUE(OpenDocument("bug_601362.pdf"));
+
+  // Invalid document / tag results in 0.
+  unsigned short buf[128];
+  EXPECT_EQ(0u, FPDF_GetMetaText(document(), nullptr, buf, sizeof(buf)));
+  EXPECT_EQ(0u, FPDF_GetMetaText(nullptr, "", buf, sizeof(buf)));
+
+  // Tags that do not eixst results in an empty wide string.
+  EXPECT_EQ(2u, FPDF_GetMetaText(document(), "", buf, sizeof(buf)));
+  EXPECT_EQ(2u, FPDF_GetMetaText(document(), "foo", buf, sizeof(buf)));
+  ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Title", buf, sizeof(buf)));
+  ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Author", buf, sizeof(buf)));
+  ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Subject", buf, sizeof(buf)));
+  ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Keywords", buf, sizeof(buf)));
+  ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Producer", buf, sizeof(buf)));
+
+  constexpr wchar_t kExpectedCreator[] = L"Microsoft Word";
+  ASSERT_EQ(30u, FPDF_GetMetaText(document(), "Creator", buf, sizeof(buf)));
+  EXPECT_EQ(WideString(kExpectedCreator),
+            WideString::FromUTF16LE(buf, FXSYS_len(kExpectedCreator)));
+
+  constexpr wchar_t kExpectedCreationDate[] = L"D:20160411190039+00'00'";
+  ASSERT_EQ(48u,
+            FPDF_GetMetaText(document(), "CreationDate", buf, sizeof(buf)));
+  EXPECT_EQ(WideString(kExpectedCreationDate),
+            WideString::FromUTF16LE(buf, FXSYS_len(kExpectedCreationDate)));
+
+  constexpr wchar_t kExpectedModDate[] = L"D:20160411190039+00'00'";
+  ASSERT_EQ(48u, FPDF_GetMetaText(document(), "ModDate", buf, sizeof(buf)));
+  EXPECT_EQ(WideString(kExpectedModDate),
+            WideString::FromUTF16LE(buf, FXSYS_len(kExpectedModDate)));
+}
+
+TEST_F(FPDFDocEmbeddertest, GetMetaTextSameObjectNumber) {
+  ASSERT_TRUE(OpenDocument("annotation_highlight_square_with_ap.pdf"));
+
+  // The PDF has been edited. It has two %%EOF markers, and 2 objects numbered
+  // (1 0). Both objects are /Info dictionaries, but contain different data.
+  // Make sure ModDate is the date of the last modification.
+  unsigned short buf[128];
+  constexpr wchar_t kExpectedModDate[] = L"D:20170612232940-04'00'";
+  ASSERT_EQ(48u, FPDF_GetMetaText(document(), "ModDate", buf, sizeof(buf)));
+  EXPECT_EQ(WideString(kExpectedModDate),
+            WideString::FromUTF16LE(buf, FXSYS_len(kExpectedModDate)));
+}
+
+TEST_F(FPDFDocEmbeddertest, GetMetaTextInAttachmentFile) {
+  ASSERT_TRUE(OpenDocument("embedded_attachments.pdf"));
+
+  // Make sure this is the date from the PDF itself and not the attached PDF.
+  unsigned short buf[128];
+  constexpr wchar_t kExpectedModDate[] = L"D:20170712214448-07'00'";
+  ASSERT_EQ(48u, FPDF_GetMetaText(document(), "ModDate", buf, sizeof(buf)));
+  EXPECT_EQ(WideString(kExpectedModDate),
+            WideString::FromUTF16LE(buf, FXSYS_len(kExpectedModDate)));
+}
+
+TEST_F(FPDFDocEmbeddertest, GetMetaTextFromNewDocument) {
+  FPDF_DOCUMENT empty_doc = FPDF_CreateNewDocument();
+  unsigned short buf[128];
+  EXPECT_EQ(2u, FPDF_GetMetaText(empty_doc, "Title", buf, sizeof(buf)));
+  FPDF_CloseDocument(empty_doc);
+}
+
 TEST_F(FPDFDocEmbeddertest, NoPageLabels) {
   EXPECT_TRUE(OpenDocument("about_blank.pdf"));
   EXPECT_EQ(1, FPDF_GetPageCount(document()));
@@ -194,44 +314,48 @@
   EXPECT_TRUE(OpenDocument("page_labels.pdf"));
   EXPECT_EQ(7, FPDF_GetPageCount(document()));
 
+  // We do not request labels, when use FPDFAvail_IsXXXAvail.
+  // Flush all data, to allow read labels.
+  SetWholeFileAvailable();
+
   unsigned short buf[128];
   EXPECT_EQ(0u, FPDF_GetPageLabel(document(), -2, buf, sizeof(buf)));
   EXPECT_EQ(0u, FPDF_GetPageLabel(document(), -1, buf, sizeof(buf)));
 
-  const FX_WCHAR kExpectedPageLabel0[] = L"i";
+  const wchar_t kExpectedPageLabel0[] = L"i";
   ASSERT_EQ(4u, FPDF_GetPageLabel(document(), 0, buf, sizeof(buf)));
-  EXPECT_EQ(CFX_WideString(kExpectedPageLabel0),
-            CFX_WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel0)));
+  EXPECT_EQ(WideString(kExpectedPageLabel0),
+            WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel0)));
 
-  const FX_WCHAR kExpectedPageLabel1[] = L"ii";
+  const wchar_t kExpectedPageLabel1[] = L"ii";
   ASSERT_EQ(6u, FPDF_GetPageLabel(document(), 1, buf, sizeof(buf)));
-  EXPECT_EQ(CFX_WideString(kExpectedPageLabel1),
-            CFX_WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel1)));
+  EXPECT_EQ(WideString(kExpectedPageLabel1),
+            WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel1)));
 
-  const FX_WCHAR kExpectedPageLabel2[] = L"1";
+  const wchar_t kExpectedPageLabel2[] = L"1";
   ASSERT_EQ(4u, FPDF_GetPageLabel(document(), 2, buf, sizeof(buf)));
-  EXPECT_EQ(CFX_WideString(kExpectedPageLabel2),
-            CFX_WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel2)));
+  EXPECT_EQ(WideString(kExpectedPageLabel2),
+            WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel2)));
 
-  const FX_WCHAR kExpectedPageLabel3[] = L"2";
+  const wchar_t kExpectedPageLabel3[] = L"2";
   ASSERT_EQ(4u, FPDF_GetPageLabel(document(), 3, buf, sizeof(buf)));
-  EXPECT_EQ(CFX_WideString(kExpectedPageLabel3),
-            CFX_WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel3)));
+  EXPECT_EQ(WideString(kExpectedPageLabel3),
+            WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel3)));
 
-  const FX_WCHAR kExpectedPageLabel4[] = L"zzA";
+  const wchar_t kExpectedPageLabel4[] = L"zzA";
   ASSERT_EQ(8u, FPDF_GetPageLabel(document(), 4, buf, sizeof(buf)));
-  EXPECT_EQ(CFX_WideString(kExpectedPageLabel4),
-            CFX_WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel4)));
+  EXPECT_EQ(WideString(kExpectedPageLabel4),
+            WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel4)));
 
-  const FX_WCHAR kExpectedPageLabel5[] = L"zzB";
+  const wchar_t kExpectedPageLabel5[] = L"zzB";
   ASSERT_EQ(8u, FPDF_GetPageLabel(document(), 5, buf, sizeof(buf)));
-  EXPECT_EQ(CFX_WideString(kExpectedPageLabel5),
-            CFX_WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel5)));
+  EXPECT_EQ(WideString(kExpectedPageLabel5),
+            WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel5)));
 
-  const FX_WCHAR kExpectedPageLabel6[] = L"";
+  const wchar_t kExpectedPageLabel6[] = L"";
   ASSERT_EQ(2u, FPDF_GetPageLabel(document(), 6, buf, sizeof(buf)));
-  EXPECT_EQ(CFX_WideString(kExpectedPageLabel6),
-            CFX_WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel6)));
+  EXPECT_EQ(WideString(kExpectedPageLabel6),
+            WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel6)));
 
   ASSERT_EQ(0u, FPDF_GetPageLabel(document(), 7, buf, sizeof(buf)));
   ASSERT_EQ(0u, FPDF_GetPageLabel(document(), 8, buf, sizeof(buf)));
diff --git a/fpdfsdk/fpdfdoc_unittest.cpp b/fpdfsdk/fpdfdoc_unittest.cpp
index c63d6c2..b52cccf 100644
--- a/fpdfsdk/fpdfdoc_unittest.cpp
+++ b/fpdfsdk/fpdfdoc_unittest.cpp
@@ -58,10 +58,7 @@
   };
 
   void SetUp() override {
-    // We don't need page module or render module, but
-    // initialize them to keep the code sane.
-    CPDF_ModuleMgr* module_mgr = CPDF_ModuleMgr::Get();
-    module_mgr->InitPageModule();
+    CPDF_ModuleMgr::Get()->Init();
 
     m_pDoc = pdfium::MakeUnique<CPDF_TestPdfDocument>();
     m_pIndirectObjs = m_pDoc->GetHolder();
@@ -90,7 +87,7 @@
 
  protected:
   std::unique_ptr<CPDF_TestPdfDocument> m_pDoc;
-  CPDF_IndirectObjectHolder* m_pIndirectObjs;
+  UnownedPtr<CPDF_IndirectObjectHolder> m_pIndirectObjs;
   std::unique_ptr<CPDF_Dictionary> m_pRootObj;
 };
 
@@ -119,25 +116,25 @@
     auto bookmarks = CreateDictObjs(3);
 
     bookmarks[1].obj->SetNewFor<CPDF_String>("Title", L"Chapter 1");
-    bookmarks[1].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs,
+    bookmarks[1].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs.Get(),
                                                 bookmarks[0].num);
-    bookmarks[1].obj->SetNewFor<CPDF_Reference>("Next", m_pIndirectObjs,
+    bookmarks[1].obj->SetNewFor<CPDF_Reference>("Next", m_pIndirectObjs.Get(),
                                                 bookmarks[2].num);
 
     bookmarks[2].obj->SetNewFor<CPDF_String>("Title", L"Chapter 2");
-    bookmarks[2].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs,
+    bookmarks[2].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs.Get(),
                                                 bookmarks[0].num);
-    bookmarks[2].obj->SetNewFor<CPDF_Reference>("Prev", m_pIndirectObjs,
+    bookmarks[2].obj->SetNewFor<CPDF_Reference>("Prev", m_pIndirectObjs.Get(),
                                                 bookmarks[1].num);
 
     bookmarks[0].obj->SetNewFor<CPDF_Name>("Type", "Outlines");
     bookmarks[0].obj->SetNewFor<CPDF_Number>("Count", 2);
-    bookmarks[0].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs,
+    bookmarks[0].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs.Get(),
                                                 bookmarks[1].num);
-    bookmarks[0].obj->SetNewFor<CPDF_Reference>("Last", m_pIndirectObjs,
+    bookmarks[0].obj->SetNewFor<CPDF_Reference>("Last", m_pIndirectObjs.Get(),
                                                 bookmarks[2].num);
 
-    m_pRootObj->SetNewFor<CPDF_Reference>("Outlines", m_pIndirectObjs,
+    m_pRootObj->SetNewFor<CPDF_Reference>("Outlines", m_pIndirectObjs.Get(),
                                           bookmarks[0].num);
 
     // Title with no match.
@@ -162,25 +159,25 @@
     auto bookmarks = CreateDictObjs(3);
 
     bookmarks[1].obj->SetNewFor<CPDF_String>("Title", L"Chapter 1");
-    bookmarks[1].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs,
+    bookmarks[1].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs.Get(),
                                                 bookmarks[0].num);
-    bookmarks[1].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs,
+    bookmarks[1].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs.Get(),
                                                 bookmarks[2].num);
 
     bookmarks[2].obj->SetNewFor<CPDF_String>("Title", L"Chapter 2");
-    bookmarks[2].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs,
+    bookmarks[2].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs.Get(),
                                                 bookmarks[1].num);
-    bookmarks[2].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs,
+    bookmarks[2].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs.Get(),
                                                 bookmarks[1].num);
 
     bookmarks[0].obj->SetNewFor<CPDF_Name>("Type", "Outlines");
     bookmarks[0].obj->SetNewFor<CPDF_Number>("Count", 2);
-    bookmarks[0].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs,
+    bookmarks[0].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs.Get(),
                                                 bookmarks[1].num);
-    bookmarks[0].obj->SetNewFor<CPDF_Reference>("Last", m_pIndirectObjs,
+    bookmarks[0].obj->SetNewFor<CPDF_Reference>("Last", m_pIndirectObjs.Get(),
                                                 bookmarks[2].num);
 
-    m_pRootObj->SetNewFor<CPDF_Reference>("Outlines", m_pIndirectObjs,
+    m_pRootObj->SetNewFor<CPDF_Reference>("Outlines", m_pIndirectObjs.Get(),
                                           bookmarks[0].num);
 
     // Title with no match.
@@ -197,31 +194,31 @@
     auto bookmarks = CreateDictObjs(4);
 
     bookmarks[1].obj->SetNewFor<CPDF_String>("Title", L"Chapter 1");
-    bookmarks[1].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs,
+    bookmarks[1].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs.Get(),
                                                 bookmarks[0].num);
-    bookmarks[1].obj->SetNewFor<CPDF_Reference>("Next", m_pIndirectObjs,
+    bookmarks[1].obj->SetNewFor<CPDF_Reference>("Next", m_pIndirectObjs.Get(),
                                                 bookmarks[2].num);
 
     bookmarks[2].obj->SetNewFor<CPDF_String>("Title", L"Chapter 2");
-    bookmarks[2].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs,
+    bookmarks[2].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs.Get(),
                                                 bookmarks[0].num);
-    bookmarks[2].obj->SetNewFor<CPDF_Reference>("Next", m_pIndirectObjs,
+    bookmarks[2].obj->SetNewFor<CPDF_Reference>("Next", m_pIndirectObjs.Get(),
                                                 bookmarks[3].num);
 
     bookmarks[3].obj->SetNewFor<CPDF_String>("Title", L"Chapter 3");
-    bookmarks[3].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs,
+    bookmarks[3].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs.Get(),
                                                 bookmarks[0].num);
-    bookmarks[3].obj->SetNewFor<CPDF_Reference>("Next", m_pIndirectObjs,
+    bookmarks[3].obj->SetNewFor<CPDF_Reference>("Next", m_pIndirectObjs.Get(),
                                                 bookmarks[1].num);
 
     bookmarks[0].obj->SetNewFor<CPDF_Name>("Type", "Outlines");
     bookmarks[0].obj->SetNewFor<CPDF_Number>("Count", 2);
-    bookmarks[0].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs,
+    bookmarks[0].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs.Get(),
                                                 bookmarks[1].num);
-    bookmarks[0].obj->SetNewFor<CPDF_Reference>("Last", m_pIndirectObjs,
+    bookmarks[0].obj->SetNewFor<CPDF_Reference>("Last", m_pIndirectObjs.Get(),
                                                 bookmarks[2].num);
 
-    m_pRootObj->SetNewFor<CPDF_Reference>("Outlines", m_pIndirectObjs,
+    m_pRootObj->SetNewFor<CPDF_Reference>("Outlines", m_pIndirectObjs.Get(),
                                           bookmarks[0].num);
 
     // Title with no match.
diff --git a/fpdfsdk/fpdfedit_embeddertest.cpp b/fpdfsdk/fpdfedit_embeddertest.cpp
index 53554a1..ee2fc7e 100644
--- a/fpdfsdk/fpdfedit_embeddertest.cpp
+++ b/fpdfsdk/fpdfedit_embeddertest.cpp
@@ -4,14 +4,19 @@
 
 #include <memory>
 #include <string>
+#include <utility>
+#include <vector>
 
 #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_number.h"
 #include "core/fpdfapi/parser/cpdf_stream.h"
 #include "core/fxcrt/fx_system.h"
 #include "fpdfsdk/fsdk_define.h"
+#include "public/cpp/fpdf_deleters.h"
+#include "public/fpdf_annot.h"
 #include "public/fpdf_edit.h"
 #include "public/fpdfview.h"
 #include "testing/embedder_test.h"
@@ -19,7 +24,113 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/test_support.h"
 
-class FPDFEditEmbeddertest : public EmbedderTest, public TestSaver {};
+class FPDFEditEmbeddertest : public EmbedderTest {
+ protected:
+  FPDF_DOCUMENT CreateNewDocument() {
+    document_ = FPDF_CreateNewDocument();
+    cpdf_doc_ = CPDFDocumentFromFPDFDocument(document_);
+    return document_;
+  }
+
+  void CheckFontDescriptor(CPDF_Dictionary* font_dict,
+                           int font_type,
+                           bool bold,
+                           bool italic,
+                           uint32_t size,
+                           const uint8_t* data) {
+    CPDF_Dictionary* font_desc = font_dict->GetDictFor("FontDescriptor");
+    ASSERT_TRUE(font_desc);
+    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 spec
+    // 1.7 Table 5.19
+    ASSERT_TRUE(font_desc->KeyExist("Flags"));
+
+    int font_flags = font_desc->GetIntegerFor("Flags");
+    EXPECT_EQ(bold, FontStyleIsBold(font_flags));
+    EXPECT_EQ(italic, FontStyleIsItalic(font_flags));
+    EXPECT_TRUE(FontStyleIsNonSymbolic(font_flags));
+    ASSERT_TRUE(font_desc->KeyExist("FontBBox"));
+
+    CPDF_Array* fontBBox = font_desc->GetArrayFor("FontBBox");
+    ASSERT_TRUE(fontBBox);
+    EXPECT_EQ(4U, fontBBox->GetCount());
+    // Check that the coordinates are in the preferred order according to spec
+    // 1.7 Section 3.8.4
+    EXPECT_TRUE(fontBBox->GetIntegerAt(0) < fontBBox->GetIntegerAt(2));
+    EXPECT_TRUE(fontBBox->GetIntegerAt(1) < fontBBox->GetIntegerAt(3));
+
+    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"));
+    ByteString present("FontFile");
+    ByteString absent("FontFile2");
+    if (font_type == FPDF_FONT_TRUETYPE)
+      std::swap(present, absent);
+    EXPECT_TRUE(font_desc->KeyExist(present));
+    EXPECT_FALSE(font_desc->KeyExist(absent));
+
+    // Check that the font stream is the one that was provided
+    CPDF_Stream* font_stream = font_desc->GetStreamFor(present);
+    ASSERT_EQ(size, font_stream->GetRawSize());
+    if (font_type == FPDF_FONT_TRUETYPE) {
+      ASSERT_EQ(static_cast<int>(size),
+                font_stream->GetDict()->GetIntegerFor("Length1"));
+    }
+    uint8_t* stream_data = font_stream->GetRawData();
+    for (size_t j = 0; j < size; j++)
+      EXPECT_EQ(data[j], stream_data[j]) << " at byte " << j;
+  }
+
+  void CheckCompositeFontWidths(CPDF_Array* widths_array,
+                                CPDF_Font* typed_font) {
+    // Check that W array is in a format that conforms to PDF spec 1.7 section
+    // "Glyph Metrics in CIDFonts" (these checks are not
+    // implementation-specific).
+    EXPECT_GT(widths_array->GetCount(), 1U);
+    int num_cids_checked = 0;
+    int cur_cid = 0;
+    for (size_t idx = 0; idx < widths_array->GetCount(); idx++) {
+      int cid = widths_array->GetNumberAt(idx);
+      EXPECT_GE(cid, cur_cid);
+      ASSERT_FALSE(++idx == widths_array->GetCount());
+      CPDF_Object* next = widths_array->GetObjectAt(idx);
+      if (next->IsArray()) {
+        // We are in the c [w1 w2 ...] case
+        CPDF_Array* arr = next->AsArray();
+        int cnt = static_cast<int>(arr->GetCount());
+        size_t inner_idx = 0;
+        for (cur_cid = cid; cur_cid < cid + cnt; cur_cid++) {
+          int width = arr->GetNumberAt(inner_idx++);
+          EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid)) << " at cid "
+                                                               << cur_cid;
+        }
+        num_cids_checked += cnt;
+        continue;
+      }
+      // Otherwise, are in the c_first c_last w case.
+      ASSERT_TRUE(next->IsNumber());
+      int last_cid = next->AsNumber()->GetInteger();
+      ASSERT_FALSE(++idx == widths_array->GetCount());
+      int width = widths_array->GetNumberAt(idx);
+      for (cur_cid = cid; cur_cid <= last_cid; cur_cid++) {
+        EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid)) << " at cid "
+                                                             << cur_cid;
+      }
+      num_cids_checked += last_cid - cid + 1;
+    }
+    // Make sure we have a good amount of cids described
+    EXPECT_GT(num_cids_checked, 900);
+  }
+  CPDF_Document* cpdf_doc() { return cpdf_doc_; }
+
+ private:
+  CPDF_Document* cpdf_doc_;
+};
 
 namespace {
 
@@ -36,15 +147,13 @@
     "<</CreationDate\\(D:.*\\)/Creator\\(PDFium\\)>>\r\n"
     "endobj\r\n"
     "4 0 obj\r\n"
-    "<</Contents 5 0 R /MediaBox\\[ 0 0 640 480\\]"
-    "/Parent 2 0 R /Resources<<>>/Rotate 0/Type/Page"
+    "<</MediaBox\\[ 0 0 640 480\\]/Parent 2 0 R "
+    "/Resources<</ExtGState<</FXE1 5 0 R >>>>"
+    "/Rotate 0/Type/Page"
     ">>\r\n"
     "endobj\r\n"
     "5 0 obj\r\n"
-    "<</Filter/FlateDecode/Length 8>>stream\r\n"
-    // Character '_' is matching '\0' (see comment below).
-    "x\x9C\x3____\x1\r\n"
-    "endstream\r\n"
+    "<</BM/Normal/CA 1/ca 1>>\r\n"
     "endobj\r\n"
     "xref\r\n"
     "0 6\r\n"
@@ -53,47 +162,28 @@
     "0000000066 00000 n\r\n"
     "0000000122 00000 n\r\n"
     "0000000192 00000 n\r\n"
-    "0000000301 00000 n\r\n"
+    "0000000311 00000 n\r\n"
     "trailer\r\n"
     "<<\r\n"
     "/Root 1 0 R\r\n"
     "/Info 3 0 R\r\n"
     "/Size 6/ID\\[<.*><.*>\\]>>\r\n"
     "startxref\r\n"
-    "379\r\n"
+    "354\r\n"
     "%%EOF\r\n";
 
-int GetBlockFromString(void* param,
-                       unsigned long pos,
-                       unsigned char* buf,
-                       unsigned long size) {
-  std::string* new_file = static_cast<std::string*>(param);
-  if (!new_file || pos + size < pos)
-    return 0;
-
-  unsigned long file_size = new_file->size();
-  if (pos + size > file_size)
-    return 0;
-
-  memcpy(buf, new_file->data() + pos, size);
-  return 1;
-}
-
 }  // namespace
 
 TEST_F(FPDFEditEmbeddertest, EmptyCreation) {
   EXPECT_TRUE(CreateEmptyDocument());
   FPDF_PAGE page = FPDFPage_New(document(), 0, 640.0, 480.0);
   EXPECT_NE(nullptr, page);
+  // The FPDFPage_GenerateContent call should do nothing.
   EXPECT_TRUE(FPDFPage_GenerateContent(page));
   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
 
-  // The MatchesRegexp doesn't support embedded NUL ('\0') characters. They are
-  // replaced by '_' for the purpose of the test.
-  std::string result = GetString();
-  std::replace(result.begin(), result.end(), '\0', '_');
-  EXPECT_THAT(result, testing::MatchesRegex(
-                          std::string(kExpectedPDF, sizeof(kExpectedPDF))));
+  EXPECT_THAT(GetString(), testing::MatchesRegex(std::string(
+                               kExpectedPDF, sizeof(kExpectedPDF))));
   FPDF_ClosePage(page);
 }
 
@@ -119,7 +209,7 @@
 
     // Add the bitmap to an image object and add the image object to the output
     // page.
-    FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImgeObj(temp_doc);
+    FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImageObj(temp_doc);
     EXPECT_TRUE(FPDFImageObj_SetBitmap(&temp_page, 1, temp_img, orig_bitmap));
     EXPECT_TRUE(FPDFImageObj_SetMatrix(temp_img, 612, 0, 0, 792, 0, 0));
     FPDFPage_InsertObject(temp_page, temp_img);
@@ -132,33 +222,13 @@
 
   // Get the generated content. Make sure it is at least as big as the original
   // PDF.
-  std::string new_file = GetString();
-  EXPECT_GT(new_file.size(), 923U);
-
-  // Read |new_file| in, and verify its rendered bitmap.
-  {
-    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);
-    EXPECT_EQ(1, FPDF_GetPageCount(document_));
-    FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
-    EXPECT_NE(nullptr, new_page);
-    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);
-  }
+  EXPECT_GT(GetString().size(), 923U);
+  VerifySavedDocument(612, 792, kAllBlackMd5sum);
 }
 
 TEST_F(FPDFEditEmbeddertest, AddPaths) {
   // Start with a blank page
-  FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
-  FPDF_PAGE page = FPDFPage_New(doc, 0, 612, 792);
+  FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
 
   // We will first add a red rectangle
   FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
@@ -171,7 +241,6 @@
   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);
@@ -179,9 +248,60 @@
   // 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));
+
+  // Make sure the type of the rectangle is a path.
+  EXPECT_EQ(FPDF_PAGEOBJ_PATH, FPDFPageObj_GetType(green_rect));
+
+  // Make sure we get back the same color we set previously.
+  unsigned int R;
+  unsigned int G;
+  unsigned int B;
+  unsigned int A;
+  EXPECT_TRUE(FPDFPath_GetFillColor(green_rect, &R, &G, &B, &A));
+  EXPECT_EQ(0U, R);
+  EXPECT_EQ(255U, G);
+  EXPECT_EQ(0U, B);
+  EXPECT_EQ(128U, A);
+
+  // Make sure the path has 5 points (1 FXPT_TYPE::MoveTo and 4
+  // FXPT_TYPE::LineTo).
+  ASSERT_EQ(5, FPDFPath_CountSegments(green_rect));
+  // Verify actual coordinates.
+  FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(green_rect, 0);
+  float x;
+  float y;
+  EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
+  EXPECT_EQ(100, x);
+  EXPECT_EQ(100, y);
+  EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
+  EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
+  segment = FPDFPath_GetPathSegment(green_rect, 1);
+  EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
+  EXPECT_EQ(100, x);
+  EXPECT_EQ(140, y);
+  EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
+  EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
+  segment = FPDFPath_GetPathSegment(green_rect, 2);
+  EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
+  EXPECT_EQ(140, x);
+  EXPECT_EQ(140, y);
+  EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
+  EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
+  segment = FPDFPath_GetPathSegment(green_rect, 3);
+  EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
+  EXPECT_EQ(140, x);
+  EXPECT_EQ(100, y);
+  EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
+  EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
+  segment = FPDFPath_GetPathSegment(green_rect, 4);
+  EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
+  EXPECT_EQ(100, x);
+  EXPECT_EQ(100, y);
+  EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
+  EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
+
   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);
@@ -193,8 +313,33 @@
   EXPECT_TRUE(FPDFPath_LineTo(black_path, 400, 200));
   EXPECT_TRUE(FPDFPath_LineTo(black_path, 300, 100));
   EXPECT_TRUE(FPDFPath_Close(black_path));
+
+  // Make sure the path has 3 points (1 FXPT_TYPE::MoveTo and 2
+  // FXPT_TYPE::LineTo).
+  ASSERT_EQ(3, FPDFPath_CountSegments(black_path));
+  // Verify actual coordinates.
+  segment = FPDFPath_GetPathSegment(black_path, 0);
+  EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
+  EXPECT_EQ(400, x);
+  EXPECT_EQ(100, y);
+  EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
+  EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
+  segment = FPDFPath_GetPathSegment(black_path, 1);
+  EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
+  EXPECT_EQ(400, x);
+  EXPECT_EQ(200, y);
+  EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
+  EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
+  segment = FPDFPath_GetPathSegment(black_path, 2);
+  EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
+  EXPECT_EQ(300, x);
+  EXPECT_EQ(100, y);
+  EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
+  EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
+  // Make sure out of bounds index access fails properly.
+  EXPECT_EQ(nullptr, FPDFPath_GetPathSegment(black_path, 3));
+
   FPDFPage_InsertObject(page, black_path);
-  EXPECT_TRUE(FPDFPage_GenerateContent(page));
   page_bitmap = RenderPage(page);
   CompareBitmap(page_bitmap, 612, 792, "eadc8020a14dfcf091da2688733d8806");
   FPDFBitmap_Destroy(page_bitmap);
@@ -210,33 +355,45 @@
   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");
+  const char last_md5[] = "9823e1a21bd9b72b6a442ba4f12af946";
+  CompareBitmap(page_bitmap, 612, 792, last_md5);
   FPDFBitmap_Destroy(page_bitmap);
 
   // Now save the result, closing the page and document
-  EXPECT_TRUE(FPDF_SaveAsCopy(doc, this, 0));
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  EXPECT_TRUE(FPDF_SaveAsCopy(document(), 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);
+  VerifySavedDocument(612, 792, last_md5);
+}
+
+TEST_F(FPDFEditEmbeddertest, PathsPoints) {
+  CreateNewDocument();
+  FPDF_PAGEOBJECT img = FPDFPageObj_NewImageObj(document_);
+  // This should fail gracefully, even if img is not a path.
+  ASSERT_EQ(-1, FPDFPath_CountSegments(img));
+
+  // This should fail gracefully, even if path is NULL.
+  ASSERT_EQ(-1, FPDFPath_CountSegments(nullptr));
+
+  // FPDFPath_GetPathSegment() with a non-path.
+  ASSERT_EQ(nullptr, FPDFPath_GetPathSegment(img, 0));
+  // FPDFPath_GetPathSegment() with a NULL path.
+  ASSERT_EQ(nullptr, FPDFPath_GetPathSegment(nullptr, 0));
+  float x;
+  float y;
+  // FPDFPathSegment_GetPoint() with a NULL segment.
+  EXPECT_FALSE(FPDFPathSegment_GetPoint(nullptr, &x, &y));
+
+  // FPDFPathSegment_GetType() with a NULL segment.
+  ASSERT_EQ(FPDF_SEGMENT_UNKNOWN, FPDFPathSegment_GetType(nullptr));
+
+  // FPDFPathSegment_GetClose() with a NULL segment.
+  EXPECT_FALSE(FPDFPathSegment_GetClose(nullptr));
+
+  FPDFPageObj_Destroy(img);
 }
 
 TEST_F(FPDFEditEmbeddertest, PathOnTopOfText) {
@@ -250,7 +407,6 @@
   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);
@@ -260,24 +416,81 @@
   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";
+#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+  const char md5[] = "f9e6fa74230f234286bfcada9f7606d8";
 #else
-  const char md5[] = "17c942c76ff229200f2c98073bb60d85";
+  const char md5[] = "aa71b09b93b55f467f1290e5111babee";
 #endif
   CompareBitmap(bitmap, 200, 200, md5);
   FPDFBitmap_Destroy(bitmap);
   UnloadPage(page);
 }
 
+TEST_F(FPDFEditEmbeddertest, EditOverExistingContent) {
+  // Load document with existing content
+  EXPECT_TRUE(OpenDocument("bug_717.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  EXPECT_NE(nullptr, page);
+
+  // Add a transparent rectangle on top of the existing content
+  FPDF_PAGEOBJECT red_rect2 = FPDFPageObj_CreateNewRect(90, 700, 25, 50);
+  EXPECT_TRUE(FPDFPath_SetFillColor(red_rect2, 255, 0, 0, 100));
+  EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect2, FPDF_FILLMODE_ALTERNATE, 0));
+  FPDFPage_InsertObject(page, red_rect2);
+
+  // Add an opaque rectangle on top of the existing content
+  FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(115, 700, 25, 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);
+
+  FPDF_BITMAP bitmap = RenderPage(page);
+  CompareBitmap(bitmap, 612, 792, "ad04e5bd0f471a9a564fb034bd0fb073");
+  FPDFBitmap_Destroy(bitmap);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+
+  // Now save the result, closing the page and document
+  EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+  UnloadPage(page);
+
+  OpenSavedDocument();
+  page = LoadSavedPage(0);
+  VerifySavedRendering(page, 612, 792, "ad04e5bd0f471a9a564fb034bd0fb073");
+
+  ClearString();
+  // Add another opaque rectangle on top of the existing content
+  FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(150, 700, 25, 50);
+  EXPECT_TRUE(FPDFPath_SetFillColor(green_rect, 0, 255, 0, 255));
+  EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_ALTERNATE, 0));
+  FPDFPage_InsertObject(page, green_rect);
+
+  // Add another transparent rectangle on top of existing content
+  FPDF_PAGEOBJECT green_rect2 = FPDFPageObj_CreateNewRect(175, 700, 25, 50);
+  EXPECT_TRUE(FPDFPath_SetFillColor(green_rect2, 0, 255, 0, 100));
+  EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect2, FPDF_FILLMODE_ALTERNATE, 0));
+  FPDFPage_InsertObject(page, green_rect2);
+  FPDF_BITMAP new_bitmap = RenderPageWithFlags(page, m_SavedForm, 0);
+  const char last_md5[] = "4b5b00f824620f8c9b8801ebb98e1cdd";
+  CompareBitmap(new_bitmap, 612, 792, last_md5);
+  FPDFBitmap_Destroy(new_bitmap);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+
+  // Now save the result, closing the page and document
+  EXPECT_TRUE(FPDF_SaveAsCopy(m_SavedDocument, this, 0));
+
+  CloseSavedPage(page);
+  CloseSavedDocument();
+
+  // Render the saved result
+  VerifySavedDocument(612, 792, last_md5);
+}
+
 TEST_F(FPDFEditEmbeddertest, AddStrokedPaths) {
   // Start with a blank page
-  FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
-  FPDF_PAGE page = FPDFPage_New(doc, 0, 612, 792);
+  FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
 
   // Add a large stroked rectangle (fill color should not affect it).
   FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(20, 20, 200, 400);
@@ -286,7 +499,6 @@
   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);
@@ -301,7 +513,6 @@
   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);
@@ -317,64 +528,70 @@
   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);
+  FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 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_PAGEOBJECT text_object1 =
+      FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
+  EXPECT_TRUE(text_object1);
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text1 =
+      GetFPDFWideString(L"I'm at the bottom of the page");
+  EXPECT_TRUE(FPDFText_SetText(text_object1, text1.get()));
+  FPDFPageObj_Transform(text_object1, 1, 0, 0, 1, 20, 20);
+  FPDFPage_InsertObject(page, text_object1);
   FPDF_BITMAP page_bitmap = RenderPage(page);
-#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
-  const char md5[] = "e19c90395d73cb9f37a6c3b0e8b18a9e";
+#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+  const char md5[] = "a4dddc1a3930fa694bbff9789dab4161";
 #else
-  const char md5[] = "7c3a36ba7cec01688a16a14bfed9ecfc";
+  const char md5[] = "eacaa24573b8ce997b3882595f096f00";
 #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));
+  FPDF_PAGEOBJECT text_object2 =
+      FPDFPageObj_NewTextObj(document(), "TimesNewRomanBold", 15.0f);
+  EXPECT_TRUE(text_object2);
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
+      GetFPDFWideString(L"Hi, I'm Bold. Times New Roman Bold.");
+  EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
+  FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 600);
+  FPDFPage_InsertObject(page, text_object2);
   page_bitmap = RenderPage(page);
-#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
-  const char md5_2[] = "8e1c43dca6be68d364dbc283f5521041";
+#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+  const char md5_2[] = "a5c4ace4c6f27644094813fe1441a21c";
+#elif _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+  const char md5_2[] = "2587eac9a787e97a37636d54d11bd28d";
 #else
-  const char md5_2[] = "e0e0873e3a2634a6394a431a51ce90ff";
+  const char md5_2[] = "76fcc7d08aa15445efd2e2ceb7c6cc3b";
 #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));
+  FPDF_PAGEOBJECT text_object3 =
+      FPDFPageObj_NewTextObj(document(), "Courier-Bold", 20.0f);
+  EXPECT_TRUE(text_object3);
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text3 =
+      GetFPDFWideString(L"Can you read me? <:)>");
+  EXPECT_TRUE(FPDFText_SetText(text_object3, text3.get()));
+  FPDFPageObj_Transform(text_object3, 1, 1.5, 2, 0.5, 200, 200);
+  FPDFPage_InsertObject(page, text_object3);
   page_bitmap = RenderPage(page);
-#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
-  const char md5_3[] = "c6e5df448428793c7e4b0c820bd8c85e";
+#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+  const char md5_3[] = "40b3ef04f915ff4c4208948001763544";
+#elif _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+  const char md5_3[] = "7cb61ec112cf400b489360d443ffc9d2";
 #else
-  const char md5_3[] = "903ee10b6a9f0be51ecad0a1a0eeb171";
+  const char md5_3[] = "b8a21668f1dab625af7c072e07fcefc4";
 #endif
   CompareBitmap(page_bitmap, 612, 792, md5_3);
   FPDFBitmap_Destroy(page_bitmap);
@@ -382,13 +599,65 @@
   // 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, GraphicsData) {
+  // New page
+  std::unique_ptr<void, FPDFPageDeleter> page(
+      FPDFPage_New(CreateNewDocument(), 0, 612, 792));
+
+  // Create a rect with nontrivial graphics
+  FPDF_PAGEOBJECT rect1 = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
+  FPDFPageObj_SetBlendMode(rect1, "Color");
+  FPDFPage_InsertObject(page.get(), rect1);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
+
+  // Check that the ExtGState was created
+  CPDF_Page* the_page = CPDFPageFromFPDFPage(page.get());
+  CPDF_Dictionary* graphics_dict =
+      the_page->m_pResources->GetDictFor("ExtGState");
+  ASSERT_TRUE(graphics_dict);
+  EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
+
+  // Add a text object causing no change to the graphics dictionary
+  FPDF_PAGEOBJECT text1 = FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
+  // Only alpha, the last component, matters for the graphics dictionary. And
+  // the default value is 255.
+  EXPECT_TRUE(FPDFText_SetFillColor(text1, 100, 100, 100, 255));
+  FPDFPage_InsertObject(page.get(), text1);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
+  EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
+
+  // Add a text object increasing the size of the graphics dictionary
+  FPDF_PAGEOBJECT text2 =
+      FPDFPageObj_NewTextObj(document(), "Times-Roman", 12.0f);
+  FPDFPage_InsertObject(page.get(), text2);
+  FPDFPageObj_SetBlendMode(text2, "Darken");
+  EXPECT_TRUE(FPDFText_SetFillColor(text2, 0, 0, 255, 150));
+  EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
+  EXPECT_EQ(3, static_cast<int>(graphics_dict->GetCount()));
+
+  // Add a path that should reuse graphics
+  FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(400, 100);
+  FPDFPageObj_SetBlendMode(path, "Darken");
+  EXPECT_TRUE(FPDFPath_SetFillColor(path, 200, 200, 100, 150));
+  FPDFPage_InsertObject(page.get(), path);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
+  EXPECT_EQ(3, static_cast<int>(graphics_dict->GetCount()));
+
+  // Add a rect increasing the size of the graphics dictionary
+  FPDF_PAGEOBJECT rect2 = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
+  FPDFPageObj_SetBlendMode(rect2, "Darken");
+  EXPECT_TRUE(FPDFPath_SetFillColor(rect2, 0, 0, 255, 150));
+  EXPECT_TRUE(FPDFPath_SetStrokeColor(rect2, 0, 0, 0, 200));
+  FPDFPage_InsertObject(page.get(), rect2);
+  EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
+  EXPECT_EQ(4, static_cast<int>(graphics_dict->GetCount()));
 }
 
 TEST_F(FPDFEditEmbeddertest, DoubleGenerating) {
   // Start with a blank page
-  FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
-  FPDF_PAGE page = FPDFPage_New(doc, 0, 612, 792);
+  FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
 
   // Add a red rectangle with some non-default alpha
   FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
@@ -402,7 +671,7 @@
   CPDF_Dictionary* graphics_dict =
       the_page->m_pResources->GetDictFor("ExtGState");
   ASSERT_TRUE(graphics_dict);
-  EXPECT_EQ(1, static_cast<int>(graphics_dict->GetCount()));
+  EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
 
   // Check the bitmap
   FPDF_BITMAP page_bitmap = RenderPage(page);
@@ -412,7 +681,7 @@
   // 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()));
+  EXPECT_EQ(3, static_cast<int>(graphics_dict->GetCount()));
 
   // Check that bitmap displays changed content
   page_bitmap = RenderPage(page);
@@ -421,16 +690,19 @@
 
   // And now generate, without changes
   EXPECT_TRUE(FPDFPage_GenerateContent(page));
-  EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
+  EXPECT_EQ(3, 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);
+  FPDF_PAGEOBJECT text_object =
+      FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
+      GetFPDFWideString(L"Something something #text# something");
+  EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
+  FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 300, 300);
+  FPDFPage_InsertObject(page, text_object);
   EXPECT_TRUE(FPDFPage_GenerateContent(page));
   CPDF_Dictionary* font_dict = the_page->m_pResources->GetDictFor("Font");
   ASSERT_TRUE(font_dict);
@@ -438,68 +710,530 @@
 
   // Generate yet again, check dicts are reasonably sized
   EXPECT_TRUE(FPDFPage_GenerateContent(page));
-  EXPECT_EQ(2, static_cast<int>(graphics_dict->GetCount()));
+  EXPECT_EQ(3, 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);
+TEST_F(FPDFEditEmbeddertest, LoadSimpleType1Font) {
+  CreateNewDocument();
+  // TODO(npm): use other fonts after disallowing loading any font as any type
+  const CPDF_Font* stock_font =
+      CPDF_Font::GetStockFont(cpdf_doc(), "Times-Bold");
+  const uint8_t* data = stock_font->GetFont()->GetFontData();
+  const uint32_t size = stock_font->GetFont()->GetSize();
+  std::unique_ptr<void, FPDFFontDeleter> font(
+      FPDFText_LoadFont(document(), data, size, FPDF_FONT_TYPE1, false));
+  ASSERT_TRUE(font.get());
+  CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
+  EXPECT_TRUE(typed_font->IsType1Font());
 
-  // 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();
+  CPDF_Dictionary* font_dict = typed_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"));
+  EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
+
   CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
-  EXPECT_EQ(65501U, widths_array->GetCount());
+  ASSERT_TRUE(widths_array);
+  ASSERT_EQ(224U, 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"));
+  EXPECT_EQ(569, widths_array->GetNumberAt(11));
+  EXPECT_EQ(500, widths_array->GetNumberAt(223));
+  CheckFontDescriptor(font_dict, FPDF_FONT_TYPE1, true, false, size, data);
+}
 
-  // 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"));
+TEST_F(FPDFEditEmbeddertest, LoadSimpleTrueTypeFont) {
+  CreateNewDocument();
+  const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Courier");
+  const uint8_t* data = stock_font->GetFont()->GetFontData();
+  const uint32_t size = stock_font->GetFont()->GetSize();
+  std::unique_ptr<void, FPDFFontDeleter> font(
+      FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, false));
+  ASSERT_TRUE(font.get());
+  CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
+  EXPECT_TRUE(typed_font->IsTrueTypeFont());
 
-  // 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]);
+  CPDF_Dictionary* font_dict = typed_font->GetFontDict();
+  EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
+  EXPECT_EQ("TrueType", font_dict->GetStringFor("Subtype"));
+  EXPECT_EQ("Courier New", 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(255, font_dict->GetIntegerFor("LastChar"));
 
-  // Close document
-  FPDF_CloseDocument(doc);
+  CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
+  ASSERT_TRUE(widths_array);
+  ASSERT_EQ(224U, widths_array->GetCount());
+  EXPECT_EQ(600, widths_array->GetNumberAt(33));
+  EXPECT_EQ(600, widths_array->GetNumberAt(74));
+  EXPECT_EQ(600, widths_array->GetNumberAt(223));
+  CheckFontDescriptor(font_dict, FPDF_FONT_TRUETYPE, false, false, size, data);
+}
+
+TEST_F(FPDFEditEmbeddertest, LoadCIDType0Font) {
+  CreateNewDocument();
+  const CPDF_Font* stock_font =
+      CPDF_Font::GetStockFont(cpdf_doc(), "Times-Roman");
+  const uint8_t* data = stock_font->GetFont()->GetFontData();
+  const uint32_t size = stock_font->GetFont()->GetSize();
+  std::unique_ptr<void, FPDFFontDeleter> font(
+      FPDFText_LoadFont(document(), data, size, FPDF_FONT_TYPE1, 1));
+  ASSERT_TRUE(font.get());
+  CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
+  EXPECT_TRUE(typed_font->IsCIDFont());
+
+  // Check font dictionary entries
+  CPDF_Dictionary* font_dict = typed_font->GetFontDict();
+  EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
+  EXPECT_EQ("Type0", font_dict->GetStringFor("Subtype"));
+  EXPECT_EQ("Times New Roman-Identity-H", font_dict->GetStringFor("BaseFont"));
+  EXPECT_EQ("Identity-H", font_dict->GetStringFor("Encoding"));
+  CPDF_Array* descendant_array = font_dict->GetArrayFor("DescendantFonts");
+  ASSERT_TRUE(descendant_array);
+  EXPECT_EQ(1U, descendant_array->GetCount());
+
+  // Check the CIDFontDict
+  CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
+  EXPECT_EQ("Font", cidfont_dict->GetStringFor("Type"));
+  EXPECT_EQ("CIDFontType0", cidfont_dict->GetStringFor("Subtype"));
+  EXPECT_EQ("Times New Roman", cidfont_dict->GetStringFor("BaseFont"));
+  CPDF_Dictionary* cidinfo_dict = cidfont_dict->GetDictFor("CIDSystemInfo");
+  ASSERT_TRUE(cidinfo_dict);
+  EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
+  EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
+  EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
+  CheckFontDescriptor(cidfont_dict, FPDF_FONT_TYPE1, false, false, size, data);
+
+  // Check widths
+  CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
+  ASSERT_TRUE(widths_array);
+  EXPECT_GT(widths_array->GetCount(), 1U);
+  CheckCompositeFontWidths(widths_array, typed_font);
+}
+
+TEST_F(FPDFEditEmbeddertest, LoadCIDType2Font) {
+  CreateNewDocument();
+  const CPDF_Font* stock_font =
+      CPDF_Font::GetStockFont(cpdf_doc(), "Helvetica-Oblique");
+  const uint8_t* data = stock_font->GetFont()->GetFontData();
+  const uint32_t size = stock_font->GetFont()->GetSize();
+
+  std::unique_ptr<void, FPDFFontDeleter> font(
+      FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 1));
+  ASSERT_TRUE(font.get());
+  CPDF_Font* typed_font = static_cast<CPDF_Font*>(font.get());
+  EXPECT_TRUE(typed_font->IsCIDFont());
+
+  // Check font dictionary entries
+  CPDF_Dictionary* font_dict = typed_font->GetFontDict();
+  EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
+  EXPECT_EQ("Type0", font_dict->GetStringFor("Subtype"));
+  EXPECT_EQ("Arial Italic", font_dict->GetStringFor("BaseFont"));
+  EXPECT_EQ("Identity-H", font_dict->GetStringFor("Encoding"));
+  CPDF_Array* descendant_array = font_dict->GetArrayFor("DescendantFonts");
+  ASSERT_TRUE(descendant_array);
+  EXPECT_EQ(1U, descendant_array->GetCount());
+
+  // Check the CIDFontDict
+  CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
+  EXPECT_EQ("Font", cidfont_dict->GetStringFor("Type"));
+  EXPECT_EQ("CIDFontType2", cidfont_dict->GetStringFor("Subtype"));
+  EXPECT_EQ("Arial Italic", cidfont_dict->GetStringFor("BaseFont"));
+  CPDF_Dictionary* cidinfo_dict = cidfont_dict->GetDictFor("CIDSystemInfo");
+  ASSERT_TRUE(cidinfo_dict);
+  EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
+  EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
+  EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
+  CheckFontDescriptor(cidfont_dict, FPDF_FONT_TRUETYPE, false, true, size,
+                      data);
+
+  // Check widths
+  CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
+  ASSERT_TRUE(widths_array);
+  CheckCompositeFontWidths(widths_array, typed_font);
+}
+
+TEST_F(FPDFEditEmbeddertest, NormalizeNegativeRotation) {
+  // Load document with a -90 degree rotation
+  EXPECT_TRUE(OpenDocument("bug_713197.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  EXPECT_NE(nullptr, page);
+
+  EXPECT_EQ(3, FPDFPage_GetRotation(page));
+  UnloadPage(page);
+}
+
+TEST_F(FPDFEditEmbeddertest, AddTrueTypeFontText) {
+  // Start with a blank page
+  FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
+  {
+    const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
+    const uint8_t* data = stock_font->GetFont()->GetFontData();
+    const uint32_t size = stock_font->GetFont()->GetSize();
+    std::unique_ptr<void, FPDFFontDeleter> font(
+        FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 0));
+    ASSERT_TRUE(font.get());
+
+    // Add some text to the page
+    FPDF_PAGEOBJECT text_object =
+        FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
+    EXPECT_TRUE(text_object);
+    std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
+        GetFPDFWideString(L"I am testing my loaded font, WEE.");
+    EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
+    FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
+    FPDFPage_InsertObject(page, text_object);
+    FPDF_BITMAP page_bitmap = RenderPage(page);
+#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+    const char md5[] = "17d2b6cd574cf66170b09c8927529a94";
+#else
+    const char md5[] = "70592859010ffbf532a2237b8118bcc4";
+#endif  // _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+    CompareBitmap(page_bitmap, 612, 792, md5);
+    FPDFBitmap_Destroy(page_bitmap);
+
+    // Add some more text, same font
+    FPDF_PAGEOBJECT text_object2 =
+        FPDFPageObj_CreateTextObj(document(), font.get(), 15.0f);
+    std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
+        GetFPDFWideString(L"Bigger font size");
+    EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
+    FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 200, 200);
+    FPDFPage_InsertObject(page, text_object2);
+  }
+  FPDF_BITMAP page_bitmap2 = RenderPage(page);
+#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+  const char md5_2[] = "8eded4193ff1f0f77b8b600a825e97ea";
+#else
+  const char md5_2[] = "c1d10cce1761c4a998a16b2562030568";
+#endif  // _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+  CompareBitmap(page_bitmap2, 612, 792, md5_2);
+  FPDFBitmap_Destroy(page_bitmap2);
+
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+  FPDF_ClosePage(page);
+
+  VerifySavedDocument(612, 792, md5_2);
+}
+
+TEST_F(FPDFEditEmbeddertest, TransformAnnot) {
+  // Open a file with one annotation and load its first page.
+  ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
+  FPDF_PAGE page = FPDF_LoadPage(document(), 0);
+  ASSERT_TRUE(page);
+
+  // Add an underline annotation to the page without specifying its rectangle.
+  FPDF_ANNOTATION annot = FPDFPage_CreateAnnot(page, FPDF_ANNOT_UNDERLINE);
+  ASSERT_TRUE(annot);
+
+  // FPDFPage_TransformAnnots() should run without errors when modifying
+  // annotation rectangles.
+  FPDFPage_TransformAnnots(page, 1, 2, 3, 4, 5, 6);
+
+  FPDFPage_CloseAnnot(annot);
+  UnloadPage(page);
+}
+
+// TODO(npm): Add tests using Japanese fonts in other OS.
+#if _FX_PLATFORM_ == _FX_PLATFORM_LINUX_
+TEST_F(FPDFEditEmbeddertest, AddCIDFontText) {
+  // Start with a blank page
+  FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
+  CFX_Font CIDfont;
+  {
+    // First, get the data from the font
+    CIDfont.LoadSubst("IPAGothic", 1, 0, 400, 0, 932, 0);
+    EXPECT_EQ("IPAGothic", CIDfont.GetFaceName());
+    const uint8_t* data = CIDfont.GetFontData();
+    const uint32_t size = CIDfont.GetSize();
+
+    // Load the data into a FPDF_Font.
+    std::unique_ptr<void, FPDFFontDeleter> font(
+        FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 1));
+    ASSERT_TRUE(font.get());
+
+    // Add some text to the page
+    FPDF_PAGEOBJECT text_object =
+        FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
+    ASSERT_TRUE(text_object);
+    std::wstring wstr = L"ABCDEFGhijklmnop.";
+    std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
+        GetFPDFWideString(wstr);
+    EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
+    FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 200, 200);
+    FPDFPage_InsertObject(page, text_object);
+
+    // And add some Japanese characters
+    FPDF_PAGEOBJECT text_object2 =
+        FPDFPageObj_CreateTextObj(document(), font.get(), 18.0f);
+    ASSERT_TRUE(text_object2);
+    std::wstring wstr2 =
+        L"\u3053\u3093\u306B\u3061\u306f\u4e16\u754C\u3002\u3053\u3053\u306B1"
+        L"\u756A";
+    std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
+        GetFPDFWideString(wstr2);
+    EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
+    FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 500);
+    FPDFPage_InsertObject(page, text_object2);
+  }
+
+  // Check that the text renders properly.
+  FPDF_BITMAP page_bitmap = RenderPage(page);
+  const char md5[] = "c68cd79aa72bf83a7b25271370d46b21";
+  CompareBitmap(page_bitmap, 612, 792, md5);
+  FPDFBitmap_Destroy(page_bitmap);
+
+  // Save the document, close the page.
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+  FPDF_ClosePage(page);
+
+  VerifySavedDocument(612, 792, md5);
+}
+#endif  // _FX_PLATFORM_ == _FX_PLATFORM_LINUX_
+
+TEST_F(FPDFEditEmbeddertest, SaveAndRender) {
+  const char md5[] = "3c20472b0552c0c22b88ab1ed8c6202b";
+  {
+    EXPECT_TRUE(OpenDocument("bug_779.pdf"));
+    FPDF_PAGE page = LoadPage(0);
+    ASSERT_NE(nullptr, page);
+
+    // Now add a more complex blue path.
+    FPDF_PAGEOBJECT green_path = FPDFPageObj_CreateNewPath(20, 20);
+    EXPECT_TRUE(FPDFPath_SetFillColor(green_path, 0, 255, 0, 200));
+    // TODO(npm): stroking will cause the MD5s to differ.
+    EXPECT_TRUE(FPDFPath_SetDrawMode(green_path, FPDF_FILLMODE_WINDING, 0));
+    EXPECT_TRUE(FPDFPath_LineTo(green_path, 20, 63));
+    EXPECT_TRUE(FPDFPath_BezierTo(green_path, 55, 55, 78, 78, 90, 90));
+    EXPECT_TRUE(FPDFPath_LineTo(green_path, 133, 133));
+    EXPECT_TRUE(FPDFPath_LineTo(green_path, 133, 33));
+    EXPECT_TRUE(FPDFPath_BezierTo(green_path, 38, 33, 39, 36, 40, 40));
+    EXPECT_TRUE(FPDFPath_Close(green_path));
+    FPDFPage_InsertObject(page, green_path);
+    FPDF_BITMAP page_bitmap = RenderPage(page);
+    CompareBitmap(page_bitmap, 612, 792, md5);
+    FPDFBitmap_Destroy(page_bitmap);
+
+    // Now save the result, closing the page and document
+    EXPECT_TRUE(FPDFPage_GenerateContent(page));
+    EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+    UnloadPage(page);
+  }
+
+  VerifySavedDocument(612, 792, md5);
+}
+
+TEST_F(FPDFEditEmbeddertest, ExtractImageBitmap) {
+  ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+  ASSERT_EQ(39, FPDFPage_CountObjects(page));
+
+  FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32);
+  EXPECT_NE(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
+  EXPECT_FALSE(FPDFImageObj_GetBitmap(obj));
+
+  obj = FPDFPage_GetObject(page, 33);
+  ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
+  FPDF_BITMAP bitmap = FPDFImageObj_GetBitmap(obj);
+  EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap));
+  CompareBitmap(bitmap, 109, 88, "d65e98d968d196abf13f78aec655ffae");
+  FPDFBitmap_Destroy(bitmap);
+
+  obj = FPDFPage_GetObject(page, 34);
+  ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
+  bitmap = FPDFImageObj_GetBitmap(obj);
+  EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap));
+  CompareBitmap(bitmap, 103, 75, "1287711c84dbef767c435d11697661d6");
+  FPDFBitmap_Destroy(bitmap);
+
+  obj = FPDFPage_GetObject(page, 35);
+  ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
+  bitmap = FPDFImageObj_GetBitmap(obj);
+  EXPECT_EQ(FPDFBitmap_Gray, FPDFBitmap_GetFormat(bitmap));
+  CompareBitmap(bitmap, 92, 68, "9c6d76cb1e37ef8514f9455d759391f3");
+  FPDFBitmap_Destroy(bitmap);
+
+  obj = FPDFPage_GetObject(page, 36);
+  ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
+  bitmap = FPDFImageObj_GetBitmap(obj);
+  EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap));
+  CompareBitmap(bitmap, 79, 60, "15cb6a49a2e354ed0e9f45dd34e3da1a");
+  FPDFBitmap_Destroy(bitmap);
+
+  obj = FPDFPage_GetObject(page, 37);
+  ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
+  bitmap = FPDFImageObj_GetBitmap(obj);
+  EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap));
+  CompareBitmap(bitmap, 126, 106, "be5a64ba7890d2657522af6524118534");
+  FPDFBitmap_Destroy(bitmap);
+
+  obj = FPDFPage_GetObject(page, 38);
+  ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
+  bitmap = FPDFImageObj_GetBitmap(obj);
+  EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap));
+  CompareBitmap(bitmap, 194, 119, "f9e24207ee1bc0db6c543d33a5f12ec5");
+  FPDFBitmap_Destroy(bitmap);
+  UnloadPage(page);
+}
+
+TEST_F(FPDFEditEmbeddertest, GetImageData) {
+  EXPECT_TRUE(OpenDocument("embedded_images.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+  ASSERT_EQ(39, FPDFPage_CountObjects(page));
+
+  // Retrieve an image object with flate-encoded data stream.
+  FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
+  ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
+
+  // Check that the raw image data has the correct length and hash value.
+  unsigned long len = FPDFImageObj_GetImageDataRaw(obj, nullptr, 0);
+  std::vector<char> buf(len);
+  EXPECT_EQ(4091u, FPDFImageObj_GetImageDataRaw(obj, buf.data(), len));
+  EXPECT_EQ("f73802327d2e88e890f653961bcda81a",
+            GenerateMD5Base16(reinterpret_cast<uint8_t*>(buf.data()), len));
+
+  // Check that the decoded image data has the correct length and hash value.
+  len = FPDFImageObj_GetImageDataDecoded(obj, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  EXPECT_EQ(28776u, FPDFImageObj_GetImageDataDecoded(obj, buf.data(), len));
+  EXPECT_EQ("cb3637934bb3b95a6e4ae1ea9eb9e56e",
+            GenerateMD5Base16(reinterpret_cast<uint8_t*>(buf.data()), len));
+
+  // Retrieve an image obejct with DCTDecode-encoded data stream.
+  obj = FPDFPage_GetObject(page, 37);
+  ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
+
+  // Check that the raw image data has the correct length and hash value.
+  len = FPDFImageObj_GetImageDataRaw(obj, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  EXPECT_EQ(4370u, FPDFImageObj_GetImageDataRaw(obj, buf.data(), len));
+  EXPECT_EQ("6aae1f3710335023a9e12191be66b64b",
+            GenerateMD5Base16(reinterpret_cast<uint8_t*>(buf.data()), len));
+
+  // Check that the decoded image data has the correct length and hash value,
+  // which should be the same as those of the raw data, since this image is
+  // encoded by a single DCTDecode filter and decoding is a noop.
+  len = FPDFImageObj_GetImageDataDecoded(obj, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  EXPECT_EQ(4370u, FPDFImageObj_GetImageDataDecoded(obj, buf.data(), len));
+  EXPECT_EQ("6aae1f3710335023a9e12191be66b64b",
+            GenerateMD5Base16(reinterpret_cast<uint8_t*>(buf.data()), len));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFEditEmbeddertest, DestroyPageObject) {
+  FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
+  ASSERT_TRUE(rect);
+
+  // There should be no memory leaks with a call to FPDFPageObj_Destroy().
+  FPDFPageObj_Destroy(rect);
+}
+
+TEST_F(FPDFEditEmbeddertest, GetImageFilters) {
+  EXPECT_TRUE(OpenDocument("embedded_images.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Verify that retrieving the filter of a non-image object would fail.
+  FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32);
+  ASSERT_NE(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
+  ASSERT_EQ(0, FPDFImageObj_GetImageFilterCount(obj));
+  EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0));
+
+  // Verify the returned filter string for an image object with a single filter.
+  obj = FPDFPage_GetObject(page, 33);
+  ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
+  ASSERT_EQ(1, FPDFImageObj_GetImageFilterCount(obj));
+  unsigned long len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0);
+  std::vector<char> buf(len);
+  static constexpr char kFlateDecode[] = "FlateDecode";
+  EXPECT_EQ(sizeof(kFlateDecode),
+            FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len));
+  EXPECT_STREQ(kFlateDecode, buf.data());
+  EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0));
+
+  // Verify all the filters for an image object with a list of filters.
+  obj = FPDFPage_GetObject(page, 38);
+  ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
+  ASSERT_EQ(2, FPDFImageObj_GetImageFilterCount(obj));
+  len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  static constexpr char kASCIIHexDecode[] = "ASCIIHexDecode";
+  EXPECT_EQ(sizeof(kASCIIHexDecode),
+            FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len));
+  EXPECT_STREQ(kASCIIHexDecode, buf.data());
+
+  len = FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  static constexpr char kDCTDecode[] = "DCTDecode";
+  EXPECT_EQ(sizeof(kDCTDecode),
+            FPDFImageObj_GetImageFilter(obj, 1, buf.data(), len));
+  EXPECT_STREQ(kDCTDecode, buf.data());
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFEditEmbeddertest, GetImageMetadata) {
+  ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Check that getting the metadata of a null object would fail.
+  FPDF_IMAGEOBJ_METADATA metadata;
+  EXPECT_FALSE(FPDFImageObj_GetImageMetadata(nullptr, page, &metadata));
+
+  // Check that receiving the metadata with a null metadata object would fail.
+  FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 35);
+  EXPECT_FALSE(FPDFImageObj_GetImageMetadata(obj, page, nullptr));
+
+  // Check that when retrieving an image object's metadata without passing in
+  // |page|, all values are correct, with the last two being default values.
+  ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
+  ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, nullptr, &metadata));
+  EXPECT_EQ(7, metadata.marked_content_id);
+  EXPECT_EQ(92u, metadata.width);
+  EXPECT_EQ(68u, metadata.height);
+  EXPECT_NEAR(96.000000, metadata.horizontal_dpi, 0.001);
+  EXPECT_NEAR(96.000000, metadata.vertical_dpi, 0.001);
+  EXPECT_EQ(0u, metadata.bits_per_pixel);
+  EXPECT_EQ(FPDF_COLORSPACE_UNKNOWN, metadata.colorspace);
+
+  // Verify the metadata of a bitmap image with indexed colorspace.
+  ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
+  EXPECT_EQ(7, metadata.marked_content_id);
+  EXPECT_EQ(92u, metadata.width);
+  EXPECT_EQ(68u, metadata.height);
+  EXPECT_NEAR(96.000000, metadata.horizontal_dpi, 0.001);
+  EXPECT_NEAR(96.000000, metadata.vertical_dpi, 0.001);
+  EXPECT_EQ(1u, metadata.bits_per_pixel);
+  EXPECT_EQ(FPDF_COLORSPACE_INDEXED, metadata.colorspace);
+
+  // Verify the metadata of an image with RGB colorspace.
+  obj = FPDFPage_GetObject(page, 37);
+  ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
+  ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
+  EXPECT_EQ(9, metadata.marked_content_id);
+  EXPECT_EQ(126u, metadata.width);
+  EXPECT_EQ(106u, metadata.height);
+  EXPECT_NEAR(162.173752, metadata.horizontal_dpi, 0.001);
+  EXPECT_NEAR(162.555878, metadata.vertical_dpi, 0.001);
+  EXPECT_EQ(24u, metadata.bits_per_pixel);
+  EXPECT_EQ(FPDF_COLORSPACE_DEVICERGB, metadata.colorspace);
+
+  UnloadPage(page);
 }
diff --git a/fpdfsdk/fpdfeditimg.cpp b/fpdfsdk/fpdfeditimg.cpp
index 56875e2..0d7ba56 100644
--- a/fpdfsdk/fpdfeditimg.cpp
+++ b/fpdfsdk/fpdfeditimg.cpp
@@ -9,97 +9,296 @@
 #include "core/fpdfapi/cpdf_modulemgr.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_pageobject.h"
+#include "core/fpdfapi/parser/cpdf_array.h"
+#include "core/fpdfapi/parser/cpdf_name.h"
+#include "core/fpdfapi/render/cpdf_dibsource.h"
 #include "fpdfsdk/fsdk_define.h"
 #include "third_party/base/ptr_util.h"
 
-DLLEXPORT FPDF_PAGEOBJECT STDCALL
-FPDFPageObj_NewImgeObj(FPDF_DOCUMENT document) {
-  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
-  if (!pDoc)
-    return nullptr;
+namespace {
 
-  CPDF_ImageObject* pImageObj = new CPDF_ImageObject;
-  pImageObj->SetOwnedImage(pdfium::MakeUnique<CPDF_Image>(pDoc));
-  return pImageObj;
-}
+// These checks ensure the consistency of colorspace values across core/ and
+// public/.
+static_assert(PDFCS_DEVICEGRAY == FPDF_COLORSPACE_DEVICEGRAY,
+              "PDFCS_DEVICEGRAY value mismatch");
+static_assert(PDFCS_DEVICERGB == FPDF_COLORSPACE_DEVICERGB,
+              "PDFCS_DEVICERGB value mismatch");
+static_assert(PDFCS_DEVICECMYK == FPDF_COLORSPACE_DEVICECMYK,
+              "PDFCS_DEVICECMYK value mismatch");
+static_assert(PDFCS_CALGRAY == FPDF_COLORSPACE_CALGRAY,
+              "PDFCS_CALGRAY value mismatch");
+static_assert(PDFCS_CALRGB == FPDF_COLORSPACE_CALRGB,
+              "PDFCS_CALRGB value mismatch");
+static_assert(PDFCS_LAB == FPDF_COLORSPACE_LAB, "PDFCS_LAB value mismatch");
+static_assert(PDFCS_ICCBASED == FPDF_COLORSPACE_ICCBASED,
+              "PDFCS_ICCBASED value mismatch");
+static_assert(PDFCS_SEPARATION == FPDF_COLORSPACE_SEPARATION,
+              "PDFCS_SEPARATION value mismatch");
+static_assert(PDFCS_DEVICEN == FPDF_COLORSPACE_DEVICEN,
+              "PDFCS_DEVICEN value mismatch");
+static_assert(PDFCS_INDEXED == FPDF_COLORSPACE_INDEXED,
+              "PDFCS_INDEXED value mismatch");
+static_assert(PDFCS_PATTERN == FPDF_COLORSPACE_PATTERN,
+              "PDFCS_PATTERN value mismatch");
 
-FPDF_BOOL FPDFImageObj_LoadJpegHelper(FPDF_PAGE* pages,
-                                      int nCount,
-                                      FPDF_PAGEOBJECT image_object,
-                                      FPDF_FILEACCESS* fileAccess,
-                                      bool inlineJpeg) {
-  if (!image_object || !fileAccess || !pages)
+bool LoadJpegHelper(FPDF_PAGE* pages,
+                    int nCount,
+                    FPDF_PAGEOBJECT image_object,
+                    FPDF_FILEACCESS* fileAccess,
+                    bool inlineJpeg) {
+  if (!image_object || !fileAccess)
     return false;
 
-  CFX_RetainPtr<IFX_SeekableReadStream> pFile =
-      MakeSeekableReadStream(fileAccess);
-  CPDF_ImageObject* pImgObj = reinterpret_cast<CPDF_ImageObject*>(image_object);
-  for (int index = 0; index < nCount; index++) {
-    CPDF_Page* pPage = CPDFPageFromFPDFPage(pages[index]);
-    if (pPage)
-      pImgObj->GetImage()->ResetCache(pPage, nullptr);
+  RetainPtr<IFX_SeekableReadStream> pFile = MakeSeekableReadStream(fileAccess);
+  CPDF_ImageObject* pImgObj = static_cast<CPDF_ImageObject*>(image_object);
+
+  if (pages) {
+    for (int index = 0; index < nCount; index++) {
+      CPDF_Page* pPage = CPDFPageFromFPDFPage(pages[index]);
+      if (pPage)
+        pImgObj->GetImage()->ResetCache(pPage, nullptr);
+    }
   }
 
   if (inlineJpeg)
     pImgObj->GetImage()->SetJpegImageInline(pFile);
   else
     pImgObj->GetImage()->SetJpegImage(pFile);
-
+  pImgObj->SetDirty(true);
   return true;
 }
 
-DLLEXPORT FPDF_BOOL STDCALL
+}  // namespace
+
+FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
+FPDFPageObj_NewImageObj(FPDF_DOCUMENT document) {
+  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+  if (!pDoc)
+    return nullptr;
+
+  auto pImageObj = pdfium::MakeUnique<CPDF_ImageObject>();
+  pImageObj->SetImage(pdfium::MakeRetain<CPDF_Image>(pDoc));
+  return pImageObj.release();
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
 FPDFImageObj_LoadJpegFile(FPDF_PAGE* pages,
                           int nCount,
                           FPDF_PAGEOBJECT image_object,
                           FPDF_FILEACCESS* fileAccess) {
-  return FPDFImageObj_LoadJpegHelper(pages, nCount, image_object, fileAccess,
-                                     false);
+  return LoadJpegHelper(pages, nCount, image_object, fileAccess, false);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
 FPDFImageObj_LoadJpegFileInline(FPDF_PAGE* pages,
                                 int nCount,
                                 FPDF_PAGEOBJECT image_object,
                                 FPDF_FILEACCESS* fileAccess) {
-  return FPDFImageObj_LoadJpegHelper(pages, nCount, image_object, fileAccess,
-                                     true);
+  return LoadJpegHelper(pages, nCount, image_object, fileAccess, true);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDFImageObj_SetMatrix(FPDF_PAGEOBJECT image_object,
-                                                   double a,
-                                                   double b,
-                                                   double c,
-                                                   double d,
-                                                   double e,
-                                                   double f) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFImageObj_SetMatrix(FPDF_PAGEOBJECT image_object,
+                       double a,
+                       double b,
+                       double c,
+                       double d,
+                       double e,
+                       double f) {
   if (!image_object)
     return false;
 
-  CPDF_ImageObject* pImgObj = reinterpret_cast<CPDF_ImageObject*>(image_object);
-  pImgObj->set_matrix(
-      CFX_Matrix(static_cast<FX_FLOAT>(a), static_cast<FX_FLOAT>(b),
-                 static_cast<FX_FLOAT>(c), static_cast<FX_FLOAT>(d),
-                 static_cast<FX_FLOAT>(e), static_cast<FX_FLOAT>(f)));
+  CPDF_ImageObject* pImgObj = static_cast<CPDF_ImageObject*>(image_object);
+  pImgObj->set_matrix(CFX_Matrix(static_cast<float>(a), static_cast<float>(b),
+                                 static_cast<float>(c), static_cast<float>(d),
+                                 static_cast<float>(e), static_cast<float>(f)));
   pImgObj->CalcBoundingBox();
+  pImgObj->SetDirty(true);
   return true;
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDFImageObj_SetBitmap(FPDF_PAGE* pages,
-                                                   int nCount,
-                                                   FPDF_PAGEOBJECT image_object,
-                                                   FPDF_BITMAP bitmap) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFImageObj_SetBitmap(FPDF_PAGE* pages,
+                       int nCount,
+                       FPDF_PAGEOBJECT image_object,
+                       FPDF_BITMAP bitmap) {
   if (!image_object || !bitmap || !pages)
     return false;
 
-  CPDF_ImageObject* pImgObj = reinterpret_cast<CPDF_ImageObject*>(image_object);
+  CPDF_ImageObject* pImgObj = static_cast<CPDF_ImageObject*>(image_object);
   for (int index = 0; index < nCount; index++) {
     CPDF_Page* pPage = CPDFPageFromFPDFPage(pages[index]);
     if (pPage)
       pImgObj->GetImage()->ResetCache(pPage, nullptr);
   }
-  pImgObj->GetImage()->SetImage(reinterpret_cast<CFX_DIBitmap*>(bitmap));
+  RetainPtr<CFX_DIBitmap> holder(CFXBitmapFromFPDFBitmap(bitmap));
+  pImgObj->GetImage()->SetImage(holder);
   pImgObj->CalcBoundingBox();
+  pImgObj->SetDirty(true);
+  return true;
+}
+
+FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV
+FPDFImageObj_GetBitmap(FPDF_PAGEOBJECT image_object) {
+  CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object);
+  if (!pObj || !pObj->IsImage())
+    return nullptr;
+
+  RetainPtr<CPDF_Image> pImg = pObj->AsImage()->GetImage();
+  if (!pImg)
+    return nullptr;
+
+  RetainPtr<CFX_DIBSource> pSource = pImg->LoadDIBSource();
+  if (!pSource)
+    return nullptr;
+
+  RetainPtr<CFX_DIBitmap> pBitmap;
+  // If the source image has a representation of 1 bit per pixel, then convert
+  // it to a grayscale bitmap having 1 byte per pixel, since bitmaps have no
+  // concept of bits. Otherwise, convert the source image to a bitmap directly,
+  // retaining its color representation.
+  if (pSource->GetBPP() == 1)
+    pBitmap = pSource->CloneConvert(FXDIB_8bppRgb);
+  else
+    pBitmap = pSource->Clone(nullptr);
+
+  return pBitmap.Leak();
+}
+
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDFImageObj_GetImageDataDecoded(FPDF_PAGEOBJECT image_object,
+                                 void* buffer,
+                                 unsigned long buflen) {
+  CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object);
+  if (!pObj || !pObj->IsImage())
+    return 0;
+
+  RetainPtr<CPDF_Image> pImg = pObj->AsImage()->GetImage();
+  if (!pImg)
+    return 0;
+
+  CPDF_Stream* pImgStream = pImg->GetStream();
+  if (!pImgStream)
+    return 0;
+
+  return DecodeStreamMaybeCopyAndReturnLength(pImgStream, buffer, buflen);
+}
+
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDFImageObj_GetImageDataRaw(FPDF_PAGEOBJECT image_object,
+                             void* buffer,
+                             unsigned long buflen) {
+  CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object);
+  if (!pObj || !pObj->IsImage())
+    return 0;
+
+  RetainPtr<CPDF_Image> pImg = pObj->AsImage()->GetImage();
+  if (!pImg)
+    return 0;
+
+  CPDF_Stream* pImgStream = pImg->GetStream();
+  if (!pImgStream)
+    return 0;
+
+  uint32_t len = pImgStream->GetRawSize();
+  if (buffer && buflen >= len)
+    memcpy(buffer, pImgStream->GetRawData(), len);
+
+  return len;
+}
+
+FPDF_EXPORT int FPDF_CALLCONV
+FPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object) {
+  CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object);
+  if (!pObj || !pObj->IsImage())
+    return 0;
+
+  RetainPtr<CPDF_Image> pImg = pObj->AsImage()->GetImage();
+  if (!pImg)
+    return 0;
+
+  CPDF_Dictionary* pDict = pImg->GetDict();
+  CPDF_Object* pFilter = pDict ? pDict->GetDirectObjectFor("Filter") : nullptr;
+  if (!pFilter)
+    return 0;
+
+  if (pFilter->IsArray())
+    return pFilter->AsArray()->GetCount();
+  if (pFilter->IsName())
+    return 1;
+
+  return 0;
+}
+
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object,
+                            int index,
+                            void* buffer,
+                            unsigned long buflen) {
+  if (index < 0 || index >= FPDFImageObj_GetImageFilterCount(image_object))
+    return 0;
+
+  CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object);
+  CPDF_Object* pFilter =
+      pObj->AsImage()->GetImage()->GetDict()->GetDirectObjectFor("Filter");
+  ByteString bsFilter;
+  if (pFilter->IsName())
+    bsFilter = pFilter->AsName()->GetString();
+  else
+    bsFilter = pFilter->AsArray()->GetStringAt(index);
+
+  unsigned long len = bsFilter.GetLength() + 1;
+  if (buffer && len <= buflen)
+    memcpy(buffer, bsFilter.c_str(), len);
+  return len;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFImageObj_GetImageMetadata(FPDF_PAGEOBJECT image_object,
+                              FPDF_PAGE page,
+                              FPDF_IMAGEOBJ_METADATA* metadata) {
+  CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object);
+  if (!pObj || !pObj->IsImage() || !metadata)
+    return false;
+
+  RetainPtr<CPDF_Image> pImg = pObj->AsImage()->GetImage();
+  if (!pImg)
+    return false;
+
+  metadata->marked_content_id = pObj->m_ContentMark.GetMarkedContentID();
+
+  const int nPixelWidth = pImg->GetPixelWidth();
+  const int nPixelHeight = pImg->GetPixelHeight();
+  metadata->width = nPixelWidth;
+  metadata->height = nPixelHeight;
+
+  const float nWidth = pObj->m_Right - pObj->m_Left;
+  const float nHeight = pObj->m_Top - pObj->m_Bottom;
+  constexpr int nPointsPerInch = 72;
+  if (nWidth != 0 && nHeight != 0) {
+    metadata->horizontal_dpi = nPixelWidth / nWidth * nPointsPerInch;
+    metadata->vertical_dpi = nPixelHeight / nHeight * nPointsPerInch;
+  }
+
+  metadata->bits_per_pixel = 0;
+  metadata->colorspace = FPDF_COLORSPACE_UNKNOWN;
+
+  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
+  if (!pPage || !pPage->m_pDocument.Get() || !pImg->GetStream())
+    return true;
+
+  auto pSource = pdfium::MakeRetain<CPDF_DIBSource>();
+  if (!pSource->StartLoadDIBSource(pPage->m_pDocument.Get(), pImg->GetStream(),
+                                   false, nullptr,
+                                   pPage->m_pPageResources.Get())) {
+    return true;
+  }
+
+  metadata->bits_per_pixel = pSource->GetBPP();
+  if (pSource->GetColorSpace())
+    metadata->colorspace = pSource->GetColorSpace()->GetFamily();
+
   return true;
 }
diff --git a/fpdfsdk/fpdfeditimg_unittest.cpp b/fpdfsdk/fpdfeditimg_unittest.cpp
index ae4af25..fcc081a 100644
--- a/fpdfsdk/fpdfeditimg_unittest.cpp
+++ b/fpdfsdk/fpdfeditimg_unittest.cpp
@@ -8,10 +8,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 class PDFEditTest : public testing::Test {
-  void SetUp() override {
-    CPDF_ModuleMgr* module_mgr = CPDF_ModuleMgr::Get();
-    module_mgr->InitPageModule();
-  }
+  void SetUp() override { CPDF_ModuleMgr::Get()->Init(); }
 
   void TearDown() override { CPDF_ModuleMgr::Destroy(); }
 };
@@ -19,40 +16,40 @@
 TEST_F(PDFEditTest, InsertObjectWithInvalidPage) {
   FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
   FPDF_PAGE page = FPDFPage_New(doc, 0, 100, 100);
-  EXPECT_EQ(0, FPDFPage_CountObject(page));
+  EXPECT_EQ(0, FPDFPage_CountObjects(page));
 
   FPDFPage_InsertObject(nullptr, nullptr);
-  EXPECT_EQ(0, FPDFPage_CountObject(page));
+  EXPECT_EQ(0, FPDFPage_CountObjects(page));
 
   FPDFPage_InsertObject(page, nullptr);
-  EXPECT_EQ(0, FPDFPage_CountObject(page));
+  EXPECT_EQ(0, FPDFPage_CountObjects(page));
 
-  FPDF_PAGEOBJECT page_image = FPDFPageObj_NewImgeObj(doc);
+  FPDF_PAGEOBJECT page_image = FPDFPageObj_NewImageObj(doc);
   FPDFPage_InsertObject(nullptr, page_image);
-  EXPECT_EQ(0, FPDFPage_CountObject(page));
+  EXPECT_EQ(0, FPDFPage_CountObjects(page));
 
   FPDF_ClosePage(page);
   FPDF_CloseDocument(doc);
 }
 
-TEST_F(PDFEditTest, NewImgeObj) {
+TEST_F(PDFEditTest, NewImageObj) {
   FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
   FPDF_PAGE page = FPDFPage_New(doc, 0, 100, 100);
-  EXPECT_EQ(0, FPDFPage_CountObject(page));
+  EXPECT_EQ(0, FPDFPage_CountObjects(page));
 
-  FPDF_PAGEOBJECT page_image = FPDFPageObj_NewImgeObj(doc);
+  FPDF_PAGEOBJECT page_image = FPDFPageObj_NewImageObj(doc);
   FPDFPage_InsertObject(page, page_image);
-  EXPECT_EQ(1, FPDFPage_CountObject(page));
+  EXPECT_EQ(1, FPDFPage_CountObjects(page));
   EXPECT_TRUE(FPDFPage_GenerateContent(page));
 
   FPDF_ClosePage(page);
   FPDF_CloseDocument(doc);
 }
 
-TEST_F(PDFEditTest, NewImgeObjGenerateContent) {
+TEST_F(PDFEditTest, NewImageObjGenerateContent) {
   FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
   FPDF_PAGE page = FPDFPage_New(doc, 0, 100, 100);
-  EXPECT_EQ(0, FPDFPage_CountObject(page));
+  EXPECT_EQ(0, FPDFPage_CountObjects(page));
 
   constexpr int kBitmapSize = 50;
   FPDF_BITMAP bitmap = FPDFBitmap_Create(kBitmapSize, kBitmapSize, 0);
@@ -60,12 +57,12 @@
   EXPECT_EQ(kBitmapSize, FPDFBitmap_GetWidth(bitmap));
   EXPECT_EQ(kBitmapSize, FPDFBitmap_GetHeight(bitmap));
 
-  FPDF_PAGEOBJECT page_image = FPDFPageObj_NewImgeObj(doc);
+  FPDF_PAGEOBJECT page_image = FPDFPageObj_NewImageObj(doc);
   ASSERT_TRUE(FPDFImageObj_SetBitmap(&page, 0, page_image, bitmap));
   ASSERT_TRUE(
       FPDFImageObj_SetMatrix(page_image, kBitmapSize, 0, 0, kBitmapSize, 0, 0));
   FPDFPage_InsertObject(page, page_image);
-  EXPECT_EQ(1, FPDFPage_CountObject(page));
+  EXPECT_EQ(1, FPDFPage_CountObjects(page));
   EXPECT_TRUE(FPDFPage_GenerateContent(page));
 
   FPDFBitmap_Destroy(bitmap);
diff --git a/fpdfsdk/fpdfeditpage.cpp b/fpdfsdk/fpdfeditpage.cpp
index 63740ba..a032bf6 100644
--- a/fpdfsdk/fpdfeditpage.cpp
+++ b/fpdfsdk/fpdfeditpage.cpp
@@ -26,6 +26,7 @@
 #include "core/fpdfdoc/cpdf_annotlist.h"
 #include "fpdfsdk/fsdk_define.h"
 #include "public/fpdf_formfill.h"
+#include "third_party/base/logging.h"
 #include "third_party/base/stl_util.h"
 
 #ifdef PDF_ENABLE_XFA
@@ -33,7 +34,7 @@
 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
 #endif  // PDF_ENABLE_XFA
 
-#if _FX_OS_ == _FX_ANDROID_
+#if _FX_OS_ == _FX_OS_ANDROID_
 #include <time.h>
 #else
 #include <ctime>
@@ -60,107 +61,7 @@
   return pObject && !pObject->GetString().Compare("Page");
 }
 
-}  // namespace
-
-DLLEXPORT FPDF_DOCUMENT STDCALL FPDF_CreateNewDocument() {
-  CPDF_Document* pDoc = new CPDF_Document(nullptr);
-  pDoc->CreateNewDoc();
-  time_t currentTime;
-
-  CFX_ByteString DateStr;
-
-  if (FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS)) {
-    if (-1 != time(&currentTime)) {
-      tm* pTM = localtime(&currentTime);
-      if (pTM) {
-        DateStr.Format("D:%04d%02d%02d%02d%02d%02d", pTM->tm_year + 1900,
-                       pTM->tm_mon + 1, pTM->tm_mday, pTM->tm_hour, pTM->tm_min,
-                       pTM->tm_sec);
-      }
-    }
-  }
-
-  CPDF_Dictionary* pInfoDict = nullptr;
-  pInfoDict = pDoc->GetInfo();
-  if (pInfoDict) {
-    if (FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
-      pInfoDict->SetNewFor<CPDF_String>("CreationDate", DateStr, false);
-    pInfoDict->SetNewFor<CPDF_String>("Creator", L"PDFium");
-  }
-
-  return FPDFDocumentFromCPDFDocument(pDoc);
-}
-
-DLLEXPORT void STDCALL FPDFPage_Delete(FPDF_DOCUMENT document, int page_index) {
-  if (UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document))
-    pDoc->DeletePage(page_index);
-}
-
-DLLEXPORT FPDF_PAGE STDCALL FPDFPage_New(FPDF_DOCUMENT document,
-                                         int page_index,
-                                         double width,
-                                         double height) {
-  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
-  if (!pDoc)
-    return nullptr;
-
-  page_index = std::min(std::max(page_index, 0), pDoc->GetPageCount());
-  CPDF_Dictionary* pPageDict = pDoc->CreateNewPage(page_index);
-  if (!pPageDict)
-    return nullptr;
-
-  CPDF_Array* pMediaBoxArray = pPageDict->SetNewFor<CPDF_Array>("MediaBox");
-  pMediaBoxArray->AddNew<CPDF_Number>(0);
-  pMediaBoxArray->AddNew<CPDF_Number>(0);
-  pMediaBoxArray->AddNew<CPDF_Number>(static_cast<FX_FLOAT>(width));
-  pMediaBoxArray->AddNew<CPDF_Number>(static_cast<FX_FLOAT>(height));
-  pPageDict->SetNewFor<CPDF_Number>("Rotate", 0);
-  pPageDict->SetNewFor<CPDF_Dictionary>("Resources");
-
-#ifdef PDF_ENABLE_XFA
-  CPDFXFA_Page* pPage =
-      new CPDFXFA_Page(static_cast<CPDFXFA_Context*>(document), page_index);
-  pPage->LoadPDFPage(pPageDict);
-#else   // PDF_ENABLE_XFA
-  CPDF_Page* pPage = new CPDF_Page(pDoc, pPageDict, true);
-  pPage->ParseContent();
-#endif  // PDF_ENABLE_XFA
-
-  return pPage;
-}
-
-DLLEXPORT int STDCALL FPDFPage_GetRotation(FPDF_PAGE page) {
-  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
-  if (!IsPageObject(pPage))
-    return -1;
-
-  CPDF_Dictionary* pDict = pPage->m_pFormDict;
-  while (pDict) {
-    if (pDict->KeyExist("Rotate")) {
-      CPDF_Object* pRotateObj = pDict->GetObjectFor("Rotate")->GetDirect();
-      return pRotateObj ? pRotateObj->GetInteger() / 90 : 0;
-    }
-    if (!pDict->KeyExist("Parent"))
-      break;
-
-    pDict = ToDictionary(pDict->GetObjectFor("Parent")->GetDirect());
-  }
-
-  return 0;
-}
-
-DLLEXPORT void STDCALL FPDFPage_InsertObject(FPDF_PAGE page,
-                                             FPDF_PAGEOBJECT page_obj) {
-  CPDF_PageObject* pPageObj = reinterpret_cast<CPDF_PageObject*>(page_obj);
-  if (!pPageObj)
-    return;
-
-  std::unique_ptr<CPDF_PageObject> pPageObjHolder(pPageObj);
-  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
-  if (!IsPageObject(pPage))
-    return;
-
-  pPage->GetPageObjectList()->push_back(std::move(pPageObjHolder));
+void CalcBoundingBox(CPDF_PageObject* pPageObj) {
   switch (pPageObj->GetType()) {
     case CPDF_PageObject::TEXT: {
       break;
@@ -186,38 +87,135 @@
       break;
     }
     default: {
-      ASSERT(false);
+      NOTREACHED();
       break;
     }
   }
 }
 
-DLLEXPORT int STDCALL FPDFPage_CountObject(FPDF_PAGE page) {
+}  // namespace
+
+FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_CreateNewDocument() {
+  auto pDoc = pdfium::MakeUnique<CPDF_Document>(nullptr);
+  pDoc->CreateNewDoc();
+
+  time_t currentTime;
+  ByteString DateStr;
+  if (FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS)) {
+    if (time(&currentTime) != -1) {
+      tm* pTM = localtime(&currentTime);
+      if (pTM) {
+        DateStr = ByteString::Format(
+            "D:%04d%02d%02d%02d%02d%02d", pTM->tm_year + 1900, pTM->tm_mon + 1,
+            pTM->tm_mday, pTM->tm_hour, pTM->tm_min, pTM->tm_sec);
+      }
+    }
+  }
+
+  CPDF_Dictionary* pInfoDict = pDoc->GetInfo();
+  if (pInfoDict) {
+    if (FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
+      pInfoDict->SetNewFor<CPDF_String>("CreationDate", DateStr, false);
+    pInfoDict->SetNewFor<CPDF_String>("Creator", L"PDFium");
+  }
+
+  // Caller takes ownership of pDoc.
+  return FPDFDocumentFromCPDFDocument(pDoc.release());
+}
+
+FPDF_EXPORT void FPDF_CALLCONV FPDFPage_Delete(FPDF_DOCUMENT document,
+                                               int page_index) {
+  if (UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document))
+    pDoc->DeletePage(page_index);
+}
+
+FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDFPage_New(FPDF_DOCUMENT document,
+                                                 int page_index,
+                                                 double width,
+                                                 double height) {
+  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+  if (!pDoc)
+    return nullptr;
+
+  page_index = pdfium::clamp(page_index, 0, pDoc->GetPageCount());
+  CPDF_Dictionary* pPageDict = pDoc->CreateNewPage(page_index);
+  if (!pPageDict)
+    return nullptr;
+
+  CPDF_Array* pMediaBoxArray = pPageDict->SetNewFor<CPDF_Array>("MediaBox");
+  pMediaBoxArray->AddNew<CPDF_Number>(0);
+  pMediaBoxArray->AddNew<CPDF_Number>(0);
+  pMediaBoxArray->AddNew<CPDF_Number>(static_cast<float>(width));
+  pMediaBoxArray->AddNew<CPDF_Number>(static_cast<float>(height));
+  pPageDict->SetNewFor<CPDF_Number>("Rotate", 0);
+  pPageDict->SetNewFor<CPDF_Dictionary>("Resources");
+
+#ifdef PDF_ENABLE_XFA
+  auto pXFAPage = pdfium::MakeRetain<CPDFXFA_Page>(
+      static_cast<CPDFXFA_Context*>(document), page_index);
+  pXFAPage->LoadPDFPage(pPageDict);
+  return pXFAPage.Leak();  // Caller takes ownership.
+#else   // PDF_ENABLE_XFA
+  auto pPage = pdfium::MakeUnique<CPDF_Page>(pDoc, pPageDict, true);
+  pPage->ParseContent();
+  return pPage.release();  // Caller takes ownership.
+#endif  // PDF_ENABLE_XFA
+}
+
+FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetRotation(FPDF_PAGE page) {
+  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
+  return IsPageObject(pPage) ? pPage->GetPageRotation() : -1;
+}
+
+FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertObject(FPDF_PAGE page,
+                                                     FPDF_PAGEOBJECT page_obj) {
+  CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_obj);
+  if (!pPageObj)
+    return;
+
+  std::unique_ptr<CPDF_PageObject> pPageObjHolder(pPageObj);
+  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
+  if (!IsPageObject(pPage))
+    return;
+  pPageObj->SetDirty(true);
+  pPage->GetPageObjectList()->push_back(std::move(pPageObjHolder));
+  CalcBoundingBox(pPageObj);
+}
+
+FPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObject(FPDF_PAGE page) {
+  return FPDFPage_CountObjects(page);
+}
+
+FPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObjects(FPDF_PAGE page) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!IsPageObject(pPage))
     return -1;
   return pdfium::CollectionSize<int>(*pPage->GetPageObjectList());
 }
 
-DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPage_GetObject(FPDF_PAGE page,
-                                                     int index) {
+FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPage_GetObject(FPDF_PAGE page,
+                                                             int index) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!IsPageObject(pPage))
     return nullptr;
   return pPage->GetPageObjectList()->GetPageObjectByIndex(index);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDFPage_HasTransparency(FPDF_PAGE page) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_HasTransparency(FPDF_PAGE page) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   return pPage && pPage->BackgroundAlphaNeeded();
 }
 
-DLLEXPORT FPDF_BOOL STDCALL
+FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_obj) {
+  delete CPDFPageObjectFromFPDFPageObject(page_obj);
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
 FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT pageObject) {
   if (!pageObject)
     return false;
 
-  CPDF_PageObject* pPageObj = reinterpret_cast<CPDF_PageObject*>(pageObject);
+  CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(pageObject);
   int blend_type = pPageObj->m_GeneralState.GetBlendType();
   if (blend_type != FXDIB_BLEND_NORMAL)
     return true;
@@ -237,7 +235,7 @@
   if (pPageObj->IsForm()) {
     const CPDF_Form* pForm = pPageObj->AsForm()->form();
     if (pForm) {
-      int trans = pForm->m_Transparency;
+      int trans = pForm->m_iTransparency;
       if ((trans & PDFTRANS_ISOLATED) || (trans & PDFTRANS_GROUP))
         return true;
     }
@@ -246,7 +244,15 @@
   return false;
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDFPage_GenerateContent(FPDF_PAGE page) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetType(FPDF_PAGEOBJECT pageObject) {
+  if (!pageObject)
+    return FPDF_PAGEOBJ_UNKNOWN;
+
+  CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(pageObject);
+  return pPageObj->GetType();
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GenerateContent(FPDF_PAGE page) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!IsPageObject(pPage))
     return false;
@@ -256,29 +262,40 @@
   return true;
 }
 
-DLLEXPORT void STDCALL FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object,
-                                             double a,
-                                             double b,
-                                             double c,
-                                             double d,
-                                             double e,
-                                             double f) {
-  CPDF_PageObject* pPageObj = reinterpret_cast<CPDF_PageObject*>(page_object);
+FPDF_EXPORT void FPDF_CALLCONV
+FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object,
+                      double a,
+                      double b,
+                      double c,
+                      double d,
+                      double e,
+                      double f) {
+  CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
   if (!pPageObj)
     return;
 
-  CFX_Matrix matrix((FX_FLOAT)a, (FX_FLOAT)b, (FX_FLOAT)c, (FX_FLOAT)d,
-                    (FX_FLOAT)e, (FX_FLOAT)f);
+  CFX_Matrix matrix((float)a, (float)b, (float)c, (float)d, (float)e, (float)f);
   pPageObj->Transform(matrix);
 }
 
-DLLEXPORT void STDCALL FPDFPage_TransformAnnots(FPDF_PAGE page,
-                                                double a,
-                                                double b,
-                                                double c,
-                                                double d,
-                                                double e,
-                                                double f) {
+FPDF_EXPORT void FPDF_CALLCONV
+FPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object,
+                         FPDF_BYTESTRING blend_mode) {
+  CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
+  if (!pPageObj)
+    return;
+
+  pPageObj->m_GeneralState.SetBlendMode(blend_mode);
+  pPageObj->SetDirty(true);
+}
+
+FPDF_EXPORT void FPDF_CALLCONV FPDFPage_TransformAnnots(FPDF_PAGE page,
+                                                        double a,
+                                                        double b,
+                                                        double c,
+                                                        double d,
+                                                        double e,
+                                                        double f) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!pPage)
     return;
@@ -286,30 +303,67 @@
   CPDF_AnnotList AnnotList(pPage);
   for (size_t i = 0; i < AnnotList.Count(); ++i) {
     CPDF_Annot* pAnnot = AnnotList.GetAt(i);
-    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);
-    matrix.TransformRect(rect);
+    CFX_Matrix matrix((float)a, (float)b, (float)c, (float)d, (float)e,
+                      (float)f);
+    CFX_FloatRect rect = matrix.TransformRect(pAnnot->GetRect());
 
-    CPDF_Array* pRectArray = pAnnot->GetAnnotDict()->GetArrayFor("Rect");
-    if (!pRectArray)
-      pRectArray = pAnnot->GetAnnotDict()->SetNewFor<CPDF_Array>("Rect");
+    CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict();
+    CPDF_Array* pRectArray = pAnnotDict->GetArrayFor("Rect");
+    if (pRectArray)
+      pRectArray->Clear();
+    else
+      pRectArray = pAnnotDict->SetNewFor<CPDF_Array>("Rect");
 
-    pRectArray->SetNewAt<CPDF_Number>(0, rect.left);
-    pRectArray->SetNewAt<CPDF_Number>(1, rect.bottom);
-    pRectArray->SetNewAt<CPDF_Number>(2, rect.right);
-    pRectArray->SetNewAt<CPDF_Number>(3, rect.top);
+    pRectArray->AddNew<CPDF_Number>(rect.left);
+    pRectArray->AddNew<CPDF_Number>(rect.bottom);
+    pRectArray->AddNew<CPDF_Number>(rect.right);
+    pRectArray->AddNew<CPDF_Number>(rect.top);
 
     // TODO(unknown): Transform AP's rectangle
   }
 }
 
-DLLEXPORT void STDCALL FPDFPage_SetRotation(FPDF_PAGE page, int rotate) {
+FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetRotation(FPDF_PAGE page,
+                                                    int rotate) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!IsPageObject(pPage))
     return;
 
-  CPDF_Dictionary* pDict = pPage->m_pFormDict;
   rotate %= 4;
-  pDict->SetNewFor<CPDF_Number>("Rotate", rotate * 90);
+  pPage->m_pFormDict->SetNewFor<CPDF_Number>("Rotate", rotate * 90);
+}
+
+FPDF_BOOL FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object,
+                                   unsigned int R,
+                                   unsigned int G,
+                                   unsigned int B,
+                                   unsigned int A) {
+  if (!page_object || R > 255 || G > 255 || B > 255 || A > 255)
+    return false;
+
+  float rgb[3] = {R / 255.f, G / 255.f, B / 255.f};
+  auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
+  pPageObj->m_GeneralState.SetFillAlpha(A / 255.f);
+  pPageObj->m_ColorState.SetFillColor(
+      CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb, 3);
+  pPageObj->SetDirty(true);
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPageObj_GetBounds(FPDF_PAGEOBJECT pageObject,
+                      float* left,
+                      float* bottom,
+                      float* right,
+                      float* top) {
+  if (!pageObject)
+    return false;
+
+  CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(pageObject);
+  CFX_FloatRect bbox = pPageObj->GetRect();
+  *left = bbox.left;
+  *bottom = bbox.bottom;
+  *right = bbox.right;
+  *top = bbox.top;
+  return true;
 }
diff --git a/fpdfsdk/fpdfeditpath.cpp b/fpdfsdk/fpdfeditpath.cpp
index 074f083..a291987 100644
--- a/fpdfsdk/fpdfeditpath.cpp
+++ b/fpdfsdk/fpdfeditpath.cpp
@@ -2,125 +2,210 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <vector>
+
 #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"
+#include "fpdfsdk/fsdk_define.h"
+#include "third_party/base/ptr_util.h"
 
-DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_CreateNewPath(float x, float y) {
-  CPDF_PathObject* pPathObj = new CPDF_PathObject;
+// These checks are here because core/ and public/ cannot depend on each other.
+static_assert(CFX_GraphStateData::LineCapButt == FPDF_LINECAP_BUTT,
+              "CFX_GraphStateData::LineCapButt value mismatch");
+static_assert(CFX_GraphStateData::LineCapRound == FPDF_LINECAP_ROUND,
+              "CFX_GraphStateData::LineCapRound value mismatch");
+static_assert(CFX_GraphStateData::LineCapSquare ==
+                  FPDF_LINECAP_PROJECTING_SQUARE,
+              "CFX_GraphStateData::LineCapSquare value mismatch");
+
+static_assert(CFX_GraphStateData::LineJoinMiter == FPDF_LINEJOIN_MITER,
+              "CFX_GraphStateData::LineJoinMiter value mismatch");
+static_assert(CFX_GraphStateData::LineJoinRound == FPDF_LINEJOIN_ROUND,
+              "CFX_GraphStateData::LineJoinRound value mismatch");
+static_assert(CFX_GraphStateData::LineJoinBevel == FPDF_LINEJOIN_BEVEL,
+              "CFX_GraphStateData::LineJoinBevel value mismatch");
+
+static_assert(static_cast<int>(FXPT_TYPE::LineTo) == FPDF_SEGMENT_LINETO,
+              "FXPT_TYPE::LineTo value mismatch");
+static_assert(static_cast<int>(FXPT_TYPE::BezierTo) == FPDF_SEGMENT_BEZIERTO,
+              "FXPT_TYPE::BezierTo value mismatch");
+static_assert(static_cast<int>(FXPT_TYPE::MoveTo) == FPDF_SEGMENT_MOVETO,
+              "FXPT_TYPE::MoveTo value mismatch");
+
+FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewPath(float x,
+                                                                    float y) {
+  auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
   pPathObj->m_Path.AppendPoint(CFX_PointF(x, y), FXPT_TYPE::MoveTo, false);
   pPathObj->DefaultStates();
-  return pPathObj;
+  return pPathObj.release();  // Caller takes ownership.
 }
 
-DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_CreateNewRect(float x,
-                                                            float y,
-                                                            float w,
-                                                            float h) {
-  CPDF_PathObject* pPathObj = new CPDF_PathObject;
+FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewRect(float x,
+                                                                    float y,
+                                                                    float w,
+                                                                    float h) {
+  auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
   pPathObj->m_Path.AppendRect(x, y, x + w, y + h);
   pPathObj->DefaultStates();
-  return pPathObj;
+  return pPathObj.release();  // Caller takes ownership.
 }
 
-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)
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPath_SetStrokeColor(FPDF_PAGEOBJECT path,
+                        unsigned int R,
+                        unsigned int G,
+                        unsigned int B,
+                        unsigned int A) {
+  auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
+  if (!pPathObj || R > 255 || G > 255 || B > 255 || A > 255)
     return false;
 
-  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+  float rgb[3] = {R / 255.f, G / 255.f, B / 255.f};
   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);
+  pPathObj->SetDirty(true);
   return true;
 }
 
-DLLEXPORT FPDF_BOOL FPDFPath_SetStrokeWidth(FPDF_PAGEOBJECT path, float width) {
-  if (!path || width < 0.0f)
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPath_GetStrokeColor(FPDF_PAGEOBJECT path,
+                        unsigned int* R,
+                        unsigned int* G,
+                        unsigned int* B,
+                        unsigned int* A) {
+  auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
+  if (!pPathObj || !R || !G || !B || !A)
     return false;
 
-  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+  uint32_t strokeRGB = pPathObj->m_ColorState.GetStrokeRGB();
+  *R = FXSYS_GetRValue(strokeRGB);
+  *G = FXSYS_GetGValue(strokeRGB);
+  *B = FXSYS_GetBValue(strokeRGB);
+  *A = static_cast<unsigned int>(
+      (pPathObj->m_GeneralState.GetStrokeAlpha() * 255.f) + 0.5f);
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPath_SetStrokeWidth(FPDF_PAGEOBJECT path, float width) {
+  auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
+  if (!pPathObj || width < 0.0f)
+    return false;
+
   pPathObj->m_GraphState.SetLineWidth(width);
+  pPathObj->SetDirty(true);
   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)
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_SetFillColor(FPDF_PAGEOBJECT path,
+                                                          unsigned int R,
+                                                          unsigned int G,
+                                                          unsigned int B,
+                                                          unsigned int A) {
+  return FPDFPageObj_SetFillColor(path, R, G, B, A);
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_GetFillColor(FPDF_PAGEOBJECT path,
+                                                          unsigned int* R,
+                                                          unsigned int* G,
+                                                          unsigned int* B,
+                                                          unsigned int* A) {
+  auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
+  if (!pPathObj || !R || !G || !B || !A)
     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);
+  uint32_t fillRGB = pPathObj->m_ColorState.GetFillRGB();
+  *R = FXSYS_GetRValue(fillRGB);
+  *G = FXSYS_GetGValue(fillRGB);
+  *B = FXSYS_GetBValue(fillRGB);
+  *A = static_cast<unsigned int>(
+      (pPathObj->m_GeneralState.GetFillAlpha() * 255.f) + 0.5f);
   return true;
 }
 
-DLLEXPORT FPDF_BOOL FPDFPath_MoveTo(FPDF_PAGEOBJECT path, float x, float y) {
-  if (!path)
+FPDF_EXPORT int FPDF_CALLCONV FPDFPath_CountSegments(FPDF_PAGEOBJECT path) {
+  auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
+  if (!pPathObj)
+    return -1;
+  return pdfium::CollectionSize<int>(pPathObj->m_Path.GetPoints());
+}
+
+FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV
+FPDFPath_GetPathSegment(FPDF_PAGEOBJECT path, int index) {
+  auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
+  if (!pPathObj)
+    return nullptr;
+
+  const std::vector<FX_PATHPOINT>& points = pPathObj->m_Path.GetPoints();
+  return pdfium::IndexInBounds(points, index) ? &points[index] : nullptr;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_MoveTo(FPDF_PAGEOBJECT path,
+                                                    float x,
+                                                    float y) {
+  auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
+  if (!pPathObj)
     return false;
 
-  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
   pPathObj->m_Path.AppendPoint(CFX_PointF(x, y), FXPT_TYPE::MoveTo, false);
+  pPathObj->SetDirty(true);
   return true;
 }
 
-DLLEXPORT FPDF_BOOL FPDFPath_LineTo(FPDF_PAGEOBJECT path, float x, float y) {
-  if (!path)
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_LineTo(FPDF_PAGEOBJECT path,
+                                                    float x,
+                                                    float y) {
+  auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
+  if (!pPathObj)
     return false;
 
-  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
   pPathObj->m_Path.AppendPoint(CFX_PointF(x, y), FXPT_TYPE::LineTo, false);
+  pPathObj->SetDirty(true);
   return true;
 }
 
-DLLEXPORT FPDF_BOOL FPDFPath_BezierTo(FPDF_PAGEOBJECT path,
-                                      float x1,
-                                      float y1,
-                                      float x2,
-                                      float y2,
-                                      float x3,
-                                      float y3) {
-  if (!path)
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_BezierTo(FPDF_PAGEOBJECT path,
+                                                      float x1,
+                                                      float y1,
+                                                      float x2,
+                                                      float y2,
+                                                      float x3,
+                                                      float y3) {
+  auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
+  if (!pPathObj)
     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);
+  pPathObj->SetDirty(true);
   return true;
 }
 
-DLLEXPORT FPDF_BOOL FPDFPath_Close(FPDF_PAGEOBJECT path) {
-  if (!path)
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_Close(FPDF_PAGEOBJECT path) {
+  auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
+  if (!pPathObj)
     return false;
 
-  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
   if (pPathObj->m_Path.GetPoints().empty())
     return false;
 
   pPathObj->m_Path.ClosePath();
+  pPathObj->SetDirty(true);
   return true;
 }
 
-DLLEXPORT FPDF_BOOL FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path,
-                                         int fillmode,
-                                         FPDF_BOOL stroke) {
-  if (!path)
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path,
+                                                         int fillmode,
+                                                         FPDF_BOOL stroke) {
+  auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
+  if (!pPathObj)
     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)
@@ -128,5 +213,65 @@
   else
     pPathObj->m_FillType = 0;
   pPathObj->m_bStroke = stroke != 0;
+  pPathObj->SetDirty(true);
   return true;
 }
+
+FPDF_EXPORT void FPDF_CALLCONV FPDFPath_SetLineJoin(FPDF_PAGEOBJECT path,
+                                                    int line_join) {
+  if (!path)
+    return;
+  if (line_join <
+          static_cast<int>(CFX_GraphStateData::LineJoin::LineJoinMiter) ||
+      line_join >
+          static_cast<int>(CFX_GraphStateData::LineJoin::LineJoinBevel)) {
+    return;
+  }
+  auto* pPathObj = CPDFPageObjectFromFPDFPageObject(path);
+  CFX_GraphStateData::LineJoin lineJoin =
+      static_cast<CFX_GraphStateData::LineJoin>(line_join);
+  pPathObj->m_GraphState.SetLineJoin(lineJoin);
+  pPathObj->SetDirty(true);
+}
+
+FPDF_EXPORT void FPDF_CALLCONV FPDFPath_SetLineCap(FPDF_PAGEOBJECT path,
+                                                   int line_cap) {
+  if (!path)
+    return;
+  if (line_cap < static_cast<int>(CFX_GraphStateData::LineCap::LineCapButt) ||
+      line_cap > static_cast<int>(CFX_GraphStateData::LineCap::LineCapSquare)) {
+    return;
+  }
+  auto* pPathObj = CPDFPageObjectFromFPDFPageObject(path);
+  CFX_GraphStateData::LineCap lineCap =
+      static_cast<CFX_GraphStateData::LineCap>(line_cap);
+  pPathObj->m_GraphState.SetLineCap(lineCap);
+  pPathObj->SetDirty(true);
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment, float* x, float* y) {
+  auto* pPathPoint = FXPathPointFromFPDFPathSegment(segment);
+  if (!pPathPoint || !x || !y)
+    return false;
+
+  *x = pPathPoint->m_Point.x;
+  *y = pPathPoint->m_Point.y;
+
+  return true;
+}
+
+FPDF_EXPORT int FPDF_CALLCONV
+FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment) {
+  auto* pPathPoint = FXPathPointFromFPDFPathSegment(segment);
+
+  return pPathPoint ? static_cast<int>(pPathPoint->m_Type)
+                    : FPDF_SEGMENT_UNKNOWN;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment) {
+  auto* pPathPoint = FXPathPointFromFPDFPathSegment(segment);
+
+  return pPathPoint ? pPathPoint->m_CloseFigure : false;
+}
diff --git a/fpdfsdk/fpdfeditpath_embeddertest.cpp b/fpdfsdk/fpdfeditpath_embeddertest.cpp
new file mode 100644
index 0000000..59e5dbb
--- /dev/null
+++ b/fpdfsdk/fpdfeditpath_embeddertest.cpp
@@ -0,0 +1,63 @@
+// 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/fxcrt/fx_system.h"
+#include "public/fpdf_edit.h"
+#include "testing/embedder_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/test_support.h"
+
+class FPDFEditPathEmbedderTest : public EmbedderTest {};
+
+TEST_F(FPDFEditPathEmbedderTest, VerifyCorrectColoursReturned) {
+  CreateEmptyDocument();
+  FPDF_PAGE page = FPDFPage_New(document(), 0, 612, 792);
+
+  for (size_t i = 0; i < 256; ++i) {
+    FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(400, 100);
+    EXPECT_TRUE(FPDFPath_SetFillColor(path, i, i, i, i));
+    EXPECT_TRUE(FPDFPath_SetStrokeColor(path, i, i, i, i));
+    EXPECT_TRUE(FPDFPath_SetDrawMode(path, FPDF_FILLMODE_ALTERNATE, 0));
+    EXPECT_TRUE(FPDFPath_LineTo(path, 400, 200));
+    EXPECT_TRUE(FPDFPath_LineTo(path, 300, 100));
+    EXPECT_TRUE(FPDFPath_Close(path));
+
+    FPDFPage_InsertObject(page, path);
+  }
+
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+  FPDF_ClosePage(page);
+  page = nullptr;
+
+  OpenSavedDocument();
+  page = LoadSavedPage(0);
+  ASSERT(page);
+
+  for (size_t i = 0; i < 256; ++i) {
+    FPDF_PAGEOBJECT path = FPDFPage_GetObject(page, i);
+    ASSERT(path);
+
+    EXPECT_EQ(FPDF_PAGEOBJ_PATH, FPDFPageObj_GetType(path));
+
+    unsigned int r;
+    unsigned int g;
+    unsigned int b;
+    unsigned int a;
+    FPDFPath_GetFillColor(path, &r, &g, &b, &a);
+    EXPECT_EQ(i, r);
+    EXPECT_EQ(i, g);
+    EXPECT_EQ(i, b);
+    EXPECT_EQ(i, a);
+
+    FPDFPath_GetStrokeColor(path, &r, &g, &b, &a);
+    EXPECT_EQ(i, r);
+    EXPECT_EQ(i, g);
+    EXPECT_EQ(i, b);
+    EXPECT_EQ(i, a);
+  }
+
+  CloseSavedPage(page);
+  CloseSavedDocument();
+}
diff --git a/fpdfsdk/fpdfedittext.cpp b/fpdfsdk/fpdfedittext.cpp
index 8bf0a0a..22c6266 100644
--- a/fpdfsdk/fpdfedittext.cpp
+++ b/fpdfsdk/fpdfedittext.cpp
@@ -2,11 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <map>
+#include <memory>
 #include <utility>
+#include <vector>
 
 #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_docpagedata.h"
 #include "core/fpdfapi/page/cpdf_textobject.h"
 #include "core/fpdfapi/parser/cpdf_array.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
@@ -15,92 +19,34 @@
 #include "core/fpdfapi/parser/cpdf_number.h"
 #include "core/fpdfapi/parser/cpdf_reference.h"
 #include "core/fpdfapi/parser/cpdf_stream.h"
+#include "core/fxcrt/fx_extension.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;
+namespace {
 
-  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* LoadFontDesc(CPDF_Document* pDoc,
+                              const ByteString& font_name,
+                              CFX_Font* pFont,
+                              const uint8_t* data,
+                              uint32_t size,
+                              int font_type) {
   CPDF_Dictionary* fontDesc = pDoc->NewIndirect<CPDF_Dictionary>();
   fontDesc->SetNewFor<CPDF_Name>("Type", "FontDescriptor");
-  fontDesc->SetNewFor<CPDF_Name>("FontName", name);
+  fontDesc->SetNewFor<CPDF_Name>("FontName", font_name);
   int flags = 0;
   if (FXFT_Is_Face_fixedwidth(pFont->GetFace()))
     flags |= FXFONT_FIXED_PITCH;
-  if (name.Find("Serif") > -1)
+  if (font_name.Contains("Serif"))
     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
+  // TODO(npm): How do I know if a  font is symbolic, script, allcap, smallcap
   flags |= FXFONT_NONSYMBOLIC;
 
   fontDesc->SetNewFor<CPDF_Number>("Flags", flags);
@@ -108,9 +54,9 @@
   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);
+  pBBox->AddNew<CPDF_Number>(bbox.right);
+  pBBox->AddNew<CPDF_Number>(bbox.bottom);
   fontDesc->SetFor("FontBBox", std::move(pBBox));
 
   // TODO(npm): calculate italic angle correctly
@@ -125,8 +71,429 @@
 
   CPDF_Stream* pStream = pDoc->NewIndirect<CPDF_Stream>();
   pStream->SetData(data, size);
-  fontDesc->SetNewFor<CPDF_Reference>("FontFile", pDoc, pStream->GetObjNum());
+  // TODO(npm): Lengths for Type1 fonts.
+  if (font_type == FPDF_FONT_TRUETYPE) {
+    pStream->GetDict()->SetNewFor<CPDF_Number>("Length1",
+                                               static_cast<int>(size));
+  }
+  ByteString fontFile = font_type == FPDF_FONT_TYPE1 ? "FontFile" : "FontFile2";
+  fontDesc->SetNewFor<CPDF_Reference>(fontFile, pDoc, pStream->GetObjNum());
+  return fontDesc;
+}
+
+const char ToUnicodeStart[] =
+    "/CIDInit /ProcSet findresource begin\n"
+    "12 dict begin\n"
+    "begincmap\n"
+    "/CIDSystemInfo\n"
+    "<</Registry (Adobe)\n"
+    "/Ordering (Identity)\n"
+    "/Supplement 0\n"
+    ">> def\n"
+    "/CMapName /Adobe-Identity-H def\n"
+    "CMapType 2 def\n"
+    "1 begincodespacerange\n"
+    "<0000> <FFFFF>\n"
+    "endcodespacerange\n";
+
+const char ToUnicodeEnd[] =
+    "endcmap\n"
+    "CMapName currentdict /CMap defineresource pop\n"
+    "end\n"
+    "end\n";
+
+void AddCharcode(std::ostringstream* pBuffer, uint32_t number) {
+  ASSERT(number <= 0xFFFF);
+  *pBuffer << "<";
+  char ans[4];
+  FXSYS_IntToFourHexChars(number, ans);
+  for (size_t i = 0; i < 4; ++i)
+    *pBuffer << ans[i];
+  *pBuffer << ">";
+}
+
+// PDF spec 1.7 Section 5.9.2: "Unicode character sequences as expressed in
+// UTF-16BE encoding." See https://en.wikipedia.org/wiki/UTF-16#Description
+void AddUnicode(std::ostringstream* pBuffer, uint32_t unicode) {
+  if (unicode >= 0xD800 && unicode <= 0xDFFF)
+    unicode = 0;
+
+  char ans[8];
+  *pBuffer << "<";
+  size_t numChars = FXSYS_ToUTF16BE(unicode, ans);
+  for (size_t i = 0; i < numChars; ++i)
+    *pBuffer << ans[i];
+  *pBuffer << ">";
+}
+
+// Loads the charcode to unicode mapping into a stream
+CPDF_Stream* LoadUnicode(CPDF_Document* pDoc,
+                         const std::map<uint32_t, uint32_t>& to_unicode) {
+  // A map charcode->unicode
+  std::map<uint32_t, uint32_t> char_to_uni;
+  // A map <char_start, char_end> to vector v of unicode characters of size (end
+  // - start + 1). This abbreviates: start->v[0], start+1->v[1], etc. PDF spec
+  // 1.7 Section 5.9.2 says that only the last byte of the unicode may change.
+  std::map<std::pair<uint32_t, uint32_t>, std::vector<uint32_t>>
+      map_range_vector;
+  // A map <start, end> -> unicode
+  // This abbreviates: start->unicode, start+1->unicode+1, etc.
+  // PDF spec 1.7 Section 5.9.2 says that only the last byte of the unicode may
+  // change.
+  std::map<std::pair<uint32_t, uint32_t>, uint32_t> map_range;
+
+  // Calculate the maps
+  for (auto iter = to_unicode.begin(); iter != to_unicode.end(); ++iter) {
+    uint32_t firstCharcode = iter->first;
+    uint32_t firstUnicode = iter->second;
+    if (std::next(iter) == to_unicode.end() ||
+        firstCharcode + 1 != std::next(iter)->first) {
+      char_to_uni[firstCharcode] = firstUnicode;
+      continue;
+    }
+    ++iter;
+    uint32_t curCharcode = iter->first;
+    uint32_t curUnicode = iter->second;
+    if (curCharcode % 256 == 0) {
+      char_to_uni[firstCharcode] = firstUnicode;
+      char_to_uni[curCharcode] = curUnicode;
+      continue;
+    }
+    const size_t maxExtra = 255 - (curCharcode % 256);
+    auto next_it = std::next(iter);
+    if (firstUnicode + 1 != curUnicode) {
+      // Consecutive charcodes mapping to non-consecutive unicodes
+      std::vector<uint32_t> unicodes;
+      unicodes.push_back(firstUnicode);
+      unicodes.push_back(curUnicode);
+      for (size_t i = 0; i < maxExtra; ++i) {
+        if (next_it == to_unicode.end() || curCharcode + 1 != next_it->first)
+          break;
+        ++iter;
+        ++curCharcode;
+        unicodes.push_back(iter->second);
+        next_it = std::next(iter);
+      }
+      ASSERT(iter->first - firstCharcode + 1 == unicodes.size());
+      map_range_vector[std::make_pair(firstCharcode, iter->first)] = unicodes;
+      continue;
+    }
+    // Consecutive charcodes mapping to consecutive unicodes
+    for (size_t i = 0; i < maxExtra; ++i) {
+      if (next_it == to_unicode.end() || curCharcode + 1 != next_it->first ||
+          curUnicode + 1 != next_it->second) {
+        break;
+      }
+      ++iter;
+      ++curCharcode;
+      ++curUnicode;
+      next_it = std::next(iter);
+    }
+    map_range[std::make_pair(firstCharcode, curCharcode)] = firstUnicode;
+  }
+  std::ostringstream buffer;
+  buffer << ToUnicodeStart;
+  // Add maps to buffer
+  buffer << static_cast<uint32_t>(char_to_uni.size()) << " beginbfchar\n";
+  for (const auto& iter : char_to_uni) {
+    AddCharcode(&buffer, iter.first);
+    buffer << " ";
+    AddUnicode(&buffer, iter.second);
+    buffer << "\n";
+  }
+  buffer << "endbfchar\n"
+         << static_cast<uint32_t>(map_range_vector.size() + map_range.size())
+         << " beginbfrange\n";
+  for (const auto& iter : map_range_vector) {
+    const std::pair<uint32_t, uint32_t>& charcodeRange = iter.first;
+    AddCharcode(&buffer, charcodeRange.first);
+    buffer << " ";
+    AddCharcode(&buffer, charcodeRange.second);
+    buffer << " [";
+    const std::vector<uint32_t>& unicodes = iter.second;
+    for (size_t i = 0; i < unicodes.size(); ++i) {
+      uint32_t uni = unicodes[i];
+      AddUnicode(&buffer, uni);
+      if (i != unicodes.size() - 1)
+        buffer << " ";
+    }
+    buffer << "]\n";
+  }
+  for (const auto& iter : map_range) {
+    const std::pair<uint32_t, uint32_t>& charcodeRange = iter.first;
+    AddCharcode(&buffer, charcodeRange.first);
+    buffer << " ";
+    AddCharcode(&buffer, charcodeRange.second);
+    buffer << " ";
+    AddUnicode(&buffer, iter.second);
+    buffer << "\n";
+  }
+  buffer << "endbfrange\n";
+  buffer << ToUnicodeEnd;
+  // TODO(npm): Encrypt / Compress?
+  CPDF_Stream* stream = pDoc->NewIndirect<CPDF_Stream>();
+  stream->SetData(&buffer);
+  return stream;
+}
+
+const uint32_t kMaxSimpleFontChar = 0xFF;
+
+void* LoadSimpleFont(CPDF_Document* pDoc,
+                     std::unique_ptr<CFX_Font> pFont,
+                     const uint8_t* data,
+                     uint32_t size,
+                     int font_type) {
+  CPDF_Dictionary* fontDict = pDoc->NewIndirect<CPDF_Dictionary>();
+  fontDict->SetNewFor<CPDF_Name>("Type", "Font");
+  fontDict->SetNewFor<CPDF_Name>(
+      "Subtype", font_type == FPDF_FONT_TYPE1 ? "Type1" : "TrueType");
+  ByteString name = pFont->GetFaceName();
+  if (name.IsEmpty())
+    name = "Unnamed";
+  fontDict->SetNewFor<CPDF_Name>("BaseFont", name);
+
+  uint32_t glyphIndex;
+  uint32_t currentChar = FXFT_Get_First_Char(pFont->GetFace(), &glyphIndex);
+  if (currentChar > kMaxSimpleFontChar || glyphIndex == 0)
+    return nullptr;
+  fontDict->SetNewFor<CPDF_Number>("FirstChar", static_cast<int>(currentChar));
+  CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
+  while (true) {
+    widthsArray->AddNew<CPDF_Number>(pFont->GetGlyphWidth(glyphIndex));
+    uint32_t nextChar =
+        FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
+    // Simple fonts have 1-byte charcodes only.
+    if (nextChar > kMaxSimpleFontChar || glyphIndex == 0)
+      break;
+    for (uint32_t i = currentChar + 1; i < nextChar; i++)
+      widthsArray->AddNew<CPDF_Number>(0);
+    currentChar = nextChar;
+  }
+  fontDict->SetNewFor<CPDF_Number>("LastChar", static_cast<int>(currentChar));
+  fontDict->SetNewFor<CPDF_Reference>("Widths", pDoc, widthsArray->GetObjNum());
+  CPDF_Dictionary* fontDesc =
+      LoadFontDesc(pDoc, name, pFont.get(), data, size, font_type);
+
   fontDict->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
                                       fontDesc->GetObjNum());
   return pDoc->LoadFont(fontDict);
 }
+
+const uint32_t kMaxUnicode = 0x10FFFF;
+
+void* LoadCompositeFont(CPDF_Document* pDoc,
+                        std::unique_ptr<CFX_Font> pFont,
+                        const uint8_t* data,
+                        uint32_t size,
+                        int font_type) {
+  CPDF_Dictionary* fontDict = pDoc->NewIndirect<CPDF_Dictionary>();
+  fontDict->SetNewFor<CPDF_Name>("Type", "Font");
+  fontDict->SetNewFor<CPDF_Name>("Subtype", "Type0");
+  // TODO(npm): Get the correct encoding, if it's not identity.
+  ByteString encoding = "Identity-H";
+  fontDict->SetNewFor<CPDF_Name>("Encoding", encoding);
+  ByteString name = pFont->GetFaceName();
+  if (name.IsEmpty())
+    name = "Unnamed";
+  fontDict->SetNewFor<CPDF_Name>(
+      "BaseFont", font_type == FPDF_FONT_TYPE1 ? name + "-" + encoding : name);
+
+  CPDF_Dictionary* pCIDFont = pDoc->NewIndirect<CPDF_Dictionary>();
+  pCIDFont->SetNewFor<CPDF_Name>("Type", "Font");
+  pCIDFont->SetNewFor<CPDF_Name>("Subtype", font_type == FPDF_FONT_TYPE1
+                                                ? "CIDFontType0"
+                                                : "CIDFontType2");
+  pCIDFont->SetNewFor<CPDF_Name>("BaseFont", name);
+
+  // TODO(npm): Maybe use FT_Get_CID_Registry_Ordering_Supplement to get the
+  // CIDSystemInfo
+  CPDF_Dictionary* pCIDSystemInfo = pDoc->NewIndirect<CPDF_Dictionary>();
+  pCIDSystemInfo->SetNewFor<CPDF_Name>("Registry", "Adobe");
+  pCIDSystemInfo->SetNewFor<CPDF_Name>("Ordering", "Identity");
+  pCIDSystemInfo->SetNewFor<CPDF_Number>("Supplement", 0);
+  pCIDFont->SetNewFor<CPDF_Reference>("CIDSystemInfo", pDoc,
+                                      pCIDSystemInfo->GetObjNum());
+
+  CPDF_Dictionary* fontDesc =
+      LoadFontDesc(pDoc, name, pFont.get(), data, size, font_type);
+  pCIDFont->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
+                                      fontDesc->GetObjNum());
+
+  uint32_t glyphIndex;
+  uint32_t currentChar = FXFT_Get_First_Char(pFont->GetFace(), &glyphIndex);
+  // If it doesn't have a single char, just fail
+  if (glyphIndex == 0 || currentChar > kMaxUnicode)
+    return nullptr;
+
+  std::map<uint32_t, uint32_t> to_unicode;
+  std::map<uint32_t, uint32_t> widths;
+  while (true) {
+    if (currentChar > kMaxUnicode)
+      break;
+
+    widths[glyphIndex] = pFont->GetGlyphWidth(glyphIndex);
+    to_unicode[glyphIndex] = currentChar;
+    currentChar =
+        FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
+    if (glyphIndex == 0)
+      break;
+  }
+  CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
+  for (auto it = widths.begin(); it != widths.end(); ++it) {
+    int ch = it->first;
+    int w = it->second;
+    if (std::next(it) == widths.end()) {
+      // Only one char left, use format c [w]
+      auto oneW = pdfium::MakeUnique<CPDF_Array>();
+      oneW->AddNew<CPDF_Number>(w);
+      widthsArray->AddNew<CPDF_Number>(ch);
+      widthsArray->Add(std::move(oneW));
+      break;
+    }
+    ++it;
+    int next_ch = it->first;
+    int next_w = it->second;
+    if (next_ch == ch + 1 && next_w == w) {
+      // The array can have a group c_first c_last w: all CIDs in the range from
+      // c_first to c_last will have width w
+      widthsArray->AddNew<CPDF_Number>(ch);
+      ch = next_ch;
+      while (true) {
+        auto next_it = std::next(it);
+        if (next_it == widths.end() || next_it->first != it->first + 1 ||
+            next_it->second != it->second) {
+          break;
+        }
+        ++it;
+        ch = it->first;
+      }
+      widthsArray->AddNew<CPDF_Number>(ch);
+      widthsArray->AddNew<CPDF_Number>(w);
+      continue;
+    }
+    // Otherwise we can have a group of the form c [w1 w2 ...]: c has width
+    // w1, c+1 has width w2, etc.
+    widthsArray->AddNew<CPDF_Number>(ch);
+    auto curWidthArray = pdfium::MakeUnique<CPDF_Array>();
+    curWidthArray->AddNew<CPDF_Number>(w);
+    curWidthArray->AddNew<CPDF_Number>(next_w);
+    while (true) {
+      auto next_it = std::next(it);
+      if (next_it == widths.end() || next_it->first != it->first + 1)
+        break;
+      ++it;
+      curWidthArray->AddNew<CPDF_Number>(static_cast<int>(it->second));
+    }
+    widthsArray->Add(std::move(curWidthArray));
+  }
+  pCIDFont->SetNewFor<CPDF_Reference>("W", pDoc, widthsArray->GetObjNum());
+  // TODO(npm): Support vertical writing
+
+  auto pDescendant = pdfium::MakeUnique<CPDF_Array>();
+  pDescendant->AddNew<CPDF_Reference>(pDoc, pCIDFont->GetObjNum());
+  fontDict->SetFor("DescendantFonts", std::move(pDescendant));
+  CPDF_Stream* toUnicodeStream = LoadUnicode(pDoc, to_unicode);
+  fontDict->SetNewFor<CPDF_Reference>("ToUnicode", pDoc,
+                                      toUnicodeStream->GetObjNum());
+  return pDoc->LoadFont(fontDict);
+}
+
+}  // namespace
+
+FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
+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, ByteStringView(font));
+  if (!pFont)
+    return nullptr;
+
+  auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>();
+  pTextObj->m_TextState.SetFont(pFont);
+  pTextObj->m_TextState.SetFontSize(font_size);
+  pTextObj->DefaultStates();
+  return pTextObj.release();  // Caller takes ownership.
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFText_SetText(FPDF_PAGEOBJECT text_object, FPDF_WIDESTRING text) {
+  auto* pTextObj = static_cast<CPDF_TextObject*>(text_object);
+  if (!pTextObj)
+    return false;
+
+  size_t len = WideString::WStringLength(text);
+  WideString encodedText = WideString::FromUTF16LE(text, len);
+  ByteString byteText;
+  for (wchar_t wc : encodedText) {
+    pTextObj->GetFont()->AppendChar(
+        &byteText, pTextObj->GetFont()->CharCodeFromUnicode(wc));
+  }
+  pTextObj->SetText(byteText);
+  return true;
+}
+
+FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadFont(FPDF_DOCUMENT document,
+                                                      const uint8_t* data,
+                                                      uint32_t size,
+                                                      int font_type,
+                                                      FPDF_BOOL cid) {
+  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+  if (!pDoc || !data || size == 0 ||
+      (font_type != FPDF_FONT_TYPE1 && font_type != FPDF_FONT_TRUETYPE)) {
+    return nullptr;
+  }
+
+  auto pFont = pdfium::MakeUnique<CFX_Font>();
+
+  // TODO(npm): Maybe use FT_Get_X11_Font_Format to check format? Otherwise, we
+  // are allowing giving any font that can be loaded on freetype and setting it
+  // as any font type.
+  if (!pFont->LoadEmbedded(data, size))
+    return nullptr;
+
+  return cid ? LoadCompositeFont(pDoc, std::move(pFont), data, size, font_type)
+             : LoadSimpleFont(pDoc, std::move(pFont), data, size, font_type);
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFText_SetFillColor(FPDF_PAGEOBJECT text_object,
+                      unsigned int R,
+                      unsigned int G,
+                      unsigned int B,
+                      unsigned int A) {
+  return FPDFPageObj_SetFillColor(text_object, R, G, B, A);
+}
+
+FPDF_EXPORT void FPDF_CALLCONV FPDFFont_Close(FPDF_FONT font) {
+  CPDF_Font* pFont = static_cast<CPDF_Font*>(font);
+  if (!pFont)
+    return;
+
+  CPDF_Document* pDoc = pFont->GetDocument();
+  if (!pDoc)
+    return;
+
+  CPDF_DocPageData* pPageData = pDoc->GetPageData();
+  if (!pPageData->IsForceClear())
+    pPageData->ReleaseFont(pFont->GetFontDict());
+}
+
+FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
+FPDFPageObj_CreateTextObj(FPDF_DOCUMENT document,
+                          FPDF_FONT font,
+                          float font_size) {
+  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+  CPDF_Font* pFont = static_cast<CPDF_Font*>(font);
+  if (!pDoc || !pFont)
+    return nullptr;
+
+  auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>();
+  pTextObj->m_TextState.SetFont(pDoc->LoadFont(pFont->GetFontDict()));
+  pTextObj->m_TextState.SetFontSize(font_size);
+  pTextObj->DefaultStates();
+  return pTextObj.release();
+}
diff --git a/fpdfsdk/fpdfformfill.cpp b/fpdfsdk/fpdfformfill.cpp
index 57ff6b6..10aecb3 100644
--- a/fpdfsdk/fpdfformfill.cpp
+++ b/fpdfsdk/fpdfformfill.cpp
@@ -16,7 +16,7 @@
 #include "core/fpdfdoc/cpdf_formfield.h"
 #include "core/fpdfdoc/cpdf_interform.h"
 #include "core/fpdfdoc/cpdf_occontext.h"
-#include "core/fxge/cfx_fxgedevice.h"
+#include "core/fxge/cfx_defaultrenderdevice.h"
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 #include "fpdfsdk/cpdfsdk_interform.h"
 #include "fpdfsdk/cpdfsdk_pageview.h"
@@ -29,11 +29,73 @@
 #ifdef PDF_ENABLE_XFA
 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
-#include "xfa/fxfa/xfa_ffdocview.h"
-#include "xfa/fxfa/xfa_ffpageview.h"
-#include "xfa/fxfa/xfa_ffwidget.h"
+#include "xfa/fxfa/cxfa_ffdocview.h"
+#include "xfa/fxfa/cxfa_ffpageview.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
+
+static_assert(static_cast<int>(FormType::kNone) == FORMTYPE_NONE,
+              "None form types must match");
+static_assert(static_cast<int>(FormType::kAcroForm) == FORMTYPE_ACRO_FORM,
+              "AcroForm form types must match");
+static_assert(static_cast<int>(FormType::kXFAFull) == FORMTYPE_XFA_FULL,
+              "XFA full form types must match");
+static_assert(static_cast<int>(FormType::kXFAForeground) ==
+                  FORMTYPE_XFA_FOREGROUND,
+              "XFA foreground form types must match");
 #endif  // PDF_ENABLE_XFA
 
+static_assert(static_cast<int>(FormFieldType::kUnknown) ==
+                  FPDF_FORMFIELD_UNKNOWN,
+              "Unknown form field types must match");
+static_assert(static_cast<int>(FormFieldType::kPushButton) ==
+                  FPDF_FORMFIELD_PUSHBUTTON,
+              "PushButton form field types must match");
+static_assert(static_cast<int>(FormFieldType::kCheckBox) ==
+                  FPDF_FORMFIELD_CHECKBOX,
+              "CheckBox form field types must match");
+static_assert(static_cast<int>(FormFieldType::kRadioButton) ==
+                  FPDF_FORMFIELD_RADIOBUTTON,
+              "RadioButton form field types must match");
+static_assert(static_cast<int>(FormFieldType::kComboBox) ==
+                  FPDF_FORMFIELD_COMBOBOX,
+              "ComboBox form field types must match");
+static_assert(static_cast<int>(FormFieldType::kListBox) ==
+                  FPDF_FORMFIELD_LISTBOX,
+              "ListBox form field types must match");
+static_assert(static_cast<int>(FormFieldType::kTextField) ==
+                  FPDF_FORMFIELD_TEXTFIELD,
+              "TextField form field types must match");
+static_assert(static_cast<int>(FormFieldType::kSignature) ==
+                  FPDF_FORMFIELD_SIGNATURE,
+              "Signature form field types must match");
+#ifdef PDF_ENABLE_XFA
+static_assert(static_cast<int>(FormFieldType::kXFA) == FPDF_FORMFIELD_XFA,
+              "XFA form field types must match");
+static_assert(static_cast<int>(FormFieldType::kXFA_CheckBox) ==
+                  FPDF_FORMFIELD_XFA_CHECKBOX,
+              "XFA CheckBox form field types must match");
+static_assert(static_cast<int>(FormFieldType::kXFA_ComboBox) ==
+                  FPDF_FORMFIELD_XFA_COMBOBOX,
+              "XFA ComboBox form field types must match");
+static_assert(static_cast<int>(FormFieldType::kXFA_ImageField) ==
+                  FPDF_FORMFIELD_XFA_IMAGEFIELD,
+              "XFA ImageField form field types must match");
+static_assert(static_cast<int>(FormFieldType::kXFA_ListBox) ==
+                  FPDF_FORMFIELD_XFA_LISTBOX,
+              "XFA ListBox form field types must match");
+static_assert(static_cast<int>(FormFieldType::kXFA_PushButton) ==
+                  FPDF_FORMFIELD_XFA_PUSHBUTTON,
+              "XFA PushButton form field types must match");
+static_assert(static_cast<int>(FormFieldType::kXFA_Signature) ==
+                  FPDF_FORMFIELD_XFA_SIGNATURE,
+              "XFA Signature form field types must match");
+static_assert(static_cast<int>(FormFieldType::kXFA_TextField) ==
+                  FPDF_FORMFIELD_XFA_TEXTFIELD,
+              "XFA TextField form field types must match");
+#endif  // PDF_ENABLE_XFA
+static_assert(kFormFieldTypeCount == FPDF_FORMFIELD_COUNT,
+              "Number of form field types must match");
+
 namespace {
 
 CPDFSDK_FormFillEnvironment* HandleToCPDFSDKEnvironment(
@@ -59,12 +121,12 @@
 }
 
 #ifdef PDF_ENABLE_XFA
-std::vector<CFX_ByteString>* FromFPDFStringHandle(FPDF_STRINGHANDLE handle) {
-  return reinterpret_cast<std::vector<CFX_ByteString>*>(handle);
+std::vector<ByteString>* FromFPDFStringHandle(FPDF_STRINGHANDLE handle) {
+  return static_cast<std::vector<ByteString>*>(handle);
 }
 
-FPDF_STRINGHANDLE ToFPDFStringHandle(std::vector<CFX_ByteString>* strings) {
-  return reinterpret_cast<FPDF_STRINGHANDLE>(strings);
+FPDF_STRINGHANDLE ToFPDFStringHandle(std::vector<ByteString>* strings) {
+  return static_cast<FPDF_STRINGHANDLE>(strings);
 }
 #endif  // PDF_ENABLE_XFA
 
@@ -102,67 +164,68 @@
       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);
+  auto pDevice = pdfium::MakeUnique<CFX_DefaultRenderDevice>();
 #ifdef _SKIA_SUPPORT_
   pDevice->AttachRecorder(static_cast<SkPictureRecorder*>(recorder));
 #endif
-  pDevice->Attach(CFXBitmapFromFPDFBitmap(bitmap), false, nullptr, false);
-  pDevice->SaveState();
-  pDevice->SetClip_Rect(clip);
+  RetainPtr<CFX_DIBitmap> holder(CFXBitmapFromFPDFBitmap(bitmap));
+  pDevice->Attach(holder, false, nullptr, false);
+  {
+    CFX_RenderDevice::StateRestorer restorer(pDevice.get());
+    pDevice->SetClip_Rect(clip);
 
-  CPDF_RenderOptions options;
-  if (flags & FPDF_LCD_TEXT)
-    options.m_Flags |= RENDER_CLEARTYPE;
-  else
-    options.m_Flags &= ~RENDER_CLEARTYPE;
+    CPDF_RenderOptions options;
+    uint32_t option_flags = options.GetFlags();
+    if (flags & FPDF_LCD_TEXT)
+      option_flags |= RENDER_CLEARTYPE;
+    else
+      option_flags &= ~RENDER_CLEARTYPE;
+    options.SetFlags(option_flags);
 
-  // Grayscale output
-  if (flags & FPDF_GRAYSCALE) {
-    options.m_ColorMode = RENDER_COLOR_GRAY;
-    options.m_ForeColor = 0;
-    options.m_BackColor = 0xffffff;
-  }
-  options.m_AddFlags = flags >> 8;
-  options.m_bDrawAnnots = flags & FPDF_ANNOT;
+    // Grayscale output
+    if (flags & FPDF_GRAYSCALE)
+      options.SetColorMode(CPDF_RenderOptions::kGray);
+
+    options.SetDrawAnnots(flags & FPDF_ANNOT);
 
 #ifdef PDF_ENABLE_XFA
-  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);
+    options.SetOCContext(
+        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 = pdfium::MakeRetain<CPDF_OCContext>(
-      pPage->m_pDocument, CPDF_OCContext::View);
-  if (CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, pPage))
-    pPageView->PageView_OnDraw(pDevice.get(), &matrix, &options);
+    options.SetOCContext(pdfium::MakeRetain<CPDF_OCContext>(
+        pPage->m_pDocument.Get(), CPDF_OCContext::View));
+    if (CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, pPage))
+      pPageView->PageView_OnDraw(pDevice.get(), &matrix, &options);
 #endif  // PDF_ENABLE_XFA
-
-  pDevice->RestoreState(false);
+  }
 #ifdef _SKIA_SUPPORT_PATHS_
-  pDevice->Flush();
-  CFXBitmapFromFPDFBitmap(bitmap)->UnPreMultiply();
+  pDevice->Flush(true);
+  holder->UnPreMultiply();
 #endif
 }
 
 }  // namespace
 
-DLLEXPORT int STDCALL FPDFPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle,
-                                                   FPDF_PAGE page,
-                                                   double page_x,
-                                                   double page_y) {
+FPDF_EXPORT int FPDF_CALLCONV
+FPDFPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle,
+                             FPDF_PAGE page,
+                             double page_x,
+                             double page_y) {
   if (!hHandle)
     return -1;
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (pPage) {
-    CPDF_InterForm interform(pPage->m_pDocument);
+    CPDF_InterForm interform(pPage->m_pDocument.Get());
     CPDF_FormControl* pFormCtrl = interform.GetControlAtPoint(
-        pPage, CFX_PointF(static_cast<FX_FLOAT>(page_x),
-                          static_cast<FX_FLOAT>(page_y)),
+        pPage,
+        CFX_PointF(static_cast<float>(page_x), static_cast<float>(page_y)),
         nullptr);
     if (!pFormCtrl)
       return -1;
     CPDF_FormField* pFormField = pFormCtrl->GetField();
-    return pFormField ? pFormField->GetFieldType() : -1;
+    return pFormField ? static_cast<int>(pFormField->GetFieldType()) : -1;
   }
 
 #ifdef PDF_ENABLE_XFA
@@ -188,52 +251,40 @@
   if (!pWidgetIterator)
     return -1;
 
-  CXFA_FFWidget* pXFAAnnot = pWidgetIterator->MoveToNext();
-  while (pXFAAnnot) {
+  CXFA_FFWidget* pXFAAnnot;
+  while ((pXFAAnnot = pWidgetIterator->MoveToNext()) != nullptr) {
     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;
-    rcWidget.right += 1.0f;
-    rcWidget.bottom -= 1.0f;
-    rcWidget.top += 1.0f;
-
-    if (rcWidget.Contains(CFX_PointF(static_cast<FX_FLOAT>(page_x),
-                                     static_cast<FX_FLOAT>(page_y)))) {
-      return FPDF_FORMFIELD_XFA;
+    rcWidget.Inflate(1.0f, 1.0f);
+    if (rcWidget.Contains(CFX_PointF(static_cast<float>(page_x),
+                                     static_cast<float>(page_y)))) {
+      return static_cast<int>(pXFAAnnot->GetFormFieldType());
     }
-    pXFAAnnot = pWidgetIterator->MoveToNext();
   }
 #endif  // PDF_ENABLE_XFA
   return -1;
 }
 
-DLLEXPORT int STDCALL FPDPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle,
-                                                  FPDF_PAGE page,
-                                                  double page_x,
-                                                  double page_y) {
-  return FPDFPage_HasFormFieldAtPoint(hHandle, page, page_x, page_y);
-}
-
-DLLEXPORT int STDCALL FPDFPage_FormFieldZOrderAtPoint(FPDF_FORMHANDLE hHandle,
-                                                      FPDF_PAGE page,
-                                                      double page_x,
-                                                      double page_y) {
+FPDF_EXPORT int FPDF_CALLCONV
+FPDFPage_FormFieldZOrderAtPoint(FPDF_FORMHANDLE hHandle,
+                                FPDF_PAGE page,
+                                double page_x,
+                                double page_y) {
   if (!hHandle)
     return -1;
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!pPage)
     return -1;
-  CPDF_InterForm interform(pPage->m_pDocument);
+  CPDF_InterForm interform(pPage->m_pDocument.Get());
   int z_order = -1;
   (void)interform.GetControlAtPoint(
-      pPage,
-      CFX_PointF(static_cast<FX_FLOAT>(page_x), static_cast<FX_FLOAT>(page_y)),
+      pPage, CFX_PointF(static_cast<float>(page_x), static_cast<float>(page_y)),
       &z_order);
   return z_order;
 }
 
-DLLEXPORT FPDF_FORMHANDLE STDCALL
+FPDF_EXPORT FPDF_FORMHANDLE FPDF_CALLCONV
 FPDFDOC_InitFormFillEnvironment(FPDF_DOCUMENT document,
                                 FPDF_FORMFILLINFO* formInfo) {
 #ifdef PDF_ENABLE_XFA
@@ -256,23 +307,22 @@
     return pDocument->GetFormFillEnv();
 #endif
 
-  CPDFSDK_FormFillEnvironment* pFormFillEnv =
-      new CPDFSDK_FormFillEnvironment(pDocument, formInfo);
+  auto pFormFillEnv =
+      pdfium::MakeUnique<CPDFSDK_FormFillEnvironment>(pDocument, formInfo);
 
 #ifdef PDF_ENABLE_XFA
-  pDocument->SetFormFillEnv(pFormFillEnv);
+  pDocument->SetFormFillEnv(pFormFillEnv.get());
 #endif  // PDF_ENABLE_XFA
 
-  return pFormFillEnv;
+  return pFormFillEnv.release();  // Caller takes ownership.
 }
 
-DLLEXPORT void STDCALL
+FPDF_EXPORT void FPDF_CALLCONV
 FPDFDOC_ExitFormFillEnvironment(FPDF_FORMHANDLE hHandle) {
-  if (!hHandle)
-    return;
-
   CPDFSDK_FormFillEnvironment* pFormFillEnv =
       HandleToCPDFSDKEnvironment(hHandle);
+  if (!pFormFillEnv)
+    return;
 
 #ifdef PDF_ENABLE_XFA
   // Reset the focused annotations and remove the SDK document from the
@@ -283,105 +333,141 @@
   if (pFormFillEnv->GetXFAContext())
     pFormFillEnv->GetXFAContext()->SetFormFillEnv(nullptr);
 #endif  // PDF_ENABLE_XFA
-
   delete pFormFillEnv;
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FORM_OnMouseMove(FPDF_FORMHANDLE hHandle,
-                                             FPDF_PAGE page,
-                                             int modifier,
-                                             double page_x,
-                                             double page_y) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseMove(FPDF_FORMHANDLE hHandle,
+                                                     FPDF_PAGE page,
+                                                     int modifier,
+                                                     double page_x,
+                                                     double page_y) {
   CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
   if (!pPageView)
     return false;
   return pPageView->OnMouseMove(CFX_PointF(page_x, page_y), modifier);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FORM_OnLButtonDown(FPDF_FORMHANDLE hHandle,
-                                               FPDF_PAGE page,
-                                               int modifier,
-                                               double page_x,
-                                               double page_y) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnFocus(FPDF_FORMHANDLE hHandle,
+                                                 FPDF_PAGE page,
+                                                 int modifier,
+                                                 double page_x,
+                                                 double page_y) {
+  CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
+  if (!pPageView)
+    return false;
+  return pPageView->OnFocus(CFX_PointF(page_x, page_y), modifier);
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonDown(FPDF_FORMHANDLE hHandle,
+                                                       FPDF_PAGE page,
+                                                       int modifier,
+                                                       double page_x,
+                                                       double page_y) {
   CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
   if (!pPageView)
     return false;
   return pPageView->OnLButtonDown(CFX_PointF(page_x, page_y), modifier);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FORM_OnLButtonUp(FPDF_FORMHANDLE hHandle,
-                                             FPDF_PAGE page,
-                                             int modifier,
-                                             double page_x,
-                                             double page_y) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonUp(FPDF_FORMHANDLE hHandle,
+                                                     FPDF_PAGE page,
+                                                     int modifier,
+                                                     double page_x,
+                                                     double page_y) {
   CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
   if (!pPageView)
     return false;
-
-  CFX_PointF pt((FX_FLOAT)page_x, (FX_FLOAT)page_y);
-  return pPageView->OnLButtonUp(pt, modifier);
+  return pPageView->OnLButtonUp(CFX_PointF(page_x, page_y), modifier);
 }
 
 #ifdef PDF_ENABLE_XFA
-DLLEXPORT FPDF_BOOL STDCALL FORM_OnRButtonDown(FPDF_FORMHANDLE hHandle,
-                                               FPDF_PAGE page,
-                                               int modifier,
-                                               double page_x,
-                                               double page_y) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonDown(FPDF_FORMHANDLE hHandle,
+                                                       FPDF_PAGE page,
+                                                       int modifier,
+                                                       double page_x,
+                                                       double page_y) {
   CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
   if (!pPageView)
     return false;
   return pPageView->OnRButtonDown(CFX_PointF(page_x, page_y), modifier);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FORM_OnRButtonUp(FPDF_FORMHANDLE hHandle,
-                                             FPDF_PAGE page,
-                                             int modifier,
-                                             double page_x,
-                                             double page_y) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonUp(FPDF_FORMHANDLE hHandle,
+                                                     FPDF_PAGE page,
+                                                     int modifier,
+                                                     double page_x,
+                                                     double page_y) {
   CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
   if (!pPageView)
     return false;
-
-  CFX_PointF pt((FX_FLOAT)page_x, (FX_FLOAT)page_y);
-  return pPageView->OnRButtonUp(pt, modifier);
+  return pPageView->OnRButtonUp(CFX_PointF(page_x, page_y), modifier);
 }
 #endif  // PDF_ENABLE_XFA
 
-DLLEXPORT FPDF_BOOL STDCALL FORM_OnKeyDown(FPDF_FORMHANDLE hHandle,
-                                           FPDF_PAGE page,
-                                           int nKeyCode,
-                                           int modifier) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyDown(FPDF_FORMHANDLE hHandle,
+                                                   FPDF_PAGE page,
+                                                   int nKeyCode,
+                                                   int modifier) {
   CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
   if (!pPageView)
     return false;
-
   return pPageView->OnKeyDown(nKeyCode, modifier);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FORM_OnKeyUp(FPDF_FORMHANDLE hHandle,
-                                         FPDF_PAGE page,
-                                         int nKeyCode,
-                                         int modifier) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyUp(FPDF_FORMHANDLE hHandle,
+                                                 FPDF_PAGE page,
+                                                 int nKeyCode,
+                                                 int modifier) {
   CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
   if (!pPageView)
     return false;
-
   return pPageView->OnKeyUp(nKeyCode, modifier);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FORM_OnChar(FPDF_FORMHANDLE hHandle,
-                                        FPDF_PAGE page,
-                                        int nChar,
-                                        int modifier) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnChar(FPDF_FORMHANDLE hHandle,
+                                                FPDF_PAGE page,
+                                                int nChar,
+                                                int modifier) {
   CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
   if (!pPageView)
     return false;
-
   return pPageView->OnChar(nChar, modifier);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FORM_ForceToKillFocus(FPDF_FORMHANDLE hHandle) {
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FORM_GetSelectedText(FPDF_FORMHANDLE hHandle,
+                     FPDF_PAGE page,
+                     void* buffer,
+                     unsigned long buflen) {
+  CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
+  if (!pPageView)
+    return 0;
+
+  WideString wide_str_form_text = pPageView->GetSelectedText();
+  ByteString encoded_form_text = wide_str_form_text.UTF16LE_Encode();
+  unsigned long form_text_len = encoded_form_text.GetLength();
+
+  if (buffer && buflen >= form_text_len)
+    memcpy(buffer, encoded_form_text.c_str(), form_text_len);
+
+  return form_text_len;
+}
+
+FPDF_EXPORT void FPDF_CALLCONV FORM_ReplaceSelection(FPDF_FORMHANDLE hHandle,
+                                                     FPDF_PAGE page,
+                                                     FPDF_WIDESTRING wsText) {
+  CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
+  if (!pPageView)
+    return;
+
+  size_t len = WideString::WStringLength(wsText);
+  WideString wide_str_text = WideString::FromUTF16LE(wsText, len);
+
+  pPageView->ReplaceSelection(wide_str_text);
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FORM_ForceToKillFocus(FPDF_FORMHANDLE hHandle) {
   CPDFSDK_FormFillEnvironment* pFormFillEnv =
       HandleToCPDFSDKEnvironment(hHandle);
   if (!pFormFillEnv)
@@ -389,90 +475,86 @@
   return pFormFillEnv->KillFocusAnnot(0);
 }
 
-DLLEXPORT void STDCALL FPDF_FFLDraw(FPDF_FORMHANDLE hHandle,
-                                    FPDF_BITMAP bitmap,
-                                    FPDF_PAGE page,
-                                    int start_x,
-                                    int start_y,
-                                    int size_x,
-                                    int size_y,
-                                    int rotate,
-                                    int flags) {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDraw(FPDF_FORMHANDLE hHandle,
+                                            FPDF_BITMAP bitmap,
+                                            FPDF_PAGE page,
+                                            int start_x,
+                                            int start_y,
+                                            int size_x,
+                                            int size_y,
+                                            int rotate,
+                                            int flags) {
   FFLCommon(hHandle, bitmap, nullptr, page, start_x, start_y, size_x, size_y,
             rotate, flags);
 }
 
 #ifdef _SKIA_SUPPORT_
-DLLEXPORT void STDCALL FPDF_FFLRecord(FPDF_FORMHANDLE hHandle,
-                                      FPDF_RECORDER recorder,
-                                      FPDF_PAGE page,
-                                      int start_x,
-                                      int start_y,
-                                      int size_x,
-                                      int size_y,
-                                      int rotate,
-                                      int flags) {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_FFLRecord(FPDF_FORMHANDLE hHandle,
+                                              FPDF_RECORDER recorder,
+                                              FPDF_PAGE page,
+                                              int start_x,
+                                              int start_y,
+                                              int size_x,
+                                              int size_y,
+                                              int rotate,
+                                              int flags) {
   FFLCommon(hHandle, nullptr, recorder, page, start_x, start_y, size_x, size_y,
             rotate, flags);
 }
 #endif
 
 #ifdef PDF_ENABLE_XFA
-DLLEXPORT void STDCALL FPDF_Widget_Undo(FPDF_DOCUMENT document,
-                                        FPDF_WIDGET hWidget) {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_Widget_Undo(FPDF_DOCUMENT document,
+                                                FPDF_WIDGET hWidget) {
   if (!hWidget || !document)
     return;
 
   CPDFXFA_Context* pContext = static_cast<CPDFXFA_Context*>(document);
-  if (pContext->GetDocType() != XFA_DOCTYPE_Dynamic &&
-      pContext->GetDocType() != XFA_DOCTYPE_Static)
+  if (!pContext->ContainsXFAForm())
     return;
 
   static_cast<CXFA_FFWidget*>(hWidget)->Undo();
 }
 
-DLLEXPORT void STDCALL FPDF_Widget_Redo(FPDF_DOCUMENT document,
-                                        FPDF_WIDGET hWidget) {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_Widget_Redo(FPDF_DOCUMENT document,
+                                                FPDF_WIDGET hWidget) {
   if (!hWidget || !document)
     return;
 
   CPDFXFA_Context* pContext = static_cast<CPDFXFA_Context*>(document);
-  if (pContext->GetDocType() != XFA_DOCTYPE_Dynamic &&
-      pContext->GetDocType() != XFA_DOCTYPE_Static)
+  if (!pContext->ContainsXFAForm())
     return;
 
   static_cast<CXFA_FFWidget*>(hWidget)->Redo();
 }
 
-DLLEXPORT void STDCALL FPDF_Widget_SelectAll(FPDF_DOCUMENT document,
-                                             FPDF_WIDGET hWidget) {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_Widget_SelectAll(FPDF_DOCUMENT document,
+                                                     FPDF_WIDGET hWidget) {
   if (!hWidget || !document)
     return;
 
   CPDFXFA_Context* pContext = static_cast<CPDFXFA_Context*>(document);
-  if (pContext->GetDocType() != XFA_DOCTYPE_Dynamic &&
-      pContext->GetDocType() != XFA_DOCTYPE_Static)
+  if (!pContext->ContainsXFAForm())
     return;
 
   static_cast<CXFA_FFWidget*>(hWidget)->SelectAll();
 }
 
-DLLEXPORT void STDCALL FPDF_Widget_Copy(FPDF_DOCUMENT document,
-                                        FPDF_WIDGET hWidget,
-                                        FPDF_WIDESTRING wsText,
-                                        FPDF_DWORD* size) {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_Widget_Copy(FPDF_DOCUMENT document,
+                                                FPDF_WIDGET hWidget,
+                                                FPDF_WIDESTRING wsText,
+                                                FPDF_DWORD* size) {
   if (!hWidget || !document)
     return;
 
   CPDFXFA_Context* pContext = static_cast<CPDFXFA_Context*>(document);
-  if (pContext->GetDocType() != XFA_DOCTYPE_Dynamic &&
-      pContext->GetDocType() != XFA_DOCTYPE_Static)
+  if (!pContext->ContainsXFAForm())
     return;
 
-  CFX_WideString wsCpText;
-  static_cast<CXFA_FFWidget*>(hWidget)->Copy(wsCpText);
+  WideString wsCpText =
+      static_cast<CXFA_FFWidget*>(hWidget)->Copy().value_or(WideString());
 
-  CFX_ByteString bsCpText = wsCpText.UTF16LE_Encode();
+  ByteString bsCpText = wsCpText.UTF16LE_Encode();
   uint32_t len = bsCpText.GetLength() / sizeof(unsigned short);
   if (!wsText) {
     *size = len;
@@ -481,30 +563,29 @@
 
   uint32_t real_size = len < *size ? len : *size;
   if (real_size > 0) {
-    FXSYS_memcpy((void*)wsText,
-                 bsCpText.GetBuffer(real_size * sizeof(unsigned short)),
-                 real_size * sizeof(unsigned short));
+    memcpy((void*)wsText,
+           bsCpText.GetBuffer(real_size * sizeof(unsigned short)),
+           real_size * sizeof(unsigned short));
     bsCpText.ReleaseBuffer(real_size * sizeof(unsigned short));
   }
   *size = real_size;
 }
 
-DLLEXPORT void STDCALL FPDF_Widget_Cut(FPDF_DOCUMENT document,
-                                       FPDF_WIDGET hWidget,
-                                       FPDF_WIDESTRING wsText,
-                                       FPDF_DWORD* size) {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_Widget_Cut(FPDF_DOCUMENT document,
+                                               FPDF_WIDGET hWidget,
+                                               FPDF_WIDESTRING wsText,
+                                               FPDF_DWORD* size) {
   if (!hWidget || !document)
     return;
 
   CPDFXFA_Context* pContext = static_cast<CPDFXFA_Context*>(document);
-  if (pContext->GetDocType() != XFA_DOCTYPE_Dynamic &&
-      pContext->GetDocType() != XFA_DOCTYPE_Static)
+  if (!pContext->ContainsXFAForm())
     return;
 
-  CFX_WideString wsCpText;
-  static_cast<CXFA_FFWidget*>(hWidget)->Cut(wsCpText);
+  WideString wsCpText =
+      static_cast<CXFA_FFWidget*>(hWidget)->Cut().value_or(WideString());
 
-  CFX_ByteString bsCpText = wsCpText.UTF16LE_Encode();
+  ByteString bsCpText = wsCpText.UTF16LE_Encode();
   uint32_t len = bsCpText.GetLength() / sizeof(unsigned short);
   if (!wsText) {
     *size = len;
@@ -513,31 +594,30 @@
 
   uint32_t real_size = len < *size ? len : *size;
   if (real_size > 0) {
-    FXSYS_memcpy((void*)wsText,
-                 bsCpText.GetBuffer(real_size * sizeof(unsigned short)),
-                 real_size * sizeof(unsigned short));
+    memcpy((void*)wsText,
+           bsCpText.GetBuffer(real_size * sizeof(unsigned short)),
+           real_size * sizeof(unsigned short));
     bsCpText.ReleaseBuffer(real_size * sizeof(unsigned short));
   }
   *size = real_size;
 }
 
-DLLEXPORT void STDCALL FPDF_Widget_Paste(FPDF_DOCUMENT document,
-                                         FPDF_WIDGET hWidget,
-                                         FPDF_WIDESTRING wsText,
-                                         FPDF_DWORD size) {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_Widget_Paste(FPDF_DOCUMENT document,
+                                                 FPDF_WIDGET hWidget,
+                                                 FPDF_WIDESTRING wsText,
+                                                 FPDF_DWORD size) {
   if (!hWidget || !document)
     return;
 
   CPDFXFA_Context* pContext = static_cast<CPDFXFA_Context*>(document);
-  if (pContext->GetDocType() != XFA_DOCTYPE_Dynamic &&
-      pContext->GetDocType() != XFA_DOCTYPE_Static)
+  if (!pContext->ContainsXFAForm())
     return;
 
-  CFX_WideString wstr = CFX_WideString::FromUTF16LE(wsText, size);
+  WideString wstr = WideString::FromUTF16LE(wsText, size);
   static_cast<CXFA_FFWidget*>(hWidget)->Paste(wstr);
 }
 
-DLLEXPORT void STDCALL
+FPDF_EXPORT void FPDF_CALLCONV
 FPDF_Widget_ReplaceSpellCheckWord(FPDF_DOCUMENT document,
                                   FPDF_WIDGET hWidget,
                                   float x,
@@ -547,18 +627,17 @@
     return;
 
   CPDFXFA_Context* pContext = static_cast<CPDFXFA_Context*>(document);
-  if (pContext->GetDocType() != XFA_DOCTYPE_Dynamic &&
-      pContext->GetDocType() != XFA_DOCTYPE_Static)
+  if (!pContext->ContainsXFAForm())
     return;
 
   CFX_PointF ptPopup;
   ptPopup.x = x;
   ptPopup.y = y;
-  CFX_ByteStringC bs(bsText);
+  ByteStringView bs(bsText);
   static_cast<CXFA_FFWidget*>(hWidget)->ReplaceSpellCheckWord(ptPopup, bs);
 }
 
-DLLEXPORT void STDCALL
+FPDF_EXPORT void FPDF_CALLCONV
 FPDF_Widget_GetSpellCheckWords(FPDF_DOCUMENT document,
                                FPDF_WIDGET hWidget,
                                float x,
@@ -567,26 +646,28 @@
   if (!hWidget || !document)
     return;
 
-  CPDFXFA_Context* pContext = static_cast<CPDFXFA_Context*>(document);
-  if (pContext->GetDocType() != XFA_DOCTYPE_Dynamic &&
-      pContext->GetDocType() != XFA_DOCTYPE_Static)
+  auto* pContext = static_cast<CPDFXFA_Context*>(document);
+  if (!pContext->ContainsXFAForm())
     return;
 
-  std::vector<CFX_ByteString>* sSuggestWords = new std::vector<CFX_ByteString>;
   CFX_PointF ptPopup;
   ptPopup.x = x;
   ptPopup.y = y;
-  static_cast<CXFA_FFWidget*>(hWidget)
-      ->GetSuggestWords(ptPopup, *sSuggestWords);
-  *stringHandle = ToFPDFStringHandle(sSuggestWords);
+  auto sSuggestWords = pdfium::MakeUnique<std::vector<ByteString>>();
+  static_cast<CXFA_FFWidget*>(hWidget)->GetSuggestWords(ptPopup,
+                                                        sSuggestWords.get());
+
+  // Caller takes ownership.
+  *stringHandle = ToFPDFStringHandle(sSuggestWords.release());
 }
 
-DLLEXPORT int STDCALL FPDF_StringHandleCounts(FPDF_STRINGHANDLE sHandle) {
-  std::vector<CFX_ByteString>* sSuggestWords = FromFPDFStringHandle(sHandle);
+FPDF_EXPORT int FPDF_CALLCONV
+FPDF_StringHandleCounts(FPDF_STRINGHANDLE sHandle) {
+  std::vector<ByteString>* sSuggestWords = FromFPDFStringHandle(sHandle);
   return sSuggestWords ? pdfium::CollectionSize<int>(*sSuggestWords) : -1;
 }
 
-DLLEXPORT FPDF_BOOL STDCALL
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
 FPDF_StringHandleGetStringByIndex(FPDF_STRINGHANDLE sHandle,
                                   int index,
                                   FPDF_BYTESTRING bsText,
@@ -598,7 +679,7 @@
   if (index < 0 || index >= count)
     return false;
 
-  std::vector<CFX_ByteString>* sSuggestWords = FromFPDFStringHandle(sHandle);
+  std::vector<ByteString>* sSuggestWords = FromFPDFStringHandle(sHandle);
   uint32_t len = (*sSuggestWords)[index].GetLength();
   if (!bsText) {
     *size = len;
@@ -607,57 +688,67 @@
 
   uint32_t real_size = len < *size ? len : *size;
   if (real_size > 0)
-    FXSYS_memcpy((void*)bsText, (*sSuggestWords)[index].c_str(), real_size);
+    memcpy((void*)bsText, (*sSuggestWords)[index].c_str(), real_size);
   *size = real_size;
   return true;
 }
 
-DLLEXPORT void STDCALL
+FPDF_EXPORT void FPDF_CALLCONV
 FPDF_StringHandleRelease(FPDF_STRINGHANDLE stringHandle) {
   delete FromFPDFStringHandle(stringHandle);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
 FPDF_StringHandleAddString(FPDF_STRINGHANDLE stringHandle,
                            FPDF_BYTESTRING bsText,
                            FPDF_DWORD size) {
   if (!stringHandle || !bsText || size == 0)
     return false;
 
-  FromFPDFStringHandle(stringHandle)->push_back(CFX_ByteString(bsText, size));
+  FromFPDFStringHandle(stringHandle)->push_back(ByteString(bsText, size));
   return true;
 }
 #endif  // PDF_ENABLE_XFA
 
-DLLEXPORT void STDCALL FPDF_SetFormFieldHighlightColor(FPDF_FORMHANDLE hHandle,
-                                                       int fieldType,
-                                                       unsigned long color) {
-  if (CPDFSDK_InterForm* pInterForm = FormHandleToInterForm(hHandle))
-    pInterForm->SetHighlightColor(color, fieldType);
+FPDF_EXPORT void FPDF_CALLCONV
+FPDF_SetFormFieldHighlightColor(FPDF_FORMHANDLE hHandle,
+                                int fieldType,
+                                unsigned long color) {
+  CPDFSDK_InterForm* interForm = FormHandleToInterForm(hHandle);
+  if (!interForm)
+    return;
+
+  Optional<FormFieldType> cast_input = IntToFormFieldType(fieldType);
+  if (!cast_input)
+    return;
+
+  if (cast_input.value() == FormFieldType::kUnknown) {
+    interForm->SetAllHighlightColors(color);
+  } else {
+    interForm->SetHighlightColor(color, cast_input.value());
+  }
 }
 
-DLLEXPORT void STDCALL FPDF_SetFormFieldHighlightAlpha(FPDF_FORMHANDLE hHandle,
-                                                       unsigned char alpha) {
+FPDF_EXPORT void FPDF_CALLCONV
+FPDF_SetFormFieldHighlightAlpha(FPDF_FORMHANDLE hHandle, unsigned char alpha) {
   if (CPDFSDK_InterForm* pInterForm = FormHandleToInterForm(hHandle))
     pInterForm->SetHighlightAlpha(alpha);
 }
 
-DLLEXPORT void STDCALL FPDF_RemoveFormFieldHighlight(FPDF_FORMHANDLE hHandle) {
+FPDF_EXPORT void FPDF_CALLCONV
+FPDF_RemoveFormFieldHighlight(FPDF_FORMHANDLE hHandle) {
   if (CPDFSDK_InterForm* pInterForm = FormHandleToInterForm(hHandle))
-    pInterForm->RemoveAllHighLight();
+    pInterForm->RemoveAllHighLights();
 }
 
-DLLEXPORT void STDCALL FORM_OnAfterLoadPage(FPDF_PAGE page,
-                                            FPDF_FORMHANDLE hHandle) {
+FPDF_EXPORT void FPDF_CALLCONV FORM_OnAfterLoadPage(FPDF_PAGE page,
+                                                    FPDF_FORMHANDLE hHandle) {
   if (CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page))
     pPageView->SetValid(true);
 }
 
-DLLEXPORT void STDCALL FORM_OnBeforeClosePage(FPDF_PAGE page,
-                                              FPDF_FORMHANDLE hHandle) {
-  if (!hHandle)
-    return;
-
+FPDF_EXPORT void FPDF_CALLCONV FORM_OnBeforeClosePage(FPDF_PAGE page,
+                                                      FPDF_FORMHANDLE hHandle) {
   CPDFSDK_FormFillEnvironment* pFormFillEnv =
       HandleToCPDFSDKEnvironment(hHandle);
   if (!pFormFillEnv)
@@ -675,48 +766,47 @@
   }
 }
 
-DLLEXPORT void STDCALL FORM_DoDocumentJSAction(FPDF_FORMHANDLE hHandle) {
+FPDF_EXPORT void FPDF_CALLCONV
+FORM_DoDocumentJSAction(FPDF_FORMHANDLE hHandle) {
   CPDFSDK_FormFillEnvironment* pFormFillEnv =
       HandleToCPDFSDKEnvironment(hHandle);
   if (pFormFillEnv && pFormFillEnv->IsJSInitiated())
     pFormFillEnv->ProcJavascriptFun();
 }
 
-DLLEXPORT void STDCALL FORM_DoDocumentOpenAction(FPDF_FORMHANDLE hHandle) {
+FPDF_EXPORT void FPDF_CALLCONV
+FORM_DoDocumentOpenAction(FPDF_FORMHANDLE hHandle) {
   CPDFSDK_FormFillEnvironment* pFormFillEnv =
       HandleToCPDFSDKEnvironment(hHandle);
   if (pFormFillEnv && pFormFillEnv->IsJSInitiated())
     pFormFillEnv->ProcOpenAction();
 }
 
-DLLEXPORT void STDCALL FORM_DoDocumentAAction(FPDF_FORMHANDLE hHandle,
-                                              int aaType) {
+FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentAAction(FPDF_FORMHANDLE hHandle,
+                                                      int aaType) {
   CPDFSDK_FormFillEnvironment* pFormFillEnv =
       HandleToCPDFSDKEnvironment(hHandle);
   if (!pFormFillEnv)
     return;
 
   CPDF_Document* pDoc = pFormFillEnv->GetPDFDocument();
-  CPDF_Dictionary* pDic = pDoc->GetRoot();
-  if (!pDic)
+  const CPDF_Dictionary* pDict = pDoc->GetRoot();
+  if (!pDict)
     return;
 
-  CPDF_AAction aa(pDic->GetDictFor("AA"));
-  if (aa.ActionExist((CPDF_AAction::AActionType)aaType)) {
-    CPDF_Action action = aa.GetAction((CPDF_AAction::AActionType)aaType);
+  CPDF_AAction aa(pDict->GetDictFor("AA"));
+  auto type = static_cast<CPDF_AAction::AActionType>(aaType);
+  if (aa.ActionExist(type)) {
+    CPDF_Action action = aa.GetAction(type);
     CPDFSDK_ActionHandler* pActionHandler =
-        HandleToCPDFSDKEnvironment(hHandle)->GetActionHander();
-    pActionHandler->DoAction_Document(action, (CPDF_AAction::AActionType)aaType,
-                                      pFormFillEnv);
+        HandleToCPDFSDKEnvironment(hHandle)->GetActionHandler();
+    pActionHandler->DoAction_Document(action, type, pFormFillEnv);
   }
 }
 
-DLLEXPORT void STDCALL FORM_DoPageAAction(FPDF_PAGE page,
-                                          FPDF_FORMHANDLE hHandle,
-                                          int aaType) {
-  if (!hHandle)
-    return;
-
+FPDF_EXPORT void FPDF_CALLCONV FORM_DoPageAAction(FPDF_PAGE page,
+                                                  FPDF_FORMHANDLE hHandle,
+                                                  int aaType) {
   CPDFSDK_FormFillEnvironment* pFormFillEnv =
       HandleToCPDFSDKEnvironment(hHandle);
   if (!pFormFillEnv)
@@ -730,20 +820,14 @@
   if (!pFormFillEnv->GetPageView(pPage, false))
     return;
 
-  CPDFSDK_ActionHandler* pActionHandler = pFormFillEnv->GetActionHander();
-  CPDF_Dictionary* pPageDict = pPDFPage->m_pFormDict;
+  CPDFSDK_ActionHandler* pActionHandler = pFormFillEnv->GetActionHandler();
+  CPDF_Dictionary* pPageDict = pPDFPage->m_pFormDict.Get();
   CPDF_AAction aa(pPageDict->GetDictFor("AA"));
-  if (FPDFPAGE_AACTION_OPEN == aaType) {
-    if (aa.ActionExist(CPDF_AAction::OpenPage)) {
-      CPDF_Action action = aa.GetAction(CPDF_AAction::OpenPage);
-      pActionHandler->DoAction_Page(action, CPDF_AAction::OpenPage,
-                                    pFormFillEnv);
-    }
-  } else {
-    if (aa.ActionExist(CPDF_AAction::ClosePage)) {
-      CPDF_Action action = aa.GetAction(CPDF_AAction::ClosePage);
-      pActionHandler->DoAction_Page(action, CPDF_AAction::ClosePage,
-                                    pFormFillEnv);
-    }
+  CPDF_AAction::AActionType type = aaType == FPDFPAGE_AACTION_OPEN
+                                       ? CPDF_AAction::OpenPage
+                                       : CPDF_AAction::ClosePage;
+  if (aa.ActionExist(type)) {
+    CPDF_Action action = aa.GetAction(type);
+    pActionHandler->DoAction_Page(action, type, pFormFillEnv);
   }
 }
diff --git a/fpdfsdk/fpdfformfill_embeddertest.cpp b/fpdfsdk/fpdfformfill_embeddertest.cpp
index 47f1a75..ae1c02e 100644
--- a/fpdfsdk/fpdfformfill_embeddertest.cpp
+++ b/fpdfsdk/fpdfformfill_embeddertest.cpp
@@ -2,7 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "core/fxcrt/fx_coordinates.h"
+#include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/fx_system.h"
+#include "public/cpp/fpdf_deleters.h"
 #include "public/fpdf_formfill.h"
+#include "public/fpdf_fwlevent.h"
 #include "testing/embedder_test.h"
 #include "testing/embedder_test_mock_delegate.h"
 #include "testing/embedder_test_timer_handling_delegate.h"
@@ -10,9 +19,291 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using testing::_;
-using testing::Return;
 
-class FPDFFormFillEmbeddertest : public EmbedderTest {};
+using FPDFFormFillEmbeddertest = EmbedderTest;
+
+// A base class for many related tests that involve clicking and typing into
+// form fields.
+class FPDFFormFillInteractiveEmbeddertest : public FPDFFormFillEmbeddertest {
+ protected:
+  FPDFFormFillInteractiveEmbeddertest() = default;
+  ~FPDFFormFillInteractiveEmbeddertest() override = default;
+
+  void SetUp() override {
+    FPDFFormFillEmbeddertest::SetUp();
+    ASSERT_TRUE(OpenDocument(GetDocumentName()));
+    page_ = LoadPage(0);
+    ASSERT_TRUE(page_);
+    FormSanityChecks();
+  }
+
+  void TearDown() override {
+    UnloadPage(page_);
+    FPDFFormFillEmbeddertest::TearDown();
+  }
+
+  // Returns the name of the PDF to use.
+  virtual const char* GetDocumentName() const = 0;
+
+  // Returns the type of field(s) in the PDF.
+  virtual int GetFormType() const = 0;
+
+  // Optionally do some sanity check on the document after loading.
+  virtual void FormSanityChecks() {}
+
+  FPDF_PAGE page() { return page_; }
+
+  int GetFormTypeAtPoint(const CFX_PointF& point) {
+    return FPDFPage_HasFormFieldAtPoint(form_handle(), page_, point.x, point.y);
+  }
+
+  void ClickOnFormFieldAtPoint(const CFX_PointF& point) {
+    // Click on the text field or combobox as specified by coordinates.
+    FORM_OnMouseMove(form_handle(), page_, 0, point.x, point.y);
+    FORM_OnLButtonDown(form_handle(), page_, 0, point.x, point.y);
+    FORM_OnLButtonUp(form_handle(), page_, 0, point.x, point.y);
+  }
+
+  void TypeTextIntoTextField(int num_chars, const CFX_PointF& point) {
+    EXPECT_EQ(GetFormType(), GetFormTypeAtPoint(point));
+    ClickOnFormFieldAtPoint(point);
+
+    // Type text starting with 'A' to as many chars as specified by |num_chars|.
+    for (int i = 0; i < num_chars; ++i) {
+      FORM_OnChar(form_handle(), page_, 'A' + i, 0);
+    }
+  }
+
+  // Navigates to text field using the mouse and then selects text via the
+  // shift and specfied left or right arrow key.
+  void SelectTextWithKeyboard(int num_chars,
+                              int arrow_key,
+                              const CFX_PointF& point) {
+    // Navigate to starting position for selection.
+    ClickOnFormFieldAtPoint(point);
+
+    // Hold down shift (and don't release until entire text is selected).
+    FORM_OnKeyDown(form_handle(), page_, FWL_VKEY_Shift, 0);
+
+    // Select text char by char via left or right arrow key.
+    for (int i = 0; i < num_chars; ++i) {
+      FORM_OnKeyDown(form_handle(), page_, arrow_key, FWL_EVENTFLAG_ShiftKey);
+      FORM_OnKeyUp(form_handle(), page_, arrow_key, FWL_EVENTFLAG_ShiftKey);
+    }
+    FORM_OnKeyUp(form_handle(), page_, FWL_VKEY_Shift, 0);
+  }
+
+  // Uses the mouse to navigate to text field and select text.
+  void SelectTextWithMouse(const CFX_PointF& start, const CFX_PointF& end) {
+    ASSERT(start.y == end.y);
+
+    // Navigate to starting position and click mouse.
+    FORM_OnMouseMove(form_handle(), page_, 0, start.x, start.y);
+    FORM_OnLButtonDown(form_handle(), page_, 0, start.x, start.y);
+
+    // Hold down mouse until reach end of desired selection.
+    FORM_OnMouseMove(form_handle(), page_, 0, end.x, end.y);
+    FORM_OnLButtonUp(form_handle(), page_, 0, end.x, end.y);
+  }
+
+  void CheckSelection(const WideStringView& expected_string) {
+    // Calculate expected length for selected text.
+    int num_chars = expected_string.GetLength();
+
+    // Check actual selection against expected selection.
+    const unsigned long expected_length =
+        sizeof(unsigned short) * (num_chars + 1);
+    unsigned long sel_text_len =
+        FORM_GetSelectedText(form_handle(), page_, nullptr, 0);
+    ASSERT_EQ(expected_length, sel_text_len);
+
+    std::vector<unsigned short> buf(sel_text_len);
+    EXPECT_EQ(expected_length, FORM_GetSelectedText(form_handle(), page_,
+                                                    buf.data(), sel_text_len));
+
+    EXPECT_EQ(expected_string, WideString::FromUTF16LE(buf.data(), num_chars));
+  }
+
+ private:
+  FPDF_PAGE page_ = nullptr;
+};
+
+class FPDFFormFillTextFormEmbeddertest
+    : public FPDFFormFillInteractiveEmbeddertest {
+ protected:
+  FPDFFormFillTextFormEmbeddertest() = default;
+  ~FPDFFormFillTextFormEmbeddertest() override = default;
+
+  const char* GetDocumentName() const override {
+    // PDF with several form text fields:
+    // - "Text Box" - Regular text box with no special attributes.
+    // - "ReadOnly" - Ff: 1.
+    // - "CharLimit" - MaxLen: 10, V: Elephant.
+    return "text_form_multiple.pdf";
+  }
+
+  int GetFormType() const override { return FPDF_FORMFIELD_TEXTFIELD; }
+
+  void FormSanityChecks() override {
+    EXPECT_EQ(GetFormType(), GetFormTypeAtPoint(CharLimitFormBegin()));
+    EXPECT_EQ(GetFormType(), GetFormTypeAtPoint(CharLimitFormEnd()));
+    EXPECT_EQ(GetFormType(), GetFormTypeAtPoint(RegularFormBegin()));
+    EXPECT_EQ(GetFormType(), GetFormTypeAtPoint(RegularFormEnd()));
+  }
+
+  void SelectAllCharLimitFormTextWithMouse() {
+    SelectTextWithMouse(CharLimitFormEnd(), CharLimitFormBegin());
+  }
+
+  void SelectAllRegularFormTextWithMouse() {
+    SelectTextWithMouse(RegularFormEnd(), RegularFormBegin());
+  }
+
+  const CFX_PointF& CharLimitFormBegin() const {
+    static const CFX_PointF point = CharLimitFormAtX(kFormBeginX);
+    return point;
+  }
+
+  const CFX_PointF& CharLimitFormEnd() const {
+    static const CFX_PointF point = CharLimitFormAtX(kFormEndX);
+    return point;
+  }
+
+  const CFX_PointF& RegularFormBegin() const {
+    static const CFX_PointF point = RegularFormAtX(kFormBeginX);
+    return point;
+  }
+
+  const CFX_PointF& RegularFormEnd() const {
+    static const CFX_PointF point = RegularFormAtX(kFormEndX);
+    return point;
+  }
+
+  static CFX_PointF CharLimitFormAtX(float x) {
+    ASSERT(x >= kFormBeginX);
+    ASSERT(x <= kFormEndX);
+    return CFX_PointF(x, kCharLimitFormY);
+  }
+
+  static CFX_PointF RegularFormAtX(float x) {
+    ASSERT(x >= kFormBeginX);
+    ASSERT(x <= kFormEndX);
+    return CFX_PointF(x, kRegularFormY);
+  }
+
+ private:
+  static constexpr float kFormBeginX = 102.0;
+  static constexpr float kFormEndX = 195.0;
+  static constexpr float kCharLimitFormY = 60.0;
+  static constexpr float kRegularFormY = 115.0;
+};
+
+class FPDFFormFillComboBoxFormEmbeddertest
+    : public FPDFFormFillInteractiveEmbeddertest {
+ protected:
+  FPDFFormFillComboBoxFormEmbeddertest() = default;
+  ~FPDFFormFillComboBoxFormEmbeddertest() override = default;
+
+  const char* GetDocumentName() const override {
+    // PDF with form comboboxes:
+    // - "Combo_Editable" - Ff: 393216, 3 options with pair values.
+    // - "Combo1" - Ff: 131072, 3 options with single values.
+    // - "Combo_ReadOnly" - Ff: 131073, 3 options with single values.
+    return "combobox_form.pdf";
+  }
+
+  int GetFormType() const override { return FPDF_FORMFIELD_COMBOBOX; }
+
+  void FormSanityChecks() override {
+    EXPECT_EQ(GetFormType(), GetFormTypeAtPoint(EditableFormBegin()));
+    EXPECT_EQ(GetFormType(), GetFormTypeAtPoint(EditableFormEnd()));
+    EXPECT_EQ(GetFormType(), GetFormTypeAtPoint(EditableFormDropDown()));
+    EXPECT_EQ(GetFormType(), GetFormTypeAtPoint(NonEditableFormBegin()));
+    EXPECT_EQ(GetFormType(), GetFormTypeAtPoint(NonEditableFormEnd()));
+    EXPECT_EQ(GetFormType(), GetFormTypeAtPoint(NonEditableFormDropDown()));
+  }
+
+  void SelectEditableFormOption(int item_index) {
+    SelectOption(item_index, EditableFormDropDown());
+  }
+
+  void SelectNonEditableFormOption(int item_index) {
+    SelectOption(item_index, NonEditableFormDropDown());
+  }
+
+  void SelectAllEditableFormTextWithMouse() {
+    SelectTextWithMouse(EditableFormEnd(), EditableFormBegin());
+  }
+
+  const CFX_PointF& EditableFormBegin() const {
+    static const CFX_PointF point = EditableFormAtX(kFormBeginX);
+    return point;
+  }
+
+  const CFX_PointF& EditableFormEnd() const {
+    static const CFX_PointF point = EditableFormAtX(kFormEndX);
+    return point;
+  }
+
+  const CFX_PointF& EditableFormDropDown() const {
+    static const CFX_PointF point(kFormDropDownX, kEditableFormY);
+    return point;
+  }
+
+  const CFX_PointF& NonEditableFormBegin() const {
+    static const CFX_PointF point = NonEditableFormAtX(kFormBeginX);
+    return point;
+  }
+
+  const CFX_PointF& NonEditableFormEnd() const {
+    static const CFX_PointF point = NonEditableFormAtX(kFormEndX);
+    return point;
+  }
+
+  const CFX_PointF& NonEditableFormDropDown() const {
+    static const CFX_PointF point(kFormDropDownX, kNonEditableFormY);
+    return point;
+  }
+
+  static CFX_PointF EditableFormAtX(float x) {
+    ASSERT(x >= kFormBeginX);
+    ASSERT(x <= kFormEndX);
+    return CFX_PointF(x, kEditableFormY);
+  }
+
+  static CFX_PointF NonEditableFormAtX(float x) {
+    ASSERT(x >= kFormBeginX);
+    ASSERT(x <= kFormEndX);
+    return CFX_PointF(x, kNonEditableFormY);
+  }
+
+ private:
+  // Selects one of the pre-selected values from a combobox with three options.
+  // Options are specified by |item_index|, which is 0-based.
+  void SelectOption(int item_index, const CFX_PointF& point) {
+    // Only relevant for comboboxes with three choices and the same dimensions
+    // as those in combobox_form.pdf.
+    ASSERT(item_index >= 0);
+    ASSERT(item_index < 3);
+
+    // Navigate to button for drop down and click mouse to reveal options.
+    ClickOnFormFieldAtPoint(point);
+
+    // Calculate to Y-coordinate of dropdown option to be selected.
+    constexpr double kChoiceHeight = 15;
+    CFX_PointF option_point = point;
+    option_point.y -= kChoiceHeight * (item_index + 1);
+
+    // Navigate to option and click mouse to select it.
+    ClickOnFormFieldAtPoint(option_point);
+  }
+
+  static constexpr float kFormBeginX = 102.0;
+  static constexpr float kFormEndX = 183.0;
+  static constexpr float kFormDropDownX = 192.0;
+  static constexpr float kEditableFormY = 60.0;
+  static constexpr float kNonEditableFormY = 110.0;
+};
 
 TEST_F(FPDFFormFillEmbeddertest, FirstTest) {
   EmbedderTestMockDelegate mock;
@@ -196,4 +487,888 @@
   EXPECT_EQ(0u, alerts.size());
 }
 
+TEST_F(FPDFFormFillEmbeddertest, BUG_707673) {
+  EmbedderTestTimerHandlingDelegate delegate;
+  SetDelegate(&delegate);
+
+  EXPECT_TRUE(OpenDocument("bug_707673.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  EXPECT_TRUE(page);
+
+  DoOpenActions();
+  FORM_OnLButtonDown(form_handle(), page, 0, 140, 590);
+  FORM_OnLButtonUp(form_handle(), page, 0, 140, 590);
+  delegate.AdvanceTime(1000);
+  UnloadPage(page);
+
+  const auto& alerts = delegate.GetAlerts();
+  EXPECT_EQ(0u, alerts.size());
+}
+
+TEST_F(FPDFFormFillEmbeddertest, BUG_765384) {
+  EXPECT_TRUE(OpenDocument("bug_765384.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  EXPECT_TRUE(page);
+
+  DoOpenActions();
+  FORM_OnLButtonDown(form_handle(), page, 0, 140, 590);
+  FORM_OnLButtonUp(form_handle(), page, 0, 140, 590);
+  UnloadPage(page);
+}
+
 #endif  // PDF_ENABLE_V8
+
+TEST_F(FPDFFormFillEmbeddertest, FormText) {
+#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+  const char md5_1[] = "5f11dbe575fe197a37c3fb422559f8ff";
+  const char md5_2[] = "35b1a4b679eafc749a0b6fda750c0e8d";
+  const char md5_3[] = "65c64a7c355388f719a752aa1e23f6fe";
+#else
+  const char md5_1[] = "b890950d4b9bc163b1a96797f3004b53";
+  const char md5_2[] = "11487d5597599a26e8912b9c1d9422cb";
+  const char md5_3[] = "bffe0ecea9a533f217047ee41d6be466";
+#endif
+  {
+    EXPECT_TRUE(OpenDocument("text_form.pdf"));
+    FPDF_PAGE page = LoadPage(0);
+    ASSERT_TRUE(page);
+    std::unique_ptr<void, FPDFBitmapDeleter> bitmap1(RenderPage(page));
+    CompareBitmap(bitmap1.get(), 300, 300, md5_1);
+
+    // Click on the textfield
+    EXPECT_EQ(FPDF_FORMFIELD_TEXTFIELD,
+              FPDFPage_HasFormFieldAtPoint(form_handle(), page, 120.0, 120.0));
+    FORM_OnMouseMove(form_handle(), page, 0, 120.0, 120.0);
+    FORM_OnLButtonDown(form_handle(), page, 0, 120.0, 120.0);
+    FORM_OnLButtonUp(form_handle(), page, 0, 120.0, 120.0);
+
+    // Write "ABC"
+    FORM_OnChar(form_handle(), page, 65, 0);
+    FORM_OnChar(form_handle(), page, 66, 0);
+    FORM_OnChar(form_handle(), page, 67, 0);
+    std::unique_ptr<void, FPDFBitmapDeleter> bitmap2(RenderPage(page));
+    CompareBitmap(bitmap2.get(), 300, 300, md5_2);
+
+    // Take out focus by clicking out of the textfield
+    FORM_OnMouseMove(form_handle(), page, 0, 15.0, 15.0);
+    FORM_OnLButtonDown(form_handle(), page, 0, 15.0, 15.0);
+    FORM_OnLButtonUp(form_handle(), page, 0, 15.0, 15.0);
+    std::unique_ptr<void, FPDFBitmapDeleter> bitmap3(RenderPage(page));
+    CompareBitmap(bitmap3.get(), 300, 300, md5_3);
+
+    EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+
+    // Close page
+    UnloadPage(page);
+  }
+  // Check saved document
+  VerifySavedDocument(300, 300, md5_3);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, HasFormInfoNone) {
+  EXPECT_TRUE(OpenDocument("hello_world.pdf"));
+  EXPECT_EQ(FORMTYPE_NONE, FPDF_GetFormType(document_));
+}
+
+TEST_F(FPDFFormFillEmbeddertest, HasFormInfoAcroForm) {
+  EXPECT_TRUE(OpenDocument("text_form.pdf"));
+  EXPECT_EQ(FORMTYPE_ACRO_FORM, FPDF_GetFormType(document_));
+}
+
+TEST_F(FPDFFormFillEmbeddertest, HasFormInfoXFAFull) {
+  EXPECT_TRUE(OpenDocument("simple_xfa.pdf"));
+  EXPECT_EQ(FORMTYPE_XFA_FULL, FPDF_GetFormType(document_));
+}
+
+TEST_F(FPDFFormFillEmbeddertest, HasFormInfoXFAForeground) {
+  EXPECT_TRUE(OpenDocument("bug_216.pdf"));
+  EXPECT_EQ(FORMTYPE_XFA_FOREGROUND, FPDF_GetFormType(document_));
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest, GetSelectedTextEmptyAndBasicKeyboard) {
+  // Test empty selection.
+  CheckSelection(L"");
+
+  // Test basic selection.
+  TypeTextIntoTextField(3, RegularFormBegin());
+  SelectTextWithKeyboard(3, FWL_VKEY_Left, RegularFormAtX(123.0));
+  CheckSelection(L"ABC");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest, GetSelectedTextEmptyAndBasicMouse) {
+  // Test empty selection.
+  CheckSelection(L"");
+
+  // Test basic selection.
+  TypeTextIntoTextField(3, RegularFormBegin());
+  SelectTextWithMouse(RegularFormAtX(125.0), RegularFormBegin());
+  CheckSelection(L"ABC");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest, GetSelectedTextFragmentsKeyBoard) {
+  TypeTextIntoTextField(12, RegularFormBegin());
+
+  // Test selecting first character in forward direction.
+  SelectTextWithKeyboard(1, FWL_VKEY_Right, RegularFormBegin());
+  CheckSelection(L"A");
+
+  // Test selecting entire long string in backwards direction.
+  SelectTextWithKeyboard(12, FWL_VKEY_Left, RegularFormEnd());
+  CheckSelection(L"ABCDEFGHIJKL");
+
+  // Test selecting middle section in backwards direction.
+  SelectTextWithKeyboard(6, FWL_VKEY_Left, RegularFormAtX(170.0));
+  CheckSelection(L"DEFGHI");
+
+  // Test selecting middle selection in forward direction.
+  SelectTextWithKeyboard(6, FWL_VKEY_Right, RegularFormAtX(125.0));
+  CheckSelection(L"DEFGHI");
+
+  // Test selecting last character in backwards direction.
+  SelectTextWithKeyboard(1, FWL_VKEY_Left, RegularFormEnd());
+  CheckSelection(L"L");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest, GetSelectedTextFragmentsMouse) {
+  TypeTextIntoTextField(12, RegularFormBegin());
+
+  // Test selecting first character in forward direction.
+  SelectTextWithMouse(RegularFormBegin(), RegularFormAtX(106.0));
+  CheckSelection(L"A");
+
+  // Test selecting entire long string in backwards direction.
+  SelectAllRegularFormTextWithMouse();
+  CheckSelection(L"ABCDEFGHIJKL");
+
+  // Test selecting middle section in backwards direction.
+  SelectTextWithMouse(RegularFormAtX(170.0), RegularFormAtX(125.0));
+  CheckSelection(L"DEFGHI");
+
+  // Test selecting middle selection in forward direction.
+  SelectTextWithMouse(RegularFormAtX(125.0), RegularFormAtX(170.0));
+  CheckSelection(L"DEFGHI");
+
+  // Test selecting last character in backwards direction.
+  SelectTextWithMouse(RegularFormEnd(), RegularFormAtX(186.0));
+  CheckSelection(L"L");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       GetSelectedTextEmptyAndBasicNormalComboBox) {
+  // Test empty selection.
+  CheckSelection(L"");
+
+  // Non-editable comboboxes don't allow selection with keyboard.
+  SelectTextWithMouse(NonEditableFormBegin(), NonEditableFormAtX(142.0));
+  CheckSelection(L"Banana");
+
+  // Select other another provided option.
+  SelectNonEditableFormOption(0);
+  CheckSelection(L"Apple");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       GetSelectedTextEmptyAndBasicEditableComboBoxKeyboard) {
+  // Test empty selection.
+  CheckSelection(L"");
+
+  // Test basic selection of text within user editable combobox using keyboard.
+  TypeTextIntoTextField(3, EditableFormBegin());
+  SelectTextWithKeyboard(3, FWL_VKEY_Left, EditableFormAtX(128.0));
+  CheckSelection(L"ABC");
+
+  // Select a provided option.
+  SelectEditableFormOption(1);
+  CheckSelection(L"Bar");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       GetSelectedTextEmptyAndBasicEditableComboBoxMouse) {
+  // Test empty selection.
+  CheckSelection(L"");
+
+  // Test basic selection of text within user editable combobox using mouse.
+  TypeTextIntoTextField(3, EditableFormBegin());
+  SelectTextWithMouse(EditableFormAtX(128.0), EditableFormBegin());
+  CheckSelection(L"ABC");
+
+  // Select a provided option.
+  SelectEditableFormOption(2);
+  CheckSelection(L"Qux");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       GetSelectedTextFragmentsNormalComboBox) {
+  // Test selecting first character in forward direction.
+  SelectTextWithMouse(NonEditableFormBegin(), NonEditableFormAtX(107.0));
+  CheckSelection(L"B");
+
+  // Test selecting entire string in backwards direction.
+  SelectTextWithMouse(NonEditableFormAtX(142.0), NonEditableFormBegin());
+  CheckSelection(L"Banana");
+
+  // Test selecting middle section in backwards direction.
+  SelectTextWithMouse(NonEditableFormAtX(135.0), NonEditableFormAtX(117.0));
+  CheckSelection(L"nan");
+
+  // Test selecting middle section in forward direction.
+  SelectTextWithMouse(NonEditableFormAtX(117.0), NonEditableFormAtX(135.0));
+  CheckSelection(L"nan");
+
+  // Test selecting last character in backwards direction.
+  SelectTextWithMouse(NonEditableFormAtX(142.0), NonEditableFormAtX(138.0));
+  CheckSelection(L"a");
+
+  // Select another option and then reset selection as first three chars.
+  SelectNonEditableFormOption(2);
+  CheckSelection(L"Cherry");
+  SelectTextWithMouse(NonEditableFormBegin(), NonEditableFormAtX(122.0));
+  CheckSelection(L"Che");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       GetSelectedTextFragmentsEditableComboBoxKeyboard) {
+  TypeTextIntoTextField(10, EditableFormBegin());
+
+  // Test selecting first character in forward direction.
+  SelectTextWithKeyboard(1, FWL_VKEY_Right, EditableFormBegin());
+  CheckSelection(L"A");
+
+  // Test selecting entire long string in backwards direction.
+  SelectTextWithKeyboard(10, FWL_VKEY_Left, EditableFormEnd());
+  CheckSelection(L"ABCDEFGHIJ");
+
+  // Test selecting middle section in backwards direction.
+  SelectTextWithKeyboard(5, FWL_VKEY_Left, EditableFormAtX(168.0));
+  CheckSelection(L"DEFGH");
+
+  // Test selecting middle selection in forward direction.
+  SelectTextWithKeyboard(5, FWL_VKEY_Right, EditableFormAtX(127.0));
+  CheckSelection(L"DEFGH");
+
+  // Test selecting last character in backwards direction.
+  SelectTextWithKeyboard(1, FWL_VKEY_Left, EditableFormEnd());
+  CheckSelection(L"J");
+
+  // Select a provided option and then reset selection as first two chars.
+  SelectEditableFormOption(0);
+  CheckSelection(L"Foo");
+  SelectTextWithKeyboard(2, FWL_VKEY_Right, EditableFormBegin());
+  CheckSelection(L"Fo");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       GetSelectedTextFragmentsEditableComboBoxMouse) {
+  TypeTextIntoTextField(10, EditableFormBegin());
+
+  // Test selecting first character in forward direction.
+  SelectTextWithMouse(EditableFormBegin(), EditableFormAtX(107.0));
+  CheckSelection(L"A");
+
+  // Test selecting entire long string in backwards direction.
+  SelectAllEditableFormTextWithMouse();
+  CheckSelection(L"ABCDEFGHIJ");
+
+  // Test selecting middle section in backwards direction.
+  SelectTextWithMouse(EditableFormAtX(168.0), EditableFormAtX(127.0));
+  CheckSelection(L"DEFGH");
+
+  // Test selecting middle selection in forward direction.
+  SelectTextWithMouse(EditableFormAtX(127.0), EditableFormAtX(168.0));
+  CheckSelection(L"DEFGH");
+
+  // Test selecting last character in backwards direction.
+  SelectTextWithMouse(EditableFormEnd(), EditableFormAtX(174.0));
+  CheckSelection(L"J");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest, DeleteTextFieldEntireSelection) {
+  // Select entire contents of text field.
+  TypeTextIntoTextField(12, RegularFormBegin());
+  SelectAllRegularFormTextWithMouse();
+  CheckSelection(L"ABCDEFGHIJKL");
+
+  // Test deleting current text selection. Select what remains after deletion to
+  // check that remaining text is as expected.
+  FORM_ReplaceSelection(form_handle(), page(), nullptr);
+
+  SelectTextWithKeyboard(12, FWL_VKEY_Left, RegularFormEnd());
+  CheckSelection(L"");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest, DeleteTextFieldSelectionMiddle) {
+  // Select middle section of text.
+  TypeTextIntoTextField(12, RegularFormBegin());
+  SelectTextWithMouse(RegularFormAtX(170.0), RegularFormAtX(125.0));
+  CheckSelection(L"DEFGHI");
+
+  // Test deleting current text selection. Select what remains after deletion to
+  // check that remaining text is as expected.
+  FORM_ReplaceSelection(form_handle(), page(), nullptr);
+  SelectTextWithKeyboard(12, FWL_VKEY_Left, RegularFormEnd());
+  CheckSelection(L"ABCJKL");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest, DeleteTextFieldSelectionLeft) {
+  // Select first few characters of text.
+  TypeTextIntoTextField(12, RegularFormBegin());
+  SelectTextWithMouse(RegularFormBegin(), RegularFormAtX(132.0));
+  CheckSelection(L"ABCD");
+
+  // Test deleting current text selection. Select what remains after deletion to
+  // check that remaining text is as expected.
+  FORM_ReplaceSelection(form_handle(), page(), nullptr);
+  SelectTextWithKeyboard(12, FWL_VKEY_Left, RegularFormEnd());
+  CheckSelection(L"EFGHIJKL");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest, DeleteTextFieldSelectionRight) {
+  // Select last few characters of text.
+  TypeTextIntoTextField(12, RegularFormBegin());
+  SelectTextWithMouse(RegularFormEnd(), RegularFormAtX(165.0));
+  CheckSelection(L"IJKL");
+
+  // Test deleting current text selection. Select what remains after deletion to
+  // check that remaining text is as expected.
+  FORM_ReplaceSelection(form_handle(), page(), nullptr);
+  SelectTextWithKeyboard(12, FWL_VKEY_Left, RegularFormEnd());
+  CheckSelection(L"ABCDEFGH");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest, DeleteEmptyTextFieldSelection) {
+  // Do not select text.
+  TypeTextIntoTextField(12, RegularFormBegin());
+  CheckSelection(L"");
+
+  // Test that attempt to delete empty text selection has no effect.
+  FORM_ReplaceSelection(form_handle(), page(), nullptr);
+  SelectTextWithKeyboard(12, FWL_VKEY_Left, RegularFormEnd());
+  CheckSelection(L"ABCDEFGHIJKL");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       DeleteEditableComboBoxEntireSelection) {
+  // Select entire contents of user-editable combobox text field.
+  TypeTextIntoTextField(10, EditableFormBegin());
+  SelectAllEditableFormTextWithMouse();
+  CheckSelection(L"ABCDEFGHIJ");
+
+  // Test deleting current text selection. Select what remains after deletion to
+  // check that remaining text is as expected.
+  FORM_ReplaceSelection(form_handle(), page(), nullptr);
+  SelectAllEditableFormTextWithMouse();
+  CheckSelection(L"");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       DeleteEditableComboBoxSelectionMiddle) {
+  // Select middle section of text.
+  TypeTextIntoTextField(10, EditableFormBegin());
+  SelectTextWithMouse(EditableFormAtX(168.0), EditableFormAtX(127.0));
+  CheckSelection(L"DEFGH");
+
+  // Test deleting current text selection. Select what remains after deletion to
+  // check that remaining text is as expected.
+  FORM_ReplaceSelection(form_handle(), page(), nullptr);
+  SelectAllEditableFormTextWithMouse();
+  CheckSelection(L"ABCIJ");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       DeleteEditableComboBoxSelectionLeft) {
+  // Select first few characters of text.
+  TypeTextIntoTextField(10, EditableFormBegin());
+  SelectTextWithMouse(EditableFormBegin(), EditableFormAtX(132.0));
+  CheckSelection(L"ABCD");
+
+  // Test deleting current text selection. Select what remains after deletion to
+  // check that remaining text is as expected.
+  FORM_ReplaceSelection(form_handle(), page(), nullptr);
+  SelectAllEditableFormTextWithMouse();
+  CheckSelection(L"EFGHIJ");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       DeleteEditableComboBoxSelectionRight) {
+  // Select last few characters of text.
+  TypeTextIntoTextField(10, EditableFormBegin());
+  SelectTextWithMouse(EditableFormEnd(), EditableFormAtX(152.0));
+  CheckSelection(L"GHIJ");
+
+  // Test deleting current text selection. Select what remains after deletion to
+  // check that remaining text is as expected.
+  FORM_ReplaceSelection(form_handle(), page(), nullptr);
+  SelectAllEditableFormTextWithMouse();
+  CheckSelection(L"ABCDEF");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       DeleteEmptyEditableComboBoxSelection) {
+  // Do not select text.
+  TypeTextIntoTextField(10, EditableFormBegin());
+  CheckSelection(L"");
+
+  // Test that attempt to delete empty text selection has no effect.
+  FORM_ReplaceSelection(form_handle(), page(), nullptr);
+  SelectAllEditableFormTextWithMouse();
+  CheckSelection(L"ABCDEFGHIJ");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest, InsertTextInEmptyTextField) {
+  ClickOnFormFieldAtPoint(RegularFormBegin());
+
+  // Test inserting text into empty text field.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllRegularFormTextWithMouse();
+  CheckSelection(L"Hello");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest, InsertTextInPopulatedTextFieldLeft) {
+  TypeTextIntoTextField(8, RegularFormBegin());
+
+  // Click on the leftmost part of the text field.
+  ClickOnFormFieldAtPoint(RegularFormBegin());
+
+  // Test inserting text in front of existing text in text field.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllRegularFormTextWithMouse();
+  CheckSelection(L"HelloABCDEFGH");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest, InsertTextInPopulatedTextFieldMiddle) {
+  TypeTextIntoTextField(8, RegularFormBegin());
+
+  // Click on the middle of the text field.
+  ClickOnFormFieldAtPoint(RegularFormAtX(134.0));
+
+  // Test inserting text in the middle of existing text in text field.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllRegularFormTextWithMouse();
+  CheckSelection(L"ABCDHelloEFGH");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest, InsertTextInPopulatedTextFieldRight) {
+  TypeTextIntoTextField(8, RegularFormBegin());
+
+  // Click on the rightmost part of the text field.
+  ClickOnFormFieldAtPoint(RegularFormAtX(166.0));
+
+  // Test inserting text behind existing text in text field.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllRegularFormTextWithMouse();
+  CheckSelection(L"ABCDEFGHHello");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedTextFieldWhole) {
+  TypeTextIntoTextField(12, RegularFormBegin());
+
+  // Select entire string in text field.
+  SelectTextWithKeyboard(12, FWL_VKEY_Left, RegularFormEnd());
+  CheckSelection(L"ABCDEFGHIJKL");
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllRegularFormTextWithMouse();
+  CheckSelection(L"Hello");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedTextFieldLeft) {
+  TypeTextIntoTextField(12, RegularFormBegin());
+
+  // Select left portion of string in text field.
+  SelectTextWithKeyboard(6, FWL_VKEY_Left, RegularFormAtX(148.0));
+  CheckSelection(L"ABCDEF");
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllRegularFormTextWithMouse();
+  CheckSelection(L"HelloGHIJKL");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedTextFieldMiddle) {
+  TypeTextIntoTextField(12, RegularFormBegin());
+
+  // Select middle portion of string in text field.
+  SelectTextWithKeyboard(6, FWL_VKEY_Left, RegularFormAtX(171.0));
+  CheckSelection(L"DEFGHI");
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllRegularFormTextWithMouse();
+  CheckSelection(L"ABCHelloJKL");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedTextFieldRight) {
+  TypeTextIntoTextField(12, RegularFormBegin());
+
+  // Select right portion of string in text field.
+  SelectTextWithKeyboard(6, FWL_VKEY_Left, RegularFormEnd());
+  CheckSelection(L"GHIJKL");
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllRegularFormTextWithMouse();
+  CheckSelection(L"ABCDEFHello");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       InsertTextInEmptyEditableComboBox) {
+  ClickOnFormFieldAtPoint(EditableFormBegin());
+
+  // Test inserting text into empty user-editable combobox.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of user-editable combobox text field to check that
+  // insertion worked as expected.
+  SelectAllEditableFormTextWithMouse();
+  CheckSelection(L"Hello");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       InsertTextInPopulatedEditableComboBoxLeft) {
+  TypeTextIntoTextField(6, EditableFormBegin());
+
+  // Click on the leftmost part of the user-editable combobox.
+  ClickOnFormFieldAtPoint(EditableFormBegin());
+
+  // Test inserting text in front of existing text in user-editable combobox.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of user-editable combobox text field to check that
+  // insertion worked as expected.
+  SelectAllEditableFormTextWithMouse();
+  CheckSelection(L"HelloABCDEF");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       InsertTextInPopulatedEditableComboBoxMiddle) {
+  TypeTextIntoTextField(6, EditableFormBegin());
+
+  // Click on the middle of the user-editable combobox.
+  ClickOnFormFieldAtPoint(EditableFormAtX(126.0));
+
+  // Test inserting text in the middle of existing text in user-editable
+  // combobox.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of user-editable combobox text field to check that
+  // insertion worked as expected.
+  SelectAllEditableFormTextWithMouse();
+  CheckSelection(L"ABCHelloDEF");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       InsertTextInPopulatedEditableComboBoxRight) {
+  TypeTextIntoTextField(6, EditableFormBegin());
+
+  // Click on the rightmost part of the user-editable combobox.
+  ClickOnFormFieldAtPoint(EditableFormEnd());
+
+  // Test inserting text behind existing text in user-editable combobox.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of user-editable combobox text field to check that
+  // insertion worked as expected.
+  SelectAllEditableFormTextWithMouse();
+  CheckSelection(L"ABCDEFHello");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedEditableComboBoxWhole) {
+  TypeTextIntoTextField(10, EditableFormBegin());
+
+  // Select entire string in user-editable combobox.
+  SelectTextWithKeyboard(10, FWL_VKEY_Left, EditableFormEnd());
+  CheckSelection(L"ABCDEFGHIJ");
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of user-editable combobox text field to check that
+  // insertion worked as expected.
+  SelectAllEditableFormTextWithMouse();
+  CheckSelection(L"Hello");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedEditableComboBoxLeft) {
+  TypeTextIntoTextField(10, EditableFormBegin());
+
+  // Select left portion of string in user-editable combobox.
+  SelectTextWithKeyboard(5, FWL_VKEY_Left, EditableFormAtX(142.0));
+  CheckSelection(L"ABCDE");
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of user-editable combobox text field to check that
+  // insertion worked as expected.
+  SelectAllEditableFormTextWithMouse();
+  CheckSelection(L"HelloFGHIJ");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedEditableComboBoxMiddle) {
+  TypeTextIntoTextField(10, EditableFormBegin());
+
+  // Select middle portion of string in user-editable combobox.
+  SelectTextWithKeyboard(5, FWL_VKEY_Left, EditableFormAtX(167.0));
+  CheckSelection(L"DEFGH");
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of user-editable combobox text field to check that
+  // insertion worked as expected.
+  SelectAllEditableFormTextWithMouse();
+  CheckSelection(L"ABCHelloIJ");
+}
+
+TEST_F(FPDFFormFillComboBoxFormEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedEditableComboBoxRight) {
+  TypeTextIntoTextField(10, EditableFormBegin());
+
+  // Select right portion of string in user-editable combobox.
+  SelectTextWithKeyboard(5, FWL_VKEY_Left, EditableFormEnd());
+  CheckSelection(L"FGHIJ");
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of user-editable combobox text field to check that
+  // insertion worked as expected.
+  SelectAllEditableFormTextWithMouse();
+  CheckSelection(L"ABCDEHello");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest,
+       InsertTextInEmptyCharLimitTextFieldOverflow) {
+  // Click on the textfield.
+  ClickOnFormFieldAtPoint(CharLimitFormEnd());
+
+  // Delete pre-filled contents of text field with char limit.
+  SelectAllCharLimitFormTextWithMouse();
+  CheckSelection(L"Elephant");
+  FORM_ReplaceSelection(form_handle(), page(), nullptr);
+
+  // Test inserting text into now empty text field so text to be inserted
+  // exceeds the char limit and is cut off.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hippopotamus");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllCharLimitFormTextWithMouse();
+  CheckSelection(L"Hippopotam");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest,
+       InsertTextInEmptyCharLimitTextFieldFit) {
+  // Click on the textfield.
+  ClickOnFormFieldAtPoint(CharLimitFormEnd());
+
+  // Delete pre-filled contents of text field with char limit.
+  SelectAllCharLimitFormTextWithMouse();
+  CheckSelection(L"Elephant");
+  FORM_ReplaceSelection(form_handle(), page(), nullptr);
+
+  // Test inserting text into now empty text field so text to be inserted
+  // exceeds the char limit and is cut off.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Zebra");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllCharLimitFormTextWithMouse();
+  CheckSelection(L"Zebra");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest,
+       InsertTextInPopulatedCharLimitTextFieldLeft) {
+  // Click on the leftmost part of the text field.
+  ClickOnFormFieldAtPoint(CharLimitFormBegin());
+
+  // Test inserting text in front of existing text in text field.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hippopotamus");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllCharLimitFormTextWithMouse();
+  CheckSelection(L"HiElephant");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest,
+       InsertTextInPopulatedCharLimitTextFieldMiddle) {
+  TypeTextIntoTextField(8, RegularFormBegin());
+
+  // Click on the middle of the text field.
+  ClickOnFormFieldAtPoint(CharLimitFormAtX(134.0));
+
+  // Test inserting text in the middle of existing text in text field.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hippopotamus");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllCharLimitFormTextWithMouse();
+  CheckSelection(L"ElephHiant");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest,
+       InsertTextInPopulatedCharLimitTextFieldRight) {
+  TypeTextIntoTextField(8, RegularFormBegin());
+
+  // Click on the rightmost part of the text field.
+  ClickOnFormFieldAtPoint(CharLimitFormAtX(166.0));
+
+  // Test inserting text behind existing text in text field.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hippopotamus");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllCharLimitFormTextWithMouse();
+  CheckSelection(L"ElephantHi");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedCharLimitTextFieldWhole) {
+  TypeTextIntoTextField(12, RegularFormBegin());
+
+  // Select entire string in text field.
+  SelectTextWithKeyboard(12, FWL_VKEY_Left, CharLimitFormEnd());
+  CheckSelection(L"Elephant");
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hippopotamus");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllCharLimitFormTextWithMouse();
+  CheckSelection(L"Hippopotam");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedCharLimitTextFieldLeft) {
+  TypeTextIntoTextField(12, RegularFormBegin());
+
+  // Select left portion of string in text field.
+  SelectTextWithKeyboard(4, FWL_VKEY_Left, CharLimitFormAtX(122.0));
+  CheckSelection(L"Elep");
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hippopotamus");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllCharLimitFormTextWithMouse();
+  CheckSelection(L"Hippophant");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedCharLimitTextFieldMiddle) {
+  TypeTextIntoTextField(12, RegularFormBegin());
+
+  // Select middle portion of string in text field.
+  SelectTextWithKeyboard(4, FWL_VKEY_Left, CharLimitFormAtX(136.0));
+  CheckSelection(L"epha");
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hippopotamus");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllCharLimitFormTextWithMouse();
+  CheckSelection(L"ElHippopnt");
+}
+
+TEST_F(FPDFFormFillTextFormEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedCharLimitTextFieldRight) {
+  TypeTextIntoTextField(12, RegularFormBegin());
+
+  // Select right portion of string in text field.
+  SelectTextWithKeyboard(4, FWL_VKEY_Left, CharLimitFormAtX(152.0));
+  CheckSelection(L"hant");
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hippopotamus");
+  FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectAllCharLimitFormTextWithMouse();
+  CheckSelection(L"ElepHippop");
+}
diff --git a/fpdfsdk/fpdfppo.cpp b/fpdfsdk/fpdfppo.cpp
index 4e06856..d88f910 100644
--- a/fpdfsdk/fpdfppo.cpp
+++ b/fpdfsdk/fpdfppo.cpp
@@ -18,14 +18,14 @@
 #include "core/fpdfapi/parser/cpdf_reference.h"
 #include "core/fpdfapi/parser/cpdf_stream.h"
 #include "core/fpdfapi/parser/cpdf_string.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "fpdfsdk/fsdk_define.h"
 #include "third_party/base/ptr_util.h"
-#include "third_party/base/stl_util.h"
 
 namespace {
 
 CPDF_Object* PageDictGetInheritableTag(CPDF_Dictionary* pDict,
-                                       const CFX_ByteString& bsSrcTag) {
+                                       const ByteString& bsSrcTag) {
   if (!pDict || bsSrcTag.IsEmpty())
     return nullptr;
   if (!pDict->KeyExist("Parent") || !pDict->KeyExist("Type"))
@@ -57,7 +57,7 @@
 
 bool CopyInheritable(CPDF_Dictionary* pCurPageDict,
                      CPDF_Dictionary* pSrcPageDict,
-                     const CFX_ByteString& key) {
+                     const ByteString& key) {
   if (pCurPageDict->KeyExist(key))
     return true;
 
@@ -69,54 +69,57 @@
   return true;
 }
 
-bool ParserPageRangeString(CFX_ByteString rangstring,
+bool ParserPageRangeString(ByteString rangstring,
                            std::vector<uint16_t>* pageArray,
                            int nCount) {
   if (rangstring.IsEmpty())
     return true;
 
   rangstring.Remove(' ');
-  int nLength = rangstring.GetLength();
-  CFX_ByteString cbCompareString("0123456789-,");
-  for (int i = 0; i < nLength; ++i) {
-    if (cbCompareString.Find(rangstring[i]) == -1)
+  size_t nLength = rangstring.GetLength();
+  ByteString cbCompareString("0123456789-,");
+  for (size_t i = 0; i < nLength; ++i) {
+    if (!cbCompareString.Contains(rangstring[i]))
       return false;
   }
 
-  CFX_ByteString cbMidRange;
-  int nStringFrom = 0;
-  int nStringTo = 0;
+  ByteString cbMidRange;
+  size_t nStringFrom = 0;
+  Optional<size_t> nStringTo = 0;
   while (nStringTo < nLength) {
     nStringTo = rangstring.Find(',', nStringFrom);
-    if (nStringTo == -1)
+    if (!nStringTo.has_value())
       nStringTo = nLength;
-    cbMidRange = rangstring.Mid(nStringFrom, nStringTo - nStringFrom);
-    int nMid = cbMidRange.Find('-');
-    if (nMid == -1) {
-      long lPageNum = atol(cbMidRange.c_str());
-      if (lPageNum <= 0 || lPageNum > nCount)
+    cbMidRange = rangstring.Mid(nStringFrom, nStringTo.value() - nStringFrom);
+    auto nMid = cbMidRange.Find('-');
+    if (!nMid.has_value()) {
+      uint16_t pageNum =
+          pdfium::base::checked_cast<uint16_t>(atoi(cbMidRange.c_str()));
+      if (pageNum <= 0 || pageNum > nCount)
         return false;
-      pageArray->push_back((uint16_t)lPageNum);
+      pageArray->push_back(pageNum);
     } else {
-      int nStartPageNum = atol(cbMidRange.Mid(0, nMid).c_str());
+      uint16_t nStartPageNum = pdfium::base::checked_cast<uint16_t>(
+          atoi(cbMidRange.Left(nMid.value()).c_str()));
       if (nStartPageNum == 0)
         return false;
 
-      ++nMid;
-      int nEnd = cbMidRange.GetLength() - nMid;
+      nMid = nMid.value() + 1;
+      size_t nEnd = cbMidRange.GetLength() - nMid.value();
       if (nEnd == 0)
         return false;
 
-      int nEndPageNum = atol(cbMidRange.Mid(nMid, nEnd).c_str());
+      uint16_t nEndPageNum = pdfium::base::checked_cast<uint16_t>(
+          atoi(cbMidRange.Mid(nMid.value(), nEnd).c_str()));
       if (nStartPageNum < 0 || nStartPageNum > nEndPageNum ||
           nEndPageNum > nCount) {
         return false;
       }
-      for (int i = nStartPageNum; i <= nEndPageNum; ++i) {
+      for (uint16_t i = nStartPageNum; i <= nEndPageNum; ++i) {
         pageArray->push_back(i);
       }
     }
-    nStringFrom = nStringTo + 1;
+    nStringFrom = nStringTo.value() + 1;
   }
   return true;
 }
@@ -137,8 +140,8 @@
   bool UpdateReference(CPDF_Object* pObj, ObjectNumberMap* pObjNumberMap);
   uint32_t GetNewObjId(ObjectNumberMap* pObjNumberMap, CPDF_Reference* pRef);
 
-  CPDF_Document* m_pDestPDFDoc;
-  CPDF_Document* m_pSrcPDFDoc;
+  UnownedPtr<CPDF_Document> m_pDestPDFDoc;
+  UnownedPtr<CPDF_Document> m_pSrcPDFDoc;
 };
 
 CPDF_PageOrganizer::CPDF_PageOrganizer(CPDF_Document* pDestPDFDoc,
@@ -161,7 +164,7 @@
 
   pDocInfoDict->SetNewFor<CPDF_String>("Producer", "PDFium", false);
 
-  CFX_ByteString cbRootType = pNewRoot->GetStringFor("Type", "");
+  ByteString cbRootType = pNewRoot->GetStringFor("Type", "");
   if (cbRootType.IsEmpty())
     pNewRoot->SetNewFor<CPDF_Name>("Type", "Catalog");
 
@@ -170,18 +173,18 @@
       pElement ? ToDictionary(pElement->GetDirect()) : nullptr;
   if (!pNewPages) {
     pNewPages = m_pDestPDFDoc->NewIndirect<CPDF_Dictionary>();
-    pNewRoot->SetNewFor<CPDF_Reference>("Pages", m_pDestPDFDoc,
+    pNewRoot->SetNewFor<CPDF_Reference>("Pages", m_pDestPDFDoc.Get(),
                                         pNewPages->GetObjNum());
   }
 
-  CFX_ByteString cbPageType = pNewPages->GetStringFor("Type", "");
+  ByteString cbPageType = pNewPages->GetStringFor("Type", "");
   if (cbPageType.IsEmpty())
     pNewPages->SetNewFor<CPDF_Name>("Type", "Pages");
 
   if (!pNewPages->GetArrayFor("Kids")) {
     pNewPages->SetNewFor<CPDF_Number>("Count", 0);
     pNewPages->SetNewFor<CPDF_Reference>(
-        "Kids", m_pDestPDFDoc,
+        "Kids", m_pDestPDFDoc.Get(),
         m_pDestPDFDoc->NewIndirect<CPDF_Array>()->GetObjNum());
   }
 
@@ -192,8 +195,7 @@
                                     int nIndex) {
   int curpage = nIndex;
   auto pObjNumberMap = pdfium::MakeUnique<ObjectNumberMap>();
-  int nSize = pdfium::CollectionSize<int>(pageNums);
-  for (int i = 0; i < nSize; ++i) {
+  for (size_t i = 0; i < pageNums.size(); ++i) {
     CPDF_Dictionary* pCurPageDict = m_pDestPDFDoc->CreateNewPage(curpage);
     CPDF_Dictionary* pSrcPageDict = m_pSrcPDFDoc->GetPage(pageNums[i] - 1);
     if (!pSrcPageDict || !pCurPageDict)
@@ -201,7 +203,7 @@
 
     // Clone the page dictionary
     for (const auto& it : *pSrcPageDict) {
-      const CFX_ByteString& cbSrcKeyStr = it.first;
+      const ByteString& cbSrcKeyStr = it.first;
       if (cbSrcKeyStr == "Type" || cbSrcKeyStr == "Parent")
         continue;
 
@@ -210,16 +212,18 @@
     }
 
     // inheritable item
+    // Even though some entries are required by the PDF spec, there exist
+    // PDFs that omit them. Set some defaults in this case.
     // 1 MediaBox - required
     if (!CopyInheritable(pCurPageDict, pSrcPageDict, "MediaBox")) {
-      // Search for "CropBox" in the source page dictionary,
-      // if it does not exists, use the default letter size.
+      // Search for "CropBox" in the source page dictionary.
+      // If it does not exist, use the default letter size.
       CPDF_Object* pInheritable =
           PageDictGetInheritableTag(pSrcPageDict, "CropBox");
       if (pInheritable) {
         pCurPageDict->SetFor("MediaBox", pInheritable->Clone());
       } else {
-        // Make the default size to be letter size (8.5'x11')
+        // Make the default size letter size (8.5"x11")
         CPDF_Array* pArray = pCurPageDict->SetNewFor<CPDF_Array>("MediaBox");
         pArray->AddNew<CPDF_Number>(0);
         pArray->AddNew<CPDF_Number>(0);
@@ -229,8 +233,10 @@
     }
 
     // 2 Resources - required
-    if (!CopyInheritable(pCurPageDict, pSrcPageDict, "Resources"))
-      return false;
+    if (!CopyInheritable(pCurPageDict, pSrcPageDict, "Resources")) {
+      // Use a default empty resources if it does not exist.
+      pCurPageDict->SetNewFor<CPDF_Dictionary>("Resources");
+    }
 
     // 3 CropBox - optional
     CopyInheritable(pCurPageDict, pSrcPageDict, "CropBox");
@@ -256,14 +262,14 @@
       uint32_t newobjnum = GetNewObjId(pObjNumberMap, pReference);
       if (newobjnum == 0)
         return false;
-      pReference->SetRef(m_pDestPDFDoc, newobjnum);
+      pReference->SetRef(m_pDestPDFDoc.Get(), newobjnum);
       break;
     }
     case CPDF_Object::DICTIONARY: {
       CPDF_Dictionary* pDict = pObj->AsDictionary();
       auto it = pDict->begin();
       while (it != pDict->end()) {
-        const CFX_ByteString& key = it->first;
+        const ByteString& key = it->first;
         CPDF_Object* pNextObj = it->second.get();
         ++it;
         if (key == "Parent" || key == "Prev" || key == "First")
@@ -322,7 +328,7 @@
   std::unique_ptr<CPDF_Object> pClone = pDirect->Clone();
   if (CPDF_Dictionary* pDictClone = pClone->AsDictionary()) {
     if (pDictClone->KeyExist("Type")) {
-      CFX_ByteString strType = pDictClone->GetStringFor("Type");
+      ByteString strType = pDictClone->GetStringFor("Type");
       if (!FXSYS_stricmp(strType.c_str(), "Pages"))
         return 4;
       if (!FXSYS_stricmp(strType.c_str(), "Page"))
@@ -339,10 +345,10 @@
   return dwNewObjNum;
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDF_ImportPages(FPDF_DOCUMENT dest_doc,
-                                             FPDF_DOCUMENT src_doc,
-                                             FPDF_BYTESTRING pagerange,
-                                             int index) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPages(FPDF_DOCUMENT dest_doc,
+                                                     FPDF_DOCUMENT src_doc,
+                                                     FPDF_BYTESTRING pagerange,
+                                                     int index) {
   CPDF_Document* pDestDoc = CPDFDocumentFromFPDFDocument(dest_doc);
   if (!dest_doc)
     return false;
@@ -366,8 +372,8 @@
   return pageOrg.PDFDocInit() && pageOrg.ExportPage(pageArray, index);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc,
-                                                       FPDF_DOCUMENT src_doc) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc) {
   CPDF_Document* pDstDoc = CPDFDocumentFromFPDFDocument(dest_doc);
   if (!pDstDoc)
     return false;
diff --git a/fpdfsdk/fpdfppo_embeddertest.cpp b/fpdfsdk/fpdfppo_embeddertest.cpp
index 0972316..c642b71 100644
--- a/fpdfsdk/fpdfppo_embeddertest.cpp
+++ b/fpdfsdk/fpdfppo_embeddertest.cpp
@@ -1,11 +1,11 @@
 // 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.
+#include <string>
 
-#include "public/fpdf_ppo.h"
-
-#include "core/fxcrt/fx_basic.h"
 #include "public/fpdf_edit.h"
+#include "public/fpdf_ppo.h"
+#include "public/fpdf_save.h"
 #include "public/fpdfview.h"
 #include "testing/embedder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -15,6 +15,12 @@
 
 class FPDFPPOEmbeddertest : public EmbedderTest {};
 
+int FakeBlockWriter(FPDF_FILEWRITE* pThis,
+                    const void* pData,
+                    unsigned long size) {
+  return size;
+}
+
 }  // namespace
 
 TEST_F(FPDFPPOEmbeddertest, NoViewerPreferences) {
@@ -36,13 +42,13 @@
 }
 
 TEST_F(FPDFPPOEmbeddertest, ImportPages) {
-  EXPECT_TRUE(OpenDocument("viewer_ref.pdf"));
+  ASSERT_TRUE(OpenDocument("viewer_ref.pdf"));
 
   FPDF_PAGE page = LoadPage(0);
   EXPECT_TRUE(page);
 
   FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument();
-  EXPECT_TRUE(output_doc);
+  ASSERT_TRUE(output_doc);
   EXPECT_TRUE(FPDF_CopyViewerPreferences(output_doc, document()));
   EXPECT_TRUE(FPDF_ImportPages(output_doc, document(), "1", 0));
   EXPECT_EQ(1, FPDF_GetPageCount(output_doc));
@@ -51,6 +57,36 @@
   UnloadPage(page);
 }
 
+TEST_F(FPDFPPOEmbeddertest, BadRepeatViewerPref) {
+  ASSERT_TRUE(OpenDocument("repeat_viewer_ref.pdf"));
+
+  FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument();
+  EXPECT_TRUE(output_doc);
+  EXPECT_TRUE(FPDF_CopyViewerPreferences(output_doc, document()));
+
+  FPDF_FILEWRITE writer;
+  writer.version = 1;
+  writer.WriteBlock = FakeBlockWriter;
+
+  EXPECT_TRUE(FPDF_SaveAsCopy(output_doc, &writer, 0));
+  FPDF_CloseDocument(output_doc);
+}
+
+TEST_F(FPDFPPOEmbeddertest, BadCircularViewerPref) {
+  ASSERT_TRUE(OpenDocument("circular_viewer_ref.pdf"));
+
+  FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument();
+  EXPECT_TRUE(output_doc);
+  EXPECT_TRUE(FPDF_CopyViewerPreferences(output_doc, document()));
+
+  FPDF_FILEWRITE writer;
+  writer.version = 1;
+  writer.WriteBlock = FakeBlockWriter;
+
+  EXPECT_TRUE(FPDF_SaveAsCopy(output_doc, &writer, 0));
+  FPDF_CloseDocument(output_doc);
+}
+
 TEST_F(FPDFPPOEmbeddertest, BadRanges) {
   EXPECT_TRUE(OpenDocument("viewer_ref.pdf"));
 
@@ -95,7 +131,7 @@
   EXPECT_TRUE(OpenDocument("bug_664284.pdf"));
 
   FPDF_PAGE page = LoadPage(0);
-  EXPECT_TRUE(page);
+  ASSERT_NE(nullptr, page);
 
   FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument();
   EXPECT_TRUE(output_doc);
@@ -104,3 +140,81 @@
 
   UnloadPage(page);
 }
+
+TEST_F(FPDFPPOEmbeddertest, BUG_750568) {
+  const char* const kHashes[] = {
+      "64ad08132a1c5a166768298c8a578f57", "83b83e2f6bc80707d0a917c7634140b9",
+      "913cd3723a451e4e46fbc2c05702d1ee", "81fb7cfd4860f855eb468f73dfeb6d60"};
+
+  ASSERT_TRUE(OpenDocument("bug_750568.pdf"));
+  ASSERT_EQ(4, FPDF_GetPageCount(document()));
+
+  for (size_t i = 0; i < 4; ++i) {
+    FPDF_PAGE page = LoadPage(i);
+    ASSERT_NE(nullptr, page);
+
+    FPDF_BITMAP bitmap = RenderPage(page);
+    ASSERT_EQ(200, FPDFBitmap_GetWidth(bitmap));
+    ASSERT_EQ(200, FPDFBitmap_GetHeight(bitmap));
+    ASSERT_EQ(800, FPDFBitmap_GetStride(bitmap));
+
+    std::string digest = HashBitmap(bitmap);
+    FPDFBitmap_Destroy(bitmap);
+    UnloadPage(page);
+    EXPECT_EQ(kHashes[i], digest);
+  }
+
+  FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument();
+  ASSERT_TRUE(output_doc);
+  EXPECT_TRUE(FPDF_ImportPages(output_doc, document(), "1,2,3,4", 0));
+  ASSERT_EQ(4, FPDF_GetPageCount(output_doc));
+  for (size_t i = 0; i < 4; ++i) {
+    FPDF_PAGE page = FPDF_LoadPage(output_doc, i);
+    ASSERT_NE(nullptr, page);
+
+    FPDF_BITMAP bitmap = RenderPage(page);
+    ASSERT_EQ(200, FPDFBitmap_GetWidth(bitmap));
+    ASSERT_EQ(200, FPDFBitmap_GetHeight(bitmap));
+    ASSERT_EQ(800, FPDFBitmap_GetStride(bitmap));
+
+    std::string digest = HashBitmap(bitmap);
+    FPDFBitmap_Destroy(bitmap);
+    FPDF_ClosePage(page);
+    EXPECT_EQ(kHashes[i], digest);
+  }
+  FPDF_CloseDocument(output_doc);
+}
+
+TEST_F(FPDFPPOEmbeddertest, ImportWithZeroLengthStream) {
+  EXPECT_TRUE(OpenDocument("zero_length_stream.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_NE(nullptr, page);
+
+  FPDF_BITMAP bitmap = RenderPage(page);
+  ASSERT_EQ(200, FPDFBitmap_GetWidth(bitmap));
+  ASSERT_EQ(200, FPDFBitmap_GetHeight(bitmap));
+  ASSERT_EQ(800, FPDFBitmap_GetStride(bitmap));
+
+  std::string digest = HashBitmap(bitmap);
+  FPDFBitmap_Destroy(bitmap);
+  FPDF_ClosePage(page);
+
+  FPDF_DOCUMENT new_doc = FPDF_CreateNewDocument();
+  EXPECT_TRUE(new_doc);
+  EXPECT_TRUE(FPDF_ImportPages(new_doc, document(), "1", 0));
+
+  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);
+  ASSERT_EQ(200, FPDFBitmap_GetWidth(new_bitmap));
+  ASSERT_EQ(200, FPDFBitmap_GetHeight(new_bitmap));
+  ASSERT_EQ(800, FPDFBitmap_GetStride(new_bitmap));
+
+  std::string new_digest = HashBitmap(new_bitmap);
+  FPDFBitmap_Destroy(new_bitmap);
+  FPDF_ClosePage(new_page);
+  FPDF_CloseDocument(new_doc);
+
+  EXPECT_EQ(digest, new_digest);
+}
diff --git a/fpdfsdk/fpdfsave.cpp b/fpdfsdk/fpdfsave.cpp
index 0cfcd4a..ddbc994 100644
--- a/fpdfsdk/fpdfsave.cpp
+++ b/fpdfsdk/fpdfsave.cpp
@@ -16,73 +16,40 @@
 #include "core/fpdfapi/parser/cpdf_reference.h"
 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
 #include "core/fpdfapi/parser/cpdf_string.h"
-#include "core/fxcrt/fx_ext.h"
+#include "core/fxcrt/cfx_memorystream.h"
+#include "core/fxcrt/fx_extension.h"
 #include "fpdfsdk/fsdk_define.h"
+#include "fpdfsdk/fsdk_filewriteadapter.h"
 #include "public/fpdf_edit.h"
 
 #ifdef PDF_ENABLE_XFA
+#include "core/fxcrt/cfx_checksumcontext.h"
 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
 #include "fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h"
 #include "public/fpdf_formfill.h"
 #include "xfa/fxfa/cxfa_eventparam.h"
-#include "xfa/fxfa/xfa_checksum.h"
-#include "xfa/fxfa/xfa_ffapp.h"
-#include "xfa/fxfa/xfa_ffdocview.h"
-#include "xfa/fxfa/xfa_ffwidgethandler.h"
+#include "xfa/fxfa/cxfa_ffapp.h"
+#include "xfa/fxfa/cxfa_ffdocview.h"
+#include "xfa/fxfa/cxfa_ffwidgethandler.h"
+#include "xfa/fxfa/cxfa_widgetacciterator.h"
+#include "xfa/fxfa/parser/cxfa_object.h"
 #endif
 
-#if _FX_OS_ == _FX_ANDROID_
+#if _FX_OS_ == _FX_OS_ANDROID_
 #include <time.h>
 #else
 #include <ctime>
 #endif
 
-class CFX_IFileWrite final : public IFX_WriteStream {
- public:
-  static CFX_RetainPtr<CFX_IFileWrite> Create();
-  bool Init(FPDF_FILEWRITE* pFileWriteStruct);
-  bool WriteBlock(const void* pData, size_t size) override;
-
- protected:
-  CFX_IFileWrite();
-  ~CFX_IFileWrite() override {}
-
-  FPDF_FILEWRITE* m_pFileWriteStruct;
-};
-
-CFX_RetainPtr<CFX_IFileWrite> CFX_IFileWrite::Create() {
-  return CFX_RetainPtr<CFX_IFileWrite>(new CFX_IFileWrite());
-}
-
-CFX_IFileWrite::CFX_IFileWrite() : m_pFileWriteStruct(nullptr) {}
-
-bool CFX_IFileWrite::Init(FPDF_FILEWRITE* pFileWriteStruct) {
-  if (!pFileWriteStruct)
-    return false;
-
-  m_pFileWriteStruct = pFileWriteStruct;
-  return true;
-}
-
-bool CFX_IFileWrite::WriteBlock(const void* pData, size_t size) {
-  if (!m_pFileWriteStruct)
-    return false;
-
-  m_pFileWriteStruct->WriteBlock(m_pFileWriteStruct, pData, size);
-  return true;
-}
-
 namespace {
 
 #ifdef PDF_ENABLE_XFA
-bool SaveXFADocumentData(
-    CPDFXFA_Context* pContext,
-    std::vector<CFX_RetainPtr<IFX_SeekableStream>>* fileList) {
+bool SaveXFADocumentData(CPDFXFA_Context* pContext,
+                         std::vector<RetainPtr<IFX_SeekableStream>>* fileList) {
   if (!pContext)
     return false;
 
-  if (pContext->GetDocType() != DOCTYPE_DYNAMIC_XFA &&
-      pContext->GetDocType() != DOCTYPE_STATIC_XFA)
+  if (!pContext->ContainsXFAForm())
     return true;
 
   CXFA_FFDocView* pXFADocView = pContext->GetXFADocView();
@@ -93,7 +60,7 @@
   if (!pPDFDocument)
     return false;
 
-  CPDF_Dictionary* pRoot = pPDFDocument->GetRoot();
+  const CPDF_Dictionary* pRoot = pPDFDocument->GetRoot();
   if (!pRoot)
     return false;
 
@@ -125,18 +92,17 @@
     else if (pPDFObj->GetString() == "template")
       iTemplate = i + 1;
   }
-  std::unique_ptr<CXFA_ChecksumContext> pChecksum(new CXFA_ChecksumContext);
+  auto pChecksum = pdfium::MakeUnique<CFX_ChecksumContext>();
   pChecksum->StartChecksum();
 
   // template
   if (iTemplate > -1) {
     CPDF_Stream* pTemplateStream = pArray->GetStreamAt(iTemplate);
-    CPDF_StreamAcc streamAcc;
-    streamAcc.LoadAllData(pTemplateStream);
-    uint8_t* pData = (uint8_t*)streamAcc.GetData();
-    uint32_t dwSize2 = streamAcc.GetSize();
-    CFX_RetainPtr<IFX_SeekableStream> pTemplate =
-        IFX_MemoryStream::Create(pData, dwSize2);
+    auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pTemplateStream);
+    pAcc->LoadAllDataFiltered();
+    RetainPtr<IFX_SeekableStream> pTemplate =
+        pdfium::MakeRetain<CFX_MemoryStream>(
+            const_cast<uint8_t*>(pAcc->GetData()), pAcc->GetSize(), false);
     pChecksum->UpdateChecksum(pTemplate);
   }
   CPDF_Stream* pFormStream = nullptr;
@@ -169,9 +135,12 @@
   }
   // L"datasets"
   {
-    CFX_RetainPtr<IFX_SeekableStream> pDsfileWrite = IFX_MemoryStream::Create();
-    if (pXFADocView->GetDoc()->SavePackage(XFA_HASHCODE_Datasets, pDsfileWrite,
-                                           nullptr) &&
+    RetainPtr<IFX_SeekableStream> pDsfileWrite =
+        pdfium::MakeRetain<CFX_MemoryStream>(false);
+    CXFA_FFDoc* ffdoc = pXFADocView->GetDoc();
+    if (ffdoc->SavePackage(
+            ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Datasets)),
+            pDsfileWrite, nullptr) &&
         pDsfileWrite->GetSize() > 0) {
       // Datasets
       pChecksum->UpdateChecksum(pDsfileWrite);
@@ -196,9 +165,13 @@
   }
   // L"form"
   {
-    CFX_RetainPtr<IFX_SeekableStream> pfileWrite = IFX_MemoryStream::Create();
-    if (pXFADocView->GetDoc()->SavePackage(XFA_HASHCODE_Form, pfileWrite,
-                                           pChecksum.get()) &&
+    RetainPtr<IFX_SeekableStream> pfileWrite =
+        pdfium::MakeRetain<CFX_MemoryStream>(false);
+
+    CXFA_FFDoc* ffdoc = pXFADocView->GetDoc();
+    if (ffdoc->SavePackage(
+            ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form)),
+            pfileWrite, pChecksum.get()) &&
         pfileWrite->GetSize() > 0) {
       auto pDataDict = pdfium::MakeUnique<CPDF_Dictionary>(
           pPDFDocument->GetByteStringPool());
@@ -223,45 +196,42 @@
   if (!pContext)
     return false;
 
-  if (pContext->GetDocType() != DOCTYPE_DYNAMIC_XFA &&
-      pContext->GetDocType() != DOCTYPE_STATIC_XFA)
+  if (!pContext->ContainsXFAForm())
     return true;
 
   CXFA_FFDocView* pXFADocView = pContext->GetXFADocView();
   if (!pXFADocView)
     return false;
 
-  CXFA_FFWidgetHandler* pWidgetHander = pXFADocView->GetWidgetHandler();
-  std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator(
-      pXFADocView->CreateWidgetAccIterator());
+  CXFA_FFWidgetHandler* pWidgetHandler = pXFADocView->GetWidgetHandler();
+  std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator =
+      pXFADocView->CreateWidgetAccIterator();
   while (CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext()) {
     CXFA_EventParam preParam;
     preParam.m_eType = XFA_EVENT_PostSave;
-    pWidgetHander->ProcessEvent(pWidgetAcc, &preParam);
+    pWidgetHandler->ProcessEvent(pWidgetAcc, &preParam);
   }
   pXFADocView->UpdateDocView();
   pContext->ClearChangeMark();
   return true;
 }
 
-bool SendPreSaveToXFADoc(
-    CPDFXFA_Context* pContext,
-    std::vector<CFX_RetainPtr<IFX_SeekableStream>>* fileList) {
-  if (pContext->GetDocType() != DOCTYPE_DYNAMIC_XFA &&
-      pContext->GetDocType() != DOCTYPE_STATIC_XFA)
+bool SendPreSaveToXFADoc(CPDFXFA_Context* pContext,
+                         std::vector<RetainPtr<IFX_SeekableStream>>* fileList) {
+  if (!pContext->ContainsXFAForm())
     return true;
 
   CXFA_FFDocView* pXFADocView = pContext->GetXFADocView();
   if (!pXFADocView)
     return true;
 
-  CXFA_FFWidgetHandler* pWidgetHander = pXFADocView->GetWidgetHandler();
-  std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator(
-      pXFADocView->CreateWidgetAccIterator());
+  CXFA_FFWidgetHandler* pWidgetHandler = pXFADocView->GetWidgetHandler();
+  std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator =
+      pXFADocView->CreateWidgetAccIterator();
   while (CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext()) {
     CXFA_EventParam preParam;
     preParam.m_eType = XFA_EVENT_PreSave;
-    pWidgetHander->ProcessEvent(pWidgetAcc, &preParam);
+    pWidgetHandler->ProcessEvent(pWidgetAcc, &preParam);
   }
   pXFADocView->UpdateDocView();
   return SaveXFADocumentData(pContext, fileList);
@@ -279,24 +249,23 @@
 
 #ifdef PDF_ENABLE_XFA
   CPDFXFA_Context* pContext = static_cast<CPDFXFA_Context*>(document);
-  std::vector<CFX_RetainPtr<IFX_SeekableStream>> fileList;
+  std::vector<RetainPtr<IFX_SeekableStream>> fileList;
   SendPreSaveToXFADoc(pContext, &fileList);
 #endif  // PDF_ENABLE_XFA
 
   if (flags < FPDF_INCREMENTAL || flags > FPDF_REMOVE_SECURITY)
     flags = 0;
 
-  CPDF_Creator FileMaker(pPDFDoc);
+  CPDF_Creator fileMaker(pPDFDoc,
+                         pdfium::MakeRetain<FSDK_FileWriteAdapter>(pFileWrite));
   if (bSetVersion)
-    FileMaker.SetFileVersion(fileVerion);
+    fileMaker.SetFileVersion(fileVerion);
   if (flags == FPDF_REMOVE_SECURITY) {
     flags = 0;
-    FileMaker.RemoveSecurity();
+    fileMaker.RemoveSecurity();
   }
 
-  CFX_RetainPtr<CFX_IFileWrite> pStreamWrite = CFX_IFileWrite::Create();
-  pStreamWrite->Init(pFileWrite);
-  bool bRet = FileMaker.Create(pStreamWrite, flags);
+  bool bRet = fileMaker.Create(flags);
 #ifdef PDF_ENABLE_XFA
   SendPostSaveToXFADoc(pContext);
 #endif  // PDF_ENABLE_XFA
@@ -305,15 +274,16 @@
 
 }  // namespace
 
-DLLEXPORT FPDF_BOOL STDCALL FPDF_SaveAsCopy(FPDF_DOCUMENT document,
-                                            FPDF_FILEWRITE* pFileWrite,
-                                            FPDF_DWORD flags) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SaveAsCopy(FPDF_DOCUMENT document,
+                                                    FPDF_FILEWRITE* pFileWrite,
+                                                    FPDF_DWORD flags) {
   return FPDF_Doc_Save(document, pFileWrite, flags, false, 0);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDF_SaveWithVersion(FPDF_DOCUMENT document,
-                                                 FPDF_FILEWRITE* pFileWrite,
-                                                 FPDF_DWORD flags,
-                                                 int fileVersion) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDF_SaveWithVersion(FPDF_DOCUMENT document,
+                     FPDF_FILEWRITE* pFileWrite,
+                     FPDF_DWORD flags,
+                     int fileVersion) {
   return FPDF_Doc_Save(document, pFileWrite, flags, true, fileVersion);
 }
diff --git a/fpdfsdk/fpdfsave_embeddertest.cpp b/fpdfsdk/fpdfsave_embeddertest.cpp
index 9187270..3122be1 100644
--- a/fpdfsdk/fpdfsave_embeddertest.cpp
+++ b/fpdfsdk/fpdfsave_embeddertest.cpp
@@ -4,34 +4,32 @@
 
 #include "public/fpdf_save.h"
 
-#include <string.h>
+#include <string>
 
 #include "core/fxcrt/fx_string.h"
 #include "public/fpdf_edit.h"
 #include "public/fpdf_ppo.h"
 #include "public/fpdfview.h"
 #include "testing/embedder_test.h"
-#include "testing/fx_string_testhelpers.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/test_support.h"
 
-class FPDFSaveEmbedderTest : public EmbedderTest, public TestSaver {};
+class FPDFSaveEmbedderTest : public EmbedderTest {};
 
 TEST_F(FPDFSaveEmbedderTest, SaveSimpleDoc) {
   EXPECT_TRUE(OpenDocument("hello_world.pdf"));
   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
   EXPECT_THAT(GetString(), testing::StartsWith("%PDF-1.7\r\n"));
-  EXPECT_EQ(843u, GetString().length());
+  EXPECT_EQ(805u, GetString().length());
 }
 
 TEST_F(FPDFSaveEmbedderTest, SaveSimpleDocWithVersion) {
   EXPECT_TRUE(OpenDocument("hello_world.pdf"));
   EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, 0, 14));
   EXPECT_THAT(GetString(), testing::StartsWith("%PDF-1.4\r\n"));
-  EXPECT_EQ(843u, GetString().length());
+  EXPECT_EQ(805u, GetString().length());
 }
-
 TEST_F(FPDFSaveEmbedderTest, SaveSimpleDocWithBadVersion) {
   EXPECT_TRUE(OpenDocument("hello_world.pdf"));
   EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, 0, -1));
@@ -61,6 +59,39 @@
   UnloadPage(page);
 }
 
+TEST_F(FPDFSaveEmbedderTest, SaveLinearizedDoc) {
+  const int kPageCount = 3;
+  std::string original_md5[kPageCount];
+
+  EXPECT_TRUE(OpenDocument("linearized.pdf"));
+  for (int i = 0; i < kPageCount; ++i) {
+    FPDF_PAGE page = LoadPage(i);
+    FPDF_BITMAP bitmap = RenderPage(page);
+    EXPECT_EQ(612, FPDFBitmap_GetWidth(bitmap));
+    EXPECT_EQ(792, FPDFBitmap_GetHeight(bitmap));
+    original_md5[i] = HashBitmap(bitmap);
+    FPDFBitmap_Destroy(bitmap);
+    UnloadPage(page);
+  }
+
+  EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+  EXPECT_THAT(GetString(), testing::StartsWith("%PDF-1.6\r\n"));
+  EXPECT_THAT(GetString(), testing::HasSubstr("/Root "));
+  EXPECT_THAT(GetString(), testing::HasSubstr("/Info "));
+  EXPECT_EQ(8219u, GetString().length());
+
+  // Make sure new document renders the same as the old one.
+  EXPECT_TRUE(OpenSavedDocument());
+  for (int i = 0; i < kPageCount; ++i) {
+    FPDF_PAGE page = LoadSavedPage(i);
+    FPDF_BITMAP bitmap = RenderSavedPage(page);
+    EXPECT_EQ(original_md5[i], HashBitmap(bitmap));
+    FPDFBitmap_Destroy(bitmap);
+    CloseSavedPage(page);
+  }
+  CloseSavedDocument();
+}
+
 TEST_F(FPDFSaveEmbedderTest, BUG_342) {
   EXPECT_TRUE(OpenDocument("hello_world.pdf"));
   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
diff --git a/fpdfsdk/fpdftext.cpp b/fpdfsdk/fpdftext.cpp
index 0432afd..68bf4f8 100644
--- a/fpdfsdk/fpdftext.cpp
+++ b/fpdfsdk/fpdftext.cpp
@@ -29,6 +29,8 @@
 
 namespace {
 
+constexpr size_t kBytesPerCharacter = sizeof(unsigned short);
+
 CPDF_TextPage* CPDFTextPageFromFPDFTextPage(FPDF_TEXTPAGE text_page) {
   return static_cast<CPDF_TextPage*>(text_page);
 }
@@ -43,7 +45,7 @@
 
 }  // namespace
 
-DLLEXPORT FPDF_TEXTPAGE STDCALL FPDFText_LoadPage(FPDF_PAGE page) {
+FPDF_EXPORT FPDF_TEXTPAGE FPDF_CALLCONV FPDFText_LoadPage(FPDF_PAGE page) {
   CPDF_Page* pPDFPage = CPDFPageFromFPDFPage(page);
   if (!pPDFPage)
     return nullptr;
@@ -53,7 +55,7 @@
   CPDFXFA_Context* pContext = pPage->GetContext();
   CPDF_ViewerPreferences viewRef(pContext->GetPDFDoc());
 #else  // PDF_ENABLE_XFA
-  CPDF_ViewerPreferences viewRef(pPDFPage->m_pDocument);
+  CPDF_ViewerPreferences viewRef(pPDFPage->m_pDocument.Get());
 #endif  // PDF_ENABLE_XFA
 
   CPDF_TextPage* textpage = new CPDF_TextPage(
@@ -63,11 +65,11 @@
   return textpage;
 }
 
-DLLEXPORT void STDCALL FPDFText_ClosePage(FPDF_TEXTPAGE text_page) {
+FPDF_EXPORT void FPDF_CALLCONV FPDFText_ClosePage(FPDF_TEXTPAGE text_page) {
   delete CPDFTextPageFromFPDFTextPage(text_page);
 }
 
-DLLEXPORT int STDCALL FPDFText_CountChars(FPDF_TEXTPAGE text_page) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFText_CountChars(FPDF_TEXTPAGE text_page) {
   if (!text_page)
     return -1;
 
@@ -75,8 +77,8 @@
   return textpage->CountChars();
 }
 
-DLLEXPORT unsigned int STDCALL FPDFText_GetUnicode(FPDF_TEXTPAGE text_page,
-                                                   int index) {
+FPDF_EXPORT unsigned int FPDF_CALLCONV
+FPDFText_GetUnicode(FPDF_TEXTPAGE text_page, int index) {
   if (!text_page)
     return 0;
 
@@ -89,8 +91,8 @@
   return charinfo.m_Unicode;
 }
 
-DLLEXPORT double STDCALL FPDFText_GetFontSize(FPDF_TEXTPAGE text_page,
-                                              int index) {
+FPDF_EXPORT double FPDF_CALLCONV FPDFText_GetFontSize(FPDF_TEXTPAGE text_page,
+                                                      int index) {
   if (!text_page)
     return 0;
   CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
@@ -103,68 +105,101 @@
   return charinfo.m_FontSize;
 }
 
-DLLEXPORT void STDCALL FPDFText_GetCharBox(FPDF_TEXTPAGE text_page,
-                                           int index,
-                                           double* left,
-                                           double* right,
-                                           double* bottom,
-                                           double* top) {
-  if (!text_page)
-    return;
-  CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetCharBox(FPDF_TEXTPAGE text_page,
+                                                        int index,
+                                                        double* left,
+                                                        double* right,
+                                                        double* bottom,
+                                                        double* top) {
+  if (!text_page || index < 0)
+    return false;
 
-  if (index < 0 || index >= textpage->CountChars())
-    return;
+  CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
+  if (index >= textpage->CountChars())
+    return false;
+
   FPDF_CHAR_INFO charinfo;
   textpage->GetCharInfo(index, &charinfo);
   *left = charinfo.m_CharBox.left;
   *right = charinfo.m_CharBox.right;
   *bottom = charinfo.m_CharBox.bottom;
   *top = charinfo.m_CharBox.top;
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFText_GetCharOrigin(FPDF_TEXTPAGE text_page,
+                       int index,
+                       double* x,
+                       double* y) {
+  if (!text_page)
+    return false;
+  CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
+
+  if (index < 0 || index >= textpage->CountChars())
+    return false;
+  FPDF_CHAR_INFO charinfo;
+  textpage->GetCharInfo(index, &charinfo);
+  *x = charinfo.m_Origin.x;
+  *y = charinfo.m_Origin.y;
+  return true;
 }
 
 // select
-DLLEXPORT int STDCALL FPDFText_GetCharIndexAtPos(FPDF_TEXTPAGE text_page,
-                                                 double x,
-                                                 double y,
-                                                 double xTolerance,
-                                                 double yTolerance) {
+FPDF_EXPORT int FPDF_CALLCONV
+FPDFText_GetCharIndexAtPos(FPDF_TEXTPAGE text_page,
+                           double x,
+                           double y,
+                           double xTolerance,
+                           double yTolerance) {
   if (!text_page)
     return -3;
 
   CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
   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)));
+      CFX_PointF(static_cast<float>(x), static_cast<float>(y)),
+      CFX_SizeF(static_cast<float>(xTolerance),
+                static_cast<float>(yTolerance)));
 }
 
-DLLEXPORT int STDCALL FPDFText_GetText(FPDF_TEXTPAGE text_page,
-                                       int start,
-                                       int count,
-                                       unsigned short* result) {
-  if (!text_page)
+FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetText(FPDF_TEXTPAGE page,
+                                               int char_start,
+                                               int char_count,
+                                               unsigned short* result) {
+  if (!page || char_start < 0 || char_count < 0 || !result)
     return 0;
 
-  CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
-  if (start >= textpage->CountChars())
+  CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(page);
+  int char_available = textpage->CountChars() - char_start;
+  if (char_available <= 0)
     return 0;
 
-  CFX_WideString str = textpage->GetPageText(start, count);
-  if (str.GetLength() > count)
-    str = str.Left(count);
+  char_count = std::min(char_count, char_available);
+  if (char_count == 0) {
+    // Writing out "", which has a character count of 1 due to the NUL.
+    *result = '\0';
+    return 1;
+  }
 
-  CFX_ByteString cbUTF16str = str.UTF16LE_Encode();
-  FXSYS_memcpy(result, cbUTF16str.GetBuffer(cbUTF16str.GetLength()),
-               cbUTF16str.GetLength());
-  cbUTF16str.ReleaseBuffer(cbUTF16str.GetLength());
+  WideString str = textpage->GetPageText(char_start, char_count);
 
-  return cbUTF16str.GetLength() / sizeof(unsigned short);
+  if (str.GetLength() > static_cast<size_t>(char_count))
+    str = str.Left(static_cast<size_t>(char_count));
+
+  // UFT16LE_Encode doesn't handle surrogate pairs properly, so it is expected
+  // the number of items to stay the same.
+  ByteString byte_str = str.UTF16LE_Encode();
+  size_t byte_str_len = byte_str.GetLength();
+  int ret_count = byte_str_len / kBytesPerCharacter;
+
+  ASSERT(ret_count <= char_count + 1);  // +1 to account for the NUL terminator.
+  memcpy(result, byte_str.GetBuffer(byte_str_len), byte_str_len);
+  return ret_count;
 }
 
-DLLEXPORT int STDCALL FPDFText_CountRects(FPDF_TEXTPAGE text_page,
-                                          int start,
-                                          int count) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFText_CountRects(FPDF_TEXTPAGE text_page,
+                                                  int start,
+                                                  int count) {
   if (!text_page)
     return 0;
 
@@ -172,47 +207,48 @@
   return textpage->CountRects(start, count);
 }
 
-DLLEXPORT void STDCALL FPDFText_GetRect(FPDF_TEXTPAGE text_page,
-                                        int rect_index,
-                                        double* left,
-                                        double* top,
-                                        double* right,
-                                        double* bottom) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetRect(FPDF_TEXTPAGE text_page,
+                                                     int rect_index,
+                                                     double* left,
+                                                     double* top,
+                                                     double* right,
+                                                     double* bottom) {
   if (!text_page)
-    return;
+    return false;
 
   CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
   CFX_FloatRect rect;
-  textpage->GetRect(rect_index, rect.left, rect.top, rect.right, rect.bottom);
+  bool result = textpage->GetRect(rect_index, &rect);
+
   *left = rect.left;
   *top = rect.top;
   *right = rect.right;
   *bottom = rect.bottom;
+  return result;
 }
 
-DLLEXPORT int STDCALL FPDFText_GetBoundedText(FPDF_TEXTPAGE text_page,
-                                              double left,
-                                              double top,
-                                              double right,
-                                              double bottom,
-                                              unsigned short* buffer,
-                                              int buflen) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetBoundedText(FPDF_TEXTPAGE text_page,
+                                                      double left,
+                                                      double top,
+                                                      double right,
+                                                      double bottom,
+                                                      unsigned short* buffer,
+                                                      int buflen) {
   if (!text_page)
     return 0;
 
   CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
-  CFX_FloatRect rect((FX_FLOAT)left, (FX_FLOAT)bottom, (FX_FLOAT)right,
-                     (FX_FLOAT)top);
-  CFX_WideString str = textpage->GetTextByRect(rect);
+  CFX_FloatRect rect((float)left, (float)bottom, (float)right, (float)top);
+  WideString str = textpage->GetTextByRect(rect);
 
   if (buflen <= 0 || !buffer)
     return str.GetLength();
 
-  CFX_ByteString cbUTF16Str = str.UTF16LE_Encode();
+  ByteString cbUTF16Str = str.UTF16LE_Encode();
   int len = cbUTF16Str.GetLength() / sizeof(unsigned short);
   int size = buflen > len ? len : buflen;
-  FXSYS_memcpy(buffer, cbUTF16Str.GetBuffer(size * sizeof(unsigned short)),
-               size * sizeof(unsigned short));
+  memcpy(buffer, cbUTF16Str.GetBuffer(size * sizeof(unsigned short)),
+         size * sizeof(unsigned short));
   cbUTF16Str.ReleaseBuffer(size * sizeof(unsigned short));
 
   return size;
@@ -220,22 +256,24 @@
 
 // Search
 // -1 for end
-DLLEXPORT FPDF_SCHHANDLE STDCALL FPDFText_FindStart(FPDF_TEXTPAGE text_page,
-                                                    FPDF_WIDESTRING findwhat,
-                                                    unsigned long flags,
-                                                    int start_index) {
+FPDF_EXPORT FPDF_SCHHANDLE FPDF_CALLCONV
+FPDFText_FindStart(FPDF_TEXTPAGE text_page,
+                   FPDF_WIDESTRING findwhat,
+                   unsigned long flags,
+                   int start_index) {
   if (!text_page)
     return nullptr;
 
   CPDF_TextPageFind* textpageFind =
       new CPDF_TextPageFind(CPDFTextPageFromFPDFTextPage(text_page));
-  FX_STRSIZE len = CFX_WideString::WStringLength(findwhat);
-  textpageFind->FindFirst(CFX_WideString::FromUTF16LE(findwhat, len), flags,
-                          start_index);
+  size_t len = WideString::WStringLength(findwhat);
+  textpageFind->FindFirst(
+      WideString::FromUTF16LE(findwhat, len), flags,
+      start_index >= 0 ? Optional<size_t>(start_index) : Optional<size_t>());
   return textpageFind;
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDFText_FindNext(FPDF_SCHHANDLE handle) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindNext(FPDF_SCHHANDLE handle) {
   if (!handle)
     return false;
 
@@ -243,7 +281,7 @@
   return textpageFind->FindNext();
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDFText_FindPrev(FPDF_SCHHANDLE handle) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindPrev(FPDF_SCHHANDLE handle) {
   if (!handle)
     return false;
 
@@ -251,7 +289,8 @@
   return textpageFind->FindPrev();
 }
 
-DLLEXPORT int STDCALL FPDFText_GetSchResultIndex(FPDF_SCHHANDLE handle) {
+FPDF_EXPORT int FPDF_CALLCONV
+FPDFText_GetSchResultIndex(FPDF_SCHHANDLE handle) {
   if (!handle)
     return 0;
 
@@ -259,7 +298,7 @@
   return textpageFind->GetCurOrder();
 }
 
-DLLEXPORT int STDCALL FPDFText_GetSchCount(FPDF_SCHHANDLE handle) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchCount(FPDF_SCHHANDLE handle) {
   if (!handle)
     return 0;
 
@@ -267,7 +306,7 @@
   return textpageFind->GetMatchedCount();
 }
 
-DLLEXPORT void STDCALL FPDFText_FindClose(FPDF_SCHHANDLE handle) {
+FPDF_EXPORT void FPDF_CALLCONV FPDFText_FindClose(FPDF_SCHHANDLE handle) {
   if (!handle)
     return;
 
@@ -277,7 +316,8 @@
 }
 
 // web link
-DLLEXPORT FPDF_PAGELINK STDCALL FPDFLink_LoadWebLinks(FPDF_TEXTPAGE text_page) {
+FPDF_EXPORT FPDF_PAGELINK FPDF_CALLCONV
+FPDFLink_LoadWebLinks(FPDF_TEXTPAGE text_page) {
   if (!text_page)
     return nullptr;
 
@@ -287,7 +327,7 @@
   return pageLink;
 }
 
-DLLEXPORT int STDCALL FPDFLink_CountWebLinks(FPDF_PAGELINK link_page) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountWebLinks(FPDF_PAGELINK link_page) {
   if (!link_page)
     return 0;
 
@@ -295,16 +335,16 @@
   return pdfium::base::checked_cast<int>(pageLink->CountLinks());
 }
 
-DLLEXPORT int STDCALL FPDFLink_GetURL(FPDF_PAGELINK link_page,
-                                      int link_index,
-                                      unsigned short* buffer,
-                                      int buflen) {
-  CFX_WideString wsUrl(L"");
+FPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetURL(FPDF_PAGELINK link_page,
+                                              int link_index,
+                                              unsigned short* buffer,
+                                              int buflen) {
+  WideString wsUrl(L"");
   if (link_page && link_index >= 0) {
     CPDF_LinkExtract* pageLink = CPDFLinkExtractFromFPDFPageLink(link_page);
     wsUrl = pageLink->GetURL(link_index);
   }
-  CFX_ByteString cbUTF16URL = wsUrl.UTF16LE_Encode();
+  ByteString cbUTF16URL = wsUrl.UTF16LE_Encode();
   int required = cbUTF16URL.GetLength() / sizeof(unsigned short);
   if (!buffer || buflen <= 0)
     return required;
@@ -312,13 +352,13 @@
   int size = std::min(required, buflen);
   if (size > 0) {
     int buf_size = size * sizeof(unsigned short);
-    FXSYS_memcpy(buffer, cbUTF16URL.GetBuffer(buf_size), buf_size);
+    memcpy(buffer, cbUTF16URL.GetBuffer(buf_size), buf_size);
   }
   return size;
 }
 
-DLLEXPORT int STDCALL FPDFLink_CountRects(FPDF_PAGELINK link_page,
-                                          int link_index) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountRects(FPDF_PAGELINK link_page,
+                                                  int link_index) {
   if (!link_page || link_index < 0)
     return 0;
 
@@ -326,27 +366,28 @@
   return pdfium::CollectionSize<int>(pageLink->GetRects(link_index));
 }
 
-DLLEXPORT void STDCALL FPDFLink_GetRect(FPDF_PAGELINK link_page,
-                                        int link_index,
-                                        int rect_index,
-                                        double* left,
-                                        double* top,
-                                        double* right,
-                                        double* bottom) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetRect(FPDF_PAGELINK link_page,
+                                                     int link_index,
+                                                     int rect_index,
+                                                     double* left,
+                                                     double* top,
+                                                     double* right,
+                                                     double* bottom) {
   if (!link_page || link_index < 0 || rect_index < 0)
-    return;
+    return false;
 
   CPDF_LinkExtract* pageLink = CPDFLinkExtractFromFPDFPageLink(link_page);
   std::vector<CFX_FloatRect> rectArray = pageLink->GetRects(link_index);
   if (rect_index >= pdfium::CollectionSize<int>(rectArray))
-    return;
+    return false;
 
   *left = rectArray[rect_index].left;
   *right = rectArray[rect_index].right;
   *top = rectArray[rect_index].top;
   *bottom = rectArray[rect_index].bottom;
+  return true;
 }
 
-DLLEXPORT void STDCALL FPDFLink_CloseWebLinks(FPDF_PAGELINK link_page) {
+FPDF_EXPORT void FPDF_CALLCONV FPDFLink_CloseWebLinks(FPDF_PAGELINK link_page) {
   delete CPDFLinkExtractFromFPDFPageLink(link_page);
 }
diff --git a/fpdfsdk/fpdftext_embeddertest.cpp b/fpdfsdk/fpdftext_embeddertest.cpp
index 198ef8a..86d32a7 100644
--- a/fpdfsdk/fpdftext_embeddertest.cpp
+++ b/fpdfsdk/fpdftext_embeddertest.cpp
@@ -4,7 +4,7 @@
 
 #include <memory>
 
-#include "core/fxcrt/fx_basic.h"
+#include "core/fxcrt/fx_memory.h"
 #include "public/fpdf_text.h"
 #include "public/fpdfview.h"
 #include "testing/embedder_test.h"
@@ -16,13 +16,12 @@
 bool check_unsigned_shorts(const char* expected,
                            const unsigned short* actual,
                            size_t length) {
-  if (length > strlen(expected) + 1) {
+  if (length > strlen(expected) + 1)
     return false;
-  }
+
   for (size_t i = 0; i < length; ++i) {
-    if (actual[i] != static_cast<unsigned short>(expected[i])) {
+    if (actual[i] != static_cast<unsigned short>(expected[i]))
       return false;
-    }
   }
   return true;
 }
@@ -43,6 +42,19 @@
   unsigned short fixed_buffer[128];
   memset(fixed_buffer, 0xbd, sizeof(fixed_buffer));
 
+  // Check that edge cases are handled gracefully
+  EXPECT_EQ(0, FPDFText_GetText(textpage, 0, 128, nullptr));
+  EXPECT_EQ(0, FPDFText_GetText(textpage, -1, 128, fixed_buffer));
+  EXPECT_EQ(0, FPDFText_GetText(textpage, 0, -1, fixed_buffer));
+  EXPECT_EQ(1, FPDFText_GetText(textpage, 0, 0, fixed_buffer));
+  EXPECT_EQ(0, fixed_buffer[0]);
+
+  // Keep going and check the next case.
+  memset(fixed_buffer, 0xbd, sizeof(fixed_buffer));
+  EXPECT_EQ(2, FPDFText_GetText(textpage, 0, 1, fixed_buffer));
+  EXPECT_EQ(expected[0], fixed_buffer[0]);
+  EXPECT_EQ(0, fixed_buffer[1]);
+
   // Check includes the terminating NUL that is provided.
   int num_chars = FPDFText_GetText(textpage, 0, 128, fixed_buffer);
   ASSERT_GE(num_chars, 0);
@@ -58,6 +70,16 @@
         << " at " << i;
   }
 
+  // Extracting using a buffer that will be completely filled. Small buffer is
+  // 12 elements long, since it will need 2 locations per displayed character in
+  // the expected string, plus 2 more for the terminating character.
+  static const char small_expected[] = "Hello";
+  unsigned short small_buffer[12];
+  memset(fixed_buffer, 0xbd, sizeof(fixed_buffer));
+  EXPECT_EQ(6, FPDFText_GetText(textpage, 0, 5, small_buffer));
+  EXPECT_TRUE(check_unsigned_shorts(small_expected, small_buffer,
+                                    sizeof(small_expected)));
+
   EXPECT_EQ(12.0, FPDFText_GetFontSize(textpage, 0));
   EXPECT_EQ(16.0, FPDFText_GetFontSize(textpage, 15));
 
@@ -65,12 +87,34 @@
   double right = 0.0;
   double bottom = 0.0;
   double top = 0.0;
-  FPDFText_GetCharBox(textpage, 4, &left, &right, &bottom, &top);
+  EXPECT_FALSE(FPDFText_GetCharBox(nullptr, 4, &left, &right, &bottom, &top));
+  EXPECT_DOUBLE_EQ(0.0, left);
+  EXPECT_DOUBLE_EQ(0.0, right);
+  EXPECT_DOUBLE_EQ(0.0, bottom);
+  EXPECT_DOUBLE_EQ(0.0, top);
+  EXPECT_FALSE(FPDFText_GetCharBox(textpage, -1, &left, &right, &bottom, &top));
+  EXPECT_DOUBLE_EQ(0.0, left);
+  EXPECT_DOUBLE_EQ(0.0, right);
+  EXPECT_DOUBLE_EQ(0.0, bottom);
+  EXPECT_DOUBLE_EQ(0.0, top);
+  EXPECT_FALSE(FPDFText_GetCharBox(textpage, 55, &left, &right, &bottom, &top));
+  EXPECT_DOUBLE_EQ(0.0, left);
+  EXPECT_DOUBLE_EQ(0.0, right);
+  EXPECT_DOUBLE_EQ(0.0, bottom);
+  EXPECT_DOUBLE_EQ(0.0, top);
+
+  EXPECT_TRUE(FPDFText_GetCharBox(textpage, 4, &left, &right, &bottom, &top));
   EXPECT_NEAR(41.071, left, 0.001);
   EXPECT_NEAR(46.243, right, 0.001);
   EXPECT_NEAR(49.844, bottom, 0.001);
   EXPECT_NEAR(55.520, top, 0.001);
 
+  double x = 0.0;
+  double y = 0.0;
+  EXPECT_TRUE(FPDFText_GetCharOrigin(textpage, 4, &x, &y));
+  EXPECT_NEAR(40.664, x, 0.001);
+  EXPECT_NEAR(50.000, y, 0.001);
+
   EXPECT_EQ(4, FPDFText_GetCharIndexAtPos(textpage, 42.0, 50.0, 1.0, 1.0));
   EXPECT_EQ(-1, FPDFText_GetCharIndexAtPos(textpage, 0.0, 0.0, 1.0, 1.0));
   EXPECT_EQ(-1, FPDFText_GetCharIndexAtPos(textpage, 199.0, 199.0, 1.0, 1.0));
@@ -87,7 +131,7 @@
   right = 0.0;
   bottom = 0.0;
   top = 0.0;
-  FPDFText_GetRect(textpage, 1, &left, &top, &right, &bottom);
+  EXPECT_TRUE(FPDFText_GetRect(textpage, 1, &left, &top, &right, &bottom));
   EXPECT_NEAR(20.847, left, 0.001);
   EXPECT_NEAR(135.167, right, 0.001);
   EXPECT_NEAR(96.655, bottom, 0.001);
@@ -98,7 +142,7 @@
   right = -1.0;
   bottom = -1.0;
   top = -1.0;
-  FPDFText_GetRect(textpage, -1, &left, &top, &right, &bottom);
+  EXPECT_FALSE(FPDFText_GetRect(textpage, -1, &left, &top, &right, &bottom));
   EXPECT_EQ(0.0, left);
   EXPECT_EQ(0.0, right);
   EXPECT_EQ(0.0, bottom);
@@ -108,7 +152,7 @@
   right = -2.0;
   bottom = -2.0;
   top = -2.0;
-  FPDFText_GetRect(textpage, 2, &left, &top, &right, &bottom);
+  EXPECT_FALSE(FPDFText_GetRect(textpage, 2, &left, &top, &right, &bottom));
   EXPECT_EQ(0.0, left);
   EXPECT_EQ(0.0, right);
   EXPECT_EQ(0.0, bottom);
@@ -337,7 +381,7 @@
   double right = 0.0;
   double top = 0.0;
   double bottom = 0.0;
-  FPDFLink_GetRect(pagelink, 0, 0, &left, &top, &right, &bottom);
+  EXPECT_TRUE(FPDFLink_GetRect(pagelink, 0, 0, &left, &top, &right, &bottom));
   EXPECT_NEAR(50.791, left, 0.001);
   EXPECT_NEAR(187.963, right, 0.001);
   EXPECT_NEAR(97.624, bottom, 0.001);
@@ -348,7 +392,7 @@
   right = -1.0;
   top = -1.0;
   bottom = -1.0;
-  FPDFLink_GetRect(pagelink, 0, 1, &left, &top, &right, &bottom);
+  EXPECT_FALSE(FPDFLink_GetRect(pagelink, 0, 1, &left, &top, &right, &bottom));
   EXPECT_EQ(-1.0, left);
   EXPECT_EQ(-1.0, right);
   EXPECT_EQ(-1.0, bottom);
@@ -359,7 +403,7 @@
   right = -2.0;
   top = -2.0;
   bottom = -2.0;
-  FPDFLink_GetRect(pagelink, -1, 0, &left, &top, &right, &bottom);
+  EXPECT_FALSE(FPDFLink_GetRect(pagelink, -1, 0, &left, &top, &right, &bottom));
   EXPECT_EQ(-2.0, left);
   EXPECT_EQ(-2.0, right);
   EXPECT_EQ(-2.0, bottom);
@@ -370,6 +414,74 @@
   UnloadPage(page);
 }
 
+TEST_F(FPDFTextEmbeddertest, WebLinksAcrossLines) {
+  EXPECT_TRUE(OpenDocument("weblinks_across_lines.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  EXPECT_TRUE(page);
+
+  FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
+  EXPECT_TRUE(textpage);
+
+  FPDF_PAGELINK pagelink = FPDFLink_LoadWebLinks(textpage);
+  EXPECT_TRUE(pagelink);
+
+  static const char* const kExpectedUrls[] = {
+      "http://example.com",           // from "http://www.example.com?\r\nfoo"
+      "http://example.com/",          // from "http://www.example.com/\r\nfoo"
+      "http://example.com/test-foo",  // from "http://example.com/test-\r\nfoo"
+      "http://abc.com/test-foo",      // from "http://abc.com/test-\r\n\r\nfoo"
+      // Next two links from "http://www.example.com/\r\nhttp://www.abc.com/"
+      "http://example.com/", "http://www.abc.com",
+  };
+  static const int kNumLinks = static_cast<int>(FX_ArraySize(kExpectedUrls));
+
+  EXPECT_EQ(kNumLinks, FPDFLink_CountWebLinks(pagelink));
+
+  unsigned short fixed_buffer[128];
+  for (int i = 0; i < kNumLinks; i++) {
+    const size_t expected_len = strlen(kExpectedUrls[i]) + 1;
+    memset(fixed_buffer, 0, FX_ArraySize(fixed_buffer));
+    EXPECT_EQ(static_cast<int>(expected_len),
+              FPDFLink_GetURL(pagelink, i, nullptr, 0));
+    EXPECT_EQ(
+        static_cast<int>(expected_len),
+        FPDFLink_GetURL(pagelink, i, fixed_buffer, FX_ArraySize(fixed_buffer)));
+    EXPECT_TRUE(
+        check_unsigned_shorts(kExpectedUrls[i], fixed_buffer, expected_len));
+  }
+
+  FPDFLink_CloseWebLinks(pagelink);
+  FPDFText_ClosePage(textpage);
+  UnloadPage(page);
+}
+
+TEST_F(FPDFTextEmbeddertest, WebLinksAcrossLinesBug) {
+  EXPECT_TRUE(OpenDocument("bug_650.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  EXPECT_TRUE(page);
+
+  FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
+  EXPECT_TRUE(textpage);
+
+  FPDF_PAGELINK pagelink = FPDFLink_LoadWebLinks(textpage);
+  EXPECT_TRUE(pagelink);
+
+  EXPECT_EQ(2, FPDFLink_CountWebLinks(pagelink));
+  unsigned short fixed_buffer[128] = {0};
+  static const char kExpectedUrl[] =
+      "http://tutorial45.com/learn-autocad-basics-day-166/";
+  static const int kUrlSize = static_cast<int>(sizeof(kExpectedUrl));
+
+  EXPECT_EQ(kUrlSize, FPDFLink_GetURL(pagelink, 1, nullptr, 0));
+  EXPECT_EQ(kUrlSize, FPDFLink_GetURL(pagelink, 1, fixed_buffer,
+                                      FX_ArraySize(fixed_buffer)));
+  EXPECT_TRUE(check_unsigned_shorts(kExpectedUrl, fixed_buffer, kUrlSize));
+
+  FPDFLink_CloseWebLinks(pagelink);
+  FPDFText_ClosePage(textpage);
+  UnloadPage(page);
+}
+
 TEST_F(FPDFTextEmbeddertest, GetFontSize) {
   EXPECT_TRUE(OpenDocument("hello_world.pdf"));
   FPDF_PAGE page = LoadPage(0);
@@ -405,3 +517,127 @@
   FPDFText_ClosePage(textpage);
   UnloadPage(page);
 }
+
+TEST_F(FPDFTextEmbeddertest, Bug_921) {
+  EXPECT_TRUE(OpenDocument("bug_921.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  EXPECT_TRUE(page);
+
+  FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
+  EXPECT_TRUE(textpage);
+
+  static constexpr unsigned int kData[] = {
+      1095, 1077, 1083, 1086, 1074, 1077, 1095, 1077, 1089, 1082, 1086, 1077,
+      32,   1089, 1090, 1088, 1072, 1076, 1072, 1085, 1080, 1077, 46,   32};
+  static constexpr int kStartIndex = 238;
+
+  ASSERT_EQ(268, FPDFText_CountChars(textpage));
+  for (size_t i = 0; i < FX_ArraySize(kData); ++i)
+    EXPECT_EQ(kData[i], FPDFText_GetUnicode(textpage, kStartIndex + i));
+
+  unsigned short buffer[FX_ArraySize(kData) + 1];
+  memset(buffer, 0xbd, sizeof(buffer));
+  int count =
+      FPDFText_GetText(textpage, kStartIndex, FX_ArraySize(kData), buffer);
+  ASSERT_GT(count, 0);
+  ASSERT_EQ(FX_ArraySize(kData) + 1, static_cast<size_t>(count));
+  for (size_t i = 0; i < FX_ArraySize(kData); ++i)
+    EXPECT_EQ(kData[i], buffer[i]);
+  EXPECT_EQ(0, buffer[FX_ArraySize(kData)]);
+
+  FPDFText_ClosePage(textpage);
+  UnloadPage(page);
+}
+
+TEST_F(FPDFTextEmbeddertest, GetTextWithHyphen) {
+  EXPECT_TRUE(OpenDocument("bug_781804.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  EXPECT_TRUE(page);
+
+  FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
+  EXPECT_TRUE(textpage);
+
+  // Check that soft hyphens are not included
+  // Expecting 'Veritaserum', except there is a \uFFFE where the hyphen was in
+  // the original text. This is a weird thing that Adobe does, which we
+  // replicate.
+  constexpr unsigned short soft_expected[] = {
+      0x0056, 0x0065, 0x0072, 0x0069, 0x0074, 0x0061, 0xfffe,
+      0x0073, 0x0065, 0x0072, 0x0075, 0x006D, 0x0000};
+  {
+    constexpr int count = FX_ArraySize(soft_expected) - 1;
+    unsigned short buffer[FX_ArraySize(soft_expected)];
+    memset(buffer, 0, sizeof(buffer));
+
+    EXPECT_EQ(count + 1, FPDFText_GetText(textpage, 0, count, buffer));
+    for (int i = 0; i < count; i++)
+      EXPECT_EQ(soft_expected[i], buffer[i]);
+  }
+
+  // Check that hard hyphens are included
+  {
+    // There isn't the \0 in the actual doc, but there is a \r\n, so need to
+    // add 1 to get aligned.
+    constexpr size_t offset = FX_ArraySize(soft_expected) + 1;
+    // Expecting 'User-\r\ngenerated', the - is a unicode character, so cannnot
+    // store in a char[].
+    constexpr unsigned short hard_expected[] = {
+        0x0055, 0x0073, 0x0065, 0x0072, 0x2010, 0x000d, 0x000a, 0x0067, 0x0065,
+        0x006e, 0x0065, 0x0072, 0x0061, 0x0074, 0x0065, 0x0064, 0x0000};
+    constexpr int count = FX_ArraySize(hard_expected) - 1;
+    unsigned short buffer[FX_ArraySize(hard_expected)];
+
+    EXPECT_EQ(count + 1, FPDFText_GetText(textpage, offset, count, buffer));
+    for (int i = 0; i < count; i++)
+      EXPECT_EQ(hard_expected[i], buffer[i]);
+  }
+
+  FPDFText_ClosePage(textpage);
+  UnloadPage(page);
+}
+
+TEST_F(FPDFTextEmbeddertest, bug_782596) {
+  // If there is a regression in this test, it will only fail under ASAN
+  EXPECT_TRUE(OpenDocument("bug_782596.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  EXPECT_TRUE(page);
+  FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
+  EXPECT_TRUE(textpage);
+  FPDFText_ClosePage(textpage);
+  UnloadPage(page);
+}
+
+TEST_F(FPDFTextEmbeddertest, ControlCharacters) {
+  EXPECT_TRUE(OpenDocument("control_characters.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  EXPECT_TRUE(page);
+
+  FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page);
+  EXPECT_TRUE(textpage);
+
+  // Should not include the control characters in the output
+  static const char expected[] = "Hello, world!\r\nGoodbye, world!";
+  unsigned short fixed_buffer[128];
+  memset(fixed_buffer, 0xbd, sizeof(fixed_buffer));
+  int num_chars = FPDFText_GetText(textpage, 0, 128, fixed_buffer);
+
+  ASSERT_GE(num_chars, 0);
+  EXPECT_EQ(sizeof(expected), static_cast<size_t>(num_chars));
+  EXPECT_TRUE(check_unsigned_shorts(expected, fixed_buffer, sizeof(expected)));
+
+  // Attempting to get a chunk of text after the control characters
+  static const char expected_substring[] = "Goodbye, world!";
+  // Offset is the length of 'Hello, world!\r\n' + 2 control characters in the
+  // original stream
+  static const int offset = 17;
+  memset(fixed_buffer, 0xbd, sizeof(fixed_buffer));
+  num_chars = FPDFText_GetText(textpage, offset, 128, fixed_buffer);
+
+  ASSERT_GE(num_chars, 0);
+  EXPECT_EQ(sizeof(expected_substring), static_cast<size_t>(num_chars));
+  EXPECT_TRUE(check_unsigned_shorts(expected_substring, fixed_buffer,
+                                    sizeof(expected_substring)));
+
+  FPDFText_ClosePage(textpage);
+  UnloadPage(page);
+}
diff --git a/fpdfsdk/fpdfview.cpp b/fpdfsdk/fpdfview.cpp
index 1e7a651..97fc02a 100644
--- a/fpdfsdk/fpdfview.cpp
+++ b/fpdfsdk/fpdfview.cpp
@@ -8,11 +8,17 @@
 
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "core/fpdfapi/cpdf_modulemgr.h"
 #include "core/fpdfapi/cpdf_pagerendercontext.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_pageobject.h"
+#include "core/fpdfapi/page/cpdf_pathobject.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/fpdf_parser_decode.h"
 #include "core/fpdfapi/render/cpdf_progressiverenderer.h"
@@ -21,18 +27,21 @@
 #include "core/fpdfdoc/cpdf_nametree.h"
 #include "core/fpdfdoc/cpdf_occontext.h"
 #include "core/fpdfdoc/cpdf_viewerpreferences.h"
-#include "core/fxcodec/fx_codec.h"
 #include "core/fxcrt/fx_memory.h"
 #include "core/fxcrt/fx_safe_types.h"
-#include "core/fxge/cfx_fxgedevice.h"
+#include "core/fxcrt/fx_stream.h"
+#include "core/fxge/cfx_defaultrenderdevice.h"
 #include "core/fxge/cfx_gemodule.h"
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 #include "fpdfsdk/cpdfsdk_pageview.h"
 #include "fpdfsdk/fsdk_define.h"
 #include "fpdfsdk/fsdk_pauseadapter.h"
-#include "fpdfsdk/javascript/ijs_runtime.h"
+#include "fxjs/ijs_runtime.h"
+#include "public/fpdf_edit.h"
 #include "public/fpdf_ext.h"
+#include "public/fpdf_formfill.h"
 #include "public/fpdf_progressive.h"
+#include "third_party/base/allocator/partition_allocator/partition_alloc.h"
 #include "third_party/base/numerics/safe_conversions_impl.h"
 #include "third_party/base/ptr_util.h"
 
@@ -40,34 +49,26 @@
 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
 #include "fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h"
-#include "public/fpdf_formfill.h"
-#include "xfa/fxbarcode/BC_Library.h"
+#include "fxbarcode/BC_Library.h"
 #endif  // PDF_ENABLE_XFA
 
-#ifdef PDF_ENABLE_XFA_BMP
-#include "core/fxcodec/codec/ccodec_bmpmodule.h"
-#endif
+#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#include "core/fxge/cfx_windowsrenderdevice.h"
 
-#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"
+// These checks are here because core/ and public/ cannot depend on each other.
+static_assert(WindowsPrintMode::kModeEmf == FPDF_PRINTMODE_EMF,
+              "WindowsPrintMode::kModeEmf value mismatch");
+static_assert(WindowsPrintMode::kModeTextOnly == FPDF_PRINTMODE_TEXTONLY,
+              "WindowsPrintMode::kModeTextOnly value mismatch");
+static_assert(WindowsPrintMode::kModePostScript2 == FPDF_PRINTMODE_POSTSCRIPT2,
+              "WindowsPrintMode::kModePostScript2 value mismatch");
+static_assert(WindowsPrintMode::kModePostScript3 == FPDF_PRINTMODE_POSTSCRIPT3,
+              "WindowsPrintMode::kModePostScript3 value mismatch");
 #endif
 
 namespace {
 
-// Also indicates whether library is currently initialized.
-CCodec_ModuleMgr* g_pCodecModule = nullptr;
+bool g_bLibraryInitialized = false;
 
 void RenderPageImpl(CPDF_PageRenderContext* pContext,
                     CPDF_Page* pPage,
@@ -79,42 +80,39 @@
   if (!pContext->m_pOptions)
     pContext->m_pOptions = pdfium::MakeUnique<CPDF_RenderOptions>();
 
+  uint32_t option_flags = pContext->m_pOptions->GetFlags();
   if (flags & FPDF_LCD_TEXT)
-    pContext->m_pOptions->m_Flags |= RENDER_CLEARTYPE;
+    option_flags |= RENDER_CLEARTYPE;
   else
-    pContext->m_pOptions->m_Flags &= ~RENDER_CLEARTYPE;
+    option_flags &= ~RENDER_CLEARTYPE;
 
   if (flags & FPDF_NO_NATIVETEXT)
-    pContext->m_pOptions->m_Flags |= RENDER_NO_NATIVETEXT;
+    option_flags |= RENDER_NO_NATIVETEXT;
   if (flags & FPDF_RENDER_LIMITEDIMAGECACHE)
-    pContext->m_pOptions->m_Flags |= RENDER_LIMITEDIMAGECACHE;
+    option_flags |= RENDER_LIMITEDIMAGECACHE;
   if (flags & FPDF_RENDER_FORCEHALFTONE)
-    pContext->m_pOptions->m_Flags |= RENDER_FORCE_HALFTONE;
+    option_flags |= RENDER_FORCE_HALFTONE;
 #ifndef PDF_ENABLE_XFA
   if (flags & FPDF_RENDER_NO_SMOOTHTEXT)
-    pContext->m_pOptions->m_Flags |= RENDER_NOTEXTSMOOTH;
+    option_flags |= RENDER_NOTEXTSMOOTH;
   if (flags & FPDF_RENDER_NO_SMOOTHIMAGE)
-    pContext->m_pOptions->m_Flags |= RENDER_NOIMAGESMOOTH;
+    option_flags |= RENDER_NOIMAGESMOOTH;
   if (flags & FPDF_RENDER_NO_SMOOTHPATH)
-    pContext->m_pOptions->m_Flags |= RENDER_NOPATHSMOOTH;
+    option_flags |= RENDER_NOPATHSMOOTH;
 #endif  // PDF_ENABLE_XFA
+  pContext->m_pOptions->SetFlags(option_flags);
 
   // Grayscale output
-  if (flags & FPDF_GRAYSCALE) {
-    pContext->m_pOptions->m_ColorMode = RENDER_COLOR_GRAY;
-    pContext->m_pOptions->m_ForeColor = 0;
-    pContext->m_pOptions->m_BackColor = 0xffffff;
-  }
+  if (flags & FPDF_GRAYSCALE)
+    pContext->m_pOptions->SetColorMode(CPDF_RenderOptions::kGray);
 
   const CPDF_OCContext::UsageType usage =
       (flags & FPDF_PRINTING) ? CPDF_OCContext::Print : CPDF_OCContext::View;
-  pContext->m_pOptions->m_AddFlags = flags >> 8;
-  pContext->m_pOptions->m_pOCContext =
-      pdfium::MakeRetain<CPDF_OCContext>(pPage->m_pDocument, usage);
+  pContext->m_pOptions->SetOCContext(
+      pdfium::MakeRetain<CPDF_OCContext>(pPage->m_pDocument.Get(), usage));
 
   pContext->m_pDevice->SaveState();
   pContext->m_pDevice->SetClip_Rect(clipping_rect);
-
   pContext->m_pContext = pdfium::MakeUnique<CPDF_RenderContext>(pPage);
   pContext->m_pContext->AppendLayer(pPage, &matrix);
 
@@ -135,9 +133,8 @@
 
 class CPDF_CustomAccess final : public IFX_SeekableReadStream {
  public:
-  static CFX_RetainPtr<CPDF_CustomAccess> Create(FPDF_FILEACCESS* pFileAccess) {
-    return CFX_RetainPtr<CPDF_CustomAccess>(new CPDF_CustomAccess(pFileAccess));
-  }
+  template <typename T, typename... Args>
+  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
 
   // IFX_SeekableReadStream
   FX_FILESIZE GetSize() override;
@@ -169,16 +166,16 @@
     return false;
   }
   return !!m_FileAccess.m_GetBlock(m_FileAccess.m_Param, offset,
-                                   reinterpret_cast<uint8_t*>(buffer), size);
+                                   static_cast<uint8_t*>(buffer), size);
 }
 
 #ifdef PDF_ENABLE_XFA
-class CFPDF_FileStream : public IFX_SeekableStream {
+class FPDF_FileHandlerContext : public IFX_SeekableStream {
  public:
-  static CFX_RetainPtr<CFPDF_FileStream> Create(FPDF_FILEHANDLER* pFS) {
-    return CFX_RetainPtr<CFPDF_FileStream>(new CFPDF_FileStream(pFS));
-  }
-  ~CFPDF_FileStream() override;
+  template <typename T, typename... Args>
+  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
+
+  ~FPDF_FileHandlerContext() override;
 
   // IFX_SeekableStream:
   FX_FILESIZE GetSize() override;
@@ -192,39 +189,39 @@
   void SetPosition(FX_FILESIZE pos) { m_nCurPos = pos; }
 
  protected:
-  explicit CFPDF_FileStream(FPDF_FILEHANDLER* pFS);
+  explicit FPDF_FileHandlerContext(FPDF_FILEHANDLER* pFS);
 
   FPDF_FILEHANDLER* m_pFS;
   FX_FILESIZE m_nCurPos;
 };
 
-CFPDF_FileStream::CFPDF_FileStream(FPDF_FILEHANDLER* pFS) {
+FPDF_FileHandlerContext::FPDF_FileHandlerContext(FPDF_FILEHANDLER* pFS) {
   m_pFS = pFS;
   m_nCurPos = 0;
 }
 
-CFPDF_FileStream::~CFPDF_FileStream() {
+FPDF_FileHandlerContext::~FPDF_FileHandlerContext() {
   if (m_pFS && m_pFS->Release)
     m_pFS->Release(m_pFS->clientData);
 }
 
-FX_FILESIZE CFPDF_FileStream::GetSize() {
+FX_FILESIZE FPDF_FileHandlerContext::GetSize() {
   if (m_pFS && m_pFS->GetSize)
     return (FX_FILESIZE)m_pFS->GetSize(m_pFS->clientData);
   return 0;
 }
 
-bool CFPDF_FileStream::IsEOF() {
+bool FPDF_FileHandlerContext::IsEOF() {
   return m_nCurPos >= GetSize();
 }
 
-FX_FILESIZE CFPDF_FileStream::GetPosition() {
+FX_FILESIZE FPDF_FileHandlerContext::GetPosition() {
   return m_nCurPos;
 }
 
-bool CFPDF_FileStream::ReadBlock(void* buffer,
-                                 FX_FILESIZE offset,
-                                 size_t size) {
+bool FPDF_FileHandlerContext::ReadBlock(void* buffer,
+                                        FX_FILESIZE offset,
+                                        size_t size) {
   if (!buffer || !size || !m_pFS->ReadBlock)
     return false;
 
@@ -236,7 +233,7 @@
   return false;
 }
 
-size_t CFPDF_FileStream::ReadBlock(void* buffer, size_t size) {
+size_t FPDF_FileHandlerContext::ReadBlock(void* buffer, size_t size) {
   if (!buffer || !size || !m_pFS->ReadBlock)
     return 0;
 
@@ -245,7 +242,7 @@
     return 0;
   FX_FILESIZE dwAvail = nSize - m_nCurPos;
   if (dwAvail < (FX_FILESIZE)size)
-    size = (size_t)dwAvail;
+    size = static_cast<size_t>(dwAvail);
   if (m_pFS->ReadBlock(m_pFS->clientData, (FPDF_DWORD)m_nCurPos, buffer,
                        (FPDF_DWORD)size) == 0) {
     m_nCurPos += size;
@@ -255,9 +252,9 @@
   return 0;
 }
 
-bool CFPDF_FileStream::WriteBlock(const void* buffer,
-                                  FX_FILESIZE offset,
-                                  size_t size) {
+bool FPDF_FileHandlerContext::WriteBlock(const void* buffer,
+                                         FX_FILESIZE offset,
+                                         size_t size) {
   if (!m_pFS || !m_pFS->WriteBlock)
     return false;
 
@@ -269,7 +266,7 @@
   return false;
 }
 
-bool CFPDF_FileStream::Flush() {
+bool FPDF_FileHandlerContext::Flush() {
   if (!m_pFS || !m_pFS->Flush)
     return true;
 
@@ -277,6 +274,28 @@
 }
 #endif  // PDF_ENABLE_XFA
 
+FPDF_DOCUMENT LoadDocumentImpl(
+    const RetainPtr<IFX_SeekableReadStream>& pFileAccess,
+    FPDF_BYTESTRING password) {
+  if (!pFileAccess) {
+    ProcessParseError(CPDF_Parser::FILE_ERROR);
+    return nullptr;
+  }
+
+  auto pParser = pdfium::MakeUnique<CPDF_Parser>();
+  pParser->SetPassword(password);
+
+  auto pDocument = pdfium::MakeUnique<CPDF_Document>(std::move(pParser));
+  CPDF_Parser::Error error =
+      pDocument->GetParser()->StartParse(pFileAccess, pDocument.get());
+  if (error != CPDF_Parser::SUCCESS) {
+    ProcessParseError(error);
+    return nullptr;
+  }
+  CheckUnSupportError(pDocument.get(), error);
+  return FPDFDocumentFromCPDFDocument(pDocument.release());
+}
+
 }  // namespace
 
 UnderlyingDocumentType* UnderlyingFromFPDFDocument(FPDF_DOCUMENT doc) {
@@ -317,19 +336,101 @@
 #endif  // PDF_ENABLE_XFA
 }
 
+CPDF_PathObject* CPDFPathObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object) {
+  auto* obj = CPDFPageObjectFromFPDFPageObject(page_object);
+  return obj ? obj->AsPath() : nullptr;
+}
+
+CPDF_PageObject* CPDFPageObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object) {
+  return static_cast<CPDF_PageObject*>(page_object);
+}
+
+CPDF_Object* CPDFObjectFromFPDFAttachment(FPDF_ATTACHMENT attachment) {
+  return static_cast<CPDF_Object*>(attachment);
+}
+
+ByteString CFXByteStringFromFPDFWideString(FPDF_WIDESTRING wide_string) {
+  return WideString::FromUTF16LE(wide_string,
+                                 WideString::WStringLength(wide_string))
+      .UTF8Encode();
+}
+
 CFX_DIBitmap* CFXBitmapFromFPDFBitmap(FPDF_BITMAP bitmap) {
   return static_cast<CFX_DIBitmap*>(bitmap);
 }
 
-CFX_RetainPtr<IFX_SeekableReadStream> MakeSeekableReadStream(
+CFX_FloatRect CFXFloatRectFromFSRECTF(const FS_RECTF& rect) {
+  return CFX_FloatRect(rect.left, rect.bottom, rect.right, rect.top);
+}
+
+void FSRECTFFromCFXFloatRect(const CFX_FloatRect& rect, FS_RECTF* out_rect) {
+  out_rect->left = rect.left;
+  out_rect->top = rect.top;
+  out_rect->right = rect.right;
+  out_rect->bottom = rect.bottom;
+}
+
+const FX_PATHPOINT* FXPathPointFromFPDFPathSegment(FPDF_PATHSEGMENT segment) {
+  return static_cast<const FX_PATHPOINT*>(segment);
+}
+
+unsigned long Utf16EncodeMaybeCopyAndReturnLength(const WideString& text,
+                                                  void* buffer,
+                                                  unsigned long buflen) {
+  ByteString encoded_text = text.UTF16LE_Encode();
+  unsigned long len = encoded_text.GetLength();
+  if (buffer && len <= buflen)
+    memcpy(buffer, encoded_text.c_str(), len);
+  return len;
+}
+
+unsigned long DecodeStreamMaybeCopyAndReturnLength(const CPDF_Stream* stream,
+                                                   void* buffer,
+                                                   unsigned long buflen) {
+  ASSERT(stream);
+  uint8_t* data = stream->GetRawData();
+  uint32_t len = stream->GetRawSize();
+  CPDF_Dictionary* dict = stream->GetDict();
+  CPDF_Object* decoder = dict ? dict->GetDirectObjectFor("Filter") : nullptr;
+  if (decoder && (decoder->IsArray() || decoder->IsName())) {
+    // Decode the stream if one or more stream filters are specified.
+    uint8_t* decoded_data = nullptr;
+    uint32_t decoded_len = 0;
+    ByteString dummy_last_decoder;
+    CPDF_Dictionary* dummy_last_param;
+    if (PDF_DataDecode(data, len, dict, dict->GetIntegerFor("DL"), false,
+                       &decoded_data, &decoded_len, &dummy_last_decoder,
+                       &dummy_last_param)) {
+      if (buffer && buflen >= decoded_len)
+        memcpy(buffer, decoded_data, decoded_len);
+
+      // Free the buffer for the decoded data if it was allocated by
+      // PDF_DataDecode(). Note that for images with a single image-specific
+      // filter, |decoded_data| is directly assigned to be |data|, so
+      // |decoded_data| does not need to be freed.
+      if (decoded_data != data)
+        FX_Free(decoded_data);
+
+      return decoded_len;
+    }
+  }
+  // Copy the raw data and return its length if there is no valid filter
+  // specified or if decoding failed.
+  if (buffer && buflen >= len)
+    memcpy(buffer, data, len);
+
+  return len;
+}
+
+RetainPtr<IFX_SeekableReadStream> MakeSeekableReadStream(
     FPDF_FILEACCESS* pFileAccess) {
-  return CPDF_CustomAccess::Create(pFileAccess);
+  return pdfium::MakeRetain<CPDF_CustomAccess>(pFileAccess);
 }
 
 #ifdef PDF_ENABLE_XFA
-CFX_RetainPtr<IFX_SeekableStream> MakeSeekableStream(
+RetainPtr<IFX_SeekableStream> MakeSeekableStream(
     FPDF_FILEHANDLER* pFilehandler) {
-  return CFPDF_FileStream::Create(pFilehandler);
+  return pdfium::MakeRetain<FPDF_FileHandlerContext>(pFilehandler);
 }
 #endif  // PDF_ENABLE_XFA
 
@@ -358,72 +459,46 @@
   }
 }
 
-DLLEXPORT void STDCALL FPDF_InitLibrary() {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary() {
   FPDF_InitLibraryWithConfig(nullptr);
 }
 
-DLLEXPORT void STDCALL
+FPDF_EXPORT void FPDF_CALLCONV
 FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* cfg) {
-  if (g_pCodecModule)
+  if (g_bLibraryInitialized)
     return;
 
-  g_pCodecModule = new CCodec_ModuleMgr();
+  FXMEM_InitializePartitionAlloc();
 
   CFX_GEModule* pModule = CFX_GEModule::Get();
-  pModule->Init(cfg ? cfg->m_pUserFontPaths : nullptr, g_pCodecModule);
+  pModule->Init(cfg ? cfg->m_pUserFontPaths : nullptr);
 
   CPDF_ModuleMgr* pModuleMgr = CPDF_ModuleMgr::Get();
-  pModuleMgr->SetCodecModule(g_pCodecModule);
-  pModuleMgr->InitPageModule();
-  pModuleMgr->LoadEmbeddedGB1CMaps();
-  pModuleMgr->LoadEmbeddedJapan1CMaps();
-  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
+  pModuleMgr->Init();
 
 #ifdef PDF_ENABLE_XFA
-  FXJSE_Initialize();
   BC_Library_Init();
 #endif  // PDF_ENABLE_XFA
   if (cfg && cfg->version >= 2)
     IJS_Runtime::Initialize(cfg->m_v8EmbedderSlot, cfg->m_pIsolate);
+
+  g_bLibraryInitialized = true;
 }
 
-DLLEXPORT void STDCALL FPDF_DestroyLibrary() {
-  if (!g_pCodecModule)
+FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary() {
+  if (!g_bLibraryInitialized)
     return;
 
 #ifdef PDF_ENABLE_XFA
-  BC_Library_Destory();
-  FXJSE_Finalize();
+  BC_Library_Destroy();
 #endif  // PDF_ENABLE_XFA
 
   CPDF_ModuleMgr::Destroy();
   CFX_GEModule::Destroy();
 
-  delete g_pCodecModule;
-  g_pCodecModule = nullptr;
-
   IJS_Runtime::Destroy();
+
+  g_bLibraryInitialized = false;
 }
 
 #ifndef _WIN32
@@ -460,90 +535,78 @@
   SetLastError(err_code);
 }
 
-DLLEXPORT void STDCALL FPDF_SetSandBoxPolicy(FPDF_DWORD policy,
-                                             FPDF_BOOL enable) {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy,
+                                                     FPDF_BOOL enable) {
   return FSDK_SetSandBoxPolicy(policy, enable);
 }
 
 #if defined(_WIN32)
 #if defined(PDFIUM_PRINT_TEXT_WITH_GDI)
-DLLEXPORT void STDCALL
+FPDF_EXPORT void FPDF_CALLCONV
 FPDF_SetTypefaceAccessibleFunc(PDFiumEnsureTypefaceCharactersAccessible func) {
   g_pdfium_typeface_accessible_func = func;
 }
 
-DLLEXPORT void STDCALL FPDF_SetPrintTextWithGDI(FPDF_BOOL use_gdi) {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_SetPrintTextWithGDI(FPDF_BOOL use_gdi) {
   g_pdfium_print_text_with_gdi = !!use_gdi;
 }
 #endif  // PDFIUM_PRINT_TEXT_WITH_GDI
 
-DLLEXPORT FPDF_BOOL STDCALL FPDF_SetPrintPostscriptLevel(int postscript_level) {
-  if (postscript_level != 0 && postscript_level != 2 && postscript_level != 3)
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDF_SetPrintPostscriptLevel(int postscript_level) {
+  return postscript_level != 1 && FPDF_SetPrintMode(postscript_level);
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode) {
+  if (mode < FPDF_PRINTMODE_EMF || mode > FPDF_PRINTMODE_POSTSCRIPT3)
     return FALSE;
-  g_pdfium_print_postscript_level = postscript_level;
+  g_pdfium_print_mode = mode;
   return TRUE;
 }
 #endif  // defined(_WIN32)
 
-DLLEXPORT FPDF_DOCUMENT STDCALL FPDF_LoadDocument(FPDF_STRING file_path,
-                                                  FPDF_BYTESTRING password) {
+FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
+FPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password) {
   // NOTE: the creation of the file needs to be by the embedder on the
   // other side of this API.
-  CFX_RetainPtr<IFX_SeekableReadStream> pFileAccess =
-      IFX_SeekableReadStream::CreateFromFilename((const FX_CHAR*)file_path);
-  if (!pFileAccess)
-    return nullptr;
-
-  auto pParser = pdfium::MakeUnique<CPDF_Parser>();
-  pParser->SetPassword(password);
-
-  auto pDocument = pdfium::MakeUnique<CPDF_Document>(std::move(pParser));
-  CPDF_Parser::Error error =
-      pDocument->GetParser()->StartParse(pFileAccess, pDocument.get());
-  if (error != CPDF_Parser::SUCCESS) {
-    ProcessParseError(error);
-    return nullptr;
-  }
-  return FPDFDocumentFromCPDFDocument(pDocument.release());
+  return LoadDocumentImpl(IFX_SeekableReadStream::CreateFromFilename(file_path),
+                          password);
 }
 
-#ifdef PDF_ENABLE_XFA
-DLLEXPORT FPDF_BOOL STDCALL FPDF_HasXFAField(FPDF_DOCUMENT document,
-                                             int* docType) {
+FPDF_EXPORT int FPDF_CALLCONV FPDF_GetFormType(FPDF_DOCUMENT document) {
   if (!document)
     return false;
 
-  CPDF_Document* pdfDoc =
-      (static_cast<CPDFXFA_Context*>(document))->GetPDFDoc();
-  if (!pdfDoc)
-    return false;
+  const CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+  if (!pDoc)
+    return FORMTYPE_NONE;
 
-  CPDF_Dictionary* pRoot = pdfDoc->GetRoot();
+  const CPDF_Dictionary* pRoot = pDoc->GetRoot();
   if (!pRoot)
-    return false;
+    return FORMTYPE_NONE;
 
   CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm");
   if (!pAcroForm)
-    return false;
+    return FORMTYPE_NONE;
 
   CPDF_Object* pXFA = pAcroForm->GetObjectFor("XFA");
   if (!pXFA)
-    return false;
+    return FORMTYPE_ACRO_FORM;
 
-  bool bDynamicXFA = pRoot->GetBooleanFor("NeedsRendering", false);
-  *docType = bDynamicXFA ? DOCTYPE_DYNAMIC_XFA : DOCTYPE_STATIC_XFA;
-  return true;
+  bool needsRendering = pRoot->GetBooleanFor("NeedsRendering", false);
+  return needsRendering ? FORMTYPE_XFA_FULL : FORMTYPE_XFA_FOREGROUND;
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDF_LoadXFA(FPDF_DOCUMENT document) {
-  return document && (static_cast<CPDFXFA_Context*>(document))->LoadXFADoc();
+#ifdef PDF_ENABLE_XFA
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_LoadXFA(FPDF_DOCUMENT document) {
+  return document && static_cast<CPDFXFA_Context*>(document)->LoadXFADoc();
 }
 #endif  // PDF_ENABLE_XFA
 
 class CMemFile final : public IFX_SeekableReadStream {
  public:
-  static CFX_RetainPtr<CMemFile> Create(uint8_t* pBuf, FX_FILESIZE size) {
-    return CFX_RetainPtr<CMemFile>(new CMemFile(pBuf, size));
+  static RetainPtr<CMemFile> Create(const uint8_t* pBuf, FX_FILESIZE size) {
+    return RetainPtr<CMemFile>(new CMemFile(pBuf, size));
   }
 
   FX_FILESIZE GetSize() override { return m_size; }
@@ -556,56 +619,33 @@
     if (!newPos.IsValid() || newPos.ValueOrDie() > m_size)
       return false;
 
-    FXSYS_memcpy(buffer, m_pBuf + offset, size);
+    memcpy(buffer, m_pBuf + offset, size);
     return true;
   }
 
  private:
-  CMemFile(uint8_t* pBuf, FX_FILESIZE size) : m_pBuf(pBuf), m_size(size) {}
+  CMemFile(const uint8_t* pBuf, FX_FILESIZE size)
+      : m_pBuf(pBuf), m_size(size) {}
 
-  uint8_t* const m_pBuf;
+  const uint8_t* const m_pBuf;
   const FX_FILESIZE m_size;
 };
 
-DLLEXPORT FPDF_DOCUMENT STDCALL FPDF_LoadMemDocument(const void* data_buf,
-                                                     int size,
-                                                     FPDF_BYTESTRING password) {
-  CFX_RetainPtr<CMemFile> pMemFile = CMemFile::Create((uint8_t*)data_buf, size);
-  auto pParser = pdfium::MakeUnique<CPDF_Parser>();
-  pParser->SetPassword(password);
-
-  auto pDocument = pdfium::MakeUnique<CPDF_Document>(std::move(pParser));
-  CPDF_Parser::Error error =
-      pDocument->GetParser()->StartParse(pMemFile, pDocument.get());
-  if (error != CPDF_Parser::SUCCESS) {
-    ProcessParseError(error);
-    return nullptr;
-  }
-  CheckUnSupportError(pDocument.get(), error);
-  return FPDFDocumentFromCPDFDocument(pDocument.release());
+FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
+FPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password) {
+  return LoadDocumentImpl(
+      CMemFile::Create(static_cast<const uint8_t*>(data_buf), size), password);
 }
 
-DLLEXPORT FPDF_DOCUMENT STDCALL
+FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
 FPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess,
                         FPDF_BYTESTRING password) {
-  CFX_RetainPtr<CPDF_CustomAccess> pFile =
-      CPDF_CustomAccess::Create(pFileAccess);
-  auto pParser = pdfium::MakeUnique<CPDF_Parser>();
-  pParser->SetPassword(password);
-
-  auto pDocument = pdfium::MakeUnique<CPDF_Document>(std::move(pParser));
-  CPDF_Parser::Error error =
-      pDocument->GetParser()->StartParse(pFile, pDocument.get());
-  if (error != CPDF_Parser::SUCCESS) {
-    ProcessParseError(error);
-    return nullptr;
-  }
-  CheckUnSupportError(pDocument.get(), error);
-  return FPDFDocumentFromCPDFDocument(pDocument.release());
+  return LoadDocumentImpl(pdfium::MakeRetain<CPDF_CustomAccess>(pFileAccess),
+                          password);
 }
 
-DLLEXPORT FPDF_BOOL STDCALL FPDF_GetFileVersion(FPDF_DOCUMENT doc,
-                                                int* fileVersion) {
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc,
+                                                        int* fileVersion) {
   if (!fileVersion)
     return false;
 
@@ -614,7 +654,7 @@
   if (!pDoc)
     return false;
 
-  CPDF_Parser* pParser = pDoc->GetParser();
+  const CPDF_Parser* pParser = pDoc->GetParser();
   if (!pParser)
     return false;
 
@@ -624,7 +664,8 @@
 
 // jabdelmalek: changed return type from uint32_t to build on Linux (and match
 // header).
-DLLEXPORT unsigned long STDCALL FPDF_GetDocPermissions(FPDF_DOCUMENT document) {
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDF_GetDocPermissions(FPDF_DOCUMENT document) {
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
   // https://bugs.chromium.org/p/pdfium/issues/detail?id=499
   if (!pDoc) {
@@ -638,7 +679,8 @@
   return pDoc->GetUserPermissions();
 }
 
-DLLEXPORT int STDCALL FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document) {
+FPDF_EXPORT int FPDF_CALLCONV
+FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document) {
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
   if (!pDoc || !pDoc->GetParser())
     return -1;
@@ -647,13 +689,13 @@
   return pDict ? pDict->GetIntegerFor("R") : -1;
 }
 
-DLLEXPORT int STDCALL FPDF_GetPageCount(FPDF_DOCUMENT document) {
+FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document) {
   UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document);
   return pDoc ? pDoc->GetPageCount() : 0;
 }
 
-DLLEXPORT FPDF_PAGE STDCALL FPDF_LoadPage(FPDF_DOCUMENT document,
-                                          int page_index) {
+FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document,
+                                                  int page_index) {
   UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document);
   if (!pDoc)
     return nullptr;
@@ -662,7 +704,7 @@
     return nullptr;
 
 #ifdef PDF_ENABLE_XFA
-  return pDoc->GetXFAPage(page_index);
+  return pDoc->GetXFAPage(page_index).Leak();
 #else   // PDF_ENABLE_XFA
   CPDF_Dictionary* pDict = pDoc->GetPage(page_index);
   if (!pDict)
@@ -674,64 +716,258 @@
 #endif  // PDF_ENABLE_XFA
 }
 
-DLLEXPORT double STDCALL FPDF_GetPageWidth(FPDF_PAGE page) {
+FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page) {
   UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
   return pPage ? pPage->GetPageWidth() : 0.0;
 }
 
-DLLEXPORT double STDCALL FPDF_GetPageHeight(FPDF_PAGE page) {
+FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page) {
   UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
   return pPage ? pPage->GetPageHeight() : 0.0;
 }
 
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page,
+                                                            FS_RECTF* rect) {
+  if (!rect)
+    return false;
+
+  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
+  if (!pPage)
+    return false;
+
+  FSRECTFFromCFXFloatRect(pPage->GetPageBBox(), rect);
+  return true;
+}
+
 #if defined(_WIN32)
-DLLEXPORT void STDCALL FPDF_RenderPage(HDC dc,
-                                       FPDF_PAGE page,
-                                       int start_x,
-                                       int start_y,
-                                       int size_x,
-                                       int size_y,
-                                       int rotate,
-                                       int flags) {
+namespace {
+
+const double kEpsilonSize = 0.01f;
+
+void GetScaling(CPDF_Page* pPage,
+                int size_x,
+                int size_y,
+                int rotate,
+                double* scale_x,
+                double* scale_y) {
+  ASSERT(pPage);
+  ASSERT(scale_x);
+  ASSERT(scale_y);
+  double page_width = pPage->GetPageWidth();
+  double page_height = pPage->GetPageHeight();
+  if (page_width < kEpsilonSize || page_height < kEpsilonSize)
+    return;
+
+  if (rotate % 2 == 0) {
+    *scale_x = size_x / page_width;
+    *scale_y = size_y / page_height;
+  } else {
+    *scale_x = size_y / page_width;
+    *scale_y = size_x / page_height;
+  }
+}
+
+FX_RECT GetMaskDimensionsAndOffsets(CPDF_Page* pPage,
+                                    int start_x,
+                                    int start_y,
+                                    int size_x,
+                                    int size_y,
+                                    int rotate,
+                                    const CFX_FloatRect& mask_box) {
+  double scale_x = 0.0f;
+  double scale_y = 0.0f;
+  GetScaling(pPage, size_x, size_y, rotate, &scale_x, &scale_y);
+  if (scale_x < kEpsilonSize || scale_y < kEpsilonSize)
+    return FX_RECT();
+
+  // Compute sizes in page points. Round down to catch the entire bitmap.
+  int start_x_bm = static_cast<int>(mask_box.left * scale_x);
+  int start_y_bm = static_cast<int>(mask_box.bottom * scale_y);
+  int size_x_bm = static_cast<int>(mask_box.right * scale_x + 1.0f) -
+                  static_cast<int>(mask_box.left * scale_x);
+  int size_y_bm = static_cast<int>(mask_box.top * scale_y + 1.0f) -
+                  static_cast<int>(mask_box.bottom * scale_y);
+
+  // Get page rotation
+  int page_rotation = pPage->GetPageRotation();
+
+  // Compute offsets
+  int offset_x = 0;
+  int offset_y = 0;
+  if (size_x > size_y)
+    std::swap(size_x_bm, size_y_bm);
+
+  switch ((rotate + page_rotation) % 4) {
+    case 0:
+      offset_x = start_x_bm + start_x;
+      offset_y = start_y + size_y - size_y_bm - start_y_bm;
+      break;
+    case 1:
+      offset_x = start_y_bm + start_x;
+      offset_y = start_x_bm + start_y;
+      break;
+    case 2:
+      offset_x = start_x + size_x - size_x_bm - start_x_bm;
+      offset_y = start_y_bm + start_y;
+      break;
+    case 3:
+      offset_x = start_x + size_x - size_x_bm - start_y_bm;
+      offset_y = start_y + size_y - size_y_bm - start_x_bm;
+      break;
+  }
+  return FX_RECT(offset_x, offset_y, offset_x + size_x_bm,
+                 offset_y + size_y_bm);
+}
+
+// Get a bitmap of just the mask section defined by |mask_box| from a full page
+// bitmap |pBitmap|.
+RetainPtr<CFX_DIBitmap> GetMaskBitmap(CPDF_Page* pPage,
+                                      int start_x,
+                                      int start_y,
+                                      int size_x,
+                                      int size_y,
+                                      int rotate,
+                                      const RetainPtr<CFX_DIBitmap>& pSrc,
+                                      const CFX_FloatRect& mask_box,
+                                      FX_RECT* bitmap_area) {
+  ASSERT(bitmap_area);
+  *bitmap_area = GetMaskDimensionsAndOffsets(pPage, start_x, start_y, size_x,
+                                             size_y, rotate, mask_box);
+  if (bitmap_area->IsEmpty())
+    return nullptr;
+
+  // Create a new bitmap to transfer part of the page bitmap to.
+  RetainPtr<CFX_DIBitmap> pDst = pdfium::MakeRetain<CFX_DIBitmap>();
+  pDst->Create(bitmap_area->Width(), bitmap_area->Height(), FXDIB_Argb);
+  pDst->Clear(0x00ffffff);
+  pDst->TransferBitmap(0, 0, bitmap_area->Width(), bitmap_area->Height(), pSrc,
+                       bitmap_area->left, bitmap_area->top);
+  return pDst;
+}
+
+void RenderBitmap(CFX_RenderDevice* device,
+                  const RetainPtr<CFX_DIBitmap>& pSrc,
+                  const FX_RECT& mask_area) {
+  int size_x_bm = mask_area.Width();
+  int size_y_bm = mask_area.Height();
+  if (size_x_bm == 0 || size_y_bm == 0)
+    return;
+
+  // Create a new bitmap from the old one
+  RetainPtr<CFX_DIBitmap> pDst = pdfium::MakeRetain<CFX_DIBitmap>();
+  pDst->Create(size_x_bm, size_y_bm, FXDIB_Rgb32);
+  pDst->Clear(0xffffffff);
+  pDst->CompositeBitmap(0, 0, size_x_bm, size_y_bm, pSrc, 0, 0,
+                        FXDIB_BLEND_NORMAL, nullptr, false);
+
+  if (device->GetDeviceCaps(FXDC_DEVICE_CLASS) == FXDC_PRINTER) {
+    device->StretchDIBits(pDst, mask_area.left, mask_area.top, size_x_bm,
+                          size_y_bm);
+  } else {
+    device->SetDIBits(pDst, mask_area.left, mask_area.top);
+  }
+}
+
+}  // namespace
+
+FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPage(HDC dc,
+                                               FPDF_PAGE page,
+                                               int start_x,
+                                               int start_y,
+                                               int size_x,
+                                               int size_y,
+                                               int rotate,
+                                               int flags) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!pPage)
     return;
+  pPage->SetRenderContext(pdfium::MakeUnique<CPDF_PageRenderContext>());
+  CPDF_PageRenderContext* pContext = pPage->GetRenderContext();
 
-  CPDF_PageRenderContext* pContext = new CPDF_PageRenderContext;
-  pPage->SetRenderContext(pdfium::WrapUnique(pContext));
-
-  std::unique_ptr<CFX_DIBitmap> pBitmap;
-  // TODO: This results in unnecessary rasterization of some PDFs due to
-  // HasImageMask() returning true. If any image on the page is a mask, the
-  // entire page gets rasterized and the spool size gets huge.
-  const bool bNewBitmap =
-      pPage->BackgroundAlphaNeeded() || pPage->HasImageMask();
-  if (bNewBitmap) {
-    pBitmap = pdfium::MakeUnique<CFX_DIBitmap>();
+  RetainPtr<CFX_DIBitmap> pBitmap;
+  // Don't render the full page to bitmap for a mask unless there are a lot
+  // of masks. Full page bitmaps result in large spool sizes, so they should
+  // only be used when necessary. For large numbers of masks, rendering each
+  // individually is inefficient and unlikely to significantly improve spool
+  // size. TODO (rbpotter): Find out why this still breaks printing for some
+  // PDFs (see crbug.com/777837).
+  const bool bEnableImageMasks = false;
+  const bool bNewBitmap = pPage->BackgroundAlphaNeeded() ||
+                          (pPage->HasImageMask() && !bEnableImageMasks) ||
+                          pPage->GetMaskBoundingBoxes().size() > 100;
+  const bool bHasMask = pPage->HasImageMask() && !bNewBitmap;
+  if (bNewBitmap || bHasMask) {
+    pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
     pBitmap->Create(size_x, size_y, FXDIB_Argb);
     pBitmap->Clear(0x00ffffff);
-    CFX_FxgeDevice* pDevice = new CFX_FxgeDevice;
+    CFX_DefaultRenderDevice* pDevice = new CFX_DefaultRenderDevice;
     pContext->m_pDevice = pdfium::WrapUnique(pDevice);
-    pDevice->Attach(pBitmap.get(), false, nullptr, false);
+    pDevice->Attach(pBitmap, false, nullptr, false);
+    if (bHasMask) {
+      pContext->m_pOptions = pdfium::MakeUnique<CPDF_RenderOptions>();
+      uint32_t option_flags = pContext->m_pOptions->GetFlags();
+      option_flags |= RENDER_BREAKFORMASKS;
+      pContext->m_pOptions->SetFlags(option_flags);
+    }
   } else {
-    pContext->m_pDevice = pdfium::MakeUnique<CFX_WindowsDevice>(dc);
+    pContext->m_pDevice = pdfium::MakeUnique<CFX_WindowsRenderDevice>(dc);
   }
 
   FPDF_RenderPage_Retail(pContext, page, start_x, start_y, size_x, size_y,
                          rotate, flags, true, nullptr);
 
-  if (bNewBitmap) {
-    CFX_WindowsDevice WinDC(dc);
+  if (bHasMask) {
+    // Finish rendering the page to bitmap and copy the correct segments
+    // of the page to individual image mask bitmaps.
+    const std::vector<CFX_FloatRect>& mask_boxes =
+        pPage->GetMaskBoundingBoxes();
+    std::vector<FX_RECT> bitmap_areas(mask_boxes.size());
+    std::vector<RetainPtr<CFX_DIBitmap>> bitmaps(mask_boxes.size());
+    for (size_t i = 0; i < mask_boxes.size(); i++) {
+      bitmaps[i] =
+          GetMaskBitmap(pPage, start_x, start_y, size_x, size_y, rotate,
+                        pBitmap, mask_boxes[i], &bitmap_areas[i]);
+      pContext->m_pRenderer->Continue(nullptr);
+    }
+
+    // Reset rendering context
+    pPage->SetRenderContext(nullptr);
+
+    // Begin rendering to the printer. Add flag to indicate the renderer should
+    // pause after each image mask.
+    pPage->SetRenderContext(pdfium::MakeUnique<CPDF_PageRenderContext>());
+    pContext = pPage->GetRenderContext();
+    pContext->m_pDevice = pdfium::MakeUnique<CFX_WindowsRenderDevice>(dc);
+    pContext->m_pOptions = pdfium::MakeUnique<CPDF_RenderOptions>();
+
+    uint32_t option_flags = pContext->m_pOptions->GetFlags();
+    option_flags |= RENDER_BREAKFORMASKS;
+    pContext->m_pOptions->SetFlags(option_flags);
+
+    FPDF_RenderPage_Retail(pContext, page, start_x, start_y, size_x, size_y,
+                           rotate, flags, true, nullptr);
+
+    // Render masks
+    for (size_t i = 0; i < mask_boxes.size(); i++) {
+      // Render the bitmap for the mask and free the bitmap.
+      if (bitmaps[i]) {  // will be null if mask has zero area
+        RenderBitmap(pContext->m_pDevice.get(), bitmaps[i], bitmap_areas[i]);
+      }
+      // Render the next portion of page.
+      pContext->m_pRenderer->Continue(nullptr);
+    }
+  } else if (bNewBitmap) {
+    CFX_WindowsRenderDevice WinDC(dc);
     if (WinDC.GetDeviceCaps(FXDC_DEVICE_CLASS) == FXDC_PRINTER) {
-      std::unique_ptr<CFX_DIBitmap> pDst = pdfium::MakeUnique<CFX_DIBitmap>();
+      auto pDst = pdfium::MakeRetain<CFX_DIBitmap>();
       int pitch = pBitmap->GetPitch();
       pDst->Create(size_x, size_y, FXDIB_Rgb32);
-      FXSYS_memset(pDst->GetBuffer(), -1, pitch * size_y);
-      pDst->CompositeBitmap(0, 0, size_x, size_y, pBitmap.get(), 0, 0,
-                            FXDIB_BLEND_NORMAL, nullptr, false, nullptr);
-      WinDC.StretchDIBits(pDst.get(), 0, 0, size_x, size_y);
+      memset(pDst->GetBuffer(), -1, pitch * size_y);
+      pDst->CompositeBitmap(0, 0, size_x, size_y, pBitmap, 0, 0,
+                            FXDIB_BLEND_NORMAL, nullptr, false);
+      WinDC.StretchDIBits(pDst, 0, 0, size_x, size_y);
     } else {
-      WinDC.SetDIBits(pBitmap.get(), 0, 0);
+      WinDC.SetDIBits(pBitmap, 0, 0);
     }
   }
 
@@ -739,14 +975,14 @@
 }
 #endif  // defined(_WIN32)
 
-DLLEXPORT void STDCALL FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,
-                                             FPDF_PAGE page,
-                                             int start_x,
-                                             int start_y,
-                                             int size_x,
-                                             int size_y,
-                                             int rotate,
-                                             int flags) {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,
+                                                     FPDF_PAGE page,
+                                                     int start_x,
+                                                     int start_y,
+                                                     int size_x,
+                                                     int size_y,
+                                                     int rotate,
+                                                     int flags) {
   if (!bitmap)
     return;
 
@@ -756,26 +992,28 @@
 
   CPDF_PageRenderContext* pContext = new CPDF_PageRenderContext;
   pPage->SetRenderContext(pdfium::WrapUnique(pContext));
-  CFX_FxgeDevice* pDevice = new CFX_FxgeDevice;
-  pContext->m_pDevice.reset(pDevice);
-  CFX_DIBitmap* pBitmap = CFXBitmapFromFPDFBitmap(bitmap);
-  pDevice->Attach(pBitmap, !!(flags & FPDF_REVERSE_BYTE_ORDER), nullptr, false);
 
+  CFX_DefaultRenderDevice* pDevice = new CFX_DefaultRenderDevice;
+  pContext->m_pDevice.reset(pDevice);
+
+  RetainPtr<CFX_DIBitmap> pBitmap(CFXBitmapFromFPDFBitmap(bitmap));
+  pDevice->Attach(pBitmap, !!(flags & FPDF_REVERSE_BYTE_ORDER), nullptr, false);
   FPDF_RenderPage_Retail(pContext, page, start_x, start_y, size_x, size_y,
                          rotate, flags, true, nullptr);
 
 #ifdef _SKIA_SUPPORT_PATHS_
-  pDevice->Flush();
+  pDevice->Flush(true);
   pBitmap->UnPreMultiply();
 #endif
   pPage->SetRenderContext(nullptr);
 }
 
-DLLEXPORT void STDCALL FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,
-                                                       FPDF_PAGE page,
-                                                       const FS_MATRIX* matrix,
-                                                       const FS_RECTF* clipping,
-                                                       int flags) {
+FPDF_EXPORT void FPDF_CALLCONV
+FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,
+                                FPDF_PAGE page,
+                                const FS_MATRIX* matrix,
+                                const FS_RECTF* clipping,
+                                int flags) {
   if (!bitmap)
     return;
 
@@ -785,41 +1023,42 @@
 
   CPDF_PageRenderContext* pContext = new CPDF_PageRenderContext;
   pPage->SetRenderContext(pdfium::WrapUnique(pContext));
-  CFX_FxgeDevice* pDevice = new CFX_FxgeDevice;
+
+  CFX_DefaultRenderDevice* pDevice = new CFX_DefaultRenderDevice;
   pContext->m_pDevice.reset(pDevice);
-  CFX_DIBitmap* pBitmap = CFXBitmapFromFPDFBitmap(bitmap);
+
+  RetainPtr<CFX_DIBitmap> pBitmap(CFXBitmapFromFPDFBitmap(bitmap));
   pDevice->Attach(pBitmap, !!(flags & FPDF_REVERSE_BYTE_ORDER), nullptr, false);
 
-  CFX_Matrix transform_matrix = pPage->GetPageMatrix();
+  CFX_FloatRect clipping_rect;
+  if (clipping)
+    clipping_rect = CFXFloatRectFromFSRECTF(*clipping);
+  FX_RECT clip_rect = clipping_rect.ToFxRect();
+
+  CFX_Matrix transform_matrix = pPage->GetDisplayMatrix(
+      0, 0, pPage->GetPageWidth(), pPage->GetPageHeight(), 0);
+
   if (matrix) {
     transform_matrix.Concat(CFX_Matrix(matrix->a, matrix->b, matrix->c,
                                        matrix->d, matrix->e, matrix->f));
   }
-
-  CFX_FloatRect clipping_rect;
-  if (clipping) {
-    clipping_rect.left = clipping->left;
-    clipping_rect.bottom = clipping->bottom;
-    clipping_rect.right = clipping->right;
-    clipping_rect.top = clipping->top;
-  }
-  RenderPageImpl(pContext, pPage, transform_matrix, clipping_rect.ToFxRect(),
-                 flags, true, nullptr);
+  RenderPageImpl(pContext, pPage, transform_matrix, clip_rect, flags, true,
+                 nullptr);
 
   pPage->SetRenderContext(nullptr);
 }
 
 #ifdef _SKIA_SUPPORT_
-DLLEXPORT FPDF_RECORDER STDCALL FPDF_RenderPageSkp(FPDF_PAGE page,
-                                                   int size_x,
-                                                   int size_y) {
+FPDF_EXPORT FPDF_RECORDER FPDF_CALLCONV FPDF_RenderPageSkp(FPDF_PAGE page,
+                                                           int size_x,
+                                                           int size_y) {
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!pPage)
     return nullptr;
 
   CPDF_PageRenderContext* pContext = new CPDF_PageRenderContext;
   pPage->SetRenderContext(pdfium::WrapUnique(pContext));
-  CFX_FxgeDevice* skDevice = new CFX_FxgeDevice;
+  CFX_DefaultRenderDevice* skDevice = new CFX_DefaultRenderDevice;
   FPDF_RECORDER recorder = skDevice->CreateRecorder(size_x, size_y);
   pContext->m_pDevice.reset(skDevice);
   FPDF_RenderPage_Retail(pContext, page, 0, 0, size_x, size_y, 0, 0, true,
@@ -829,12 +1068,13 @@
 }
 #endif
 
-DLLEXPORT void STDCALL FPDF_ClosePage(FPDF_PAGE page) {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page) {
   UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
   if (!page)
     return;
 #ifdef PDF_ENABLE_XFA
-  pPage->Release();
+  // Take it back across the API and throw it away.
+  RetainPtr<CPDFXFA_Page>().Unleak(pPage);
 #else   // PDF_ENABLE_XFA
   CPDFSDK_PageView* pPageView =
       static_cast<CPDFSDK_PageView*>(pPage->GetView());
@@ -861,24 +1101,24 @@
 #endif  // PDF_ENABLE_XFA
 }
 
-DLLEXPORT void STDCALL FPDF_CloseDocument(FPDF_DOCUMENT document) {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document) {
   delete UnderlyingFromFPDFDocument(document);
 }
 
-DLLEXPORT unsigned long STDCALL FPDF_GetLastError() {
+FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError() {
   return GetLastError();
 }
 
-DLLEXPORT void STDCALL FPDF_DeviceToPage(FPDF_PAGE page,
-                                         int start_x,
-                                         int start_y,
-                                         int size_x,
-                                         int size_y,
-                                         int rotate,
-                                         int device_x,
-                                         int device_y,
-                                         double* page_x,
-                                         double* page_y) {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page,
+                                                 int start_x,
+                                                 int start_y,
+                                                 int size_x,
+                                                 int size_y,
+                                                 int rotate,
+                                                 int device_x,
+                                                 int device_y,
+                                                 double* page_x,
+                                                 double* page_y) {
   if (!page || !page_x || !page_y)
     return;
   UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
@@ -888,27 +1128,25 @@
 #else   // PDF_ENABLE_XFA
   CFX_Matrix page2device =
       pPage->GetDisplayMatrix(start_x, start_y, size_x, size_y, rotate);
-  CFX_Matrix device2page;
-  device2page.SetReverse(page2device);
 
-  CFX_PointF pos = device2page.Transform(CFX_PointF(
-      static_cast<FX_FLOAT>(device_x), static_cast<FX_FLOAT>(device_y)));
+  CFX_PointF pos = page2device.GetInverse().Transform(
+      CFX_PointF(static_cast<float>(device_x), static_cast<float>(device_y)));
 
   *page_x = pos.x;
   *page_y = pos.y;
 #endif  // PDF_ENABLE_XFA
 }
 
-DLLEXPORT void STDCALL FPDF_PageToDevice(FPDF_PAGE page,
-                                         int start_x,
-                                         int start_y,
-                                         int size_x,
-                                         int size_y,
-                                         int rotate,
-                                         double page_x,
-                                         double page_y,
-                                         int* device_x,
-                                         int* device_y) {
+FPDF_EXPORT void FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page,
+                                                 int start_x,
+                                                 int start_y,
+                                                 int size_x,
+                                                 int size_y,
+                                                 int rotate,
+                                                 double page_x,
+                                                 double page_y,
+                                                 int* device_x,
+                                                 int* device_y) {
   if (!device_x || !device_y)
     return;
   UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
@@ -921,28 +1159,28 @@
   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)));
+      CFX_PointF(static_cast<float>(page_x), static_cast<float>(page_y)));
 
   *device_x = FXSYS_round(pos.x);
   *device_y = FXSYS_round(pos.y);
 #endif  // PDF_ENABLE_XFA
 }
 
-DLLEXPORT FPDF_BITMAP STDCALL FPDFBitmap_Create(int width,
-                                                int height,
-                                                int alpha) {
-  auto pBitmap = pdfium::MakeUnique<CFX_DIBitmap>();
+FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width,
+                                                        int height,
+                                                        int alpha) {
+  auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
   if (!pBitmap->Create(width, height, alpha ? FXDIB_Argb : FXDIB_Rgb32))
     return nullptr;
 
-  return pBitmap.release();
+  return pBitmap.Leak();
 }
 
-DLLEXPORT FPDF_BITMAP STDCALL FPDFBitmap_CreateEx(int width,
-                                                  int height,
-                                                  int format,
-                                                  void* first_scan,
-                                                  int stride) {
+FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width,
+                                                          int height,
+                                                          int format,
+                                                          void* first_scan,
+                                                          int stride) {
   FXDIB_Format fx_format;
   switch (format) {
     case FPDFBitmap_Gray:
@@ -960,22 +1198,43 @@
     default:
       return nullptr;
   }
-  CFX_DIBitmap* pBitmap = new CFX_DIBitmap;
-  pBitmap->Create(width, height, fx_format, (uint8_t*)first_scan, stride);
-  return pBitmap;
+  auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
+  pBitmap->Create(width, height, fx_format, static_cast<uint8_t*>(first_scan),
+                  stride);
+  return pBitmap.Leak();
 }
 
-DLLEXPORT void STDCALL FPDFBitmap_FillRect(FPDF_BITMAP bitmap,
-                                           int left,
-                                           int top,
-                                           int width,
-                                           int height,
-                                           FPDF_DWORD color) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap) {
+  if (!bitmap)
+    return FPDFBitmap_Unknown;
+
+  FXDIB_Format format = CFXBitmapFromFPDFBitmap(bitmap)->GetFormat();
+  switch (format) {
+    case FXDIB_8bppRgb:
+    case FXDIB_8bppMask:
+      return FPDFBitmap_Gray;
+    case FXDIB_Rgb:
+      return FPDFBitmap_BGR;
+    case FXDIB_Rgb32:
+      return FPDFBitmap_BGRx;
+    case FXDIB_Argb:
+      return FPDFBitmap_BGRA;
+    default:
+      return FPDFBitmap_Unknown;
+  }
+}
+
+FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap,
+                                                   int left,
+                                                   int top,
+                                                   int width,
+                                                   int height,
+                                                   FPDF_DWORD color) {
   if (!bitmap)
     return;
 
-  CFX_FxgeDevice device;
-  CFX_DIBitmap* pBitmap = CFXBitmapFromFPDFBitmap(bitmap);
+  CFX_DefaultRenderDevice device;
+  RetainPtr<CFX_DIBitmap> pBitmap(CFXBitmapFromFPDFBitmap(bitmap));
   device.Attach(pBitmap, false, nullptr, false);
   if (!pBitmap->HasAlpha())
     color |= 0xFF000000;
@@ -983,24 +1242,25 @@
   device.FillRect(&rect, color);
 }
 
-DLLEXPORT void* STDCALL FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap) {
+FPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap) {
   return bitmap ? CFXBitmapFromFPDFBitmap(bitmap)->GetBuffer() : nullptr;
 }
 
-DLLEXPORT int STDCALL FPDFBitmap_GetWidth(FPDF_BITMAP bitmap) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap) {
   return bitmap ? CFXBitmapFromFPDFBitmap(bitmap)->GetWidth() : 0;
 }
 
-DLLEXPORT int STDCALL FPDFBitmap_GetHeight(FPDF_BITMAP bitmap) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap) {
   return bitmap ? CFXBitmapFromFPDFBitmap(bitmap)->GetHeight() : 0;
 }
 
-DLLEXPORT int STDCALL FPDFBitmap_GetStride(FPDF_BITMAP bitmap) {
+FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap) {
   return bitmap ? CFXBitmapFromFPDFBitmap(bitmap)->GetPitch() : 0;
 }
 
-DLLEXPORT void STDCALL FPDFBitmap_Destroy(FPDF_BITMAP bitmap) {
-  delete CFXBitmapFromFPDFBitmap(bitmap);
+FPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap) {
+  RetainPtr<CFX_DIBitmap> destroyer;
+  destroyer.Unleak(CFXBitmapFromFPDFBitmap(bitmap));
 }
 
 void FPDF_RenderPage_Retail(CPDF_PageRenderContext* pContext,
@@ -1023,10 +1283,10 @@
                  flags, bNeedToRestore, pause);
 }
 
-DLLEXPORT int STDCALL FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,
-                                              int page_index,
-                                              double* width,
-                                              double* height) {
+FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,
+                                                      int page_index,
+                                                      double* width,
+                                                      double* height) {
   UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document);
   if (!pDoc)
     return false;
@@ -1035,7 +1295,7 @@
   int count = pDoc->GetPageCount();
   if (page_index < 0 || page_index >= count)
     return false;
-  CPDFXFA_Page* pPage = pDoc->GetXFAPage(page_index);
+  RetainPtr<CPDFXFA_Page> pPage = pDoc->GetXFAPage(page_index);
   if (!pPage)
     return false;
   *width = pPage->GetPageWidth();
@@ -1053,7 +1313,7 @@
   return true;
 }
 
-DLLEXPORT FPDF_BOOL STDCALL
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
 FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document) {
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
   if (!pDoc)
@@ -1062,7 +1322,8 @@
   return viewRef.PrintScaling();
 }
 
-DLLEXPORT int STDCALL FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document) {
+FPDF_EXPORT int FPDF_CALLCONV
+FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document) {
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
   if (!pDoc)
     return 1;
@@ -1070,7 +1331,7 @@
   return viewRef.NumCopies();
 }
 
-DLLEXPORT FPDF_PAGERANGE STDCALL
+FPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV
 FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document) {
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
   if (!pDoc)
@@ -1079,13 +1340,13 @@
   return viewRef.PrintPageRange();
 }
 
-DLLEXPORT FPDF_DUPLEXTYPE STDCALL
+FPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV
 FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document) {
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
   if (!pDoc)
     return DuplexUndefined;
   CPDF_ViewerPreferences viewRef(pDoc);
-  CFX_ByteString duplex = viewRef.Duplex();
+  ByteString duplex = viewRef.Duplex();
   if ("Simplex" == duplex)
     return Simplex;
   if ("DuplexFlipShortEdge" == duplex)
@@ -1095,16 +1356,17 @@
   return DuplexUndefined;
 }
 
-DLLEXPORT unsigned long STDCALL FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,
-                                                       FPDF_BYTESTRING key,
-                                                       char* buffer,
-                                                       unsigned long length) {
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,
+                       FPDF_BYTESTRING key,
+                       char* buffer,
+                       unsigned long length) {
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
   if (!pDoc)
     return 0;
 
   CPDF_ViewerPreferences viewRef(pDoc);
-  CFX_ByteString bsVal;
+  ByteString bsVal;
   if (!viewRef.GenericName(key, &bsVal))
     return 0;
 
@@ -1114,12 +1376,13 @@
   return dwStringLen;
 }
 
-DLLEXPORT FPDF_DWORD STDCALL FPDF_CountNamedDests(FPDF_DOCUMENT document) {
+FPDF_EXPORT FPDF_DWORD FPDF_CALLCONV
+FPDF_CountNamedDests(FPDF_DOCUMENT document) {
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
   if (!pDoc)
     return 0;
 
-  CPDF_Dictionary* pRoot = pDoc->GetRoot();
+  const CPDF_Dictionary* pRoot = pDoc->GetRoot();
   if (!pRoot)
     return 0;
 
@@ -1135,8 +1398,8 @@
   return count.ValueOrDie();
 }
 
-DLLEXPORT FPDF_DEST STDCALL FPDF_GetNamedDestByName(FPDF_DOCUMENT document,
-                                                    FPDF_BYTESTRING name) {
+FPDF_EXPORT FPDF_DEST FPDF_CALLCONV
+FPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name) {
   if (!name || name[0] == 0)
     return nullptr;
 
@@ -1145,34 +1408,29 @@
     return nullptr;
 
   CPDF_NameTree name_tree(pDoc, "Dests");
-  return name_tree.LookupNamedDest(pDoc, name);
+  return name_tree.LookupNamedDest(pDoc, PDF_DecodeText(ByteString(name)));
 }
 
 #ifdef PDF_ENABLE_XFA
-DLLEXPORT FPDF_RESULT STDCALL FPDF_BStr_Init(FPDF_BSTR* str) {
+FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* str) {
   if (!str)
     return -1;
 
-  FXSYS_memset(str, 0, sizeof(FPDF_BSTR));
+  memset(str, 0, sizeof(FPDF_BSTR));
   return 0;
 }
 
-DLLEXPORT FPDF_RESULT STDCALL FPDF_BStr_Set(FPDF_BSTR* str,
-                                            FPDF_LPCSTR bstr,
-                                            int length) {
-  if (!str)
+FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* str,
+                                                    FPDF_LPCSTR bstr,
+                                                    int length) {
+  if (!str || !bstr || !length)
     return -1;
-  if (!bstr || !length)
-    return -1;
+
   if (length == -1)
-    length = FXSYS_strlen(bstr);
+    length = strlen(bstr);
 
   if (length == 0) {
-    if (str->str) {
-      FX_Free(str->str);
-      str->str = nullptr;
-    }
-    str->len = 0;
+    FPDF_BStr_Clear(str);
     return 0;
   }
 
@@ -1182,13 +1440,13 @@
     str->str = FX_Alloc(char, length + 1);
 
   str->str[length] = 0;
-  FXSYS_memcpy(str->str, bstr, length);
+  memcpy(str->str, bstr, length);
   str->len = length;
 
   return 0;
 }
 
-DLLEXPORT FPDF_RESULT STDCALL FPDF_BStr_Clear(FPDF_BSTR* str) {
+FPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* str) {
   if (!str)
     return -1;
 
@@ -1201,10 +1459,10 @@
 }
 #endif  // PDF_ENABLE_XFA
 
-DLLEXPORT FPDF_DEST STDCALL FPDF_GetNamedDest(FPDF_DOCUMENT document,
-                                              int index,
-                                              void* buffer,
-                                              long* buflen) {
+FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document,
+                                                      int index,
+                                                      void* buffer,
+                                                      long* buflen) {
   if (!buffer)
     *buflen = 0;
 
@@ -1215,12 +1473,12 @@
   if (!pDoc)
     return nullptr;
 
-  CPDF_Dictionary* pRoot = pDoc->GetRoot();
+  const CPDF_Dictionary* pRoot = pDoc->GetRoot();
   if (!pRoot)
     return nullptr;
 
   CPDF_Object* pDestObj = nullptr;
-  CFX_ByteString bsName;
+  WideString wsName;
   CPDF_NameTree nameTree(pDoc, "Dests");
   int count = nameTree.GetCount();
   if (index >= count) {
@@ -1235,6 +1493,7 @@
 
     index -= count;
     int i = 0;
+    ByteString bsName;
     for (const auto& it : *pDest) {
       bsName = it.first;
       pDestObj = it.second.get();
@@ -1244,8 +1503,9 @@
         break;
       i++;
     }
+    wsName = PDF_DecodeText(bsName);
   } else {
-    pDestObj = nameTree.LookupValue(index, bsName);
+    pDestObj = nameTree.LookupValueAndName(index, &wsName);
   }
   if (!pDestObj)
     return nullptr;
@@ -1257,8 +1517,7 @@
   if (!pDestObj->IsArray())
     return nullptr;
 
-  CFX_WideString wsName = PDF_DecodeText(bsName);
-  CFX_ByteString utf16Name = wsName.UTF16LE_Encode();
+  ByteString utf16Name = wsName.UTF16LE_Encode();
   int len = utf16Name.GetLength();
   if (!buffer) {
     *buflen = len;
diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c
index 54a3325..53d8776 100644
--- a/fpdfsdk/fpdfview_c_api_test.c
+++ b/fpdfsdk/fpdfview_c_api_test.c
@@ -9,6 +9,9 @@
 
 #include "fpdfsdk/fpdfview_c_api_test.h"
 
+#include "public/fpdf_annot.h"
+#include "public/fpdf_attachment.h"
+#include "public/fpdf_catalog.h"
 #include "public/fpdf_dataavail.h"
 #include "public/fpdf_doc.h"
 #include "public/fpdf_edit.h"
@@ -33,6 +36,56 @@
 
 // Function to call from gtest harness to ensure linker resolution.
 int CheckPDFiumCApi() {
+    // fpdf_annot.h
+    CHK(FPDFAnnot_IsSupportedSubtype);
+    CHK(FPDFPage_CreateAnnot);
+    CHK(FPDFPage_GetAnnotCount);
+    CHK(FPDFPage_GetAnnot);
+    CHK(FPDFPage_GetAnnotIndex);
+    CHK(FPDFPage_CloseAnnot);
+    CHK(FPDFPage_RemoveAnnot);
+    CHK(FPDFAnnot_GetSubtype);
+    CHK(FPDFAnnot_IsObjectSupportedSubtype);
+    CHK(FPDFAnnot_UpdateObject);
+    CHK(FPDFAnnot_AppendObject);
+    CHK(FPDFAnnot_GetObjectCount);
+    CHK(FPDFAnnot_GetObject);
+    CHK(FPDFAnnot_RemoveObject);
+    CHK(FPDFAnnot_SetColor);
+    CHK(FPDFAnnot_GetColor);
+    CHK(FPDFAnnot_HasAttachmentPoints);
+    CHK(FPDFAnnot_SetAttachmentPoints);
+    CHK(FPDFAnnot_GetAttachmentPoints);
+    CHK(FPDFAnnot_SetRect);
+    CHK(FPDFAnnot_GetRect);
+    CHK(FPDFAnnot_HasKey);
+    CHK(FPDFAnnot_GetValueType);
+    CHK(FPDFAnnot_SetStringValue);
+    CHK(FPDFAnnot_GetStringValue);
+    CHK(FPDFAnnot_SetAP);
+    CHK(FPDFAnnot_GetAP);
+    CHK(FPDFAnnot_GetLinkedAnnot);
+    CHK(FPDFAnnot_GetFlags);
+    CHK(FPDFAnnot_SetFlags);
+    CHK(FPDFAnnot_GetFormFieldFlags);
+    CHK(FPDFAnnot_GetFormFieldAtPoint);
+
+    // fpdf_attachment.h
+    CHK(FPDFDoc_GetAttachmentCount);
+    CHK(FPDFDoc_AddAttachment);
+    CHK(FPDFDoc_GetAttachment);
+    CHK(FPDFDoc_DeleteAttachment);
+    CHK(FPDFAttachment_GetName);
+    CHK(FPDFAttachment_HasKey);
+    CHK(FPDFAttachment_GetValueType);
+    CHK(FPDFAttachment_SetStringValue);
+    CHK(FPDFAttachment_GetStringValue);
+    CHK(FPDFAttachment_SetFile);
+    CHK(FPDFAttachment_GetFile);
+
+    // fpdf_catalog.h
+    CHK(FPDFCatalog_IsTagged);
+
     // fpdf_dataavail.h
     CHK(FPDFAvail_Create);
     CHK(FPDFAvail_Destroy);
@@ -56,6 +109,7 @@
     CHK(FPDFAction_GetURIPath);
     CHK(FPDFDest_GetPageIndex);
     CHK(FPDFDest_GetLocationInPage);
+    CHK(FPDFDest_GetView);
     CHK(FPDFLink_GetLinkAtPoint);
     CHK(FPDFLink_GetLinkZOrderAtPoint);
     CHK(FPDFLink_GetDest);
@@ -75,30 +129,53 @@
     CHK(FPDFPage_SetRotation);
     CHK(FPDFPage_InsertObject);
     CHK(FPDFPage_CountObject);
+    CHK(FPDFPage_CountObjects);
     CHK(FPDFPage_GetObject);
     CHK(FPDFPage_HasTransparency);
     CHK(FPDFPage_GenerateContent);
+    CHK(FPDFPageObj_Destroy);
     CHK(FPDFPageObj_HasTransparency);
+    CHK(FPDFPageObj_GetBounds);
+    CHK(FPDFPageObj_GetType);
+    CHK(FPDFPageObj_SetBlendMode);
     CHK(FPDFPageObj_Transform);
     CHK(FPDFPage_TransformAnnots);
-    CHK(FPDFPageObj_NewImgeObj);
+    CHK(FPDFPageObj_NewImageObj);
     CHK(FPDFImageObj_LoadJpegFile);
     CHK(FPDFImageObj_LoadJpegFileInline);
     CHK(FPDFImageObj_SetMatrix);
     CHK(FPDFImageObj_SetBitmap);
+    CHK(FPDFImageObj_GetBitmap);
+    CHK(FPDFImageObj_GetImageDataDecoded);
+    CHK(FPDFImageObj_GetImageDataRaw);
+    CHK(FPDFImageObj_GetImageFilterCount);
+    CHK(FPDFImageObj_GetImageFilter);
+    CHK(FPDFImageObj_GetImageMetadata);
     CHK(FPDFPageObj_CreateNewPath);
     CHK(FPDFPageObj_CreateNewRect);
     CHK(FPDFPath_SetStrokeColor);
+    CHK(FPDFPath_GetStrokeColor);
     CHK(FPDFPath_SetStrokeWidth);
     CHK(FPDFPath_SetFillColor);
+    CHK(FPDFPath_GetFillColor);
+    CHK(FPDFPath_CountSegments);
+    CHK(FPDFPath_GetPathSegment);
+    CHK(FPDFPathSegment_GetPoint);
+    CHK(FPDFPathSegment_GetType);
+    CHK(FPDFPathSegment_GetClose);
     CHK(FPDFPath_MoveTo);
     CHK(FPDFPath_LineTo);
     CHK(FPDFPath_BezierTo);
     CHK(FPDFPath_Close);
     CHK(FPDFPath_SetDrawMode);
+    CHK(FPDFPath_SetLineCap);
+    CHK(FPDFPath_SetLineJoin);
     CHK(FPDFPageObj_NewTextObj);
     CHK(FPDFText_SetText);
-    CHK(FPDFText_LoadType1Font);
+    CHK(FPDFText_SetFillColor);
+    CHK(FPDFText_LoadFont);
+    CHK(FPDFFont_Close);
+    CHK(FPDFPageObj_CreateTextObj);
 
     // fpdf_ext.h
     CHK(FSDK_SetUnSpObjProcessHandler);
@@ -119,6 +196,7 @@
     CHK(FORM_DoDocumentAAction);
     CHK(FORM_DoPageAAction);
     CHK(FORM_OnMouseMove);
+    CHK(FORM_OnFocus);
     CHK(FORM_OnLButtonDown);
     CHK(FORM_OnLButtonUp);
 #ifdef PDF_ENABLE_XFA
@@ -128,16 +206,20 @@
     CHK(FORM_OnKeyDown);
     CHK(FORM_OnKeyUp);
     CHK(FORM_OnChar);
+    CHK(FORM_GetSelectedText);
+    CHK(FORM_ReplaceSelection);
     CHK(FORM_ForceToKillFocus);
     CHK(FPDFPage_HasFormFieldAtPoint);
-    CHK(FPDPage_HasFormFieldAtPoint);  // DEPRECATED. Remove in the future.
     CHK(FPDFPage_FormFieldZOrderAtPoint);
     CHK(FPDF_SetFormFieldHighlightColor);
     CHK(FPDF_SetFormFieldHighlightAlpha);
     CHK(FPDF_RemoveFormFieldHighlight);
     CHK(FPDF_FFLDraw);
+#ifdef _SKIA_SUPPORT_
+    CHK(FPDF_FFLRecord);
+#endif
+    CHK(FPDF_GetFormType);
 #ifdef PDF_ENABLE_XFA
-    CHK(FPDF_HasXFAField);
     CHK(FPDF_LoadXFA);
     CHK(FPDF_Widget_Undo);
     CHK(FPDF_Widget_Redo);
@@ -168,6 +250,7 @@
 
     // fpdf_searchex.h
     CHK(FPDFText_GetCharIndexFromTextIndex);
+    CHK(FPDFText_GetTextIndexFromCharIndex);
 
     // fpdf_structtree.h
     CHK(FPDF_StructTree_GetForPage);
@@ -175,6 +258,9 @@
     CHK(FPDF_StructTree_CountChildren);
     CHK(FPDF_StructTree_GetChildAtIndex);
     CHK(FPDF_StructElement_GetAltText);
+    CHK(FPDF_StructElement_GetMarkedContentID);
+    CHK(FPDF_StructElement_GetType);
+    CHK(FPDF_StructElement_GetTitle);
     CHK(FPDF_StructElement_CountChildren);
     CHK(FPDF_StructElement_GetChildAtIndex);
 
@@ -192,6 +278,7 @@
     CHK(FPDFText_GetUnicode);
     CHK(FPDFText_GetFontSize);
     CHK(FPDFText_GetCharBox);
+    CHK(FPDFText_GetCharOrigin);
     CHK(FPDFText_GetCharIndexAtPos);
     CHK(FPDFText_GetText);
     CHK(FPDFText_CountRects);
@@ -226,6 +313,14 @@
     CHK(FPDF_InitLibraryWithConfig);
     CHK(FPDF_DestroyLibrary);
     CHK(FPDF_SetSandBoxPolicy);
+#if defined(_WIN32)
+#if defined(PDFIUM_PRINT_TEXT_WITH_GDI)
+    CHK(FPDF_SetTypefaceAccessibleFunc);
+    CHK(FPDF_SetPrintTextWithGDI);
+#endif
+    CHK(FPDF_SetPrintPostscriptLevel);
+    CHK(FPDF_SetPrintMode);
+#endif
     CHK(FPDF_LoadDocument);
     CHK(FPDF_LoadMemDocument);
     CHK(FPDF_LoadCustomDocument);
@@ -237,15 +332,23 @@
     CHK(FPDF_LoadPage);
     CHK(FPDF_GetPageWidth);
     CHK(FPDF_GetPageHeight);
+    CHK(FPDF_GetPageBoundingBox);
     CHK(FPDF_GetPageSizeByIndex);
+#ifdef _WIN32
+    CHK(FPDF_RenderPage);
+#endif
     CHK(FPDF_RenderPageBitmap);
     CHK(FPDF_RenderPageBitmapWithMatrix);
+#ifdef _SKIA_SUPPORT_
+    CHK(FPDF_RenderPageSkp);
+#endif
     CHK(FPDF_ClosePage);
     CHK(FPDF_CloseDocument);
     CHK(FPDF_DeviceToPage);
     CHK(FPDF_PageToDevice);
     CHK(FPDFBitmap_Create);
     CHK(FPDFBitmap_CreateEx);
+    CHK(FPDFBitmap_GetFormat);
     CHK(FPDFBitmap_FillRect);
     CHK(FPDFBitmap_GetBuffer);
     CHK(FPDFBitmap_GetWidth);
diff --git a/fpdfsdk/fpdfview_embeddertest.cpp b/fpdfsdk/fpdfview_embeddertest.cpp
index 1d94b72..cca77c9 100644
--- a/fpdfsdk/fpdfview_embeddertest.cpp
+++ b/fpdfsdk/fpdfview_embeddertest.cpp
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <cmath>
 #include <limits>
 #include <string>
 
@@ -9,12 +10,38 @@
 #include "public/fpdfview.h"
 #include "testing/embedder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "testing/utils/path_service.h"
+
+namespace {
+
+class MockDownloadHints : public FX_DOWNLOADHINTS {
+ public:
+  static void SAddSegment(FX_DOWNLOADHINTS* pThis, size_t offset, size_t size) {
+  }
+
+  MockDownloadHints() {
+    FX_DOWNLOADHINTS::version = 1;
+    FX_DOWNLOADHINTS::AddSegment = SAddSegment;
+  }
+
+  ~MockDownloadHints() {}
+};
+
+}  // namespace
 
 TEST(fpdf, CApiTest) {
   EXPECT_TRUE(CheckPDFiumCApi());
 }
 
-class FPDFViewEmbeddertest : public EmbedderTest {};
+class FPDFViewEmbeddertest : public EmbedderTest {
+ protected:
+  void TestRenderPageBitmapWithMatrix(FPDF_PAGE page,
+                                      const int bitmap_width,
+                                      const int bitmap_height,
+                                      const FS_MATRIX& matrix,
+                                      const FS_RECTF& rect,
+                                      const char* expected_md5);
+};
 
 TEST_F(FPDFViewEmbeddertest, Document) {
   EXPECT_TRUE(OpenDocument("about_blank.pdf"));
@@ -29,6 +56,12 @@
   EXPECT_EQ(-1, FPDF_GetSecurityHandlerRevision(document()));
 }
 
+TEST_F(FPDFViewEmbeddertest, LoadNonexistentDocument) {
+  FPDF_DOCUMENT doc = FPDF_LoadDocument("nonexistent_document.pdf", "");
+  ASSERT_FALSE(doc);
+  EXPECT_EQ(static_cast<int>(FPDF_GetLastError()), FPDF_ERR_FILE);
+}
+
 // See bug 465.
 TEST_F(FPDFViewEmbeddertest, EmptyDocument) {
   EXPECT_TRUE(CreateEmptyDocument());
@@ -63,12 +96,28 @@
   EXPECT_EQ(0u, FPDF_CountNamedDests(document()));
 }
 
+TEST_F(FPDFViewEmbeddertest, LinearizedDocument) {
+  EXPECT_TRUE(OpenDocumentLinearized("feature_linearized_loading.pdf"));
+  int version;
+  EXPECT_TRUE(FPDF_GetFileVersion(document(), &version));
+  EXPECT_EQ(16, version);
+}
+
 TEST_F(FPDFViewEmbeddertest, Page) {
   EXPECT_TRUE(OpenDocument("about_blank.pdf"));
   FPDF_PAGE page = LoadPage(0);
   EXPECT_NE(nullptr, page);
+
   EXPECT_EQ(612.0, FPDF_GetPageWidth(page));
   EXPECT_EQ(792.0, FPDF_GetPageHeight(page));
+
+  FS_RECTF rect;
+  EXPECT_TRUE(FPDF_GetPageBoundingBox(page, &rect));
+  EXPECT_EQ(0.0, rect.left);
+  EXPECT_EQ(0.0, rect.bottom);
+  EXPECT_EQ(612.0, rect.right);
+  EXPECT_EQ(792.0, rect.top);
+
   UnloadPage(page);
   EXPECT_EQ(nullptr, LoadPage(1));
 }
@@ -304,6 +353,14 @@
 // reference loop. Cross references will be rebuilt successfully.
 TEST_F(FPDFViewEmbeddertest, CrossRefV4Loop) {
   EXPECT_TRUE(OpenDocument("bug_xrefv4_loop.pdf"));
+  MockDownloadHints hints;
+
+  // Make sure calling FPDFAvail_IsDocAvail() on this file does not infinite
+  // loop either. See bug 875.
+  int ret = PDF_DATA_NOTAVAIL;
+  while (ret == PDF_DATA_NOTAVAIL)
+    ret = FPDFAvail_IsDocAvail(avail_, &hints);
+  EXPECT_EQ(PDF_DATA_AVAIL, ret);
 }
 
 // The test should pass when circular references to ParseIndirectObject will not
@@ -328,53 +385,217 @@
   EXPECT_FALSE(OpenDocument("bug_360.pdf"));
 }
 
-TEST_F(FPDFViewEmbeddertest, FPDF_RenderPageBitmapWithMatrix) {
-  const char kAllBlackMd5sum[] = "5708fc5c4a8bd0abde99c8e8f0390615";
-  const char kTopLeftQuarterBlackMd5sum[] = "24e4d1ec06fa0258af758cfc8b2ad50a";
+void FPDFViewEmbeddertest::TestRenderPageBitmapWithMatrix(
+    FPDF_PAGE page,
+    const int bitmap_width,
+    const int bitmap_height,
+    const FS_MATRIX& matrix,
+    const FS_RECTF& rect,
+    const char* expected_md5) {
+  FPDF_BITMAP bitmap = FPDFBitmap_Create(bitmap_width, bitmap_height, 0);
+  FPDFBitmap_FillRect(bitmap, 0, 0, bitmap_width, bitmap_height, 0xFFFFFFFF);
+  FPDF_RenderPageBitmapWithMatrix(bitmap, page, &matrix, &rect, 0);
+  CompareBitmap(bitmap, bitmap_width, bitmap_height, expected_md5);
+  FPDFBitmap_Destroy(bitmap);
+}
 
-  EXPECT_TRUE(OpenDocument("black.pdf"));
+TEST_F(FPDFViewEmbeddertest, FPDF_RenderPageBitmapWithMatrix) {
+  const char kOriginalMD5[] = "0a90de37f52127619c3dfb642b5fa2fe";
+  const char kClippedMD5[] = "a84cab93c102b9b9290fba3047ba702c";
+  const char kTopLeftQuarterMD5[] = "f11a11137c8834389e31cf555a4a6979";
+  const char kHoriStretchedMD5[] = "48ef9205941ed19691ccfa00d717187e";
+  const char kRotated90ClockwiseMD5[] = "d8da2c7bf77521550d0f2752b9cf3482";
+  const char kRotated180ClockwiseMD5[] = "0113386bb0bd45125bacc6dee78bfe78";
+  const char kRotated270ClockwiseMD5[] = "a287e0f74ce203699cda89f9cc97a240";
+  const char kMirrorHoriMD5[] = "6e8d7a6fde39d8e720fb9e620102918c";
+  const char kMirrorVertMD5[] = "8f3a555ef9c0d5031831ae3715273707";
+  const char kLargerTopLeftQuarterMD5[] = "172a2f4adafbadbe98017b1c025b9e27";
+  const char kLargerMD5[] = "c806145641c3e6fc4e022c7065343749";
+  const char kLargerClippedMD5[] = "091d3b1c7933c8f6945eb2cb41e588e9";
+  const char kLargerRotatedMD5[] = "115f13353ebfc82ddb392d1f0059eb12";
+  const char kLargerRotatedLandscapeMD5[] = "c901239d17d84ac84cb6f2124da71b0d";
+  const char kLargerRotatedDiagonalMD5[] = "3d62417468bdaff0eb14391a0c30a3b1";
+  const char kTileMD5[] = "0a190003c97220bf8877684c8d7e89cf";
+
+  EXPECT_TRUE(OpenDocument("rectangles.pdf"));
   FPDF_PAGE page = LoadPage(0);
   EXPECT_NE(nullptr, page);
-  const int width = static_cast<int>(FPDF_GetPageWidth(page));
-  const int height = static_cast<int>(FPDF_GetPageHeight(page));
-  EXPECT_EQ(612, width);
-  EXPECT_EQ(792, height);
+  const int page_width = static_cast<int>(FPDF_GetPageWidth(page));
+  const int page_height = static_cast<int>(FPDF_GetPageHeight(page));
+  EXPECT_EQ(200, page_width);
+  EXPECT_EQ(300, page_height);
 
   FPDF_BITMAP bitmap = RenderPage(page);
-  CompareBitmap(bitmap, width, height, kAllBlackMd5sum);
+  CompareBitmap(bitmap, page_width, page_height, kOriginalMD5);
   FPDFBitmap_Destroy(bitmap);
 
+  FS_RECTF page_rect{0, 0, page_width, page_height};
+
   // Try rendering with an identity matrix. The output should be the same as
   // the RenderPage() output.
-  FS_MATRIX matrix;
-  matrix.a = 1;
-  matrix.b = 0;
-  matrix.c = 0;
-  matrix.d = 1;
-  matrix.e = 0;
-  matrix.f = 0;
+  FS_MATRIX identity_matrix{1, 0, 0, 1, 0, 0};
+  TestRenderPageBitmapWithMatrix(page, page_width, page_height, identity_matrix,
+                                 page_rect, kOriginalMD5);
 
-  FS_RECTF rect;
-  rect.left = 0;
-  rect.top = 0;
-  rect.right = width;
-  rect.bottom = height;
+  // Again render with an identity matrix but with a smaller clipping rect.
+  FS_RECTF middle_of_page_rect{page_width / 4, page_height / 4,
+                               page_width * 3 / 4, page_height * 3 / 4};
+  TestRenderPageBitmapWithMatrix(page, page_width, page_height, identity_matrix,
+                                 middle_of_page_rect, kClippedMD5);
 
-  bitmap = FPDFBitmap_Create(width, height, 0);
-  FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF);
-  FPDF_RenderPageBitmapWithMatrix(bitmap, page, &matrix, &rect, 0);
-  CompareBitmap(bitmap, width, height, kAllBlackMd5sum);
-  FPDFBitmap_Destroy(bitmap);
+  // Now render again with the image scaled smaller.
+  FS_MATRIX half_scale_matrix{0.5, 0, 0, 0.5, 0, 0};
+  TestRenderPageBitmapWithMatrix(page, page_width, page_height,
+                                 half_scale_matrix, page_rect,
+                                 kTopLeftQuarterMD5);
 
-  // Now render again with the image scaled.
-  matrix.a = 0.5;
-  matrix.d = 0.5;
+  // Now render again with the image scaled larger horizontally (the right half
+  // will be clipped).
+  FS_MATRIX stretch_x_matrix{2, 0, 0, 1, 0, 0};
+  TestRenderPageBitmapWithMatrix(page, page_width, page_height,
+                                 stretch_x_matrix, page_rect,
+                                 kHoriStretchedMD5);
 
-  bitmap = FPDFBitmap_Create(width, height, 0);
-  FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF);
-  FPDF_RenderPageBitmapWithMatrix(bitmap, page, &matrix, &rect, 0);
-  CompareBitmap(bitmap, width, height, kTopLeftQuarterBlackMd5sum);
-  FPDFBitmap_Destroy(bitmap);
+  // Try a 90 degree rotation clockwise but with the same bitmap size, so part
+  // will be clipped.
+  FS_MATRIX rotate_90_matrix{0, 1, -1, 0, page_width, 0};
+  TestRenderPageBitmapWithMatrix(page, page_width, page_height,
+                                 rotate_90_matrix, page_rect,
+                                 kRotated90ClockwiseMD5);
+
+  // 180 degree rotation clockwise.
+  FS_MATRIX rotate_180_matrix{-1, 0, 0, -1, page_width, page_height};
+  TestRenderPageBitmapWithMatrix(page, page_width, page_height,
+                                 rotate_180_matrix, page_rect,
+                                 kRotated180ClockwiseMD5);
+
+  // 270 degree rotation clockwise.
+  FS_MATRIX rotate_270_matrix{0, -1, 1, 0, 0, page_width};
+  TestRenderPageBitmapWithMatrix(page, page_width, page_height,
+                                 rotate_270_matrix, page_rect,
+                                 kRotated270ClockwiseMD5);
+
+  // Mirror horizontally.
+  FS_MATRIX mirror_hori_matrix{-1, 0, 0, 1, page_width, 0};
+  TestRenderPageBitmapWithMatrix(page, page_width, page_height,
+                                 mirror_hori_matrix, page_rect, kMirrorHoriMD5);
+
+  // Mirror vertically.
+  FS_MATRIX mirror_vert_matrix{1, 0, 0, -1, 0, page_height};
+  TestRenderPageBitmapWithMatrix(page, page_width, page_height,
+                                 mirror_vert_matrix, page_rect, kMirrorVertMD5);
+
+  // Tests rendering to a larger bitmap
+  const int bitmap_width = page_width * 2;
+  const int bitmap_height = page_height * 2;
+
+  // Render using an identity matrix and the whole bitmap area as clipping rect.
+  FS_RECTF bitmap_rect{0, 0, bitmap_width, bitmap_height};
+  TestRenderPageBitmapWithMatrix(page, bitmap_width, bitmap_height,
+                                 identity_matrix, bitmap_rect,
+                                 kLargerTopLeftQuarterMD5);
+
+  // Render using a scaling matrix to fill the larger bitmap.
+  FS_MATRIX double_scale_matrix{2, 0, 0, 2, 0, 0};
+  TestRenderPageBitmapWithMatrix(page, bitmap_width, bitmap_height,
+                                 double_scale_matrix, bitmap_rect, kLargerMD5);
+
+  // Render the larger image again but with clipping.
+  FS_RECTF middle_of_bitmap_rect{bitmap_width / 4, bitmap_height / 4,
+                                 bitmap_width * 3 / 4, bitmap_height * 3 / 4};
+  TestRenderPageBitmapWithMatrix(page, bitmap_width, bitmap_height,
+                                 double_scale_matrix, middle_of_bitmap_rect,
+                                 kLargerClippedMD5);
+
+  // On the larger bitmap, try a 90 degree rotation but with the same bitmap
+  // size, so part will be clipped.
+  FS_MATRIX rotate_90_scale_2_matrix{0, 2, -2, 0, bitmap_width, 0};
+  TestRenderPageBitmapWithMatrix(page, bitmap_width, bitmap_height,
+                                 rotate_90_scale_2_matrix, bitmap_rect,
+                                 kLargerRotatedMD5);
+
+  // On the larger bitmap, apply 90 degree rotation to a bitmap with the
+  // appropriate dimensions.
+  const int landscape_bitmap_width = bitmap_height;
+  const int landscape_bitmap_height = bitmap_width;
+  FS_RECTF landscape_bitmap_rect{0, 0, landscape_bitmap_width,
+                                 landscape_bitmap_height};
+  FS_MATRIX landscape_rotate_90_scale_2_matrix{
+      0, 2, -2, 0, landscape_bitmap_width, 0};
+  TestRenderPageBitmapWithMatrix(
+      page, landscape_bitmap_width, landscape_bitmap_height,
+      landscape_rotate_90_scale_2_matrix, landscape_bitmap_rect,
+      kLargerRotatedLandscapeMD5);
+
+  // On the larger bitmap, apply 45 degree rotation to a bitmap with the
+  // appropriate dimensions.
+  const float sqrt2 = 1.41421356f;
+  const int diagonal_bitmap_size = ceil((bitmap_width + bitmap_height) / sqrt2);
+  FS_RECTF diagonal_bitmap_rect{0, 0, diagonal_bitmap_size,
+                                diagonal_bitmap_size};
+  FS_MATRIX rotate_45_scale_2_matrix{
+      sqrt2, sqrt2, -sqrt2, sqrt2, bitmap_height / sqrt2, 0};
+  TestRenderPageBitmapWithMatrix(page, diagonal_bitmap_size,
+                                 diagonal_bitmap_size, rotate_45_scale_2_matrix,
+                                 diagonal_bitmap_rect,
+                                 kLargerRotatedDiagonalMD5);
+
+  // Render the (2, 1) tile of the page (third column, second row) when the page
+  // is divided in 50x50 pixel tiles. The tile is scaled by a factor of 7.
+  const float scale = 7.0;
+  const int tile_size = 50;
+  const int tile_x = 2;
+  const int tile_y = 1;
+  int tile_bitmap_size = scale * tile_size;
+  FS_RECTF tile_bitmap_rect{0, 0, tile_bitmap_size, tile_bitmap_size};
+  FS_MATRIX tile_2_1_matrix{scale,
+                            0,
+                            0,
+                            scale,
+                            -tile_x * tile_bitmap_size,
+                            -tile_y * tile_bitmap_size};
+  TestRenderPageBitmapWithMatrix(page, tile_bitmap_size, tile_bitmap_size,
+                                 tile_2_1_matrix, tile_bitmap_rect, kTileMD5);
 
   UnloadPage(page);
 }
+
+class UnSupRecordDelegate : public EmbedderTest::Delegate {
+ public:
+  UnSupRecordDelegate() : type_(-1) {}
+  ~UnSupRecordDelegate() override {}
+
+  void UnsupportedHandler(int type) override { type_ = type; }
+
+  int type_;
+};
+
+TEST_F(FPDFViewEmbeddertest, UnSupportedOperations_NotFound) {
+  UnSupRecordDelegate delegate;
+  SetDelegate(&delegate);
+  ASSERT_TRUE(OpenDocument("hello_world.pdf"));
+  EXPECT_EQ(delegate.type_, -1);
+  SetDelegate(nullptr);
+}
+
+TEST_F(FPDFViewEmbeddertest, UnSupportedOperations_LoadCustomDocument) {
+  UnSupRecordDelegate delegate;
+  SetDelegate(&delegate);
+  ASSERT_TRUE(OpenDocument("unsupported_feature.pdf"));
+  EXPECT_EQ(FPDF_UNSP_DOC_PORTABLECOLLECTION, delegate.type_);
+  SetDelegate(nullptr);
+}
+
+TEST_F(FPDFViewEmbeddertest, UnSupportedOperations_LoadDocument) {
+  std::string file_path;
+  ASSERT_TRUE(
+      PathService::GetTestFilePath("unsupported_feature.pdf", &file_path));
+
+  UnSupRecordDelegate delegate;
+  SetDelegate(&delegate);
+  FPDF_DOCUMENT doc = FPDF_LoadDocument(file_path.c_str(), "");
+  EXPECT_TRUE(doc != nullptr);
+  EXPECT_EQ(FPDF_UNSP_DOC_PORTABLECOLLECTION, delegate.type_);
+  FPDF_CloseDocument(doc);
+  SetDelegate(nullptr);
+}
diff --git a/fpdfsdk/fpdfview_unittest.cpp b/fpdfsdk/fpdfview_unittest.cpp
deleted file mode 100644
index 27680b3..0000000
--- a/fpdfsdk/fpdfview_unittest.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2016 PDFium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "public/fpdfview.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/test_support.h"
-
-TEST(FPDFView, DoubleInit) {
-  FPDF_InitLibrary();
-  FPDF_InitLibrary();
-  FPDF_DestroyLibrary();
-}
-
-TEST(FPDFView, DoubleDestroy) {
-  FPDF_InitLibrary();
-  FPDF_DestroyLibrary();
-  FPDF_DestroyLibrary();
-}
diff --git a/fpdfsdk/fpdfxfa/DEPS b/fpdfsdk/fpdfxfa/DEPS
index 1687e30..5ba75f2 100644
--- a/fpdfsdk/fpdfxfa/DEPS
+++ b/fpdfsdk/fpdfxfa/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   '+fxjs',
-  '+xfa/fxbarcode',
+  '+fxbarcode',
+  '+xfa/fgas/font',
 ]
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_context.cpp b/fpdfsdk/fpdfxfa/cpdfxfa_context.cpp
index 88c88a1..d05e2f6 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_context.cpp
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_context.cpp
@@ -6,6 +6,7 @@
 
 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "core/fpdfapi/parser/cpdf_document.h"
@@ -15,18 +16,19 @@
 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
 #include "fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h"
 #include "fpdfsdk/fsdk_define.h"
-#include "fpdfsdk/javascript/cjs_runtime.h"
-#include "fpdfsdk/javascript/ijs_runtime.h"
+#include "fxjs/cjs_runtime.h"
+#include "fxjs/ijs_runtime.h"
 #include "public/fpdf_formfill.h"
 #include "third_party/base/ptr_util.h"
 #include "third_party/base/stl_util.h"
+#include "xfa/fgas/font/cfgas_defaultfontmanager.h"
 #include "xfa/fxfa/cxfa_eventparam.h"
-#include "xfa/fxfa/xfa_ffapp.h"
-#include "xfa/fxfa/xfa_ffdoc.h"
-#include "xfa/fxfa/xfa_ffdocview.h"
-#include "xfa/fxfa/xfa_ffpageview.h"
-#include "xfa/fxfa/xfa_ffwidgethandler.h"
-#include "xfa/fxfa/xfa_fontmgr.h"
+#include "xfa/fxfa/cxfa_ffapp.h"
+#include "xfa/fxfa/cxfa_ffdoc.h"
+#include "xfa/fxfa/cxfa_ffdocview.h"
+#include "xfa/fxfa/cxfa_ffpageview.h"
+#include "xfa/fxfa/cxfa_ffwidgethandler.h"
+#include "xfa/fxfa/cxfa_fontmgr.h"
 
 #ifndef _WIN32
 extern void SetLastError(int err);
@@ -34,15 +36,10 @@
 #endif
 
 CPDFXFA_Context::CPDFXFA_Context(std::unique_ptr<CPDF_Document> pPDFDoc)
-    : m_iDocType(DOCTYPE_PDF),
-      m_pPDFDoc(std::move(pPDFDoc)),
-      m_pFormFillEnv(nullptr),
-      m_pXFADocView(nullptr),
-      m_nLoadStatus(FXFA_LOADSTATUS_PRELOAD),
-      m_nPageCount(0),
+    : m_pPDFDoc(std::move(pPDFDoc)),
+      m_pXFAApp(pdfium::MakeUnique<CXFA_FFApp>(this)),
       m_DocEnv(this) {
-  m_pXFAApp = pdfium::MakeUnique<CXFA_FFApp>(this);
-  m_pXFAApp->SetDefaultFontMgr(pdfium::MakeUnique<CXFA_DefFontMgr>());
+  m_pXFAApp->SetDefaultFontMgr(pdfium::MakeUnique<CFGAS_DefaultFontManager>());
 }
 
 CPDFXFA_Context::~CPDFXFA_Context() {
@@ -56,7 +53,7 @@
     // Once we're deleted the FormFillEnvironment will point at a bad underlying
     // doc so we need to reset it ...
     m_pFormFillEnv->ResetXFADocument();
-    m_pFormFillEnv = nullptr;
+    m_pFormFillEnv.Reset();
   }
 
   m_nLoadStatus = FXFA_LOADSTATUS_CLOSED;
@@ -65,9 +62,10 @@
 void CPDFXFA_Context::CloseXFADoc() {
   if (!m_pXFADoc)
     return;
+
+  m_pXFADocView = nullptr;
   m_pXFADoc->CloseDoc();
   m_pXFADoc.reset();
-  m_pXFADocView = nullptr;
 }
 
 void CPDFXFA_Context::SetFormFillEnv(
@@ -78,7 +76,7 @@
   if (m_pXFADoc && m_pXFADoc->GetXFADoc())
     m_pXFADoc->GetXFADoc()->ClearLayoutData();
 
-  m_pFormFillEnv = pFormFillEnv;
+  m_pFormFillEnv.Reset(pFormFillEnv);
 }
 
 bool CPDFXFA_Context::LoadXFADoc() {
@@ -98,14 +96,8 @@
     return false;
   }
 
-  CXFA_FFDocHandler* pDocHandler = pApp->GetDocHandler();
-  if (!pDocHandler) {
-    SetLastError(FPDF_ERR_XFALOAD);
-    return false;
-  }
-
   m_pXFADoc->StartLoad();
-  int iStatus = m_pXFADoc->DoLoad(nullptr);
+  int iStatus = m_pXFADoc->DoLoad();
   if (iStatus != XFA_PARSESTATUS_Done) {
     CloseXFADoc();
     SetLastError(FPDF_ERR_XFALOAD);
@@ -114,19 +106,19 @@
   m_pXFADoc->StopLoad();
   m_pXFADoc->GetXFADoc()->InitScriptContext(GetJSERuntime());
 
-  if (m_pXFADoc->GetDocType() == XFA_DOCTYPE_Dynamic)
-    m_iDocType = DOCTYPE_DYNAMIC_XFA;
+  if (m_pXFADoc->GetFormType() == FormType::kXFAFull)
+    m_FormType = FormType::kXFAFull;
   else
-    m_iDocType = DOCTYPE_STATIC_XFA;
+    m_FormType = FormType::kXFAForeground;
 
-  m_pXFADocView = m_pXFADoc->CreateDocView(XFA_DOCVIEW_View);
+  m_pXFADocView = m_pXFADoc->CreateDocView();
   if (m_pXFADocView->StartLayout() < 0) {
     CloseXFADoc();
     SetLastError(FPDF_ERR_XFALAYOUT);
     return false;
   }
 
-  m_pXFADocView->DoLayout(nullptr);
+  m_pXFADocView->DoLayout();
   m_pXFADocView->StopLayout();
   m_nLoadStatus = FXFA_LOADSTATUS_LOADED;
 
@@ -137,59 +129,53 @@
   if (!m_pPDFDoc && !m_pXFADoc)
     return 0;
 
-  switch (m_iDocType) {
-    case DOCTYPE_PDF:
-    case DOCTYPE_STATIC_XFA:
+  switch (m_FormType) {
+    case FormType::kNone:
+    case FormType::kAcroForm:
+    case FormType::kXFAForeground:
       if (m_pPDFDoc)
         return m_pPDFDoc->GetPageCount();
-    case DOCTYPE_DYNAMIC_XFA:
+    case FormType::kXFAFull:
       if (m_pXFADoc)
         return m_pXFADocView->CountPageViews();
-    default:
-      return 0;
   }
+  return 0;
 }
 
-CPDFXFA_Page* CPDFXFA_Context::GetXFAPage(int page_index) {
+RetainPtr<CPDFXFA_Page> CPDFXFA_Context::GetXFAPage(int page_index) {
   if (page_index < 0)
     return nullptr;
 
-  CPDFXFA_Page* pPage = nullptr;
-  int nCount = pdfium::CollectionSize<int>(m_XFAPageList);
-  if (nCount > 0 && page_index < nCount) {
-    pPage = m_XFAPageList[page_index];
-    if (pPage) {
-      pPage->Retain();
-      return pPage;
-    }
+  if (pdfium::IndexInBounds(m_XFAPageList, page_index)) {
+    if (m_XFAPageList[page_index])
+      return m_XFAPageList[page_index];
   } else {
     m_nPageCount = GetPageCount();
     m_XFAPageList.resize(m_nPageCount);
   }
 
-  pPage = new CPDFXFA_Page(this, page_index);
-  if (!pPage->LoadPage()) {
-    pPage->Release();
+  auto pPage = pdfium::MakeRetain<CPDFXFA_Page>(this, page_index);
+  if (!pPage->LoadPage())
     return nullptr;
-  }
-  if (page_index >= 0 &&
-      page_index < pdfium::CollectionSize<int>(m_XFAPageList)) {
+
+  if (pdfium::IndexInBounds(m_XFAPageList, page_index))
     m_XFAPageList[page_index] = pPage;
-  }
+
   return pPage;
 }
 
-CPDFXFA_Page* CPDFXFA_Context::GetXFAPage(CXFA_FFPageView* pPage) const {
+RetainPtr<CPDFXFA_Page> CPDFXFA_Context::GetXFAPage(
+    CXFA_FFPageView* pPage) const {
   if (!pPage)
     return nullptr;
 
   if (!m_pXFADoc)
     return nullptr;
 
-  if (m_iDocType != DOCTYPE_DYNAMIC_XFA)
+  if (m_FormType != FormType::kXFAFull)
     return nullptr;
 
-  for (CPDFXFA_Page* pTempPage : m_XFAPageList) {
+  for (auto& pTempPage : m_XFAPageList) {
     if (pTempPage && pTempPage->GetXFAPageView() == pPage)
       return pTempPage;
   }
@@ -203,20 +189,8 @@
   if (m_pPDFDoc)
     m_pPDFDoc->DeletePage(page_index);
 
-  if (page_index < 0 ||
-      page_index >= pdfium::CollectionSize<int>(m_XFAPageList)) {
-    return;
-  }
-  if (CPDFXFA_Page* pPage = m_XFAPageList[page_index])
-    pPage->Release();
-}
-
-void CPDFXFA_Context::RemovePage(CPDFXFA_Page* page) {
-  int page_index = page->GetPageIndex();
-  if (page_index >= 0 &&
-      page_index < pdfium::CollectionSize<int>(m_XFAPageList)) {
-    m_XFAPageList[page_index] = nullptr;
-  }
+  if (pdfium::IndexInBounds(m_XFAPageList, page_index))
+    m_XFAPageList[page_index].Reset();
 }
 
 void CPDFXFA_Context::ClearChangeMark() {
@@ -234,19 +208,19 @@
   return runtime->GetIsolate();
 }
 
-CFX_WideString CPDFXFA_Context::GetAppTitle() const {
+WideString CPDFXFA_Context::GetAppTitle() const {
   return L"PDFium";
 }
 
-CFX_WideString CPDFXFA_Context::GetAppName() {
+WideString CPDFXFA_Context::GetAppName() {
   return m_pFormFillEnv ? m_pFormFillEnv->FFI_GetAppName() : L"";
 }
 
-CFX_WideString CPDFXFA_Context::GetLanguage() {
+WideString CPDFXFA_Context::GetLanguage() {
   return m_pFormFillEnv ? m_pFormFillEnv->GetLanguage() : L"";
 }
 
-CFX_WideString CPDFXFA_Context::GetPlatform() {
+WideString CPDFXFA_Context::GetPlatform() {
   return m_pFormFillEnv ? m_pFormFillEnv->GetPlatform() : L"";
 }
 
@@ -255,8 +229,8 @@
     m_pFormFillEnv->JS_appBeep(dwType);
 }
 
-int32_t CPDFXFA_Context::MsgBox(const CFX_WideString& wsMessage,
-                                const CFX_WideString& wsTitle,
+int32_t CPDFXFA_Context::MsgBox(const WideString& wsMessage,
+                                const WideString& wsTitle,
                                 uint32_t dwIconType,
                                 uint32_t dwButtonType) {
   if (!m_pFormFillEnv)
@@ -307,43 +281,40 @@
   return XFA_IDYes;
 }
 
-CFX_WideString CPDFXFA_Context::Response(const CFX_WideString& wsQuestion,
-                                         const CFX_WideString& wsTitle,
-                                         const CFX_WideString& wsDefaultAnswer,
-                                         bool bMark) {
-  CFX_WideString wsAnswer;
+WideString CPDFXFA_Context::Response(const WideString& wsQuestion,
+                                     const WideString& wsTitle,
+                                     const WideString& wsDefaultAnswer,
+                                     bool bMark) {
   if (!m_pFormFillEnv)
-    return wsAnswer;
+    return WideString();
 
   int nLength = 2048;
-  char* pBuff = new char[nLength];
+  std::vector<uint8_t> pBuff(nLength);
   nLength = m_pFormFillEnv->JS_appResponse(wsQuestion.c_str(), wsTitle.c_str(),
                                            wsDefaultAnswer.c_str(), nullptr,
-                                           bMark, pBuff, nLength);
-  if (nLength > 0) {
-    nLength = nLength > 2046 ? 2046 : nLength;
-    pBuff[nLength] = 0;
-    pBuff[nLength + 1] = 0;
-    wsAnswer = CFX_WideString::FromUTF16LE(
-        reinterpret_cast<const unsigned short*>(pBuff),
-        nLength / sizeof(unsigned short));
-  }
-  delete[] pBuff;
-  return wsAnswer;
+                                           bMark, pBuff.data(), nLength);
+  if (nLength <= 0)
+    return WideString();
+
+  nLength = std::min(2046, nLength);
+  pBuff[nLength] = 0;
+  pBuff[nLength + 1] = 0;
+  return WideString::FromUTF16LE(reinterpret_cast<uint16_t*>(pBuff.data()),
+                                 nLength / sizeof(uint16_t));
 }
 
-CFX_RetainPtr<IFX_SeekableReadStream> CPDFXFA_Context::DownloadURL(
-    const CFX_WideString& wsURL) {
+RetainPtr<IFX_SeekableReadStream> CPDFXFA_Context::DownloadURL(
+    const WideString& wsURL) {
   return m_pFormFillEnv ? m_pFormFillEnv->DownloadFromURL(wsURL.c_str())
                         : nullptr;
 }
 
-bool CPDFXFA_Context::PostRequestURL(const CFX_WideString& wsURL,
-                                     const CFX_WideString& wsData,
-                                     const CFX_WideString& wsContentType,
-                                     const CFX_WideString& wsEncode,
-                                     const CFX_WideString& wsHeader,
-                                     CFX_WideString& wsResponse) {
+bool CPDFXFA_Context::PostRequestURL(const WideString& wsURL,
+                                     const WideString& wsData,
+                                     const WideString& wsContentType,
+                                     const WideString& wsEncode,
+                                     const WideString& wsHeader,
+                                     WideString& wsResponse) {
   if (!m_pFormFillEnv)
     return false;
 
@@ -353,9 +324,9 @@
   return true;
 }
 
-bool CPDFXFA_Context::PutRequestURL(const CFX_WideString& wsURL,
-                                    const CFX_WideString& wsData,
-                                    const CFX_WideString& wsEncode) {
+bool CPDFXFA_Context::PutRequestURL(const WideString& wsURL,
+                                    const WideString& wsData,
+                                    const WideString& wsEncode) {
   return m_pFormFillEnv &&
          m_pFormFillEnv->PutRequestURL(wsURL.c_str(), wsData.c_str(),
                                        wsEncode.c_str());
@@ -364,6 +335,6 @@
 IFWL_AdapterTimerMgr* CPDFXFA_Context::GetTimerMgr() {
   CXFA_FWLAdapterTimerMgr* pAdapter = nullptr;
   if (m_pFormFillEnv)
-    pAdapter = new CXFA_FWLAdapterTimerMgr(m_pFormFillEnv);
+    pAdapter = new CXFA_FWLAdapterTimerMgr(m_pFormFillEnv.Get());
   return pAdapter;
 }
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_context.h b/fpdfsdk/fpdfxfa/cpdfxfa_context.h
index 9a2a517..acef8f2 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_context.h
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_context.h
@@ -10,12 +10,15 @@
 #include <memory>
 #include <vector>
 
+#include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/observable.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.h"
-#include "xfa/fxfa/xfa_ffdoc.h"
+#include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
+#include "xfa/fxfa/cxfa_ffdoc.h"
 
 class CJS_Runtime;
 class CPDFSDK_FormFillEnvironment;
-class CPDFXFA_Page;
 class CXFA_FFDocHandler;
 class IJS_EventContext;
 class IJS_Runtime;
@@ -36,50 +39,52 @@
   bool LoadXFADoc();
   CPDF_Document* GetPDFDoc() { return m_pPDFDoc.get(); }
   CXFA_FFDoc* GetXFADoc() { return m_pXFADoc.get(); }
-  CXFA_FFDocView* GetXFADocView() { return m_pXFADocView; }
-  int GetDocType() const { return m_iDocType; }
+  CXFA_FFDocView* GetXFADocView() { return m_pXFADocView.Get(); }
+  FormType GetFormType() const { return m_FormType; }
+  bool ContainsXFAForm() const {
+    return m_FormType == FormType::kXFAFull ||
+           m_FormType == FormType::kXFAForeground;
+  }
   v8::Isolate* GetJSERuntime() const;
   CXFA_FFApp* GetXFAApp() { return m_pXFAApp.get(); }
 
-  CPDFSDK_FormFillEnvironment* GetFormFillEnv() const { return m_pFormFillEnv; }
+  CPDFSDK_FormFillEnvironment* GetFormFillEnv() const {
+    return m_pFormFillEnv.Get();
+  }
   void SetFormFillEnv(CPDFSDK_FormFillEnvironment* pFormFillEnv);
 
-  void DeletePage(int page_index);
   int GetPageCount() const;
-
-  CPDFXFA_Page* GetXFAPage(int page_index);
-  CPDFXFA_Page* GetXFAPage(CXFA_FFPageView* pPage) const;
-
-  void RemovePage(CPDFXFA_Page* page);
-
+  void DeletePage(int page_index);
+  RetainPtr<CPDFXFA_Page> GetXFAPage(int page_index);
+  RetainPtr<CPDFXFA_Page> GetXFAPage(CXFA_FFPageView* pPage) const;
   void ClearChangeMark();
 
   // IFXA_AppProvider:
-  CFX_WideString GetLanguage() override;
-  CFX_WideString GetPlatform() override;
-  CFX_WideString GetAppName() override;
-  CFX_WideString GetAppTitle() const override;
+  WideString GetLanguage() override;
+  WideString GetPlatform() override;
+  WideString GetAppName() override;
+  WideString GetAppTitle() const override;
 
   void Beep(uint32_t dwType) override;
-  int32_t MsgBox(const CFX_WideString& wsMessage,
-                 const CFX_WideString& wsTitle,
+  int32_t MsgBox(const WideString& wsMessage,
+                 const WideString& wsTitle,
                  uint32_t dwIconType,
                  uint32_t dwButtonType) override;
-  CFX_WideString Response(const CFX_WideString& wsQuestion,
-                          const CFX_WideString& wsTitle,
-                          const CFX_WideString& wsDefaultAnswer,
-                          bool bMark) override;
-  CFX_RetainPtr<IFX_SeekableReadStream> DownloadURL(
-      const CFX_WideString& wsURL) override;
-  bool PostRequestURL(const CFX_WideString& wsURL,
-                      const CFX_WideString& wsData,
-                      const CFX_WideString& wsContentType,
-                      const CFX_WideString& wsEncode,
-                      const CFX_WideString& wsHeader,
-                      CFX_WideString& wsResponse) override;
-  bool PutRequestURL(const CFX_WideString& wsURL,
-                     const CFX_WideString& wsData,
-                     const CFX_WideString& wsEncode) override;
+  WideString Response(const WideString& wsQuestion,
+                      const WideString& wsTitle,
+                      const WideString& wsDefaultAnswer,
+                      bool bMark) override;
+  RetainPtr<IFX_SeekableReadStream> DownloadURL(
+      const WideString& wsURL) override;
+  bool PostRequestURL(const WideString& wsURL,
+                      const WideString& wsData,
+                      const WideString& wsContentType,
+                      const WideString& wsEncode,
+                      const WideString& wsHeader,
+                      WideString& wsResponse) override;
+  bool PutRequestURL(const WideString& wsURL,
+                     const WideString& wsData,
+                     const WideString& wsEncode) override;
 
   IFWL_AdapterTimerMgr* GetTimerMgr() override;
 
@@ -93,22 +98,23 @@
   }
 
   LoadStatus GetLoadStatus() const { return m_nLoadStatus; }
-  std::vector<CPDFXFA_Page*>* GetXFAPageList() { return &m_XFAPageList; }
+  std::vector<RetainPtr<CPDFXFA_Page>>* GetXFAPageList() {
+    return &m_XFAPageList;
+  }
 
  private:
   void CloseXFADoc();
 
-  int m_iDocType;
-
+  FormType m_FormType = FormType::kNone;
   std::unique_ptr<CPDF_Document> m_pPDFDoc;
   std::unique_ptr<CXFA_FFDoc> m_pXFADoc;
-  CPDFSDK_FormFillEnvironment* m_pFormFillEnv;  // not owned.
-  CXFA_FFDocView* m_pXFADocView;                // not owned.
+  Observable<CPDFSDK_FormFillEnvironment>::ObservedPtr m_pFormFillEnv;
+  UnownedPtr<CXFA_FFDocView> m_pXFADocView;
   std::unique_ptr<CXFA_FFApp> m_pXFAApp;
   std::unique_ptr<CJS_Runtime> m_pRuntime;
-  std::vector<CPDFXFA_Page*> m_XFAPageList;
-  LoadStatus m_nLoadStatus;
-  int m_nPageCount;
+  std::vector<RetainPtr<CPDFXFA_Page>> m_XFAPageList;
+  LoadStatus m_nLoadStatus = FXFA_LOADSTATUS_PRELOAD;
+  int m_nPageCount = 0;
 
   // Must be destroyed before |m_pFormFillEnv|.
   CPDFXFA_DocEnvironment m_DocEnv;
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp b/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp
index 731b0cc..4ebe8f9 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp
@@ -11,16 +11,18 @@
 #include "core/fpdfapi/parser/cpdf_array.h"
 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
 #include "core/fpdfapi/parser/cpdf_string.h"
-#include "core/fxcrt/cfx_retain_ptr.h"
+#include "core/fxcrt/retain_ptr.h"
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 #include "fpdfsdk/cpdfsdk_interform.h"
 #include "fpdfsdk/cpdfsdk_pageview.h"
 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
-#include "fpdfsdk/javascript/ijs_runtime.h"
-#include "xfa/fxfa/xfa_ffdocview.h"
-#include "xfa/fxfa/xfa_ffwidget.h"
-#include "xfa/fxfa/xfa_ffwidgethandler.h"
+#include "fxjs/ijs_runtime.h"
+#include "xfa/fxfa/cxfa_ffdocview.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
+#include "xfa/fxfa/cxfa_ffwidgethandler.h"
+#include "xfa/fxfa/cxfa_widgetacciterator.h"
+#include "xfa/fxfa/parser/cxfa_submit.h"
 
 #define IDS_XFA_Validate_Input                                          \
   "At least one required field was empty. Please fill in the required " \
@@ -38,16 +40,11 @@
 #define FXFA_XFA_ALL 0x01111111
 
 CPDFXFA_DocEnvironment::CPDFXFA_DocEnvironment(CPDFXFA_Context* pContext)
-    : m_pContext(pContext), m_pJSEventContext(nullptr) {
+    : m_pContext(pContext) {
   ASSERT(m_pContext);
 }
 
-CPDFXFA_DocEnvironment::~CPDFXFA_DocEnvironment() {
-  if (m_pJSEventContext && m_pContext->GetFormFillEnv()) {
-    m_pContext->GetFormFillEnv()->GetJSRuntime()->ReleaseEventContext(
-        m_pJSEventContext);
-  }
-}
+CPDFXFA_DocEnvironment::~CPDFXFA_DocEnvironment() {}
 
 void CPDFXFA_DocEnvironment::SetChangeMark(CXFA_FFDoc* hDoc) {
   if (hDoc == m_pContext->GetXFADoc() && m_pContext->GetFormFillEnv())
@@ -55,15 +52,14 @@
 }
 
 void CPDFXFA_DocEnvironment::InvalidateRect(CXFA_FFPageView* pPageView,
-                                            const CFX_RectF& rt,
-                                            uint32_t dwFlags /* = 0 */) {
+                                            const CFX_RectF& rt) {
   if (!m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
     return;
 
-  if (m_pContext->GetDocType() != DOCTYPE_DYNAMIC_XFA)
+  if (m_pContext->GetFormType() != FormType::kXFAFull)
     return;
 
-  CPDFXFA_Page* pPage = m_pContext->GetXFAPage(pPageView);
+  RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pPageView);
   if (!pPage)
     return;
 
@@ -71,8 +67,7 @@
   if (!pFormFillEnv)
     return;
 
-  pFormFillEnv->Invalidate(static_cast<FPDF_PAGE>(pPage),
-                           CFX_FloatRect::FromCFXRectF(rt).ToFxRect());
+  pFormFillEnv->Invalidate(pPage.Get(), rt.ToFloatRect().ToFxRect());
 }
 
 void CPDFXFA_DocEnvironment::DisplayCaret(CXFA_FFWidget* hWidget,
@@ -82,7 +77,7 @@
       !m_pContext->GetFormFillEnv() || !m_pContext->GetXFADocView())
     return;
 
-  if (m_pContext->GetDocType() != DOCTYPE_DYNAMIC_XFA)
+  if (m_pContext->GetFormType() != FormType::kXFAFull)
     return;
 
   CXFA_FFWidgetHandler* pWidgetHandler =
@@ -94,7 +89,7 @@
   if (!pPageView)
     return;
 
-  CPDFXFA_Page* pPage = m_pContext->GetXFAPage(pPageView);
+  RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pPageView);
   if (!pPage)
     return;
 
@@ -102,14 +97,14 @@
   if (!pFormFillEnv)
     return;
 
-  CFX_FloatRect rcCaret = CFX_FloatRect::FromCFXRectF(*pRtAnchor);
-  pFormFillEnv->DisplayCaret((FPDF_PAGE)pPage, bVisible, rcCaret.left,
-                             rcCaret.top, rcCaret.right, rcCaret.bottom);
+  CFX_FloatRect rcCaret = pRtAnchor->ToFloatRect();
+  pFormFillEnv->DisplayCaret(pPage.Get(), bVisible, rcCaret.left, rcCaret.top,
+                             rcCaret.right, rcCaret.bottom);
 }
 
 bool CPDFXFA_DocEnvironment::GetPopupPos(CXFA_FFWidget* hWidget,
-                                         FX_FLOAT fMinPopup,
-                                         FX_FLOAT fMaxPopup,
+                                         float fMinPopup,
+                                         float fMaxPopup,
                                          const CFX_RectF& rtAnchor,
                                          CFX_RectF& rtPopup) {
   if (!hWidget)
@@ -119,22 +114,21 @@
   if (!pXFAPageView)
     return false;
 
-  CPDFXFA_Page* pPage = m_pContext->GetXFAPage(pXFAPageView);
+  RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pXFAPageView);
   if (!pPage)
     return false;
 
-  CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc();
-  int nRotate = pWidgetAcc->GetRotate();
   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
   if (!pFormFillEnv)
     return false;
 
   FS_RECTF pageViewRect = {0.0f, 0.0f, 0.0f, 0.0f};
-  pFormFillEnv->GetPageViewRect(pPage, pageViewRect);
+  pFormFillEnv->GetPageViewRect(pPage.Get(), pageViewRect);
 
   int t1;
   int t2;
-  CFX_FloatRect rcAnchor = CFX_FloatRect::FromCFXRectF(rtAnchor);
+  CFX_FloatRect rcAnchor = rtAnchor.ToFloatRect();
+  int nRotate = hWidget->GetNode()->GetRotate();
   switch (nRotate) {
     case 90: {
       t1 = (int)(pageViewRect.right - rcAnchor.right);
@@ -185,13 +179,13 @@
     dwPos = 1;
   }
 
-  FX_FLOAT fPopupHeight;
+  float fPopupHeight;
   if (t < fMinPopup)
     fPopupHeight = fMinPopup;
   else if (t > fMaxPopup)
     fPopupHeight = fMaxPopup;
   else
-    fPopupHeight = static_cast<FX_FLOAT>(t);
+    fPopupHeight = static_cast<float>(t);
 
   switch (nRotate) {
     case 0:
@@ -232,7 +226,7 @@
   if (!pXFAPageView)
     return false;
 
-  CPDFXFA_Page* pPage = m_pContext->GetXFAPage(pXFAPageView);
+  RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pXFAPageView);
   if (!pPage)
     return false;
 
@@ -254,7 +248,7 @@
   if (hWidget->CanSelectAll())
     menuFlag |= FXFA_MENU_SELECTALL;
 
-  return pFormFillEnv->PopupMenu(pPage, hWidget, menuFlag, ptPopup);
+  return pFormFillEnv->PopupMenu(pPage.Get(), hWidget, menuFlag, ptPopup);
 }
 
 void CPDFXFA_DocEnvironment::PageViewEvent(CXFA_FFPageView* pPageView,
@@ -278,54 +272,57 @@
 
   for (int iPageIter = 0; iPageIter < m_pContext->GetOriginalPageCount();
        iPageIter++) {
-    CPDFXFA_Page* pPage = (*m_pContext->GetXFAPageList())[iPageIter];
+    RetainPtr<CPDFXFA_Page> pPage = (*m_pContext->GetXFAPageList())[iPageIter];
     if (!pPage)
       continue;
 
-    m_pContext->GetFormFillEnv()->RemovePageView(pPage);
+    m_pContext->GetFormFillEnv()->RemovePageView(pPage.Get());
     pPage->SetXFAPageView(pXFADocView->GetPageView(iPageIter));
   }
 
   int flag = (nNewCount < m_pContext->GetOriginalPageCount())
                  ? FXFA_PAGEVIEWEVENT_POSTREMOVED
                  : FXFA_PAGEVIEWEVENT_POSTADDED;
-  int count = FXSYS_abs(nNewCount - m_pContext->GetOriginalPageCount());
+  int count = abs(nNewCount - m_pContext->GetOriginalPageCount());
   m_pContext->SetOriginalPageCount(nNewCount);
   pFormFillEnv->PageEvent(count, flag);
 }
 
 void CPDFXFA_DocEnvironment::WidgetPostAdd(CXFA_FFWidget* hWidget,
-                                           CXFA_WidgetAcc* pWidgetData) {
-  if (m_pContext->GetDocType() != DOCTYPE_DYNAMIC_XFA || !hWidget)
+                                           CXFA_WidgetAcc* pWidgetAcc) {
+  if (m_pContext->GetFormType() != FormType::kXFAFull || !hWidget)
     return;
 
   CXFA_FFPageView* pPageView = hWidget->GetPageView();
   if (!pPageView)
     return;
 
-  CPDFXFA_Page* pXFAPage = m_pContext->GetXFAPage(pPageView);
+  RetainPtr<CPDFXFA_Page> pXFAPage = m_pContext->GetXFAPage(pPageView);
   if (!pXFAPage)
     return;
 
-  m_pContext->GetFormFillEnv()->GetPageView(pXFAPage, true)->AddAnnot(hWidget);
+  m_pContext->GetFormFillEnv()
+      ->GetPageView(pXFAPage.Get(), true)
+      ->AddAnnot(hWidget);
 }
 
 void CPDFXFA_DocEnvironment::WidgetPreRemove(CXFA_FFWidget* hWidget,
-                                             CXFA_WidgetAcc* pWidgetData) {
-  if (m_pContext->GetDocType() != DOCTYPE_DYNAMIC_XFA || !hWidget)
+                                             CXFA_WidgetAcc* pWidgetAcc) {
+  if (m_pContext->GetFormType() != FormType::kXFAFull || !hWidget)
     return;
 
   CXFA_FFPageView* pPageView = hWidget->GetPageView();
   if (!pPageView)
     return;
 
-  CPDFXFA_Page* pXFAPage = m_pContext->GetXFAPage(pPageView);
+  RetainPtr<CPDFXFA_Page> pXFAPage = m_pContext->GetXFAPage(pPageView);
   if (!pXFAPage)
     return;
 
   CPDFSDK_PageView* pSdkPageView =
-      m_pContext->GetFormFillEnv()->GetPageView(pXFAPage, true);
-  if (CPDFSDK_Annot* pAnnot = pSdkPageView->GetAnnotByXFAWidget(hWidget))
+      m_pContext->GetFormFillEnv()->GetPageView(pXFAPage.Get(), true);
+  CPDFSDK_Annot* pAnnot = pSdkPageView->GetAnnotByXFAWidget(hWidget);
+  if (pAnnot)
     pSdkPageView->DeleteAnnot(pAnnot);
 }
 
@@ -338,20 +335,20 @@
 int32_t CPDFXFA_DocEnvironment::GetCurrentPage(CXFA_FFDoc* hDoc) {
   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
     return -1;
-  if (m_pContext->GetDocType() != DOCTYPE_DYNAMIC_XFA)
+  if (m_pContext->GetFormType() != FormType::kXFAFull)
     return -1;
 
   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
   if (!pFormFillEnv)
     return -1;
 
-  return pFormFillEnv->GetCurrentPageIndex(this);
+  return pFormFillEnv->GetCurrentPageIndex(m_pContext.Get());
 }
 
 void CPDFXFA_DocEnvironment::SetCurrentPage(CXFA_FFDoc* hDoc,
                                             int32_t iCurPage) {
   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv() ||
-      m_pContext->GetDocType() != DOCTYPE_DYNAMIC_XFA || iCurPage < 0 ||
+      m_pContext->GetFormType() != FormType::kXFAFull || iCurPage < 0 ||
       iCurPage >= m_pContext->GetFormFillEnv()->GetPageCount()) {
     return;
   }
@@ -359,7 +356,7 @@
   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
   if (!pFormFillEnv)
     return;
-  pFormFillEnv->SetCurrentPage(this, iCurPage);
+  pFormFillEnv->SetCurrentPage(m_pContext.Get(), iCurPage);
 }
 
 bool CPDFXFA_DocEnvironment::IsCalculationsEnabled(CXFA_FFDoc* hDoc) {
@@ -382,53 +379,51 @@
   }
 }
 
-void CPDFXFA_DocEnvironment::GetTitle(CXFA_FFDoc* hDoc,
-                                      CFX_WideString& wsTitle) {
+void CPDFXFA_DocEnvironment::GetTitle(CXFA_FFDoc* hDoc, WideString& wsTitle) {
   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetPDFDoc())
     return;
 
-  CPDF_Dictionary* pInfoDict = m_pContext->GetPDFDoc()->GetInfo();
+  const CPDF_Dictionary* pInfoDict = m_pContext->GetPDFDoc()->GetInfo();
   if (!pInfoDict)
     return;
 
-  CFX_ByteString csTitle = pInfoDict->GetStringFor("Title");
+  ByteString csTitle = pInfoDict->GetStringFor("Title");
   wsTitle = wsTitle.FromLocal(csTitle.GetBuffer(csTitle.GetLength()));
   csTitle.ReleaseBuffer(csTitle.GetLength());
 }
 
 void CPDFXFA_DocEnvironment::SetTitle(CXFA_FFDoc* hDoc,
-                                      const CFX_WideString& wsTitle) {
+                                      const WideString& wsTitle) {
   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetPDFDoc())
     return;
 
-  if (CPDF_Dictionary* pInfoDict = m_pContext->GetPDFDoc()->GetInfo())
+  CPDF_Dictionary* pInfoDict = m_pContext->GetPDFDoc()->GetInfo();
+  if (pInfoDict)
     pInfoDict->SetNewFor<CPDF_String>("Title", wsTitle);
 }
 
 void CPDFXFA_DocEnvironment::ExportData(CXFA_FFDoc* hDoc,
-                                        const CFX_WideString& wsFilePath,
+                                        const WideString& wsFilePath,
                                         bool bXDP) {
   if (hDoc != m_pContext->GetXFADoc())
     return;
 
-  if (m_pContext->GetDocType() != DOCTYPE_DYNAMIC_XFA &&
-      m_pContext->GetDocType() != DOCTYPE_STATIC_XFA) {
+  if (!m_pContext->ContainsXFAForm())
     return;
-  }
 
   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
   if (!pFormFillEnv)
     return;
 
   int fileType = bXDP ? FXFA_SAVEAS_XDP : FXFA_SAVEAS_XML;
-  CFX_ByteString bs = wsFilePath.UTF16LE_Encode();
+  ByteString bs = wsFilePath.UTF16LE_Encode();
   if (wsFilePath.IsEmpty()) {
     if (!pFormFillEnv->GetFormFillInfo() ||
         !pFormFillEnv->GetFormFillInfo()->m_pJsPlatform) {
       return;
     }
 
-    CFX_WideString filepath = pFormFillEnv->JS_fieldBrowse();
+    WideString filepath = pFormFillEnv->JS_fieldBrowse();
     bs = filepath.UTF16LE_Encode();
   }
   int len = bs.GetLength();
@@ -439,20 +434,20 @@
   if (!pFileHandler)
     return;
 
-  CFX_RetainPtr<IFX_SeekableStream> fileWrite =
-      MakeSeekableStream(pFileHandler);
-  CFX_ByteString content;
+  RetainPtr<IFX_SeekableStream> fileWrite = MakeSeekableStream(pFileHandler);
   if (fileType == FXFA_SAVEAS_XML) {
-    content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
+    ByteString content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
     fileWrite->WriteBlock(content.c_str(), fileWrite->GetSize(),
                           content.GetLength());
-    m_pContext->GetXFADocView()->GetDoc()->SavePackage(XFA_HASHCODE_Data,
-                                                       fileWrite, nullptr);
+    CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc();
+    ffdoc->SavePackage(
+        ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Data)), fileWrite,
+        nullptr);
   } else if (fileType == FXFA_SAVEAS_XDP) {
     if (!m_pContext->GetPDFDoc())
       return;
 
-    CPDF_Dictionary* pRoot = m_pContext->GetPDFDoc()->GetRoot();
+    const CPDF_Dictionary* pRoot = m_pContext->GetPDFDoc()->GetRoot();
     if (!pRoot)
       return;
 
@@ -477,28 +472,32 @@
       if (!pStream)
         continue;
       if (pPrePDFObj->GetString() == "form") {
-        m_pContext->GetXFADocView()->GetDoc()->SavePackage(XFA_HASHCODE_Form,
-                                                           fileWrite, nullptr);
+        CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc();
+        ffdoc->SavePackage(
+            ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form)),
+            fileWrite, nullptr);
         continue;
       }
       if (pPrePDFObj->GetString() == "datasets") {
-        m_pContext->GetXFADocView()->GetDoc()->SavePackage(
-            XFA_HASHCODE_Datasets, fileWrite, nullptr);
+        CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc();
+        ffdoc->SavePackage(
+            ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Datasets)),
+            fileWrite, nullptr);
         continue;
       }
       if (i == size - 1) {
-        CFX_WideString wPath = CFX_WideString::FromUTF16LE(
+        WideString wPath = WideString::FromUTF16LE(
             reinterpret_cast<const unsigned short*>(bs.c_str()),
             bs.GetLength() / sizeof(unsigned short));
-        CFX_ByteString bPath = wPath.UTF8Encode();
+        ByteString bPath = wPath.UTF8Encode();
         const char* szFormat =
             "\n<pdf href=\"%s\" xmlns=\"http://ns.adobe.com/xdp/pdf/\"/>";
-        content.Format(szFormat, bPath.c_str());
+        ByteString content = ByteString::Format(szFormat, bPath.c_str());
         fileWrite->WriteBlock(content.c_str(), fileWrite->GetSize(),
                               content.GetLength());
       }
-      std::unique_ptr<CPDF_StreamAcc> pAcc(new CPDF_StreamAcc);
-      pAcc->LoadAllData(pStream);
+      auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream);
+      pAcc->LoadAllDataFiltered();
       fileWrite->WriteBlock(pAcc->GetData(), fileWrite->GetSize(),
                             pAcc->GetSize());
     }
@@ -507,19 +506,19 @@
 }
 
 void CPDFXFA_DocEnvironment::GotoURL(CXFA_FFDoc* hDoc,
-                                     const CFX_WideString& bsURL) {
+                                     const WideString& bsURL) {
   if (hDoc != m_pContext->GetXFADoc())
     return;
 
-  if (m_pContext->GetDocType() != DOCTYPE_DYNAMIC_XFA)
+  if (m_pContext->GetFormType() != FormType::kXFAFull)
     return;
 
   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
   if (!pFormFillEnv)
     return;
 
-  CFX_WideStringC str(bsURL.c_str());
-  pFormFillEnv->GotoURL(this, str);
+  WideStringView str(bsURL.c_str());
+  pFormFillEnv->GotoURL(m_pContext.Get(), str);
 }
 
 bool CPDFXFA_DocEnvironment::IsValidationsEnabled(CXFA_FFDoc* hDoc) {
@@ -599,7 +598,7 @@
     return 0;
 
   return ArgbEncode(pInterForm->GetHighlightAlpha(),
-                    pInterForm->GetHighlightColor(FPDF_FORMFIELD_XFA));
+                    pInterForm->GetHighlightColor(FormFieldType::kXFA));
 }
 
 bool CPDFXFA_DocEnvironment::NotifySubmit(bool bPrevOrPost) {
@@ -611,21 +610,19 @@
 }
 
 bool CPDFXFA_DocEnvironment::OnBeforeNotifySubmit() {
-  if (m_pContext->GetDocType() != DOCTYPE_DYNAMIC_XFA &&
-      m_pContext->GetDocType() != DOCTYPE_STATIC_XFA) {
-    return true;
-  }
-
-  if (!m_pContext->GetXFADocView())
+  if (!m_pContext->ContainsXFAForm())
     return true;
 
-  CXFA_FFWidgetHandler* pWidgetHandler =
-      m_pContext->GetXFADocView()->GetWidgetHandler();
+  CXFA_FFDocView* docView = m_pContext->GetXFADocView();
+  if (!docView)
+    return true;
+
+  CXFA_FFWidgetHandler* pWidgetHandler = docView->GetWidgetHandler();
   if (!pWidgetHandler)
     return true;
 
-  std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator(
-      m_pContext->GetXFADocView()->CreateWidgetAccIterator());
+  std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator =
+      docView->CreateWidgetAccIterator();
   if (pWidgetAccIterator) {
     CXFA_EventParam Param;
     Param.m_eType = XFA_EVENT_PreSubmit;
@@ -633,23 +630,21 @@
       pWidgetHandler->ProcessEvent(pWidgetAcc, &Param);
   }
 
-  pWidgetAccIterator.reset(
-      m_pContext->GetXFADocView()->CreateWidgetAccIterator());
+  pWidgetAccIterator = docView->CreateWidgetAccIterator();
   if (!pWidgetAccIterator)
     return true;
 
   CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext();
   pWidgetAcc = pWidgetAccIterator->MoveToNext();
   while (pWidgetAcc) {
-    int fRet = pWidgetAcc->ProcessValidate(-1);
+    int fRet = pWidgetAcc->GetNode()->ProcessValidate(docView, -1);
     if (fRet == XFA_EVENTERROR_Error) {
       CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
       if (!pFormFillEnv)
         return false;
 
-      CFX_WideString ws;
-      ws.FromLocal(IDS_XFA_Validate_Input);
-      CFX_ByteString bs = ws.UTF16LE_Encode();
+      WideString ws = WideString::FromLocal(IDS_XFA_Validate_Input);
+      ByteString bs = ws.UTF16LE_Encode();
       int len = bs.GetLength();
       pFormFillEnv->Alert((FPDF_WIDESTRING)bs.GetBuffer(len),
                           (FPDF_WIDESTRING)L"", 0, 1);
@@ -658,14 +653,13 @@
     }
     pWidgetAcc = pWidgetAccIterator->MoveToNext();
   }
-  m_pContext->GetXFADocView()->UpdateDocView();
+  docView->UpdateDocView();
 
   return true;
 }
 
 void CPDFXFA_DocEnvironment::OnAfterNotifySubmit() {
-  if (m_pContext->GetDocType() != DOCTYPE_DYNAMIC_XFA &&
-      m_pContext->GetDocType() != DOCTYPE_STATIC_XFA)
+  if (!m_pContext->ContainsXFAForm())
     return;
 
   if (!m_pContext->GetXFADocView())
@@ -676,8 +670,8 @@
   if (!pWidgetHandler)
     return;
 
-  std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator(
-      m_pContext->GetXFADocView()->CreateWidgetAccIterator());
+  std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator =
+      m_pContext->GetXFADocView()->CreateWidgetAccIterator();
   if (!pWidgetAccIterator)
     return;
 
@@ -691,24 +685,24 @@
   m_pContext->GetXFADocView()->UpdateDocView();
 }
 
-bool CPDFXFA_DocEnvironment::SubmitData(CXFA_FFDoc* hDoc, CXFA_Submit submit) {
+bool CPDFXFA_DocEnvironment::Submit(CXFA_FFDoc* hDoc, CXFA_Submit* submit) {
   if (!NotifySubmit(true) || !m_pContext->GetXFADocView())
     return false;
 
   m_pContext->GetXFADocView()->UpdateDocView();
-  bool ret = SubmitDataInternal(hDoc, submit);
+  bool ret = SubmitInternal(hDoc, submit);
   NotifySubmit(false);
   return ret;
 }
 
-CFX_RetainPtr<IFX_SeekableReadStream> CPDFXFA_DocEnvironment::OpenLinkedFile(
+RetainPtr<IFX_SeekableReadStream> CPDFXFA_DocEnvironment::OpenLinkedFile(
     CXFA_FFDoc* hDoc,
-    const CFX_WideString& wsLink) {
+    const WideString& wsLink) {
   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
   if (!pFormFillEnv)
     return nullptr;
 
-  CFX_ByteString bs = wsLink.UTF16LE_Encode();
+  ByteString bs = wsLink.UTF16LE_Encode();
   int len = bs.GetLength();
   FPDF_FILEHANDLER* pFileHandler =
       pFormFillEnv->OpenFile(0, (FPDF_WIDESTRING)bs.GetBuffer(len), "rb");
@@ -726,19 +720,20 @@
   if (!m_pContext->GetXFADocView())
     return false;
 
-  CFX_ByteString content;
   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
   if (!pFormFillEnv)
     return false;
 
-  CFX_RetainPtr<IFX_SeekableStream> fileStream =
-      MakeSeekableStream(pFileHandler);
-
+  CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc();
+  RetainPtr<IFX_SeekableStream> fileStream = MakeSeekableStream(pFileHandler);
   if (fileType == FXFA_SAVEAS_XML) {
-    const char kContent[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
+    static constexpr char kContent[] =
+        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
     fileStream->WriteBlock(kContent, 0, strlen(kContent));
-    m_pContext->GetXFADoc()->SavePackage(XFA_HASHCODE_Data, fileStream,
-                                         nullptr);
+
+    ffdoc->SavePackage(
+        ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Data)), fileStream,
+        nullptr);
     return true;
   }
 
@@ -754,7 +749,7 @@
     return false;
   }
 
-  CPDF_Dictionary* pRoot = m_pContext->GetPDFDoc()->GetRoot();
+  const CPDF_Dictionary* pRoot = m_pContext->GetPDFDoc()->GetRoot();
   if (!pRoot) {
     fileStream->Flush();
     return false;
@@ -798,34 +793,35 @@
       continue;
     if (pPrePDFObj->GetString() == "form" && !(flag & FXFA_FORM))
       continue;
+
     if (pPrePDFObj->GetString() == "form") {
-      m_pContext->GetXFADoc()->SavePackage(XFA_HASHCODE_Form, fileStream,
-                                           nullptr);
+      ffdoc->SavePackage(
+          ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form)),
+          fileStream, nullptr);
     } else if (pPrePDFObj->GetString() == "datasets") {
-      m_pContext->GetXFADoc()->SavePackage(XFA_HASHCODE_Datasets, fileStream,
-                                           nullptr);
-    } else {
-      // PDF,creator.
+      ffdoc->SavePackage(
+          ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Datasets)),
+          fileStream, nullptr);
     }
   }
   return true;
 }
 
-void CPDFXFA_DocEnvironment::ToXFAContentFlags(CFX_WideString csSrcContent,
+void CPDFXFA_DocEnvironment::ToXFAContentFlags(WideString csSrcContent,
                                                FPDF_DWORD& flag) {
-  if (csSrcContent.Find(L" config ", 0) != -1)
+  if (csSrcContent.Contains(L" config "))
     flag |= FXFA_CONFIG;
-  if (csSrcContent.Find(L" template ", 0) != -1)
+  if (csSrcContent.Contains(L" template "))
     flag |= FXFA_TEMPLATE;
-  if (csSrcContent.Find(L" localeSet ", 0) != -1)
+  if (csSrcContent.Contains(L" localeSet "))
     flag |= FXFA_LOCALESET;
-  if (csSrcContent.Find(L" datasets ", 0) != -1)
+  if (csSrcContent.Contains(L" datasets "))
     flag |= FXFA_DATASETS;
-  if (csSrcContent.Find(L" xmpmeta ", 0) != -1)
+  if (csSrcContent.Contains(L" xmpmeta "))
     flag |= FXFA_XMPMETA;
-  if (csSrcContent.Find(L" xfdf ", 0) != -1)
+  if (csSrcContent.Contains(L" xfdf "))
     flag |= FXFA_XFDF;
-  if (csSrcContent.Find(L" form ", 0) != -1)
+  if (csSrcContent.Contains(L" form "))
     flag |= FXFA_FORM;
   if (flag == 0) {
     flag = FXFA_CONFIG | FXFA_TEMPLATE | FXFA_LOCALESET | FXFA_DATASETS |
@@ -833,43 +829,40 @@
   }
 }
 
-bool CPDFXFA_DocEnvironment::MailToInfo(CFX_WideString& csURL,
-                                        CFX_WideString& csToAddress,
-                                        CFX_WideString& csCCAddress,
-                                        CFX_WideString& csBCCAddress,
-                                        CFX_WideString& csSubject,
-                                        CFX_WideString& csMsg) {
-  CFX_WideString srcURL = csURL;
+bool CPDFXFA_DocEnvironment::MailToInfo(WideString& csURL,
+                                        WideString& csToAddress,
+                                        WideString& csCCAddress,
+                                        WideString& csBCCAddress,
+                                        WideString& csSubject,
+                                        WideString& csMsg) {
+  WideString srcURL = csURL;
   srcURL.TrimLeft();
   if (srcURL.Left(7).CompareNoCase(L"mailto:") != 0)
     return false;
 
-  int pos = srcURL.Find(L'?', 0);
-  CFX_WideString tmp;
-  if (pos == -1) {
-    pos = srcURL.Find(L'@', 0);
-    if (pos == -1)
+  auto pos = srcURL.Find(L'?');
+  WideString tmp;
+  if (!pos.has_value()) {
+    pos = srcURL.Find(L'@');
+    if (!pos.has_value())
       return false;
 
     tmp = srcURL.Right(csURL.GetLength() - 7);
   } else {
-    tmp = srcURL.Left(pos);
+    tmp = srcURL.Left(pos.value());
     tmp = tmp.Right(tmp.GetLength() - 7);
   }
-  tmp.TrimLeft();
-  tmp.TrimRight();
+  tmp.Trim();
 
   csToAddress = tmp;
 
-  srcURL = srcURL.Right(srcURL.GetLength() - (pos + 1));
+  srcURL = srcURL.Right(srcURL.GetLength() - (pos.value() + 1));
   while (!srcURL.IsEmpty()) {
-    srcURL.TrimLeft();
-    srcURL.TrimRight();
-    pos = srcURL.Find(L'&', 0);
+    srcURL.Trim();
+    pos = srcURL.Find(L'&');
 
-    tmp = (pos == -1) ? srcURL : srcURL.Left(pos);
-    tmp.TrimLeft();
-    tmp.TrimRight();
+    tmp = (!pos.has_value()) ? srcURL : srcURL.Left(pos.value());
+    tmp.Trim();
     if (tmp.GetLength() >= 3 && tmp.Left(3).CompareNoCase(L"cc=") == 0) {
       tmp = tmp.Right(tmp.GetLength() - 3);
       if (!csCCAddress.IsEmpty())
@@ -890,7 +883,9 @@
       tmp = tmp.Right(tmp.GetLength() - 5);
       csMsg += tmp;
     }
-    srcURL = (pos == -1) ? L"" : srcURL.Right(csURL.GetLength() - (pos + 1));
+    srcURL = !pos.has_value()
+                 ? L""
+                 : srcURL.Right(csURL.GetLength() - (pos.value() + 1));
   }
   csToAddress.Replace(L",", L";");
   csCCAddress.Replace(L",", L";");
@@ -898,41 +893,34 @@
   return true;
 }
 
-bool CPDFXFA_DocEnvironment::SubmitDataInternal(CXFA_FFDoc* hDoc,
-                                                CXFA_Submit submit) {
+bool CPDFXFA_DocEnvironment::SubmitInternal(CXFA_FFDoc* hDoc,
+                                            CXFA_Submit* submit) {
   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
   if (!pFormFillEnv)
     return false;
 
-  CFX_WideStringC csURLC;
-  submit.GetSubmitTarget(csURLC);
-  CFX_WideString csURL(csURLC);
+  WideString csURL = submit->GetSubmitTarget();
   if (csURL.IsEmpty()) {
-    CFX_WideString ws;
-    ws.FromLocal("Submit cancelled.");
-    CFX_ByteString bs = ws.UTF16LE_Encode();
+    WideString ws = WideString::FromLocal("Submit cancelled.");
+    ByteString bs = ws.UTF16LE_Encode();
     int len = bs.GetLength();
-    pFormFillEnv->Alert((FPDF_WIDESTRING)bs.GetBuffer(len),
-                        (FPDF_WIDESTRING)L"", 0, 4);
+    pFormFillEnv->Alert(reinterpret_cast<FPDF_WIDESTRING>(bs.GetBuffer(len)),
+                        reinterpret_cast<FPDF_WIDESTRING>(L""), 0, 4);
     bs.ReleaseBuffer(len);
     return false;
   }
 
   FPDF_FILEHANDLER* pFileHandler = nullptr;
   int fileFlag = -1;
-  switch (submit.GetSubmitFormat()) {
-    case XFA_ATTRIBUTEENUM_Xdp: {
-      CFX_WideStringC csContentC;
-      submit.GetSubmitXDPContent(csContentC);
-      CFX_WideString csContent;
-      csContent = csContentC;
-      csContent.TrimLeft();
-      csContent.TrimRight();
-      CFX_WideString space;
-      space.FromLocal(" ");
+  switch (submit->GetSubmitFormat()) {
+    case XFA_AttributeEnum::Xdp: {
+      WideString csContent = submit->GetSubmitXDPContent();
+      csContent.Trim();
+
+      WideString space = WideString::FromLocal(" ");
       csContent = space + csContent + space;
       FPDF_DWORD flag = 0;
-      if (submit.IsSubmitEmbedPDF())
+      if (submit->IsSubmitEmbedPDF())
         flag |= FXFA_PDF;
 
       ToXFAContentFlags(csContent, flag);
@@ -941,14 +929,14 @@
       ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XDP, 0, flag);
       break;
     }
-    case XFA_ATTRIBUTEENUM_Xml:
+    case XFA_AttributeEnum::Xml:
       pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XML, nullptr, "wb");
       fileFlag = FXFA_SAVEAS_XML;
       ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XML, 0, FXFA_XFA_ALL);
       break;
-    case XFA_ATTRIBUTEENUM_Pdf:
+    case XFA_AttributeEnum::Pdf:
       break;
-    case XFA_ATTRIBUTEENUM_Urlencoded:
+    case XFA_AttributeEnum::Urlencoded:
       pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XML, nullptr, "wb");
       fileFlag = FXFA_SAVEAS_XML;
       ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XML, 0, FXFA_XFA_ALL);
@@ -958,21 +946,22 @@
   }
   if (!pFileHandler)
     return false;
+
   if (csURL.Left(7).CompareNoCase(L"mailto:") == 0) {
-    CFX_WideString csToAddress;
-    CFX_WideString csCCAddress;
-    CFX_WideString csBCCAddress;
-    CFX_WideString csSubject;
-    CFX_WideString csMsg;
+    WideString csToAddress;
+    WideString csCCAddress;
+    WideString csBCCAddress;
+    WideString csSubject;
+    WideString csMsg;
     if (!MailToInfo(csURL, csToAddress, csCCAddress, csBCCAddress, csSubject,
                     csMsg)) {
       return false;
     }
-    CFX_ByteString bsTo = CFX_WideString(csToAddress).UTF16LE_Encode();
-    CFX_ByteString bsCC = CFX_WideString(csCCAddress).UTF16LE_Encode();
-    CFX_ByteString bsBcc = CFX_WideString(csBCCAddress).UTF16LE_Encode();
-    CFX_ByteString bsSubject = CFX_WideString(csSubject).UTF16LE_Encode();
-    CFX_ByteString bsMsg = CFX_WideString(csMsg).UTF16LE_Encode();
+    ByteString bsTo = WideString(csToAddress).UTF16LE_Encode();
+    ByteString bsCC = WideString(csCCAddress).UTF16LE_Encode();
+    ByteString bsBcc = WideString(csBCCAddress).UTF16LE_Encode();
+    ByteString bsSubject = WideString(csSubject).UTF16LE_Encode();
+    ByteString bsMsg = WideString(csMsg).UTF16LE_Encode();
     FPDF_WIDESTRING pTo = (FPDF_WIDESTRING)bsTo.GetBuffer(bsTo.GetLength());
     FPDF_WIDESTRING pCC = (FPDF_WIDESTRING)bsCC.GetBuffer(bsCC.GetLength());
     FPDF_WIDESTRING pBcc = (FPDF_WIDESTRING)bsBcc.GetBuffer(bsBcc.GetLength());
@@ -980,15 +969,15 @@
         (FPDF_WIDESTRING)bsSubject.GetBuffer(bsSubject.GetLength());
     FPDF_WIDESTRING pMsg = (FPDF_WIDESTRING)bsMsg.GetBuffer(bsMsg.GetLength());
     pFormFillEnv->EmailTo(pFileHandler, pTo, pSubject, pCC, pBcc, pMsg);
-    bsTo.ReleaseBuffer();
-    bsCC.ReleaseBuffer();
-    bsBcc.ReleaseBuffer();
-    bsSubject.ReleaseBuffer();
-    bsMsg.ReleaseBuffer();
+    bsTo.ReleaseBuffer(bsTo.GetStringLength());
+    bsCC.ReleaseBuffer(bsCC.GetStringLength());
+    bsBcc.ReleaseBuffer(bsBcc.GetStringLength());
+    bsSubject.ReleaseBuffer(bsSubject.GetStringLength());
+    bsMsg.ReleaseBuffer(bsMsg.GetStringLength());
   } else {
     // HTTP or FTP
-    CFX_WideString ws;
-    CFX_ByteString bs = csURL.UTF16LE_Encode();
+    WideString ws;
+    ByteString bs = csURL.UTF16LE_Encode();
     int len = bs.GetLength();
     pFormFillEnv->UploadTo(pFileHandler, fileFlag,
                            (FPDF_WIDESTRING)bs.GetBuffer(len));
@@ -997,35 +986,34 @@
   return true;
 }
 
-bool CPDFXFA_DocEnvironment::SetGlobalProperty(
-    CXFA_FFDoc* hDoc,
-    const CFX_ByteStringC& szPropName,
-    CFXJSE_Value* pValue) {
-  if (hDoc != m_pContext->GetXFADoc())
-    return false;
-
-  if (m_pContext->GetFormFillEnv() &&
-      m_pContext->GetFormFillEnv()->GetJSRuntime()) {
-    return m_pContext->GetFormFillEnv()->GetJSRuntime()->SetValueByName(
-        szPropName, pValue);
-  }
-  return false;
-}
-
-bool CPDFXFA_DocEnvironment::GetGlobalProperty(
-    CXFA_FFDoc* hDoc,
-    const CFX_ByteStringC& szPropName,
-    CFXJSE_Value* pValue) {
+bool CPDFXFA_DocEnvironment::SetGlobalProperty(CXFA_FFDoc* hDoc,
+                                               const ByteStringView& szPropName,
+                                               CFXJSE_Value* pValue) {
   if (hDoc != m_pContext->GetXFADoc())
     return false;
   if (!m_pContext->GetFormFillEnv() ||
       !m_pContext->GetFormFillEnv()->GetJSRuntime()) {
     return false;
   }
-
   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
-  if (!m_pJSEventContext)
-    m_pJSEventContext = pFormFillEnv->GetJSRuntime()->NewEventContext();
+  IJS_EventContext* pContext = pFormFillEnv->GetJSRuntime()->NewEventContext();
+  bool bRet = pFormFillEnv->GetJSRuntime()->SetValueByName(szPropName, pValue);
+  pFormFillEnv->GetJSRuntime()->ReleaseEventContext(pContext);
+  return bRet;
+}
 
-  return pFormFillEnv->GetJSRuntime()->GetValueByName(szPropName, pValue);
+bool CPDFXFA_DocEnvironment::GetGlobalProperty(CXFA_FFDoc* hDoc,
+                                               const ByteStringView& szPropName,
+                                               CFXJSE_Value* pValue) {
+  if (hDoc != m_pContext->GetXFADoc())
+    return false;
+  if (!m_pContext->GetFormFillEnv() ||
+      !m_pContext->GetFormFillEnv()->GetJSRuntime()) {
+    return false;
+  }
+  CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
+  IJS_EventContext* pContext = pFormFillEnv->GetJSRuntime()->NewEventContext();
+  bool bRet = pFormFillEnv->GetJSRuntime()->GetValueByName(szPropName, pValue);
+  pFormFillEnv->GetJSRuntime()->ReleaseEventContext(pContext);
+  return bRet;
 }
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.h b/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.h
index dc18d9a..9eabf8d 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.h
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.h
@@ -7,7 +7,8 @@
 #ifndef FPDFSDK_FPDFXFA_CPDFXFA_DOCENVIRONMENT_H_
 #define FPDFSDK_FPDFXFA_CPDFXFA_DOCENVIRONMENT_H_
 
-#include "core/fxcrt/cfx_retain_ptr.h"
+#include "core/fxcrt/retain_ptr.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "public/fpdfview.h"
 #include "xfa/fxfa/fxfa.h"
 
@@ -21,18 +22,16 @@
 
   // IXFA_DocEnvironment
   void SetChangeMark(CXFA_FFDoc* hDoc) override;
-  // used in dynamic xfa, dwFlags refer to XFA_INVALIDATE_XXX macros.
-  void InvalidateRect(CXFA_FFPageView* pPageView,
-                      const CFX_RectF& rt,
-                      uint32_t dwFlags) override;
-  // show or hide caret
+  // Used in dynamic xfa.
+  void InvalidateRect(CXFA_FFPageView* pPageView, const CFX_RectF& rt) override;
+  // Show or hide caret.
   void DisplayCaret(CXFA_FFWidget* hWidget,
                     bool bVisible,
                     const CFX_RectF* pRtAnchor) override;
   // dwPos: (0:bottom 1:top)
   bool GetPopupPos(CXFA_FFWidget* hWidget,
-                   FX_FLOAT fMinPopup,
-                   FX_FLOAT fMaxPopup,
+                   float fMinPopup,
+                   float fMaxPopup,
                    const CFX_RectF& rtAnchor,
                    CFX_RectF& rtPopup) override;
   bool PopupMenu(CXFA_FFWidget* hWidget, CFX_PointF ptPopup) override;
@@ -40,9 +39,9 @@
   // dwFlags XFA_PAGEVIEWEVENT_Added, XFA_PAGEVIEWEVENT_Removing
   void PageViewEvent(CXFA_FFPageView* pPageView, uint32_t dwFlags) override;
   void WidgetPostAdd(CXFA_FFWidget* hWidget,
-                     CXFA_WidgetAcc* pWidgetData) override;
+                     CXFA_WidgetAcc* pWidgetAcc) override;
   void WidgetPreRemove(CXFA_FFWidget* hWidget,
-                       CXFA_WidgetAcc* pWidgetData) override;
+                       CXFA_WidgetAcc* pWidgetAcc) override;
 
   // Host method
   int32_t CountPages(CXFA_FFDoc* hDoc) override;
@@ -50,12 +49,12 @@
   void SetCurrentPage(CXFA_FFDoc* hDoc, int32_t iCurPage) override;
   bool IsCalculationsEnabled(CXFA_FFDoc* hDoc) override;
   void SetCalculationsEnabled(CXFA_FFDoc* hDoc, bool bEnabled) override;
-  void GetTitle(CXFA_FFDoc* hDoc, CFX_WideString& wsTitle) override;
-  void SetTitle(CXFA_FFDoc* hDoc, const CFX_WideString& wsTitle) override;
+  void GetTitle(CXFA_FFDoc* hDoc, WideString& wsTitle) override;
+  void SetTitle(CXFA_FFDoc* hDoc, const WideString& wsTitle) override;
   void ExportData(CXFA_FFDoc* hDoc,
-                  const CFX_WideString& wsFilePath,
+                  const WideString& wsFilePath,
                   bool bXDP) override;
-  void GotoURL(CXFA_FFDoc* hDoc, const CFX_WideString& bsURL) override;
+  void GotoURL(CXFA_FFDoc* hDoc, const WideString& bsURL) override;
   bool IsValidationsEnabled(CXFA_FFDoc* hDoc) override;
   void SetValidationsEnabled(CXFA_FFDoc* hDoc, bool bEnabled) override;
   void SetFocusWidget(CXFA_FFDoc* hDoc, CXFA_FFWidget* hWidget) override;
@@ -65,50 +64,37 @@
              uint32_t dwOptions) override;
   FX_ARGB GetHighlightColor(CXFA_FFDoc* hDoc) override;
 
-  /**
-   *Submit data to email, http, ftp.
-   * @param[in] hDoc The document handler.
-   * @param[in] eFormat Determines the format in which the data will be
-   *submitted. XFA_ATTRIBUTEENUM_Xdp, XFA_ATTRIBUTEENUM_Xml...
-   * @param[in] wsTarget The URL to which the data will be submitted.
-   * @param[in] eEncoding The encoding of text content.
-   * @param[in] pXDPContent Controls what subset of the data is submitted, used
-   *only when the format property is xdp.
-   * @param[in] bEmbedPDF, specifies whether PDF is embedded in the submitted
-   *content or not.
-   */
-  bool SubmitData(CXFA_FFDoc* hDoc, CXFA_Submit submit) override;
+  bool Submit(CXFA_FFDoc* hDoc, CXFA_Submit* submit) override;
 
   bool GetGlobalProperty(CXFA_FFDoc* hDoc,
-                         const CFX_ByteStringC& szPropName,
+                         const ByteStringView& szPropName,
                          CFXJSE_Value* pValue) override;
   bool SetGlobalProperty(CXFA_FFDoc* hDoc,
-                         const CFX_ByteStringC& szPropName,
+                         const ByteStringView& szPropName,
                          CFXJSE_Value* pValue) override;
 
-  CFX_RetainPtr<IFX_SeekableReadStream> OpenLinkedFile(
+  RetainPtr<IFX_SeekableReadStream> OpenLinkedFile(
       CXFA_FFDoc* hDoc,
-      const CFX_WideString& wsLink) override;
+      const WideString& wsLink) override;
 
  private:
   bool OnBeforeNotifySubmit();
   void OnAfterNotifySubmit();
   bool NotifySubmit(bool bPrevOrPost);
-  bool SubmitDataInternal(CXFA_FFDoc* hDoc, CXFA_Submit submit);
-  bool MailToInfo(CFX_WideString& csURL,
-                  CFX_WideString& csToAddress,
-                  CFX_WideString& csCCAddress,
-                  CFX_WideString& csBCCAddress,
-                  CFX_WideString& csSubject,
-                  CFX_WideString& csMsg);
+  bool SubmitInternal(CXFA_FFDoc* hDoc, CXFA_Submit* submit);
+  bool MailToInfo(WideString& csURL,
+                  WideString& csToAddress,
+                  WideString& csCCAddress,
+                  WideString& csBCCAddress,
+                  WideString& csSubject,
+                  WideString& csMsg);
   bool ExportSubmitFile(FPDF_FILEHANDLER* ppFileHandler,
                         int fileType,
                         FPDF_DWORD encodeType,
                         FPDF_DWORD flag);
-  void ToXFAContentFlags(CFX_WideString csSrcContent, FPDF_DWORD& flag);
+  void ToXFAContentFlags(WideString csSrcContent, FPDF_DWORD& flag);
 
-  CPDFXFA_Context* const m_pContext;    // Not owned.
-  IJS_EventContext* m_pJSEventContext;  // Not owned.
+  UnownedPtr<CPDFXFA_Context> const m_pContext;
 };
 
 #endif  // FPDFSDK_FPDFXFA_CPDFXFA_DOCENVIRONMENT_H_
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_page.cpp b/fpdfsdk/fpdfxfa/cpdfxfa_page.cpp
index 8b5bb3d..fbea90d 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_page.cpp
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_page.cpp
@@ -13,19 +13,13 @@
 #include "fpdfsdk/fsdk_define.h"
 #include "public/fpdf_formfill.h"
 #include "third_party/base/ptr_util.h"
-#include "xfa/fxfa/xfa_ffdocview.h"
-#include "xfa/fxfa/xfa_ffpageview.h"
+#include "xfa/fxfa/cxfa_ffdocview.h"
+#include "xfa/fxfa/cxfa_ffpageview.h"
 
 CPDFXFA_Page::CPDFXFA_Page(CPDFXFA_Context* pContext, int page_index)
-    : m_pXFAPageView(nullptr),
-      m_pContext(pContext),
-      m_iPageIndex(page_index),
-      m_iRef(1) {}
+    : m_pXFAPageView(nullptr), m_pContext(pContext), m_iPageIndex(page_index) {}
 
-CPDFXFA_Page::~CPDFXFA_Page() {
-  if (m_pContext)
-    m_pContext->RemovePage(this);
-}
+CPDFXFA_Page::~CPDFXFA_Page() {}
 
 bool CPDFXFA_Page::LoadPDFPage() {
   if (!m_pContext)
@@ -70,18 +64,15 @@
   if (!m_pContext || m_iPageIndex < 0)
     return false;
 
-  int iDocType = m_pContext->GetDocType();
-  switch (iDocType) {
-    case DOCTYPE_PDF:
-    case DOCTYPE_STATIC_XFA: {
+  switch (m_pContext->GetFormType()) {
+    case FormType::kNone:
+    case FormType::kAcroForm:
+    case FormType::kXFAForeground:
       return LoadPDFPage();
-    }
-    case DOCTYPE_DYNAMIC_XFA: {
+    case FormType::kXFAFull:
       return LoadXFAPageView();
-    }
-    default:
-      return false;
   }
+  return false;
 }
 
 bool CPDFXFA_Page::LoadPDFPage(CPDF_Dictionary* pageDict) {
@@ -94,49 +85,37 @@
   return true;
 }
 
-FX_FLOAT CPDFXFA_Page::GetPageWidth() const {
+float CPDFXFA_Page::GetPageWidth() const {
   if (!m_pPDFPage && !m_pXFAPageView)
     return 0.0f;
 
-  int nDocType = m_pContext->GetDocType();
-  switch (nDocType) {
-    case DOCTYPE_DYNAMIC_XFA: {
-      if (m_pXFAPageView)
-        return m_pXFAPageView->GetPageViewRect().width;
-      break;
-    }
-    case DOCTYPE_STATIC_XFA:
-    case DOCTYPE_PDF: {
+  switch (m_pContext->GetFormType()) {
+    case FormType::kNone:
+    case FormType::kAcroForm:
+    case FormType::kXFAForeground:
       if (m_pPDFPage)
         return m_pPDFPage->GetPageWidth();
-      break;
-    }
-    default:
-      return 0.0f;
+    case FormType::kXFAFull:
+      if (m_pXFAPageView)
+        return m_pXFAPageView->GetPageViewRect().width;
   }
 
   return 0.0f;
 }
 
-FX_FLOAT CPDFXFA_Page::GetPageHeight() const {
+float CPDFXFA_Page::GetPageHeight() const {
   if (!m_pPDFPage && !m_pXFAPageView)
     return 0.0f;
 
-  int nDocType = m_pContext->GetDocType();
-  switch (nDocType) {
-    case DOCTYPE_PDF:
-    case DOCTYPE_STATIC_XFA: {
+  switch (m_pContext->GetFormType()) {
+    case FormType::kNone:
+    case FormType::kAcroForm:
+    case FormType::kXFAForeground:
       if (m_pPDFPage)
         return m_pPDFPage->GetPageHeight();
-      break;
-    }
-    case DOCTYPE_DYNAMIC_XFA: {
+    case FormType::kXFAFull:
       if (m_pXFAPageView)
         return m_pXFAPageView->GetPageViewRect().height;
-      break;
-    }
-    default:
-      return 0.0f;
   }
 
   return 0.0f;
@@ -154,12 +133,10 @@
   if (!m_pPDFPage && !m_pXFAPageView)
     return;
 
-  CFX_Matrix device2page;
-  device2page.SetReverse(
-      GetDisplayMatrix(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)));
+  CFX_PointF pos = GetDisplayMatrix(start_x, start_y, size_x, size_y, rotate)
+                       .GetInverse()
+                       .Transform(CFX_PointF(static_cast<float>(device_x),
+                                             static_cast<float>(device_y)));
 
   *page_x = pos.x;
   *page_y = pos.y;
@@ -181,7 +158,7 @@
       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)));
+      CFX_PointF(static_cast<float>(page_x), static_cast<float>(page_y)));
 
   *device_x = FXSYS_round(pos.x);
   *device_y = FXSYS_round(pos.y);
@@ -195,23 +172,17 @@
   if (!m_pPDFPage && !m_pXFAPageView)
     return CFX_Matrix();
 
-  int nDocType = m_pContext->GetDocType();
-  switch (nDocType) {
-    case DOCTYPE_DYNAMIC_XFA: {
-      if (m_pXFAPageView) {
-        return m_pXFAPageView->GetDisplayMatrix(
-            CFX_Rect(xPos, yPos, xSize, ySize), iRotate);
-      }
-      break;
-    }
-    case DOCTYPE_PDF:
-    case DOCTYPE_STATIC_XFA: {
+  switch (m_pContext->GetFormType()) {
+    case FormType::kNone:
+    case FormType::kAcroForm:
+    case FormType::kXFAForeground:
       if (m_pPDFPage)
         return m_pPDFPage->GetDisplayMatrix(xPos, yPos, xSize, ySize, iRotate);
-      break;
-    }
-    default:
-      return CFX_Matrix();
+    case FormType::kXFAFull:
+      if (m_pXFAPageView)
+        return m_pXFAPageView->GetDisplayMatrix(
+            CFX_Rect(xPos, yPos, xSize, ySize), iRotate);
   }
+
   return CFX_Matrix();
 }
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_page.h b/fpdfsdk/fpdfxfa/cpdfxfa_page.h
index 993885d..f64d66b 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_page.h
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_page.h
@@ -10,6 +10,8 @@
 #include <memory>
 
 #include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/retain_ptr.h"
+#include "core/fxcrt/unowned_ptr.h"
 
 class CFX_Matrix;
 class CPDFXFA_Context;
@@ -17,19 +19,14 @@
 class CPDF_Page;
 class CXFA_FFPageView;
 
-class CPDFXFA_Page {
+class CPDFXFA_Page : public Retainable {
  public:
-  CPDFXFA_Page(CPDFXFA_Context* pContext, int page_index);
-
-  void Retain() { m_iRef++; }
-  void Release() {
-    if (--m_iRef <= 0)
-      delete this;
-  }
+  template <typename T, typename... Args>
+  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
 
   bool LoadPage();
   bool LoadPDFPage(CPDF_Dictionary* pageDict);
-  CPDFXFA_Context* GetContext() const { return m_pContext; }
+  CPDFXFA_Context* GetContext() const { return m_pContext.Get(); }
   int GetPageIndex() const { return m_iPageIndex; }
   CPDF_Page* GetPDFPage() const { return m_pPDFPage.get(); }
   CXFA_FFPageView* GetXFAPageView() const { return m_pXFAPageView; }
@@ -38,8 +35,8 @@
     m_pXFAPageView = pPageView;
   }
 
-  FX_FLOAT GetPageWidth() const;
-  FX_FLOAT GetPageHeight() const;
+  float GetPageWidth() const;
+  float GetPageHeight() const;
 
   void DeviceToPage(int start_x,
                     int start_y,
@@ -68,7 +65,8 @@
 
  protected:
   // Refcounted class.
-  ~CPDFXFA_Page();
+  CPDFXFA_Page(CPDFXFA_Context* pContext, int page_index);
+  ~CPDFXFA_Page() override;
 
   bool LoadPDFPage();
   bool LoadXFAPageView();
@@ -76,9 +74,8 @@
  private:
   std::unique_ptr<CPDF_Page> m_pPDFPage;
   CXFA_FFPageView* m_pXFAPageView;
-  CPDFXFA_Context* const m_pContext;
+  UnownedPtr<CPDFXFA_Context> const m_pContext;
   const int m_iPageIndex;
-  int m_iRef;
 };
 
 #endif  // FPDFSDK_FPDFXFA_CPDFXFA_PAGE_H_
diff --git a/fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.cpp b/fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.cpp
index 39aa72b..c7201c3 100644
--- a/fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.cpp
+++ b/fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.cpp
@@ -29,6 +29,12 @@
 
 std::vector<CFWL_TimerInfo*>* CXFA_FWLAdapterTimerMgr::s_TimerArray = nullptr;
 
+CXFA_FWLAdapterTimerMgr::CXFA_FWLAdapterTimerMgr(
+    CPDFSDK_FormFillEnvironment* pFormFillEnv)
+    : m_pFormFillEnv(pFormFillEnv) {}
+
+CXFA_FWLAdapterTimerMgr::~CXFA_FWLAdapterTimerMgr() {}
+
 void CXFA_FWLAdapterTimerMgr::Start(CFWL_Timer* pTimer,
                                     uint32_t dwElapse,
                                     bool bImmediately,
@@ -66,7 +72,7 @@
   if (!s_TimerArray)
     return;
 
-  for (const auto info : *s_TimerArray) {
+  for (auto* info : *s_TimerArray) {
     CFWL_FWLAdapterTimerInfo* pInfo =
         static_cast<CFWL_FWLAdapterTimerInfo*>(info);
     if (pInfo->idEvent == idEvent) {
diff --git a/fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h b/fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h
index fdb5635..d763f02 100644
--- a/fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h
+++ b/fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h
@@ -10,14 +10,15 @@
 #include <memory>
 #include <vector>
 
+#include "core/fxcrt/unowned_ptr.h"
 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
 #include "xfa/fwl/cfwl_timerinfo.h"
 #include "xfa/fwl/ifwl_adaptertimermgr.h"
 
 class CXFA_FWLAdapterTimerMgr : public IFWL_AdapterTimerMgr {
  public:
-  explicit CXFA_FWLAdapterTimerMgr(CPDFSDK_FormFillEnvironment* pFormFillEnv)
-      : m_pFormFillEnv(pFormFillEnv) {}
+  explicit CXFA_FWLAdapterTimerMgr(CPDFSDK_FormFillEnvironment* pFormFillEnv);
+  ~CXFA_FWLAdapterTimerMgr();
 
   void Start(CFWL_Timer* pTimer,
              uint32_t dwElapse,
@@ -29,7 +30,7 @@
   static void TimerProc(int32_t idEvent);
 
   static std::vector<CFWL_TimerInfo*>* s_TimerArray;
-  CPDFSDK_FormFillEnvironment* const m_pFormFillEnv;
+  UnownedPtr<CPDFSDK_FormFillEnvironment> const m_pFormFillEnv;
 };
 
 #endif  // FPDFSDK_FPDFXFA_CXFA_FWLADAPTERTIMERMGR_H_
diff --git a/fpdfsdk/fsdk_actionhandler.cpp b/fpdfsdk/fsdk_actionhandler.cpp
index dc99f32..de5c931 100644
--- a/fpdfsdk/fsdk_actionhandler.cpp
+++ b/fpdfsdk/fsdk_actionhandler.cpp
@@ -7,6 +7,7 @@
 #include "fpdfsdk/fsdk_actionhandler.h"
 
 #include <set>
+#include <vector>
 
 #include "core/fpdfapi/parser/cpdf_array.h"
 #include "core/fpdfdoc/cpdf_formfield.h"
@@ -14,8 +15,9 @@
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 #include "fpdfsdk/cpdfsdk_interform.h"
 #include "fpdfsdk/fsdk_define.h"
-#include "fpdfsdk/javascript/ijs_event_context.h"
-#include "fpdfsdk/javascript/ijs_runtime.h"
+#include "fxjs/ijs_event_context.h"
+#include "fxjs/ijs_runtime.h"
+#include "third_party/base/logging.h"
 #include "third_party/base/stl_util.h"
 
 bool CPDFSDK_ActionHandler::DoAction_DocOpen(
@@ -27,10 +29,10 @@
 
 bool CPDFSDK_ActionHandler::DoAction_JavaScript(
     const CPDF_Action& JsAction,
-    CFX_WideString csJSName,
+    WideString csJSName,
     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
   if (JsAction.GetType() == CPDF_Action::JavaScript) {
-    CFX_WideString swJS = JsAction.GetJavaScript();
+    WideString swJS = JsAction.GetJavaScript();
     if (!swJS.IsEmpty()) {
       RunDocumentOpenJavaScript(pFormFillEnv, csJSName, swJS);
       return true;
@@ -49,7 +51,7 @@
   ASSERT(pFormFillEnv);
   if (pFormFillEnv->IsJSInitiated() &&
       JsAction.GetType() == CPDF_Action::JavaScript) {
-    CFX_WideString swJS = JsAction.GetJavaScript();
+    WideString swJS = JsAction.GetJavaScript();
     if (!swJS.IsEmpty()) {
       RunFieldJavaScript(pFormFillEnv, pFormField, type, data, swJS);
       return true;
@@ -123,7 +125,7 @@
   ASSERT(pFormFillEnv);
   if (action.GetType() == CPDF_Action::JavaScript) {
     if (pFormFillEnv->IsJSInitiated()) {
-      CFX_WideString swJS = action.GetJavaScript();
+      WideString swJS = action.GetJavaScript();
       if (!swJS.IsEmpty()) {
         RunDocumentOpenJavaScript(pFormFillEnv, L"", swJS);
       }
@@ -154,13 +156,13 @@
   ASSERT(pFormFillEnv);
   if (action.GetType() == CPDF_Action::JavaScript) {
     if (pFormFillEnv->IsJSInitiated()) {
-      CFX_WideString swJS = action.GetJavaScript();
+      WideString swJS = action.GetJavaScript();
       if (!swJS.IsEmpty()) {
         IJS_Runtime* pRuntime = pFormFillEnv->GetJSRuntime();
         IJS_EventContext* pContext = pRuntime->NewEventContext();
         pContext->OnLink_MouseUp(pFormFillEnv);
 
-        CFX_WideString csInfo;
+        WideString csInfo;
         bool bRet = pContext->RunScript(swJS, &csInfo);
         pRuntime->ReleaseEventContext(pContext);
         if (!bRet) {
@@ -195,7 +197,7 @@
   ASSERT(pFormFillEnv);
   if (action.GetType() == CPDF_Action::JavaScript) {
     if (pFormFillEnv->IsJSInitiated()) {
-      CFX_WideString swJS = action.GetJavaScript();
+      WideString swJS = action.GetJavaScript();
       if (!swJS.IsEmpty()) {
         RunDocumentPageJavaScript(pFormFillEnv, type, swJS);
       }
@@ -242,7 +244,7 @@
   ASSERT(pFormFillEnv);
   if (action.GetType() == CPDF_Action::JavaScript) {
     if (pFormFillEnv->IsJSInitiated()) {
-      CFX_WideString swJS = action.GetJavaScript();
+      WideString swJS = action.GetJavaScript();
       if (!swJS.IsEmpty()) {
         RunFieldJavaScript(pFormFillEnv, pFormField, type, data, swJS);
         if (!IsValidField(pFormFillEnv, pFormField->GetFieldDict()))
@@ -278,11 +280,11 @@
   ASSERT(pFormFillEnv);
   if (action.GetType() == CPDF_Action::JavaScript) {
     if (pFormFillEnv->IsJSInitiated()) {
-      CFX_WideString swJS = action.GetJavaScript();
+      WideString swJS = action.GetJavaScript();
       if (!swJS.IsEmpty()) {
         IJS_Runtime* pRuntime = pFormFillEnv->GetJSRuntime();
         IJS_EventContext* pContext = pRuntime->NewEventContext();
-        CFX_WideString csInfo;
+        WideString csInfo;
         bool bRet = pContext->RunScript(swJS, &csInfo);
         pRuntime->ReleaseEventContext(pContext);
         if (!bRet) {
@@ -317,13 +319,13 @@
   ASSERT(pFormFillEnv);
   if (action.GetType() == CPDF_Action::JavaScript) {
     if (pFormFillEnv->IsJSInitiated()) {
-      CFX_WideString swJS = action.GetJavaScript();
+      WideString swJS = action.GetJavaScript();
       if (!swJS.IsEmpty()) {
         IJS_Runtime* pRuntime = pFormFillEnv->GetJSRuntime();
         IJS_EventContext* pContext = pRuntime->NewEventContext();
         pContext->OnBookmark_MouseUp(pBookmark);
 
-        CFX_WideString csInfo;
+        WideString csInfo;
         bool bRet = pContext->RunScript(swJS, &csInfo);
         pRuntime->ReleaseEventContext(pContext);
         if (!bRet) {
@@ -386,7 +388,7 @@
       DoAction_ImportData(action, pFormFillEnv);
       break;
     case CPDF_Action::JavaScript:
-      ASSERT(false);
+      NOTREACHED();
       break;
     case CPDF_Action::SetOCGState:
       DoAction_SetOCGState(pFormFillEnv, action);
@@ -420,19 +422,13 @@
   int nPageIndex = MyDest.GetPageIndex(pPDFDocument);
   int nFitType = MyDest.GetZoomMode();
   const CPDF_Array* pMyArray = ToArray(MyDest.GetObject());
-  float* pPosAry = nullptr;
-  int sizeOfAry = 0;
+  std::vector<float> posArray;
   if (pMyArray) {
-    pPosAry = new float[pMyArray->GetCount()];
-    int j = 0;
-    for (size_t i = 2; i < pMyArray->GetCount(); i++) {
-      pPosAry[j++] = pMyArray->GetFloatAt(i);
-    }
-    sizeOfAry = j;
+    for (size_t i = 2; i < pMyArray->GetCount(); i++)
+      posArray.push_back(pMyArray->GetFloatAt(i));
   }
-
-  pFormFillEnv->DoGoToAction(nPageIndex, nFitType, pPosAry, sizeOfAry);
-  delete[] pPosAry;
+  pFormFillEnv->DoGoToAction(nPageIndex, nFitType, posArray.data(),
+                             posArray.size());
 }
 
 void CPDFSDK_ActionHandler::DoAction_GoToR(
@@ -448,7 +444,7 @@
     const CPDF_Action& action) {
   ASSERT(action.GetDict());
 
-  CFX_ByteString sURI = action.GetURI(pFormFillEnv->GetPDFDocument());
+  ByteString sURI = action.GetURI(pFormFillEnv->GetPDFDocument());
   pFormFillEnv->DoURIAction(sURI.c_str());
 }
 
@@ -457,7 +453,7 @@
     const CPDF_Action& action) {
   ASSERT(action.GetDict());
 
-  CFX_ByteString csName = action.GetNamedAction();
+  ByteString csName = action.GetNamedAction();
   pFormFillEnv->ExecuteNamedAction(csName.c_str());
 }
 
@@ -470,7 +466,7 @@
     CPDF_FormField* pFormField,
     CPDF_AAction::AActionType type,
     PDFSDK_FieldAction& data,
-    const CFX_WideString& script) {
+    const WideString& script) {
   ASSERT(type != CPDF_AAction::Calculate);
   ASSERT(type != CPDF_AAction::Format);
 
@@ -509,11 +505,11 @@
                                  data.sValue, data.bRC);
       break;
     default:
-      ASSERT(false);
+      NOTREACHED();
       break;
   }
 
-  CFX_WideString csInfo;
+  WideString csInfo;
   bool bRet = pContext->RunScript(script, &csInfo);
   pRuntime->ReleaseEventContext(pContext);
   if (!bRet) {
@@ -523,13 +519,13 @@
 
 void CPDFSDK_ActionHandler::RunDocumentOpenJavaScript(
     CPDFSDK_FormFillEnvironment* pFormFillEnv,
-    const CFX_WideString& sScriptName,
-    const CFX_WideString& script) {
+    const WideString& sScriptName,
+    const WideString& script) {
   IJS_Runtime* pRuntime = pFormFillEnv->GetJSRuntime();
   IJS_EventContext* pContext = pRuntime->NewEventContext();
   pContext->OnDoc_Open(pFormFillEnv, sScriptName);
 
-  CFX_WideString csInfo;
+  WideString csInfo;
   bool bRet = pContext->RunScript(script, &csInfo);
   pRuntime->ReleaseEventContext(pContext);
   if (!bRet) {
@@ -540,7 +536,7 @@
 void CPDFSDK_ActionHandler::RunDocumentPageJavaScript(
     CPDFSDK_FormFillEnvironment* pFormFillEnv,
     CPDF_AAction::AActionType type,
-    const CFX_WideString& script) {
+    const WideString& script) {
   IJS_Runtime* pRuntime = pFormFillEnv->GetJSRuntime();
   IJS_EventContext* pContext = pRuntime->NewEventContext();
   switch (type) {
@@ -572,11 +568,11 @@
       pContext->OnPage_OutView(pFormFillEnv);
       break;
     default:
-      ASSERT(false);
+      NOTREACHED();
       break;
   }
 
-  CFX_WideString csInfo;
+  WideString csInfo;
   bool bRet = pContext->RunScript(script, &csInfo);
   pRuntime->ReleaseEventContext(pContext);
   if (!bRet) {
diff --git a/fpdfsdk/fsdk_actionhandler.h b/fpdfsdk/fsdk_actionhandler.h
index 1c8dede..7457b4e 100644
--- a/fpdfsdk/fsdk_actionhandler.h
+++ b/fpdfsdk/fsdk_actionhandler.h
@@ -26,7 +26,7 @@
   bool DoAction_DocOpen(const CPDF_Action& action,
                         CPDFSDK_FormFillEnvironment* pFormFillEnv);
   bool DoAction_JavaScript(const CPDF_Action& JsAction,
-                           CFX_WideString csJSName,
+                           WideString csJSName,
                            CPDFSDK_FormFillEnvironment* pFormFillEnv);
   bool DoAction_Page(const CPDF_Action& action,
                      enum CPDF_AAction::AActionType eType,
@@ -86,15 +86,15 @@
                      CPDFSDK_FormFillEnvironment* pFormFillEnv);
   void RunDocumentPageJavaScript(CPDFSDK_FormFillEnvironment* pFormFillEnv,
                                  CPDF_AAction::AActionType type,
-                                 const CFX_WideString& script);
+                                 const WideString& script);
   void RunDocumentOpenJavaScript(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                 const CFX_WideString& sScriptName,
-                                 const CFX_WideString& script);
+                                 const WideString& sScriptName,
+                                 const WideString& script);
   void RunFieldJavaScript(CPDFSDK_FormFillEnvironment* pFormFillEnv,
                           CPDF_FormField* pFormField,
                           CPDF_AAction::AActionType type,
                           PDFSDK_FieldAction& data,
-                          const CFX_WideString& script);
+                          const WideString& script);
 
   bool IsValidField(CPDFSDK_FormFillEnvironment* pFormFillEnv,
                     CPDF_Dictionary* pFieldDict);
diff --git a/fpdfsdk/fsdk_common.h b/fpdfsdk/fsdk_common.h
index d803026..78ecd98 100644
--- a/fpdfsdk/fsdk_common.h
+++ b/fpdfsdk/fsdk_common.h
@@ -10,7 +10,6 @@
 // for all fields
 #define FIELDFLAG_READONLY 1
 #define FIELDFLAG_REQUIRED 2
-#define FIELDFLAG_NOEXPORT 4
 // for text fields
 #define FIELDFLAG_MULTILINE (1 << 12)
 #define FIELDFLAG_PASSWORD (1 << 13)
@@ -20,14 +19,9 @@
 #define FIELDFLAG_COMB (1 << 24)
 #define FIELDFLAG_RICHTEXT (1 << 25)
 // for button fileds
-#define FIELDFLAG_NOTOGGLETOOFF (1 << 14)
-#define FIELDFLAG_RADIO (1 << 15)
-#define FIELDFLAG_PUSHBUTTON (1 << 16)
 #define FIELDFLAG_RADIOSINUNISON (1 << 27)
 // for choice fields
-#define FIELDFLAG_COMBO (1 << 17)
 #define FIELDFLAG_EDIT (1 << 18)
-#define FIELDFLAG_SORT (1 << 19)
 #define FIELDFLAG_MULTISELECT (1 << 21)
 #define FIELDFLAG_COMMITONSELCHANGE (1 << 26)
 
diff --git a/fpdfsdk/fsdk_define.h b/fpdfsdk/fsdk_define.h
index 9a11596..77c2315 100644
--- a/fpdfsdk/fsdk_define.h
+++ b/fpdfsdk/fsdk_define.h
@@ -8,6 +8,7 @@
 #define FPDFSDK_FSDK_DEFINE_H_
 
 #include "core/fpdfapi/parser/cpdf_parser.h"
+#include "core/fxge/dib/cfx_dibitmap.h"
 #include "core/fxge/fx_dib.h"
 #include "public/fpdfview.h"
 
@@ -22,18 +23,22 @@
 
 class CPDF_Annot;
 class CPDF_Page;
+class CPDF_PageObject;
 class CPDF_PageRenderContext;
+class CPDF_PathObject;
+class CPDF_Stream;
 class IFSDK_PAUSE_Adapter;
+class FX_PATHPOINT;
 
 // Layering prevents fxcrt from knowing about FPDF_FILEACCESS, so this can't
 // be a static method of IFX_SeekableReadStream.
-CFX_RetainPtr<IFX_SeekableReadStream> MakeSeekableReadStream(
+RetainPtr<IFX_SeekableReadStream> MakeSeekableReadStream(
     FPDF_FILEACCESS* pFileAccess);
 
 #ifdef PDF_ENABLE_XFA
 // Layering prevents fxcrt from knowing about FPDF_FILEHANDLER, so this can't
 // be a static method of IFX_SeekableStream.
-CFX_RetainPtr<IFX_SeekableStream> MakeSeekableStream(
+RetainPtr<IFX_SeekableStream> MakeSeekableStream(
     FPDF_FILEHANDLER* pFileHandler);
 #endif  // PDF_ENABLE_XFA
 
@@ -60,8 +65,29 @@
 
 CPDF_Page* CPDFPageFromFPDFPage(FPDF_PAGE page);
 
+CPDF_PathObject* CPDFPathObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object);
+
+CPDF_PageObject* CPDFPageObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object);
+
+CPDF_Object* CPDFObjectFromFPDFAttachment(FPDF_ATTACHMENT attachment);
+
+ByteString CFXByteStringFromFPDFWideString(FPDF_WIDESTRING wide_string);
+
 CFX_DIBitmap* CFXBitmapFromFPDFBitmap(FPDF_BITMAP bitmap);
 
+CFX_FloatRect CFXFloatRectFromFSRECTF(const FS_RECTF& rect);
+void FSRECTFFromCFXFloatRect(const CFX_FloatRect& rect, FS_RECTF* out_rect);
+
+const FX_PATHPOINT* FXPathPointFromFPDFPathSegment(FPDF_PATHSEGMENT segment);
+
+unsigned long Utf16EncodeMaybeCopyAndReturnLength(const WideString& text,
+                                                  void* buffer,
+                                                  unsigned long buflen);
+
+unsigned long DecodeStreamMaybeCopyAndReturnLength(const CPDF_Stream* stream,
+                                                   void* buffer,
+                                                   unsigned long buflen);
+
 void FSDK_SetSandBoxPolicy(FPDF_DWORD policy, FPDF_BOOL enable);
 FPDF_BOOL FSDK_IsSandBoxPolicyEnabled(FPDF_DWORD policy);
 void FPDF_RenderPage_Retail(CPDF_PageRenderContext* pContext,
@@ -78,5 +104,10 @@
 void CheckUnSupportError(CPDF_Document* pDoc, uint32_t err_code);
 void CheckUnSupportAnnot(CPDF_Document* pDoc, const CPDF_Annot* pPDFAnnot);
 void ProcessParseError(CPDF_Parser::Error err);
+FPDF_BOOL FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object,
+                                   unsigned int R,
+                                   unsigned int G,
+                                   unsigned int B,
+                                   unsigned int A);
 
 #endif  // FPDFSDK_FSDK_DEFINE_H_
diff --git a/fpdfsdk/fsdk_filewriteadapter.cpp b/fpdfsdk/fsdk_filewriteadapter.cpp
new file mode 100644
index 0000000..fad058f
--- /dev/null
+++ b/fpdfsdk/fsdk_filewriteadapter.cpp
@@ -0,0 +1,22 @@
+// 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/fsdk_filewriteadapter.h"
+
+FSDK_FileWriteAdapter::FSDK_FileWriteAdapter(FPDF_FILEWRITE* fileWriteStruct)
+    : fileWriteStruct_(fileWriteStruct) {
+  ASSERT(fileWriteStruct_);
+}
+
+FSDK_FileWriteAdapter::~FSDK_FileWriteAdapter() {}
+
+bool FSDK_FileWriteAdapter::WriteBlock(const void* data, size_t size) {
+  return fileWriteStruct_->WriteBlock(fileWriteStruct_, data, size) != 0;
+}
+
+bool FSDK_FileWriteAdapter::WriteString(const ByteStringView& str) {
+  return WriteBlock(str.unterminated_c_str(), str.GetLength());
+}
diff --git a/fpdfsdk/fsdk_filewriteadapter.h b/fpdfsdk/fsdk_filewriteadapter.h
new file mode 100644
index 0000000..6bba1da
--- /dev/null
+++ b/fpdfsdk/fsdk_filewriteadapter.h
@@ -0,0 +1,29 @@
+// 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_FSDK_FILEWRITEADAPTER_H_
+#define FPDFSDK_FSDK_FILEWRITEADAPTER_H_
+
+#include "core/fxcrt/fx_stream.h"
+#include "core/fxcrt/retain_ptr.h"
+#include "public/fpdf_save.h"
+
+class FSDK_FileWriteAdapter : public IFX_WriteStream {
+ public:
+  template <typename T, typename... Args>
+  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
+
+  bool WriteBlock(const void* data, size_t size) override;
+  bool WriteString(const ByteStringView& str) override;
+
+ private:
+  explicit FSDK_FileWriteAdapter(FPDF_FILEWRITE* fileWriteStruct);
+  ~FSDK_FileWriteAdapter() override;
+
+  FPDF_FILEWRITE* fileWriteStruct_;
+};
+
+#endif  // FPDFSDK_FSDK_FILEWRITEADAPTER_H_
diff --git a/fpdfsdk/fsdk_pauseadapter.cpp b/fpdfsdk/fsdk_pauseadapter.cpp
index 237266b..cf99253 100644
--- a/fpdfsdk/fsdk_pauseadapter.cpp
+++ b/fpdfsdk/fsdk_pauseadapter.cpp
@@ -12,5 +12,5 @@
 IFSDK_PAUSE_Adapter::~IFSDK_PAUSE_Adapter() {}
 
 bool IFSDK_PAUSE_Adapter::NeedToPauseNow() {
-  return m_IPause->NeedToPauseNow && m_IPause->NeedToPauseNow(m_IPause);
+  return m_IPause->NeedToPauseNow && m_IPause->NeedToPauseNow(m_IPause.Get());
 }
diff --git a/fpdfsdk/fsdk_pauseadapter.h b/fpdfsdk/fsdk_pauseadapter.h
index bd302f2..a0d0098 100644
--- a/fpdfsdk/fsdk_pauseadapter.h
+++ b/fpdfsdk/fsdk_pauseadapter.h
@@ -7,11 +7,12 @@
 #ifndef FPDFSDK_FSDK_PAUSEADAPTER_H_
 #define FPDFSDK_FSDK_PAUSEADAPTER_H_
 
-#include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/ifx_pauseindicator.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "public/fpdf_progressive.h"
 
-class IFSDK_PAUSE_Adapter : public IFX_Pause {
+class IFSDK_PAUSE_Adapter : public IFX_PauseIndicator {
  public:
   explicit IFSDK_PAUSE_Adapter(IFSDK_PAUSE* IPause);
   ~IFSDK_PAUSE_Adapter() override;
@@ -19,7 +20,7 @@
   bool NeedToPauseNow() override;
 
  private:
-  IFSDK_PAUSE* const m_IPause;
+  UnownedPtr<IFSDK_PAUSE> const m_IPause;
 };
 
 #endif  // FPDFSDK_FSDK_PAUSEADAPTER_H_
diff --git a/fpdfsdk/fxedit/fx_edit.h b/fpdfsdk/fxedit/fx_edit.h
deleted file mode 100644
index 6c91667..0000000
--- a/fpdfsdk/fxedit/fx_edit.h
+++ /dev/null
@@ -1,23 +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 FPDFSDK_FXEDIT_FX_EDIT_H_
-#define FPDFSDK_FXEDIT_FX_EDIT_H_
-
-#include "core/fxcrt/fx_basic.h"
-
-class IPVT_FontMap;
-
-#define FX_EDIT_ISLATINWORD(u)                  \
-  (u == 0x2D || (u <= 0x005A && u >= 0x0041) || \
-   (u <= 0x007A && u >= 0x0061) || (u <= 0x02AF && u >= 0x00C0))
-
-CFX_ByteString GetPDFWordString(IPVT_FontMap* pFontMap,
-                                int32_t nFontIndex,
-                                uint16_t Word,
-                                uint16_t SubWord);
-
-#endif  // FPDFSDK_FXEDIT_FX_EDIT_H_
diff --git a/fpdfsdk/fxedit/fxet_ap.cpp b/fpdfsdk/fxedit/fxet_ap.cpp
deleted file mode 100644
index 448a539..0000000
--- a/fpdfsdk/fxedit/fxet_ap.cpp
+++ /dev/null
@@ -1,38 +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 "core/fpdfapi/font/cpdf_font.h"
-#include "core/fpdfapi/parser/fpdf_parser_decode.h"
-#include "core/fpdfdoc/cpvt_word.h"
-#include "core/fpdfdoc/ipvt_fontmap.h"
-#include "fpdfsdk/fxedit/fx_edit.h"
-#include "fpdfsdk/fxedit/fxet_edit.h"
-
-CFX_ByteString GetPDFWordString(IPVT_FontMap* pFontMap,
-                                int32_t nFontIndex,
-                                uint16_t Word,
-                                uint16_t SubWord) {
-  CPDF_Font* pPDFFont = pFontMap->GetPDFFont(nFontIndex);
-  if (!pPDFFont)
-    return CFX_ByteString();
-
-  CFX_ByteString sWord;
-  if (SubWord > 0) {
-    Word = SubWord;
-  } else {
-    uint32_t dwCharCode = pPDFFont->IsUnicodeCompatible()
-                              ? pPDFFont->CharCodeFromUnicode(Word)
-                              : pFontMap->CharCodeFromUnicode(nFontIndex, Word);
-
-    if (dwCharCode > 0) {
-      pPDFFont->AppendChar(sWord, dwCharCode);
-      return sWord;
-    }
-  }
-
-  pPDFFont->AppendChar(sWord, Word);
-  return sWord;
-}
diff --git a/fpdfsdk/fxedit/fxet_edit.cpp b/fpdfsdk/fxedit/fxet_edit.cpp
deleted file mode 100644
index 1acc577..0000000
--- a/fpdfsdk/fxedit/fxet_edit.cpp
+++ /dev/null
@@ -1,2307 +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/fxedit/fxet_edit.h"
-
-#include <algorithm>
-#include <memory>
-#include <utility>
-
-#include "core/fpdfapi/font/cpdf_font.h"
-#include "core/fpdfapi/page/cpdf_pageobject.h"
-#include "core/fpdfapi/page/cpdf_pageobjectholder.h"
-#include "core/fpdfapi/page/cpdf_pathobject.h"
-#include "core/fpdfapi/page/cpdf_textobject.h"
-#include "core/fpdfapi/parser/fpdf_parser_decode.h"
-#include "core/fpdfapi/render/cpdf_renderoptions.h"
-#include "core/fpdfapi/render/cpdf_textrenderer.h"
-#include "core/fpdfdoc/cpvt_section.h"
-#include "core/fpdfdoc/cpvt_word.h"
-#include "core/fpdfdoc/ipvt_fontmap.h"
-#include "core/fxge/cfx_graphstatedata.h"
-#include "core/fxge/cfx_pathdata.h"
-#include "core/fxge/cfx_renderdevice.h"
-#include "fpdfsdk/cfx_systemhandler.h"
-#include "fpdfsdk/fxedit/fx_edit.h"
-#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 {
-
-const int kEditUndoMaxItems = 10000;
-
-CFX_ByteString GetWordRenderString(const CFX_ByteString& strWords) {
-  if (strWords.GetLength() > 0)
-    return PDF_EncodeString(strWords) + " Tj\n";
-  return CFX_ByteString();
-}
-
-CFX_ByteString GetFontSetString(IPVT_FontMap* pFontMap,
-                                int32_t nFontIndex,
-                                FX_FLOAT fFontSize) {
-  if (!pFontMap)
-    return CFX_ByteString();
-
-  CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex);
-  if (sFontAlias.GetLength() <= 0 || fFontSize <= 0)
-    return CFX_ByteString();
-
-  CFX_ByteTextBuf sRet;
-  sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n";
-  return sRet.MakeString();
-}
-
-void DrawTextString(CFX_RenderDevice* pDevice,
-                    const CFX_PointF& pt,
-                    CPDF_Font* pFont,
-                    FX_FLOAT fFontSize,
-                    CFX_Matrix* pUser2Device,
-                    const CFX_ByteString& str,
-                    FX_ARGB crTextFill,
-                    int32_t nHorzScale) {
-  CFX_PointF pos = pUser2Device->Transform(pt);
-
-  if (pFont) {
-    if (nHorzScale != 100) {
-      CFX_Matrix mt(nHorzScale / 100.0f, 0, 0, 1, 0, 0);
-      mt.Concat(*pUser2Device);
-
-      CPDF_RenderOptions ro;
-      ro.m_Flags = RENDER_CLEARTYPE;
-      ro.m_ColorMode = RENDER_COLOR_NORMAL;
-
-      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;
-
-      CPDF_TextRenderer::DrawTextString(pDevice, pos.x, pos.y, pFont, fFontSize,
-                                        pUser2Device, str, crTextFill, nullptr,
-                                        &ro);
-    }
-  }
-}
-
-}  // namespace
-
-CFX_Edit_Iterator::CFX_Edit_Iterator(CFX_Edit* pEdit,
-                                     CPDF_VariableText::Iterator* pVTIterator)
-    : m_pEdit(pEdit), m_pVTIterator(pVTIterator) {}
-
-CFX_Edit_Iterator::~CFX_Edit_Iterator() {}
-
-bool CFX_Edit_Iterator::NextWord() {
-  return m_pVTIterator->NextWord();
-}
-
-bool CFX_Edit_Iterator::PrevWord() {
-  return m_pVTIterator->PrevWord();
-}
-
-bool CFX_Edit_Iterator::GetWord(CPVT_Word& word) const {
-  ASSERT(m_pEdit);
-
-  if (m_pVTIterator->GetWord(word)) {
-    word.ptWord = m_pEdit->VTToEdit(word.ptWord);
-    return true;
-  }
-  return false;
-}
-
-bool CFX_Edit_Iterator::GetLine(CPVT_Line& line) const {
-  ASSERT(m_pEdit);
-
-  if (m_pVTIterator->GetLine(line)) {
-    line.ptLine = m_pEdit->VTToEdit(line.ptLine);
-    return true;
-  }
-  return false;
-}
-
-bool CFX_Edit_Iterator::GetSection(CPVT_Section& section) const {
-  ASSERT(m_pEdit);
-
-  if (m_pVTIterator->GetSection(section)) {
-    section.rcSection = m_pEdit->VTToEdit(section.rcSection);
-    return true;
-  }
-  return false;
-}
-
-void CFX_Edit_Iterator::SetAt(int32_t nWordIndex) {
-  m_pVTIterator->SetAt(nWordIndex);
-}
-
-void CFX_Edit_Iterator::SetAt(const CPVT_WordPlace& place) {
-  m_pVTIterator->SetAt(place);
-}
-
-const CPVT_WordPlace& CFX_Edit_Iterator::GetAt() const {
-  return m_pVTIterator->GetAt();
-}
-
-CFX_Edit_Provider::CFX_Edit_Provider(IPVT_FontMap* pFontMap)
-    : CPDF_VariableText::Provider(pFontMap), m_pFontMap(pFontMap) {
-  ASSERT(m_pFontMap);
-}
-
-CFX_Edit_Provider::~CFX_Edit_Provider() {}
-
-IPVT_FontMap* CFX_Edit_Provider::GetFontMap() {
-  return m_pFontMap;
-}
-
-int32_t CFX_Edit_Provider::GetCharWidth(int32_t nFontIndex, uint16_t word) {
-  if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) {
-    uint32_t charcode = word;
-
-    if (pPDFFont->IsUnicodeCompatible())
-      charcode = pPDFFont->CharCodeFromUnicode(word);
-    else
-      charcode = m_pFontMap->CharCodeFromUnicode(nFontIndex, word);
-
-    if (charcode != CPDF_Font::kInvalidCharCode)
-      return pPDFFont->GetCharWidthF(charcode);
-  }
-
-  return 0;
-}
-
-int32_t CFX_Edit_Provider::GetTypeAscent(int32_t nFontIndex) {
-  if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex))
-    return pPDFFont->GetTypeAscent();
-
-  return 0;
-}
-
-int32_t CFX_Edit_Provider::GetTypeDescent(int32_t nFontIndex) {
-  if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex))
-    return pPDFFont->GetTypeDescent();
-
-  return 0;
-}
-
-int32_t CFX_Edit_Provider::GetWordFontIndex(uint16_t word,
-                                            int32_t charset,
-                                            int32_t nFontIndex) {
-  return m_pFontMap->GetWordFontIndex(word, charset, nFontIndex);
-}
-
-int32_t CFX_Edit_Provider::GetDefaultFontIndex() {
-  return 0;
-}
-
-bool CFX_Edit_Provider::IsLatinWord(uint16_t word) {
-  return FX_EDIT_ISLATINWORD(word);
-}
-
-CFX_Edit_Refresh::CFX_Edit_Refresh() {}
-
-CFX_Edit_Refresh::~CFX_Edit_Refresh() {}
-
-void CFX_Edit_Refresh::BeginRefresh() {
-  m_RefreshRects.Clear();
-  m_OldLineRects = std::move(m_NewLineRects);
-}
-
-void CFX_Edit_Refresh::Push(const CPVT_WordRange& linerange,
-                            const CFX_FloatRect& rect) {
-  m_NewLineRects.Add(linerange, rect);
-}
-
-void CFX_Edit_Refresh::NoAnalyse() {
-  {
-    for (int32_t i = 0, sz = m_OldLineRects.GetSize(); i < sz; i++)
-      if (CFX_Edit_LineRect* pOldRect = m_OldLineRects.GetAt(i))
-        m_RefreshRects.Add(pOldRect->m_rcLine);
-  }
-
-  {
-    for (int32_t i = 0, sz = m_NewLineRects.GetSize(); i < sz; i++)
-      if (CFX_Edit_LineRect* pNewRect = m_NewLineRects.GetAt(i))
-        m_RefreshRects.Add(pNewRect->m_rcLine);
-  }
-}
-
-void CFX_Edit_Refresh::AddRefresh(const CFX_FloatRect& rect) {
-  m_RefreshRects.Add(rect);
-}
-
-const CFX_Edit_RectArray* CFX_Edit_Refresh::GetRefreshRects() const {
-  return &m_RefreshRects;
-}
-
-void CFX_Edit_Refresh::EndRefresh() {
-  m_RefreshRects.Clear();
-}
-
-CFX_Edit_Undo::CFX_Edit_Undo(int32_t nBufsize)
-    : m_nCurUndoPos(0),
-      m_nBufSize(nBufsize),
-      m_bModified(false),
-      m_bVirgin(true),
-      m_bWorking(false) {}
-
-CFX_Edit_Undo::~CFX_Edit_Undo() {
-  Reset();
-}
-
-bool CFX_Edit_Undo::CanUndo() const {
-  return m_nCurUndoPos > 0;
-}
-
-void CFX_Edit_Undo::Undo() {
-  m_bWorking = true;
-  if (m_nCurUndoPos > 0) {
-    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.size();
-}
-
-void CFX_Edit_Undo::Redo() {
-  m_bWorking = true;
-  if (m_nCurUndoPos < m_UndoItemStack.size()) {
-    m_UndoItemStack[m_nCurUndoPos]->Redo();
-    m_nCurUndoPos++;
-    m_bModified = true;
-  }
-  m_bWorking = false;
-}
-
-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.size())
-    RemoveTails();
-
-  if (m_UndoItemStack.size() >= m_nBufSize) {
-    RemoveHeads();
-    m_bVirgin = false;
-  }
-
-  m_UndoItemStack.push_back(std::move(pItem));
-  m_nCurUndoPos = m_UndoItemStack.size();
-  m_bModified = true;
-}
-
-bool CFX_Edit_Undo::IsModified() const {
-  return m_bVirgin ? m_bModified : true;
-}
-
-void CFX_Edit_Undo::RemoveHeads() {
-  ASSERT(m_UndoItemStack.size() > 1);
-  m_UndoItemStack.pop_front();
-}
-
-void CFX_Edit_Undo::RemoveTails() {
-  while (m_UndoItemStack.size() > m_nCurUndoPos)
-    m_UndoItemStack.pop_back();
-}
-
-void CFX_Edit_Undo::Reset() {
-  m_UndoItemStack.clear();
-  m_nCurUndoPos = 0;
-}
-
-CFX_Edit_UndoItem::CFX_Edit_UndoItem() : m_bFirst(true), m_bLast(true) {}
-
-CFX_Edit_UndoItem::~CFX_Edit_UndoItem() {}
-
-CFX_WideString CFX_Edit_UndoItem::GetUndoTitle() const {
-  return CFX_WideString();
-}
-
-void CFX_Edit_UndoItem::SetFirst(bool bFirst) {
-  m_bFirst = bFirst;
-}
-
-void CFX_Edit_UndoItem::SetLast(bool bLast) {
-  m_bLast = bLast;
-}
-
-bool CFX_Edit_UndoItem::IsLast() {
-  return m_bLast;
-}
-
-CFX_Edit_GroupUndoItem::CFX_Edit_GroupUndoItem(const CFX_WideString& sTitle)
-    : m_sTitle(sTitle) {}
-
-CFX_Edit_GroupUndoItem::~CFX_Edit_GroupUndoItem() {}
-
-void CFX_Edit_GroupUndoItem::AddUndoItem(
-    std::unique_ptr<CFX_Edit_UndoItem> pUndoItem) {
-  pUndoItem->SetFirst(false);
-  pUndoItem->SetLast(false);
-  if (m_sTitle.IsEmpty())
-    m_sTitle = pUndoItem->GetUndoTitle();
-
-  m_Items.push_back(std::move(pUndoItem));
-}
-
-void CFX_Edit_GroupUndoItem::UpdateItems() {
-  if (!m_Items.empty()) {
-    m_Items.front()->SetFirst(true);
-    m_Items.back()->SetLast(true);
-  }
-}
-
-void CFX_Edit_GroupUndoItem::Undo() {
-  for (auto iter = m_Items.rbegin(); iter != m_Items.rend(); ++iter)
-    (*iter)->Undo();
-}
-
-void CFX_Edit_GroupUndoItem::Redo() {
-  for (auto iter = m_Items.begin(); iter != m_Items.end(); ++iter)
-    (*iter)->Redo();
-}
-
-CFX_WideString CFX_Edit_GroupUndoItem::GetUndoTitle() const {
-  return m_sTitle;
-}
-
-CFXEU_InsertWord::CFXEU_InsertWord(CFX_Edit* pEdit,
-                                   const CPVT_WordPlace& wpOldPlace,
-                                   const CPVT_WordPlace& wpNewPlace,
-                                   uint16_t word,
-                                   int32_t charset,
-                                   const CPVT_WordProps* pWordProps)
-    : m_pEdit(pEdit),
-      m_wpOld(wpOldPlace),
-      m_wpNew(wpNewPlace),
-      m_Word(word),
-      m_nCharset(charset),
-      m_WordProps() {
-  if (pWordProps)
-    m_WordProps = *pWordProps;
-}
-
-CFXEU_InsertWord::~CFXEU_InsertWord() {}
-
-void CFXEU_InsertWord::Redo() {
-  if (m_pEdit) {
-    m_pEdit->SelectNone();
-    m_pEdit->SetCaret(m_wpOld);
-    m_pEdit->InsertWord(m_Word, m_nCharset, &m_WordProps, false, true);
-  }
-}
-
-void CFXEU_InsertWord::Undo() {
-  if (m_pEdit) {
-    m_pEdit->SelectNone();
-    m_pEdit->SetCaret(m_wpNew);
-    m_pEdit->Backspace(false, true);
-  }
-}
-
-CFXEU_InsertReturn::CFXEU_InsertReturn(CFX_Edit* pEdit,
-                                       const CPVT_WordPlace& wpOldPlace,
-                                       const CPVT_WordPlace& wpNewPlace,
-                                       const CPVT_SecProps* pSecProps,
-                                       const CPVT_WordProps* pWordProps)
-    : m_pEdit(pEdit),
-      m_wpOld(wpOldPlace),
-      m_wpNew(wpNewPlace),
-      m_SecProps(),
-      m_WordProps() {
-  if (pSecProps)
-    m_SecProps = *pSecProps;
-  if (pWordProps)
-    m_WordProps = *pWordProps;
-}
-
-CFXEU_InsertReturn::~CFXEU_InsertReturn() {}
-
-void CFXEU_InsertReturn::Redo() {
-  if (m_pEdit) {
-    m_pEdit->SelectNone();
-    m_pEdit->SetCaret(m_wpOld);
-    m_pEdit->InsertReturn(&m_SecProps, &m_WordProps, false, true);
-  }
-}
-
-void CFXEU_InsertReturn::Undo() {
-  if (m_pEdit) {
-    m_pEdit->SelectNone();
-    m_pEdit->SetCaret(m_wpNew);
-    m_pEdit->Backspace(false, true);
-  }
-}
-
-CFXEU_Backspace::CFXEU_Backspace(CFX_Edit* pEdit,
-                                 const CPVT_WordPlace& wpOldPlace,
-                                 const CPVT_WordPlace& wpNewPlace,
-                                 uint16_t word,
-                                 int32_t charset,
-                                 const CPVT_SecProps& SecProps,
-                                 const CPVT_WordProps& WordProps)
-    : m_pEdit(pEdit),
-      m_wpOld(wpOldPlace),
-      m_wpNew(wpNewPlace),
-      m_Word(word),
-      m_nCharset(charset),
-      m_SecProps(SecProps),
-      m_WordProps(WordProps) {}
-
-CFXEU_Backspace::~CFXEU_Backspace() {}
-
-void CFXEU_Backspace::Redo() {
-  if (m_pEdit) {
-    m_pEdit->SelectNone();
-    m_pEdit->SetCaret(m_wpOld);
-    m_pEdit->Backspace(false, true);
-  }
-}
-
-void CFXEU_Backspace::Undo() {
-  if (m_pEdit) {
-    m_pEdit->SelectNone();
-    m_pEdit->SetCaret(m_wpNew);
-    if (m_wpNew.SecCmp(m_wpOld) != 0) {
-      m_pEdit->InsertReturn(&m_SecProps, &m_WordProps, false, true);
-    } else {
-      m_pEdit->InsertWord(m_Word, m_nCharset, &m_WordProps, false, true);
-    }
-  }
-}
-
-CFXEU_Delete::CFXEU_Delete(CFX_Edit* pEdit,
-                           const CPVT_WordPlace& wpOldPlace,
-                           const CPVT_WordPlace& wpNewPlace,
-                           uint16_t word,
-                           int32_t charset,
-                           const CPVT_SecProps& SecProps,
-                           const CPVT_WordProps& WordProps,
-                           bool bSecEnd)
-    : m_pEdit(pEdit),
-      m_wpOld(wpOldPlace),
-      m_wpNew(wpNewPlace),
-      m_Word(word),
-      m_nCharset(charset),
-      m_SecProps(SecProps),
-      m_WordProps(WordProps),
-      m_bSecEnd(bSecEnd) {}
-
-CFXEU_Delete::~CFXEU_Delete() {}
-
-void CFXEU_Delete::Redo() {
-  if (m_pEdit) {
-    m_pEdit->SelectNone();
-    m_pEdit->SetCaret(m_wpOld);
-    m_pEdit->Delete(false, true);
-  }
-}
-
-void CFXEU_Delete::Undo() {
-  if (m_pEdit) {
-    m_pEdit->SelectNone();
-    m_pEdit->SetCaret(m_wpNew);
-    if (m_bSecEnd) {
-      m_pEdit->InsertReturn(&m_SecProps, &m_WordProps, false, true);
-    } else {
-      m_pEdit->InsertWord(m_Word, m_nCharset, &m_WordProps, false, true);
-    }
-  }
-}
-
-CFXEU_Clear::CFXEU_Clear(CFX_Edit* pEdit,
-                         const CPVT_WordRange& wrSel,
-                         const CFX_WideString& swText)
-    : m_pEdit(pEdit), m_wrSel(wrSel), m_swText(swText) {}
-
-CFXEU_Clear::~CFXEU_Clear() {}
-
-void CFXEU_Clear::Redo() {
-  if (m_pEdit) {
-    m_pEdit->SelectNone();
-    m_pEdit->SetSel(m_wrSel.BeginPos, m_wrSel.EndPos);
-    m_pEdit->Clear(false, true);
-  }
-}
-
-void CFXEU_Clear::Undo() {
-  if (m_pEdit) {
-    m_pEdit->SelectNone();
-    m_pEdit->SetCaret(m_wrSel.BeginPos);
-    m_pEdit->InsertText(m_swText, FXFONT_DEFAULT_CHARSET, false, true);
-    m_pEdit->SetSel(m_wrSel.BeginPos, m_wrSel.EndPos);
-  }
-}
-
-CFXEU_InsertText::CFXEU_InsertText(CFX_Edit* pEdit,
-                                   const CPVT_WordPlace& wpOldPlace,
-                                   const CPVT_WordPlace& wpNewPlace,
-                                   const CFX_WideString& swText,
-                                   int32_t charset)
-    : m_pEdit(pEdit),
-      m_wpOld(wpOldPlace),
-      m_wpNew(wpNewPlace),
-      m_swText(swText),
-      m_nCharset(charset) {}
-
-CFXEU_InsertText::~CFXEU_InsertText() {}
-
-void CFXEU_InsertText::Redo() {
-  if (m_pEdit && IsLast()) {
-    m_pEdit->SelectNone();
-    m_pEdit->SetCaret(m_wpOld);
-    m_pEdit->InsertText(m_swText, m_nCharset, false, true);
-  }
-}
-
-void CFXEU_InsertText::Undo() {
-  if (m_pEdit) {
-    m_pEdit->SelectNone();
-    m_pEdit->SetSel(m_wpOld, m_wpNew);
-    m_pEdit->Clear(false, true);
-  }
-}
-
-// static
-CFX_ByteString CFX_Edit::GetEditAppearanceStream(CFX_Edit* pEdit,
-                                                 const CFX_PointF& ptOffset,
-                                                 const CPVT_WordRange* pRange,
-                                                 bool bContinuous,
-                                                 uint16_t SubWord) {
-  CFX_Edit_Iterator* pIterator = pEdit->GetIterator();
-  if (pRange)
-    pIterator->SetAt(pRange->BeginPos);
-  else
-    pIterator->SetAt(0);
-
-  CFX_ByteTextBuf sEditStream;
-  CFX_ByteTextBuf sWords;
-  int32_t nCurFontIndex = -1;
-  CFX_PointF ptOld;
-  CFX_PointF ptNew;
-  CPVT_WordPlace oldplace;
-
-  while (pIterator->NextWord()) {
-    CPVT_WordPlace place = pIterator->GetAt();
-    if (pRange && place.WordCmp(pRange->EndPos) > 0)
-      break;
-
-    if (bContinuous) {
-      if (place.LineCmp(oldplace) != 0) {
-        if (sWords.GetSize() > 0) {
-          sEditStream << GetWordRenderString(sWords.MakeString());
-          sWords.Clear();
-        }
-
-        CPVT_Word word;
-        if (pIterator->GetWord(word)) {
-          ptNew = CFX_PointF(word.ptWord.x + ptOffset.x,
-                             word.ptWord.y + ptOffset.y);
-        } else {
-          CPVT_Line line;
-          pIterator->GetLine(line);
-          ptNew = CFX_PointF(line.ptLine.x + ptOffset.x,
-                             line.ptLine.y + ptOffset.y);
-        }
-
-        if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
-          sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
-                      << " Td\n";
-
-          ptOld = ptNew;
-        }
-      }
-
-      CPVT_Word word;
-      if (pIterator->GetWord(word)) {
-        if (word.nFontIndex != nCurFontIndex) {
-          if (sWords.GetSize() > 0) {
-            sEditStream << GetWordRenderString(sWords.MakeString());
-            sWords.Clear();
-          }
-          sEditStream << GetFontSetString(pEdit->GetFontMap(), word.nFontIndex,
-                                          word.fFontSize);
-          nCurFontIndex = word.nFontIndex;
-        }
-
-        sWords << GetPDFWordString(pEdit->GetFontMap(), nCurFontIndex,
-                                   word.Word, SubWord);
-      }
-
-      oldplace = place;
-    } else {
-      CPVT_Word word;
-      if (pIterator->GetWord(word)) {
-        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
-                      << " Td\n";
-          ptOld = ptNew;
-        }
-
-        if (word.nFontIndex != nCurFontIndex) {
-          sEditStream << GetFontSetString(pEdit->GetFontMap(), word.nFontIndex,
-                                          word.fFontSize);
-          nCurFontIndex = word.nFontIndex;
-        }
-
-        sEditStream << GetWordRenderString(GetPDFWordString(
-            pEdit->GetFontMap(), nCurFontIndex, word.Word, SubWord));
-      }
-    }
-  }
-
-  if (sWords.GetSize() > 0) {
-    sEditStream << GetWordRenderString(sWords.MakeString());
-    sWords.Clear();
-  }
-
-  CFX_ByteTextBuf sAppStream;
-  if (sEditStream.GetSize() > 0) {
-    int32_t nHorzScale = pEdit->GetHorzScale();
-    if (nHorzScale != 100) {
-      sAppStream << nHorzScale << " Tz\n";
-    }
-
-    FX_FLOAT fCharSpace = pEdit->GetCharSpace();
-    if (!IsFloatZero(fCharSpace)) {
-      sAppStream << fCharSpace << " Tc\n";
-    }
-
-    sAppStream << sEditStream;
-  }
-
-  return sAppStream.MakeString();
-}
-
-// static
-CFX_ByteString CFX_Edit::GetSelectAppearanceStream(
-    CFX_Edit* pEdit,
-    const CFX_PointF& ptOffset,
-    const CPVT_WordRange* pRange) {
-  if (!pRange || !pRange->IsExist())
-    return CFX_ByteString();
-
-  CFX_Edit_Iterator* pIterator = pEdit->GetIterator();
-  pIterator->SetAt(pRange->BeginPos);
-
-  CFX_ByteTextBuf sRet;
-  while (pIterator->NextWord()) {
-    CPVT_WordPlace place = pIterator->GetAt();
-    if (place.WordCmp(pRange->EndPos) > 0)
-      break;
-
-    CPVT_Word word;
-    CPVT_Line line;
-    if (pIterator->GetWord(word) && pIterator->GetLine(line)) {
-      sRet << word.ptWord.x + ptOffset.x << " "
-           << line.ptLine.y + line.fLineDescent << " " << word.fWidth << " "
-           << line.fLineAscent - line.fLineDescent << " re\nf\n";
-    }
-  }
-
-  return sRet.MakeString();
-}
-
-// static
-void CFX_Edit::DrawEdit(CFX_RenderDevice* pDevice,
-                        CFX_Matrix* pUser2Device,
-                        CFX_Edit* pEdit,
-                        FX_COLORREF crTextFill,
-                        const CFX_FloatRect& rcClip,
-                        const CFX_PointF& ptOffset,
-                        const CPVT_WordRange* pRange,
-                        CFX_SystemHandler* pSystemHandler,
-                        CFFL_FormFiller* pFFLData) {
-  const bool bContinuous =
-      pEdit->GetCharArray() == 0 && pEdit->GetCharSpace() <= 0.0f;
-  uint16_t SubWord = pEdit->GetPasswordChar();
-  FX_FLOAT fFontSize = pEdit->GetFontSize();
-  CPVT_WordRange wrSelect = pEdit->GetSelectWordRange();
-  int32_t nHorzScale = pEdit->GetHorzScale();
-
-  FX_COLORREF crCurFill = crTextFill;
-  FX_COLORREF crOldFill = crCurFill;
-
-  bool bSelect = false;
-  const FX_COLORREF crWhite = ArgbEncode(255, 255, 255, 255);
-  const FX_COLORREF crSelBK = ArgbEncode(255, 0, 51, 113);
-
-  CFX_ByteTextBuf sTextBuf;
-  int32_t nFontIndex = -1;
-  CFX_PointF ptBT;
-  pDevice->SaveState();
-  if (!rcClip.IsEmpty()) {
-    CFX_FloatRect rcTemp = rcClip;
-    pUser2Device->TransformRect(rcTemp);
-    pDevice->SetClip_Rect(rcTemp.ToFxRect());
-  }
-
-  CFX_Edit_Iterator* pIterator = pEdit->GetIterator();
-  if (IPVT_FontMap* pFontMap = pEdit->GetFontMap()) {
-    if (pRange)
-      pIterator->SetAt(pRange->BeginPos);
-    else
-      pIterator->SetAt(0);
-
-    CPVT_WordPlace oldplace;
-    while (pIterator->NextWord()) {
-      CPVT_WordPlace place = pIterator->GetAt();
-      if (pRange && place.WordCmp(pRange->EndPos) > 0)
-        break;
-
-      if (wrSelect.IsExist()) {
-        bSelect = place.WordCmp(wrSelect.BeginPos) > 0 &&
-                  place.WordCmp(wrSelect.EndPos) <= 0;
-        crCurFill = bSelect ? crWhite : crTextFill;
-      }
-      if (pSystemHandler && pSystemHandler->IsSelectionImplemented()) {
-        crCurFill = crTextFill;
-        crOldFill = crCurFill;
-      }
-      CPVT_Word word;
-      if (pIterator->GetWord(word)) {
-        if (bSelect) {
-          CPVT_Line line;
-          pIterator->GetLine(line);
-
-          if (pSystemHandler && pSystemHandler->IsSelectionImplemented()) {
-            CFX_FloatRect rc(word.ptWord.x, line.ptLine.y + line.fLineDescent,
-                             word.ptWord.x + word.fWidth,
-                             line.ptLine.y + line.fLineAscent);
-            rc.Intersect(rcClip);
-            pSystemHandler->OutputSelectedRect(pFFLData, rc);
-          } else {
-            CFX_PathData pathSelBK;
-            pathSelBK.AppendRect(
-                word.ptWord.x, line.ptLine.y + line.fLineDescent,
-                word.ptWord.x + word.fWidth, line.ptLine.y + line.fLineAscent);
-
-            pDevice->DrawPath(&pathSelBK, pUser2Device, nullptr, crSelBK, 0,
-                              FXFILL_WINDING);
-          }
-        }
-
-        if (bContinuous) {
-          if (place.LineCmp(oldplace) != 0 || word.nFontIndex != nFontIndex ||
-              crOldFill != crCurFill) {
-            if (sTextBuf.GetLength() > 0) {
-              DrawTextString(
-                  pDevice, CFX_PointF(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
-                  pFontMap->GetPDFFont(nFontIndex), fFontSize, pUser2Device,
-                  sTextBuf.MakeString(), crOldFill, nHorzScale);
-
-              sTextBuf.Clear();
-            }
-            nFontIndex = word.nFontIndex;
-            ptBT = word.ptWord;
-            crOldFill = crCurFill;
-          }
-
-          sTextBuf << GetPDFWordString(pFontMap, word.nFontIndex, word.Word,
-                                       SubWord)
-                          .AsStringC();
-        } else {
-          DrawTextString(
-              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, nHorzScale);
-        }
-        oldplace = place;
-      }
-    }
-
-    if (sTextBuf.GetLength() > 0) {
-      DrawTextString(pDevice,
-                     CFX_PointF(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
-                     pFontMap->GetPDFFont(nFontIndex), fFontSize, pUser2Device,
-                     sTextBuf.MakeString(), crOldFill, nHorzScale);
-    }
-  }
-
-  pDevice->RestoreState(false);
-}
-
-CFX_Edit::CFX_Edit()
-    : m_pVT(new CPDF_VariableText),
-      m_pNotify(nullptr),
-      m_pOprNotify(nullptr),
-      m_wpCaret(-1, -1, -1),
-      m_wpOldCaret(-1, -1, -1),
-      m_SelState(),
-      m_bEnableScroll(false),
-      m_Undo(kEditUndoMaxItems),
-      m_nAlignment(0),
-      m_bNotifyFlag(false),
-      m_bEnableOverflow(false),
-      m_bEnableRefresh(true),
-      m_rcOldContent(0.0f, 0.0f, 0.0f, 0.0f),
-      m_bEnableUndo(true),
-      m_bOprNotify(false),
-      m_pGroupUndoItem(nullptr) {}
-
-CFX_Edit::~CFX_Edit() {
-  ASSERT(!m_pGroupUndoItem);
-}
-
-void CFX_Edit::Initialize() {
-  m_pVT->Initialize();
-  SetCaret(m_pVT->GetBeginWordPlace());
-  SetCaretOrigin();
-}
-
-void CFX_Edit::SetFontMap(IPVT_FontMap* pFontMap) {
-  m_pVTProvider = pdfium::MakeUnique<CFX_Edit_Provider>(pFontMap);
-  m_pVT->SetProvider(m_pVTProvider.get());
-}
-
-void CFX_Edit::SetNotify(CPWL_EditCtrl* pNotify) {
-  m_pNotify = pNotify;
-}
-
-void CFX_Edit::SetOprNotify(CPWL_Edit* pOprNotify) {
-  m_pOprNotify = pOprNotify;
-}
-
-CFX_Edit_Iterator* CFX_Edit::GetIterator() {
-  if (!m_pIterator) {
-    m_pIterator =
-        pdfium::MakeUnique<CFX_Edit_Iterator>(this, m_pVT->GetIterator());
-  }
-  return m_pIterator.get();
-}
-
-IPVT_FontMap* CFX_Edit::GetFontMap() {
-  return m_pVTProvider ? m_pVTProvider->GetFontMap() : nullptr;
-}
-
-void CFX_Edit::SetPlateRect(const CFX_FloatRect& rect) {
-  m_pVT->SetPlateRect(rect);
-  m_ptScrollPos = CFX_PointF(rect.left, rect.top);
-  Paint();
-}
-
-void CFX_Edit::SetAlignmentH(int32_t nFormat, bool bPaint) {
-  m_pVT->SetAlignment(nFormat);
-  if (bPaint)
-    Paint();
-}
-
-void CFX_Edit::SetAlignmentV(int32_t nFormat, bool bPaint) {
-  m_nAlignment = nFormat;
-  if (bPaint)
-    Paint();
-}
-
-void CFX_Edit::SetPasswordChar(uint16_t wSubWord, bool bPaint) {
-  m_pVT->SetPasswordChar(wSubWord);
-  if (bPaint)
-    Paint();
-}
-
-void CFX_Edit::SetLimitChar(int32_t nLimitChar) {
-  m_pVT->SetLimitChar(nLimitChar);
-  Paint();
-}
-
-void CFX_Edit::SetCharArray(int32_t nCharArray) {
-  m_pVT->SetCharArray(nCharArray);
-  Paint();
-}
-
-void CFX_Edit::SetCharSpace(FX_FLOAT fCharSpace) {
-  m_pVT->SetCharSpace(fCharSpace);
-  Paint();
-}
-
-void CFX_Edit::SetMultiLine(bool bMultiLine, bool bPaint) {
-  m_pVT->SetMultiLine(bMultiLine);
-  if (bPaint)
-    Paint();
-}
-
-void CFX_Edit::SetAutoReturn(bool bAuto, bool bPaint) {
-  m_pVT->SetAutoReturn(bAuto);
-  if (bPaint)
-    Paint();
-}
-
-void CFX_Edit::SetAutoFontSize(bool bAuto, bool bPaint) {
-  m_pVT->SetAutoFontSize(bAuto);
-  if (bPaint)
-    Paint();
-}
-
-void CFX_Edit::SetFontSize(FX_FLOAT fFontSize) {
-  m_pVT->SetFontSize(fFontSize);
-  Paint();
-}
-
-void CFX_Edit::SetAutoScroll(bool bAuto, bool bPaint) {
-  m_bEnableScroll = bAuto;
-  if (bPaint)
-    Paint();
-}
-
-void CFX_Edit::SetTextOverflow(bool bAllowed, bool bPaint) {
-  m_bEnableOverflow = bAllowed;
-  if (bPaint)
-    Paint();
-}
-
-void CFX_Edit::SetSel(int32_t nStartChar, int32_t nEndChar) {
-  if (m_pVT->IsValid()) {
-    if (nStartChar == 0 && nEndChar < 0) {
-      SelectAll();
-    } else if (nStartChar < 0) {
-      SelectNone();
-    } else {
-      if (nStartChar < nEndChar) {
-        SetSel(m_pVT->WordIndexToWordPlace(nStartChar),
-               m_pVT->WordIndexToWordPlace(nEndChar));
-      } else {
-        SetSel(m_pVT->WordIndexToWordPlace(nEndChar),
-               m_pVT->WordIndexToWordPlace(nStartChar));
-      }
-    }
-  }
-}
-
-void CFX_Edit::SetSel(const CPVT_WordPlace& begin, const CPVT_WordPlace& end) {
-  if (m_pVT->IsValid()) {
-    SelectNone();
-
-    m_SelState.Set(begin, end);
-
-    SetCaret(m_SelState.EndPos);
-
-    if (m_SelState.IsExist()) {
-      ScrollToCaret();
-      Refresh();
-      SetCaretInfo();
-    } else {
-      ScrollToCaret();
-      SetCaretInfo();
-    }
-  }
-}
-
-void CFX_Edit::GetSel(int32_t& nStartChar, int32_t& nEndChar) const {
-  nStartChar = -1;
-  nEndChar = -1;
-
-  if (m_pVT->IsValid()) {
-    if (m_SelState.IsExist()) {
-      if (m_SelState.BeginPos.WordCmp(m_SelState.EndPos) < 0) {
-        nStartChar = m_pVT->WordPlaceToWordIndex(m_SelState.BeginPos);
-        nEndChar = m_pVT->WordPlaceToWordIndex(m_SelState.EndPos);
-      } else {
-        nStartChar = m_pVT->WordPlaceToWordIndex(m_SelState.EndPos);
-        nEndChar = m_pVT->WordPlaceToWordIndex(m_SelState.BeginPos);
-      }
-    } else {
-      nStartChar = m_pVT->WordPlaceToWordIndex(m_wpCaret);
-      nEndChar = m_pVT->WordPlaceToWordIndex(m_wpCaret);
-    }
-  }
-}
-
-int32_t CFX_Edit::GetCaret() const {
-  if (m_pVT->IsValid())
-    return m_pVT->WordPlaceToWordIndex(m_wpCaret);
-
-  return -1;
-}
-
-CPVT_WordPlace CFX_Edit::GetCaretWordPlace() const {
-  return m_wpCaret;
-}
-
-CFX_WideString CFX_Edit::GetText() const {
-  CFX_WideString swRet;
-
-  if (!m_pVT->IsValid())
-    return swRet;
-
-  CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
-  pIterator->SetAt(0);
-
-  CPVT_Word wordinfo;
-  CPVT_WordPlace oldplace = pIterator->GetAt();
-  while (pIterator->NextWord()) {
-    CPVT_WordPlace place = pIterator->GetAt();
-
-    if (pIterator->GetWord(wordinfo))
-      swRet += wordinfo.Word;
-
-    if (oldplace.SecCmp(place) != 0)
-      swRet += L"\r\n";
-
-    oldplace = place;
-  }
-
-  return swRet;
-}
-
-CFX_WideString CFX_Edit::GetRangeText(const CPVT_WordRange& range) const {
-  CFX_WideString swRet;
-
-  if (!m_pVT->IsValid())
-    return swRet;
-
-  CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
-  CPVT_WordRange wrTemp = range;
-  m_pVT->UpdateWordPlace(wrTemp.BeginPos);
-  m_pVT->UpdateWordPlace(wrTemp.EndPos);
-  pIterator->SetAt(wrTemp.BeginPos);
-
-  CPVT_Word wordinfo;
-  CPVT_WordPlace oldplace = wrTemp.BeginPos;
-  while (pIterator->NextWord()) {
-    CPVT_WordPlace place = pIterator->GetAt();
-    if (place.WordCmp(wrTemp.EndPos) > 0)
-      break;
-
-    if (pIterator->GetWord(wordinfo))
-      swRet += wordinfo.Word;
-
-    if (oldplace.SecCmp(place) != 0)
-      swRet += L"\r\n";
-
-    oldplace = place;
-  }
-
-  return swRet;
-}
-
-CFX_WideString CFX_Edit::GetSelText() const {
-  return GetRangeText(m_SelState.ConvertToWordRange());
-}
-
-int32_t CFX_Edit::GetTotalWords() const {
-  return m_pVT->GetTotalWords();
-}
-
-int32_t CFX_Edit::GetTotalLines() const {
-  int32_t nLines = 1;
-
-  CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
-  pIterator->SetAt(0);
-  while (pIterator->NextLine())
-    ++nLines;
-
-  return nLines;
-}
-
-CPVT_WordRange CFX_Edit::GetSelectWordRange() const {
-  return m_SelState.ConvertToWordRange();
-}
-
-void CFX_Edit::SetText(const CFX_WideString& sText) {
-  Empty();
-  DoInsertText(CPVT_WordPlace(0, 0, -1), sText, FXFONT_DEFAULT_CHARSET);
-  Paint();
-}
-
-bool CFX_Edit::InsertWord(uint16_t word, int32_t charset) {
-  return InsertWord(word, charset, nullptr, true, true);
-}
-
-bool CFX_Edit::InsertReturn() {
-  return InsertReturn(nullptr, nullptr, true, true);
-}
-
-bool CFX_Edit::Backspace() {
-  return Backspace(true, true);
-}
-
-bool CFX_Edit::Delete() {
-  return Delete(true, true);
-}
-
-bool CFX_Edit::Clear() {
-  return Clear(true, true);
-}
-
-bool CFX_Edit::InsertText(const CFX_WideString& sText, int32_t charset) {
-  return InsertText(sText, charset, true, true);
-}
-
-FX_FLOAT CFX_Edit::GetFontSize() const {
-  return m_pVT->GetFontSize();
-}
-
-uint16_t CFX_Edit::GetPasswordChar() const {
-  return m_pVT->GetPasswordChar();
-}
-
-int32_t CFX_Edit::GetCharArray() const {
-  return m_pVT->GetCharArray();
-}
-
-CFX_FloatRect CFX_Edit::GetContentRect() const {
-  return VTToEdit(m_pVT->GetContentRect());
-}
-
-int32_t CFX_Edit::GetHorzScale() const {
-  return m_pVT->GetHorzScale();
-}
-
-FX_FLOAT CFX_Edit::GetCharSpace() const {
-  return m_pVT->GetCharSpace();
-}
-
-CPVT_WordRange CFX_Edit::GetWholeWordRange() const {
-  if (m_pVT->IsValid())
-    return CPVT_WordRange(m_pVT->GetBeginWordPlace(), m_pVT->GetEndWordPlace());
-
-  return CPVT_WordRange();
-}
-
-CPVT_WordRange CFX_Edit::GetVisibleWordRange() const {
-  if (m_bEnableOverflow)
-    return GetWholeWordRange();
-
-  if (m_pVT->IsValid()) {
-    CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
-
-    CPVT_WordPlace place1 =
-        m_pVT->SearchWordPlace(EditToVT(CFX_PointF(rcPlate.left, rcPlate.top)));
-    CPVT_WordPlace place2 = m_pVT->SearchWordPlace(
-        EditToVT(CFX_PointF(rcPlate.right, rcPlate.bottom)));
-
-    return CPVT_WordRange(place1, place2);
-  }
-
-  return CPVT_WordRange();
-}
-
-CPVT_WordPlace CFX_Edit::SearchWordPlace(const CFX_PointF& point) const {
-  if (m_pVT->IsValid()) {
-    return m_pVT->SearchWordPlace(EditToVT(point));
-  }
-
-  return CPVT_WordPlace();
-}
-
-void CFX_Edit::Paint() {
-  if (m_pVT->IsValid()) {
-    RearrangeAll();
-    ScrollToCaret();
-    Refresh();
-    SetCaretOrigin();
-    SetCaretInfo();
-  }
-}
-
-void CFX_Edit::RearrangeAll() {
-  if (m_pVT->IsValid()) {
-    m_pVT->UpdateWordPlace(m_wpCaret);
-    m_pVT->RearrangeAll();
-    m_pVT->UpdateWordPlace(m_wpCaret);
-    SetScrollInfo();
-    SetContentChanged();
-  }
-}
-
-void CFX_Edit::RearrangePart(const CPVT_WordRange& range) {
-  if (m_pVT->IsValid()) {
-    m_pVT->UpdateWordPlace(m_wpCaret);
-    m_pVT->RearrangePart(range);
-    m_pVT->UpdateWordPlace(m_wpCaret);
-    SetScrollInfo();
-    SetContentChanged();
-  }
-}
-
-void CFX_Edit::SetContentChanged() {
-  if (m_pNotify) {
-    CFX_FloatRect rcContent = m_pVT->GetContentRect();
-    if (rcContent.Width() != m_rcOldContent.Width() ||
-        rcContent.Height() != m_rcOldContent.Height()) {
-      if (!m_bNotifyFlag) {
-        m_bNotifyFlag = true;
-        m_pNotify->IOnContentChange(rcContent);
-        m_bNotifyFlag = false;
-      }
-      m_rcOldContent = rcContent;
-    }
-  }
-}
-
-void CFX_Edit::SelectAll() {
-  if (m_pVT->IsValid()) {
-    m_SelState = CFX_Edit_Select(GetWholeWordRange());
-    SetCaret(m_SelState.EndPos);
-
-    ScrollToCaret();
-    Refresh();
-    SetCaretInfo();
-  }
-}
-
-void CFX_Edit::SelectNone() {
-  if (m_pVT->IsValid()) {
-    if (m_SelState.IsExist()) {
-      m_SelState.Default();
-      Refresh();
-    }
-  }
-}
-
-bool CFX_Edit::IsSelected() const {
-  return m_SelState.IsExist();
-}
-
-CFX_PointF CFX_Edit::VTToEdit(const CFX_PointF& point) const {
-  CFX_FloatRect rcContent = m_pVT->GetContentRect();
-  CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
-
-  FX_FLOAT fPadding = 0.0f;
-
-  switch (m_nAlignment) {
-    case 0:
-      fPadding = 0.0f;
-      break;
-    case 1:
-      fPadding = (rcPlate.Height() - rcContent.Height()) * 0.5f;
-      break;
-    case 2:
-      fPadding = rcPlate.Height() - rcContent.Height();
-      break;
-  }
-
-  return CFX_PointF(point.x - (m_ptScrollPos.x - rcPlate.left),
-                    point.y - (m_ptScrollPos.y + fPadding - rcPlate.top));
-}
-
-CFX_PointF CFX_Edit::EditToVT(const CFX_PointF& point) const {
-  CFX_FloatRect rcContent = m_pVT->GetContentRect();
-  CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
-
-  FX_FLOAT fPadding = 0.0f;
-
-  switch (m_nAlignment) {
-    case 0:
-      fPadding = 0.0f;
-      break;
-    case 1:
-      fPadding = (rcPlate.Height() - rcContent.Height()) * 0.5f;
-      break;
-    case 2:
-      fPadding = rcPlate.Height() - rcContent.Height();
-      break;
-  }
-
-  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_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);
-}
-
-void CFX_Edit::SetScrollInfo() {
-  if (m_pNotify) {
-    CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
-    CFX_FloatRect rcContent = m_pVT->GetContentRect();
-
-    if (!m_bNotifyFlag) {
-      m_bNotifyFlag = true;
-      m_pNotify->IOnSetScrollInfoY(rcPlate.bottom, rcPlate.top,
-                                   rcContent.bottom, rcContent.top,
-                                   rcPlate.Height() / 3, rcPlate.Height());
-      m_bNotifyFlag = false;
-    }
-  }
-}
-
-void CFX_Edit::SetScrollPosX(FX_FLOAT fx) {
-  if (!m_bEnableScroll)
-    return;
-
-  if (m_pVT->IsValid()) {
-    if (!IsFloatEqual(m_ptScrollPos.x, fx)) {
-      m_ptScrollPos.x = fx;
-      Refresh();
-    }
-  }
-}
-
-void CFX_Edit::SetScrollPosY(FX_FLOAT fy) {
-  if (!m_bEnableScroll)
-    return;
-
-  if (m_pVT->IsValid()) {
-    if (!IsFloatEqual(m_ptScrollPos.y, fy)) {
-      m_ptScrollPos.y = fy;
-      Refresh();
-
-      if (m_pNotify) {
-        if (!m_bNotifyFlag) {
-          m_bNotifyFlag = true;
-          m_pNotify->IOnSetScrollPosY(fy);
-          m_bNotifyFlag = false;
-        }
-      }
-    }
-  }
-}
-
-void CFX_Edit::SetScrollPos(const CFX_PointF& point) {
-  SetScrollPosX(point.x);
-  SetScrollPosY(point.y);
-  SetScrollLimit();
-  SetCaretInfo();
-}
-
-CFX_PointF CFX_Edit::GetScrollPos() const {
-  return m_ptScrollPos;
-}
-
-void CFX_Edit::SetScrollLimit() {
-  if (m_pVT->IsValid()) {
-    CFX_FloatRect rcContent = m_pVT->GetContentRect();
-    CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
-
-    if (rcPlate.Width() > rcContent.Width()) {
-      SetScrollPosX(rcPlate.left);
-    } else {
-      if (IsFloatSmaller(m_ptScrollPos.x, rcContent.left)) {
-        SetScrollPosX(rcContent.left);
-      } else if (IsFloatBigger(m_ptScrollPos.x,
-                               rcContent.right - rcPlate.Width())) {
-        SetScrollPosX(rcContent.right - rcPlate.Width());
-      }
-    }
-
-    if (rcPlate.Height() > rcContent.Height()) {
-      SetScrollPosY(rcPlate.top);
-    } else {
-      if (IsFloatSmaller(m_ptScrollPos.y,
-                         rcContent.bottom + rcPlate.Height())) {
-        SetScrollPosY(rcContent.bottom + rcPlate.Height());
-      } else if (IsFloatBigger(m_ptScrollPos.y, rcContent.top)) {
-        SetScrollPosY(rcContent.top);
-      }
-    }
-  }
-}
-
-void CFX_Edit::ScrollToCaret() {
-  SetScrollLimit();
-
-  if (!m_pVT->IsValid())
-    return;
-
-  CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
-  pIterator->SetAt(m_wpCaret);
-
-  CFX_PointF ptHead;
-  CFX_PointF ptFoot;
-  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;
-  } 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;
-  }
-
-  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) ||
-        IsFloatEqual(ptHeadEdit.x, rcPlate.left)) {
-      SetScrollPosX(ptHead.x);
-    } else if (IsFloatBigger(ptHeadEdit.x, rcPlate.right)) {
-      SetScrollPosX(ptHead.x - rcPlate.Width());
-    }
-  }
-
-  if (!IsFloatEqual(rcPlate.top, rcPlate.bottom)) {
-    if (IsFloatSmaller(ptFootEdit.y, rcPlate.bottom) ||
-        IsFloatEqual(ptFootEdit.y, rcPlate.bottom)) {
-      if (IsFloatSmaller(ptHeadEdit.y, rcPlate.top)) {
-        SetScrollPosY(ptFoot.y + rcPlate.Height());
-      }
-    } else if (IsFloatBigger(ptHeadEdit.y, rcPlate.top)) {
-      if (IsFloatBigger(ptFootEdit.y, rcPlate.bottom)) {
-        SetScrollPosY(ptHead.y);
-      }
-    }
-  }
-}
-
-void CFX_Edit::Refresh() {
-  if (m_bEnableRefresh && m_pVT->IsValid()) {
-    m_Refresh.BeginRefresh();
-    RefreshPushLineRects(GetVisibleWordRange());
-
-    m_Refresh.NoAnalyse();
-    m_ptRefreshScrollPos = m_ptScrollPos;
-
-    if (m_pNotify) {
-      if (!m_bNotifyFlag) {
-        m_bNotifyFlag = true;
-        if (const CFX_Edit_RectArray* pRects = m_Refresh.GetRefreshRects()) {
-          for (int32_t i = 0, sz = pRects->GetSize(); i < sz; i++)
-            m_pNotify->IOnInvalidateRect(pRects->GetAt(i));
-        }
-        m_bNotifyFlag = false;
-      }
-    }
-
-    m_Refresh.EndRefresh();
-  }
-}
-
-void CFX_Edit::RefreshPushLineRects(const CPVT_WordRange& wr) {
-  if (!m_pVT->IsValid())
-    return;
-
-  CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
-  CPVT_WordPlace wpBegin = wr.BeginPos;
-  m_pVT->UpdateWordPlace(wpBegin);
-  CPVT_WordPlace wpEnd = wr.EndPos;
-  m_pVT->UpdateWordPlace(wpEnd);
-  pIterator->SetAt(wpBegin);
-
-  CPVT_Line lineinfo;
-  do {
-    if (!pIterator->GetLine(lineinfo))
-      break;
-    if (lineinfo.lineplace.LineCmp(wpEnd) > 0)
-      break;
-
-    CFX_FloatRect rcLine(lineinfo.ptLine.x,
-                         lineinfo.ptLine.y + lineinfo.fLineDescent,
-                         lineinfo.ptLine.x + lineinfo.fLineWidth,
-                         lineinfo.ptLine.y + lineinfo.fLineAscent);
-
-    m_Refresh.Push(CPVT_WordRange(lineinfo.lineplace, lineinfo.lineEnd),
-                   VTToEdit(rcLine));
-  } while (pIterator->NextLine());
-}
-
-void CFX_Edit::RefreshWordRange(const CPVT_WordRange& wr) {
-  CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
-  CPVT_WordRange wrTemp = wr;
-
-  m_pVT->UpdateWordPlace(wrTemp.BeginPos);
-  m_pVT->UpdateWordPlace(wrTemp.EndPos);
-  pIterator->SetAt(wrTemp.BeginPos);
-
-  CPVT_Word wordinfo;
-  CPVT_Line lineinfo;
-  CPVT_WordPlace place;
-
-  while (pIterator->NextWord()) {
-    place = pIterator->GetAt();
-    if (place.WordCmp(wrTemp.EndPos) > 0)
-      break;
-
-    pIterator->GetWord(wordinfo);
-    pIterator->GetLine(lineinfo);
-
-    if (place.LineCmp(wrTemp.BeginPos) == 0 ||
-        place.LineCmp(wrTemp.EndPos) == 0) {
-      CFX_FloatRect rcWord(wordinfo.ptWord.x,
-                           lineinfo.ptLine.y + lineinfo.fLineDescent,
-                           wordinfo.ptWord.x + wordinfo.fWidth,
-                           lineinfo.ptLine.y + lineinfo.fLineAscent);
-
-      if (m_pNotify) {
-        if (!m_bNotifyFlag) {
-          m_bNotifyFlag = true;
-          CFX_FloatRect rcRefresh = VTToEdit(rcWord);
-          m_pNotify->IOnInvalidateRect(&rcRefresh);
-          m_bNotifyFlag = false;
-        }
-      }
-    } else {
-      CFX_FloatRect rcLine(lineinfo.ptLine.x,
-                           lineinfo.ptLine.y + lineinfo.fLineDescent,
-                           lineinfo.ptLine.x + lineinfo.fLineWidth,
-                           lineinfo.ptLine.y + lineinfo.fLineAscent);
-
-      if (m_pNotify) {
-        if (!m_bNotifyFlag) {
-          m_bNotifyFlag = true;
-          CFX_FloatRect rcRefresh = VTToEdit(rcLine);
-          m_pNotify->IOnInvalidateRect(&rcRefresh);
-          m_bNotifyFlag = false;
-        }
-      }
-
-      pIterator->NextLine();
-    }
-  }
-}
-
-void CFX_Edit::SetCaret(const CPVT_WordPlace& place) {
-  m_wpOldCaret = m_wpCaret;
-  m_wpCaret = place;
-}
-
-void CFX_Edit::SetCaretInfo() {
-  if (m_pNotify) {
-    if (!m_bNotifyFlag) {
-      CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
-      pIterator->SetAt(m_wpCaret);
-
-      CFX_PointF ptHead;
-      CFX_PointF ptFoot;
-      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;
-      } 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;
-      }
-
-      m_bNotifyFlag = true;
-      m_pNotify->IOnSetCaret(!m_SelState.IsExist(), VTToEdit(ptHead),
-                             VTToEdit(ptFoot), m_wpCaret);
-      m_bNotifyFlag = false;
-    }
-  }
-}
-
-void CFX_Edit::SetCaret(int32_t nPos) {
-  if (m_pVT->IsValid()) {
-    SelectNone();
-    SetCaret(m_pVT->WordIndexToWordPlace(nPos));
-    m_SelState.Set(m_wpCaret, m_wpCaret);
-
-    ScrollToCaret();
-    SetCaretOrigin();
-    SetCaretInfo();
-  }
-}
-
-void CFX_Edit::OnMouseDown(const CFX_PointF& point, bool bShift, bool bCtrl) {
-  if (m_pVT->IsValid()) {
-    SelectNone();
-    SetCaret(m_pVT->SearchWordPlace(EditToVT(point)));
-    m_SelState.Set(m_wpCaret, m_wpCaret);
-
-    ScrollToCaret();
-    SetCaretOrigin();
-    SetCaretInfo();
-  }
-}
-
-void CFX_Edit::OnMouseMove(const CFX_PointF& point, bool bShift, bool bCtrl) {
-  if (m_pVT->IsValid()) {
-    SetCaret(m_pVT->SearchWordPlace(EditToVT(point)));
-
-    if (m_wpCaret != m_wpOldCaret) {
-      m_SelState.SetEndPos(m_wpCaret);
-
-      ScrollToCaret();
-      Refresh();
-      SetCaretOrigin();
-      SetCaretInfo();
-    }
-  }
-}
-
-void CFX_Edit::OnVK_UP(bool bShift, bool bCtrl) {
-  if (m_pVT->IsValid()) {
-    SetCaret(m_pVT->GetUpWordPlace(m_wpCaret, m_ptCaret));
-
-    if (bShift) {
-      if (m_SelState.IsExist())
-        m_SelState.SetEndPos(m_wpCaret);
-      else
-        m_SelState.Set(m_wpOldCaret, m_wpCaret);
-
-      if (m_wpOldCaret != m_wpCaret) {
-        ScrollToCaret();
-        Refresh();
-        SetCaretInfo();
-      }
-    } else {
-      SelectNone();
-
-      ScrollToCaret();
-      SetCaretInfo();
-    }
-  }
-}
-
-void CFX_Edit::OnVK_DOWN(bool bShift, bool bCtrl) {
-  if (m_pVT->IsValid()) {
-    SetCaret(m_pVT->GetDownWordPlace(m_wpCaret, m_ptCaret));
-
-    if (bShift) {
-      if (m_SelState.IsExist())
-        m_SelState.SetEndPos(m_wpCaret);
-      else
-        m_SelState.Set(m_wpOldCaret, m_wpCaret);
-
-      if (m_wpOldCaret != m_wpCaret) {
-        ScrollToCaret();
-        Refresh();
-        SetCaretInfo();
-      }
-    } else {
-      SelectNone();
-
-      ScrollToCaret();
-      SetCaretInfo();
-    }
-  }
-}
-
-void CFX_Edit::OnVK_LEFT(bool bShift, bool bCtrl) {
-  if (m_pVT->IsValid()) {
-    if (bShift) {
-      if (m_wpCaret == m_pVT->GetLineBeginPlace(m_wpCaret) &&
-          m_wpCaret != m_pVT->GetSectionBeginPlace(m_wpCaret))
-        SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
-
-      SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
-
-      if (m_SelState.IsExist())
-        m_SelState.SetEndPos(m_wpCaret);
-      else
-        m_SelState.Set(m_wpOldCaret, m_wpCaret);
-
-      if (m_wpOldCaret != m_wpCaret) {
-        ScrollToCaret();
-        Refresh();
-        SetCaretInfo();
-      }
-    } else {
-      if (m_SelState.IsExist()) {
-        if (m_SelState.BeginPos.WordCmp(m_SelState.EndPos) < 0)
-          SetCaret(m_SelState.BeginPos);
-        else
-          SetCaret(m_SelState.EndPos);
-
-        SelectNone();
-        ScrollToCaret();
-        SetCaretInfo();
-      } else {
-        if (m_wpCaret == m_pVT->GetLineBeginPlace(m_wpCaret) &&
-            m_wpCaret != m_pVT->GetSectionBeginPlace(m_wpCaret))
-          SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
-
-        SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
-
-        ScrollToCaret();
-        SetCaretOrigin();
-        SetCaretInfo();
-      }
-    }
-  }
-}
-
-void CFX_Edit::OnVK_RIGHT(bool bShift, bool bCtrl) {
-  if (m_pVT->IsValid()) {
-    if (bShift) {
-      SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
-
-      if (m_wpCaret == m_pVT->GetLineEndPlace(m_wpCaret) &&
-          m_wpCaret != m_pVT->GetSectionEndPlace(m_wpCaret))
-        SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
-
-      if (m_SelState.IsExist())
-        m_SelState.SetEndPos(m_wpCaret);
-      else
-        m_SelState.Set(m_wpOldCaret, m_wpCaret);
-
-      if (m_wpOldCaret != m_wpCaret) {
-        ScrollToCaret();
-        Refresh();
-        SetCaretInfo();
-      }
-    } else {
-      if (m_SelState.IsExist()) {
-        if (m_SelState.BeginPos.WordCmp(m_SelState.EndPos) > 0)
-          SetCaret(m_SelState.BeginPos);
-        else
-          SetCaret(m_SelState.EndPos);
-
-        SelectNone();
-        ScrollToCaret();
-        SetCaretInfo();
-      } else {
-        SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
-
-        if (m_wpCaret == m_pVT->GetLineEndPlace(m_wpCaret) &&
-            m_wpCaret != m_pVT->GetSectionEndPlace(m_wpCaret))
-          SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
-
-        ScrollToCaret();
-        SetCaretOrigin();
-        SetCaretInfo();
-      }
-    }
-  }
-}
-
-void CFX_Edit::OnVK_HOME(bool bShift, bool bCtrl) {
-  if (m_pVT->IsValid()) {
-    if (bShift) {
-      if (bCtrl)
-        SetCaret(m_pVT->GetBeginWordPlace());
-      else
-        SetCaret(m_pVT->GetLineBeginPlace(m_wpCaret));
-
-      if (m_SelState.IsExist())
-        m_SelState.SetEndPos(m_wpCaret);
-      else
-        m_SelState.Set(m_wpOldCaret, m_wpCaret);
-
-      ScrollToCaret();
-      Refresh();
-      SetCaretInfo();
-    } else {
-      if (m_SelState.IsExist()) {
-        if (m_SelState.BeginPos.WordCmp(m_SelState.EndPos) < 0)
-          SetCaret(m_SelState.BeginPos);
-        else
-          SetCaret(m_SelState.EndPos);
-
-        SelectNone();
-        ScrollToCaret();
-        SetCaretInfo();
-      } else {
-        if (bCtrl)
-          SetCaret(m_pVT->GetBeginWordPlace());
-        else
-          SetCaret(m_pVT->GetLineBeginPlace(m_wpCaret));
-
-        ScrollToCaret();
-        SetCaretOrigin();
-        SetCaretInfo();
-      }
-    }
-  }
-}
-
-void CFX_Edit::OnVK_END(bool bShift, bool bCtrl) {
-  if (m_pVT->IsValid()) {
-    if (bShift) {
-      if (bCtrl)
-        SetCaret(m_pVT->GetEndWordPlace());
-      else
-        SetCaret(m_pVT->GetLineEndPlace(m_wpCaret));
-
-      if (m_SelState.IsExist())
-        m_SelState.SetEndPos(m_wpCaret);
-      else
-        m_SelState.Set(m_wpOldCaret, m_wpCaret);
-
-      ScrollToCaret();
-      Refresh();
-      SetCaretInfo();
-    } else {
-      if (m_SelState.IsExist()) {
-        if (m_SelState.BeginPos.WordCmp(m_SelState.EndPos) > 0)
-          SetCaret(m_SelState.BeginPos);
-        else
-          SetCaret(m_SelState.EndPos);
-
-        SelectNone();
-        ScrollToCaret();
-        SetCaretInfo();
-      } else {
-        if (bCtrl)
-          SetCaret(m_pVT->GetEndWordPlace());
-        else
-          SetCaret(m_pVT->GetLineEndPlace(m_wpCaret));
-
-        ScrollToCaret();
-        SetCaretOrigin();
-        SetCaretInfo();
-      }
-    }
-  }
-}
-
-bool CFX_Edit::InsertWord(uint16_t word,
-                          int32_t charset,
-                          const CPVT_WordProps* pWordProps,
-                          bool bAddUndo,
-                          bool bPaint) {
-  if (IsTextOverflow() || !m_pVT->IsValid())
-    return false;
-
-  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;
-
-  if (bAddUndo && m_bEnableUndo) {
-    AddEditUndoItem(pdfium::MakeUnique<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;
-}
-
-bool CFX_Edit::InsertReturn(const CPVT_SecProps* pSecProps,
-                            const CPVT_WordProps* pWordProps,
-                            bool bAddUndo,
-                            bool bPaint) {
-  if (IsTextOverflow() || !m_pVT->IsValid())
-    return false;
-
-  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 (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 true;
-}
-
-bool CFX_Edit::Backspace(bool bAddUndo, bool bPaint) {
-  if (!m_pVT->IsValid() || m_wpCaret == m_pVT->GetBeginWordPlace())
-    return false;
-
-  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 && 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 true;
-}
-
-bool CFX_Edit::Delete(bool bAddUndo, bool bPaint) {
-  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(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 true;
-}
-
-bool CFX_Edit::Empty() {
-  if (m_pVT->IsValid()) {
-    m_pVT->DeleteWords(GetWholeWordRange());
-    SetCaret(m_pVT->GetBeginWordPlace());
-
-    return true;
-  }
-
-  return false;
-}
-
-bool CFX_Edit::Clear(bool bAddUndo, bool bPaint) {
-  if (!m_pVT->IsValid() || !m_SelState.IsExist())
-    return false;
-
-  CPVT_WordRange range = m_SelState.ConvertToWordRange();
-  if (bAddUndo && m_bEnableUndo)
-    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();
-    Refresh();
-    SetCaretOrigin();
-    SetCaretInfo();
-  }
-  if (m_bOprNotify && m_pOprNotify)
-    m_pOprNotify->OnClear(m_wpCaret, m_wpOldCaret);
-
-  return true;
-}
-
-bool CFX_Edit::InsertText(const CFX_WideString& sText,
-                          int32_t charset,
-                          bool bAddUndo,
-                          bool bPaint) {
-  if (IsTextOverflow())
-    return false;
-
-  m_pVT->UpdateWordPlace(m_wpCaret);
-  SetCaret(DoInsertText(m_wpCaret, sText, charset));
-  m_SelState.Set(m_wpCaret, m_wpCaret);
-  if (m_wpCaret == m_wpOldCaret)
-    return false;
-
-  if (bAddUndo && m_bEnableUndo) {
-    AddEditUndoItem(pdfium::MakeUnique<CFXEU_InsertText>(
-        this, m_wpOldCaret, m_wpCaret, sText, charset));
-  }
-  if (bPaint)
-    PaintInsertText(m_wpOldCaret, m_wpCaret);
-
-  if (m_bOprNotify && m_pOprNotify)
-    m_pOprNotify->OnInsertText(m_wpCaret, m_wpOldCaret);
-
-  return true;
-}
-
-void CFX_Edit::PaintInsertText(const CPVT_WordPlace& wpOld,
-                               const CPVT_WordPlace& wpNew) {
-  if (m_pVT->IsValid()) {
-    RearrangePart(CPVT_WordRange(wpOld, wpNew));
-    ScrollToCaret();
-    Refresh();
-    SetCaretOrigin();
-    SetCaretInfo();
-  }
-}
-
-bool CFX_Edit::Redo() {
-  if (m_bEnableUndo) {
-    if (m_Undo.CanRedo()) {
-      m_Undo.Redo();
-      return true;
-    }
-  }
-
-  return false;
-}
-
-bool CFX_Edit::Undo() {
-  if (m_bEnableUndo) {
-    if (m_Undo.CanUndo()) {
-      m_Undo.Undo();
-      return true;
-    }
-  }
-
-  return false;
-}
-
-void CFX_Edit::SetCaretOrigin() {
-  if (!m_pVT->IsValid())
-    return;
-
-  CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
-  pIterator->SetAt(m_wpCaret);
-  CPVT_Word word;
-  CPVT_Line line;
-  if (pIterator->GetWord(word)) {
-    m_ptCaret.x = word.ptWord.x + word.fWidth;
-    m_ptCaret.y = word.ptWord.y;
-  } else if (pIterator->GetLine(line)) {
-    m_ptCaret.x = line.ptLine.x;
-    m_ptCaret.y = line.ptLine.y;
-  }
-}
-
-int32_t CFX_Edit::WordPlaceToWordIndex(const CPVT_WordPlace& place) const {
-  if (m_pVT->IsValid())
-    return m_pVT->WordPlaceToWordIndex(place);
-
-  return -1;
-}
-
-CPVT_WordPlace CFX_Edit::WordIndexToWordPlace(int32_t index) const {
-  if (m_pVT->IsValid())
-    return m_pVT->WordIndexToWordPlace(index);
-
-  return CPVT_WordPlace();
-}
-
-bool CFX_Edit::IsTextFull() const {
-  int32_t nTotalWords = m_pVT->GetTotalWords();
-  int32_t nLimitChar = m_pVT->GetLimitChar();
-  int32_t nCharArray = m_pVT->GetCharArray();
-
-  return IsTextOverflow() || (nLimitChar > 0 && nTotalWords >= nLimitChar) ||
-         (nCharArray > 0 && nTotalWords >= nCharArray);
-}
-
-bool CFX_Edit::IsTextOverflow() const {
-  if (!m_bEnableScroll && !m_bEnableOverflow) {
-    CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
-    CFX_FloatRect rcContent = m_pVT->GetContentRect();
-
-    if (m_pVT->IsMultiLine() && GetTotalLines() > 1 &&
-        IsFloatBigger(rcContent.Height(), rcPlate.Height())) {
-      return true;
-    }
-
-    if (IsFloatBigger(rcContent.Width(), rcPlate.Width()))
-      return true;
-  }
-
-  return false;
-}
-
-bool CFX_Edit::CanUndo() const {
-  if (m_bEnableUndo) {
-    return m_Undo.CanUndo();
-  }
-
-  return false;
-}
-
-bool CFX_Edit::CanRedo() const {
-  if (m_bEnableUndo) {
-    return m_Undo.CanRedo();
-  }
-
-  return false;
-}
-
-void CFX_Edit::EnableRefresh(bool bRefresh) {
-  m_bEnableRefresh = bRefresh;
-}
-
-void CFX_Edit::EnableUndo(bool bUndo) {
-  m_bEnableUndo = bUndo;
-}
-
-void CFX_Edit::EnableOprNotify(bool bNotify) {
-  m_bOprNotify = bNotify;
-}
-
-CPVT_WordPlace CFX_Edit::DoInsertText(const CPVT_WordPlace& place,
-                                      const CFX_WideString& sText,
-                                      int32_t charset) {
-  CPVT_WordPlace wp = place;
-
-  if (m_pVT->IsValid()) {
-    for (int32_t i = 0, sz = sText.GetLength(); i < sz; i++) {
-      uint16_t word = sText[i];
-      switch (word) {
-        case 0x0D:
-          wp = m_pVT->InsertSection(wp, nullptr, nullptr);
-          if (sText[i + 1] == 0x0A)
-            i++;
-          break;
-        case 0x0A:
-          wp = m_pVT->InsertSection(wp, nullptr, nullptr);
-          if (sText[i + 1] == 0x0D)
-            i++;
-          break;
-        case 0x09:
-          word = 0x20;
-        default:
-          wp = m_pVT->InsertWord(wp, word, GetCharSetFromUnicode(word, charset),
-                                 nullptr);
-          break;
-      }
-    }
-  }
-
-  return wp;
-}
-
-int32_t CFX_Edit::GetCharSetFromUnicode(uint16_t word, int32_t nOldCharset) {
-  if (IPVT_FontMap* pFontMap = GetFontMap())
-    return pFontMap->CharSetFromUnicode(word, nOldCharset);
-  return nOldCharset;
-}
-
-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() {}
-
-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.push_back(pdfium::MakeUnique<CFX_Edit_LineRect>(wrLine, rcLine));
-}
-
-int32_t CFX_Edit_LineRectArray::GetSize() const {
-  return pdfium::CollectionSize<int32_t>(m_LineRects);
-}
-
-CFX_Edit_LineRect* CFX_Edit_LineRectArray::GetAt(int32_t nIndex) const {
-  if (nIndex < 0 || nIndex >= GetSize())
-    return nullptr;
-
-  return m_LineRects[nIndex].get();
-}
-
-CFX_Edit_Select::CFX_Edit_Select() {}
-
-CFX_Edit_Select::CFX_Edit_Select(const CPVT_WordPlace& begin,
-                                 const CPVT_WordPlace& end) {
-  Set(begin, end);
-}
-
-CFX_Edit_Select::CFX_Edit_Select(const CPVT_WordRange& range) {
-  Set(range.BeginPos, range.EndPos);
-}
-
-CPVT_WordRange CFX_Edit_Select::ConvertToWordRange() const {
-  return CPVT_WordRange(BeginPos, EndPos);
-}
-
-void CFX_Edit_Select::Default() {
-  BeginPos.Default();
-  EndPos.Default();
-}
-
-void CFX_Edit_Select::Set(const CPVT_WordPlace& begin,
-                          const CPVT_WordPlace& end) {
-  BeginPos = begin;
-  EndPos = end;
-}
-
-void CFX_Edit_Select::SetBeginPos(const CPVT_WordPlace& begin) {
-  BeginPos = begin;
-}
-
-void CFX_Edit_Select::SetEndPos(const CPVT_WordPlace& end) {
-  EndPos = end;
-}
-
-bool CFX_Edit_Select::IsExist() const {
-  return BeginPos != EndPos;
-}
-
-CFX_Edit_RectArray::CFX_Edit_RectArray() {}
-
-CFX_Edit_RectArray::~CFX_Edit_RectArray() {}
-
-void CFX_Edit_RectArray::Clear() {
-  m_Rects.clear();
-}
-
-void CFX_Edit_RectArray::Add(const CFX_FloatRect& rect) {
-  // check for overlapped area
-  for (const auto& pRect : m_Rects) {
-    if (pRect && pRect->Contains(rect))
-      return;
-  }
-  m_Rects.push_back(pdfium::MakeUnique<CFX_FloatRect>(rect));
-}
-
-int32_t CFX_Edit_RectArray::GetSize() const {
-  return pdfium::CollectionSize<int32_t>(m_Rects);
-}
-
-CFX_FloatRect* CFX_Edit_RectArray::GetAt(int32_t nIndex) const {
-  if (nIndex < 0 || nIndex >= GetSize())
-    return nullptr;
-
-  return m_Rects[nIndex].get();
-}
diff --git a/fpdfsdk/fxedit/fxet_edit.h b/fpdfsdk/fxedit/fxet_edit.h
deleted file mode 100644
index ab83af2..0000000
--- a/fpdfsdk/fxedit/fxet_edit.h
+++ /dev/null
@@ -1,545 +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 FPDFSDK_FXEDIT_FXET_EDIT_H_
-#define FPDFSDK_FXEDIT_FXET_EDIT_H_
-
-#include <deque>
-#include <memory>
-#include <vector>
-
-#include "core/fpdfdoc/cpvt_secprops.h"
-#include "core/fpdfdoc/cpvt_wordprops.h"
-#include "fpdfsdk/fxedit/fx_edit.h"
-
-class CFFL_FormFiller;
-class CFX_Edit;
-class CFX_Edit_Iterator;
-class CFX_Edit_Provider;
-class CFX_RenderDevice;
-class CFX_SystemHandler;
-class CPDF_PageObjectHolder;
-class CPDF_TextObject;
-class CPWL_Edit;
-class CPWL_EditCtrl;
-
-class IFX_Edit_UndoItem;
-
-struct CFX_Edit_LineRect {
-  CFX_Edit_LineRect(const CPVT_WordRange& wrLine, const CFX_FloatRect& rcLine)
-      : m_wrLine(wrLine), m_rcLine(rcLine) {}
-
-  CPVT_WordRange m_wrLine;
-  CFX_FloatRect m_rcLine;
-};
-
-class CFX_Edit_LineRectArray {
- public:
-  CFX_Edit_LineRectArray();
-  virtual ~CFX_Edit_LineRectArray();
-
-  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:
-  std::vector<std::unique_ptr<CFX_Edit_LineRect>> m_LineRects;
-};
-
-class CFX_Edit_RectArray {
- public:
-  CFX_Edit_RectArray();
-  virtual ~CFX_Edit_RectArray();
-
-  void Clear();
-  void Add(const CFX_FloatRect& rect);
-
-  int32_t GetSize() const;
-  CFX_FloatRect* GetAt(int32_t nIndex) const;
-
- private:
-  std::vector<std::unique_ptr<CFX_FloatRect>> m_Rects;
-};
-
-class CFX_Edit_Refresh {
- public:
-  CFX_Edit_Refresh();
-  virtual ~CFX_Edit_Refresh();
-
-  void BeginRefresh();
-  void Push(const CPVT_WordRange& linerange, const CFX_FloatRect& rect);
-  void NoAnalyse();
-  void AddRefresh(const CFX_FloatRect& rect);
-  const CFX_Edit_RectArray* GetRefreshRects() const;
-  void EndRefresh();
-
- private:
-  CFX_Edit_LineRectArray m_NewLineRects;
-  CFX_Edit_LineRectArray m_OldLineRects;
-  CFX_Edit_RectArray m_RefreshRects;
-};
-
-class CFX_Edit_Select {
- public:
-  CFX_Edit_Select();
-  CFX_Edit_Select(const CPVT_WordPlace& begin, const CPVT_WordPlace& end);
-  explicit CFX_Edit_Select(const CPVT_WordRange& range);
-
-  void Default();
-  void Set(const CPVT_WordPlace& begin, const CPVT_WordPlace& end);
-  void SetBeginPos(const CPVT_WordPlace& begin);
-  void SetEndPos(const CPVT_WordPlace& end);
-
-  CPVT_WordRange ConvertToWordRange() const;
-  bool IsExist() const;
-
-  CPVT_WordPlace BeginPos;
-  CPVT_WordPlace EndPos;
-};
-
-class CFX_Edit_Undo {
- public:
-  explicit CFX_Edit_Undo(int32_t nBufsize);
-  virtual ~CFX_Edit_Undo();
-
-  void AddItem(std::unique_ptr<IFX_Edit_UndoItem> pItem);
-  void Undo();
-  void Redo();
-  bool CanUndo() const;
-  bool CanRedo() const;
-  bool IsModified() const;
-  void Reset();
-
- private:
-  void RemoveHeads();
-  void RemoveTails();
-
-  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;
-};
-
-class IFX_Edit_UndoItem {
- public:
-  virtual ~IFX_Edit_UndoItem() {}
-
-  virtual void Undo() = 0;
-  virtual void Redo() = 0;
-  virtual CFX_WideString GetUndoTitle() const = 0;
-};
-
-class CFX_Edit_UndoItem : public IFX_Edit_UndoItem {
- public:
-  CFX_Edit_UndoItem();
-  ~CFX_Edit_UndoItem() override;
-
-  CFX_WideString GetUndoTitle() const override;
-
-  void SetFirst(bool bFirst);
-  void SetLast(bool bLast);
-  bool IsLast();
-
- private:
-  bool m_bFirst;
-  bool m_bLast;
-};
-
-class CFX_Edit_GroupUndoItem : public IFX_Edit_UndoItem {
- public:
-  explicit CFX_Edit_GroupUndoItem(const CFX_WideString& sTitle);
-  ~CFX_Edit_GroupUndoItem() override;
-
-  // IFX_Edit_UndoItem
-  void Undo() override;
-  void Redo() override;
-  CFX_WideString GetUndoTitle() const override;
-
-  void AddUndoItem(std::unique_ptr<CFX_Edit_UndoItem> pUndoItem);
-  void UpdateItems();
-
- private:
-  CFX_WideString m_sTitle;
-  std::vector<std::unique_ptr<CFX_Edit_UndoItem>> m_Items;
-};
-
-class CFXEU_InsertWord : public CFX_Edit_UndoItem {
- public:
-  CFXEU_InsertWord(CFX_Edit* pEdit,
-                   const CPVT_WordPlace& wpOldPlace,
-                   const CPVT_WordPlace& wpNewPlace,
-                   uint16_t word,
-                   int32_t charset,
-                   const CPVT_WordProps* pWordProps);
-  ~CFXEU_InsertWord() override;
-
-  // CFX_Edit_UndoItem
-  void Redo() override;
-  void Undo() override;
-
- private:
-  CFX_Edit* m_pEdit;
-
-  CPVT_WordPlace m_wpOld;
-  CPVT_WordPlace m_wpNew;
-  uint16_t m_Word;
-  int32_t m_nCharset;
-  CPVT_WordProps m_WordProps;
-};
-
-class CFXEU_InsertReturn : public CFX_Edit_UndoItem {
- public:
-  CFXEU_InsertReturn(CFX_Edit* pEdit,
-                     const CPVT_WordPlace& wpOldPlace,
-                     const CPVT_WordPlace& wpNewPlace,
-                     const CPVT_SecProps* pSecProps,
-                     const CPVT_WordProps* pWordProps);
-  ~CFXEU_InsertReturn() override;
-
-  // CFX_Edit_UndoItem
-  void Redo() override;
-  void Undo() override;
-
- private:
-  CFX_Edit* m_pEdit;
-
-  CPVT_WordPlace m_wpOld;
-  CPVT_WordPlace m_wpNew;
-  CPVT_SecProps m_SecProps;
-  CPVT_WordProps m_WordProps;
-};
-
-class CFXEU_Backspace : public CFX_Edit_UndoItem {
- public:
-  CFXEU_Backspace(CFX_Edit* pEdit,
-                  const CPVT_WordPlace& wpOldPlace,
-                  const CPVT_WordPlace& wpNewPlace,
-                  uint16_t word,
-                  int32_t charset,
-                  const CPVT_SecProps& SecProps,
-                  const CPVT_WordProps& WordProps);
-  ~CFXEU_Backspace() override;
-
-  // CFX_Edit_UndoItem
-  void Redo() override;
-  void Undo() override;
-
- private:
-  CFX_Edit* m_pEdit;
-
-  CPVT_WordPlace m_wpOld;
-  CPVT_WordPlace m_wpNew;
-  uint16_t m_Word;
-  int32_t m_nCharset;
-  CPVT_SecProps m_SecProps;
-  CPVT_WordProps m_WordProps;
-};
-
-class CFXEU_Delete : public CFX_Edit_UndoItem {
- public:
-  CFXEU_Delete(CFX_Edit* pEdit,
-               const CPVT_WordPlace& wpOldPlace,
-               const CPVT_WordPlace& wpNewPlace,
-               uint16_t word,
-               int32_t charset,
-               const CPVT_SecProps& SecProps,
-               const CPVT_WordProps& WordProps,
-               bool bSecEnd);
-  ~CFXEU_Delete() override;
-
-  // CFX_Edit_UndoItem
-  void Redo() override;
-  void Undo() override;
-
- private:
-  CFX_Edit* m_pEdit;
-
-  CPVT_WordPlace m_wpOld;
-  CPVT_WordPlace m_wpNew;
-  uint16_t m_Word;
-  int32_t m_nCharset;
-  CPVT_SecProps m_SecProps;
-  CPVT_WordProps m_WordProps;
-  bool m_bSecEnd;
-};
-
-class CFXEU_Clear : public CFX_Edit_UndoItem {
- public:
-  CFXEU_Clear(CFX_Edit* pEdit,
-              const CPVT_WordRange& wrSel,
-              const CFX_WideString& swText);
-  ~CFXEU_Clear() override;
-
-  // CFX_Edit_UndoItem
-  void Redo() override;
-  void Undo() override;
-
- private:
-  CFX_Edit* m_pEdit;
-
-  CPVT_WordRange m_wrSel;
-  CFX_WideString m_swText;
-};
-
-class CFXEU_InsertText : public CFX_Edit_UndoItem {
- public:
-  CFXEU_InsertText(CFX_Edit* pEdit,
-                   const CPVT_WordPlace& wpOldPlace,
-                   const CPVT_WordPlace& wpNewPlace,
-                   const CFX_WideString& swText,
-                   int32_t charset);
-  ~CFXEU_InsertText() override;
-
-  // CFX_Edit_UndoItem
-  void Redo() override;
-  void Undo() override;
-
- private:
-  CFX_Edit* m_pEdit;
-
-  CPVT_WordPlace m_wpOld;
-  CPVT_WordPlace m_wpNew;
-  CFX_WideString m_swText;
-  int32_t m_nCharset;
-};
-
-class CFX_Edit {
- public:
-  static CFX_ByteString GetEditAppearanceStream(CFX_Edit* pEdit,
-                                                const CFX_PointF& ptOffset,
-                                                const CPVT_WordRange* pRange,
-                                                bool bContinuous,
-                                                uint16_t SubWord);
-  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,
-                       const CFX_FloatRect& rcClip,
-                       const CFX_PointF& ptOffset,
-                       const CPVT_WordRange* pRange,
-                       CFX_SystemHandler* pSystemHandler,
-                       CFFL_FormFiller* pFFLData);
-
-  CFX_Edit();
-  ~CFX_Edit();
-
-  void SetFontMap(IPVT_FontMap* pFontMap);
-  void SetNotify(CPWL_EditCtrl* pNotify);
-  void SetOprNotify(CPWL_Edit* pOprNotify);
-
-  // Returns an iterator for the contents. Should not be released.
-  CFX_Edit_Iterator* GetIterator();
-  IPVT_FontMap* GetFontMap();
-  void Initialize();
-
-  // Set the bounding box of the text area.
-  void SetPlateRect(const CFX_FloatRect& rect);
-  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);
-  // Set the vertical text alignment. (nFormat [0:left, 1:middle, 2:right])
-  void SetAlignmentV(int32_t nFormat, bool bPaint);
-
-  // Set the substitution character for hidden text.
-  void SetPasswordChar(uint16_t wSubWord, bool bPaint);
-
-  // Set the maximum number of words in the text.
-  void SetLimitChar(int32_t nLimitChar);
-  void SetCharArray(int32_t nCharArray);
-  void SetCharSpace(FX_FLOAT fCharSpace);
-  void SetMultiLine(bool bMultiLine, bool bPaint);
-  void SetAutoReturn(bool bAuto, bool bPaint);
-  void SetAutoFontSize(bool bAuto, bool bPaint);
-  void SetAutoScroll(bool bAuto, bool bPaint);
-  void SetFontSize(FX_FLOAT fFontSize);
-  void SetTextOverflow(bool bAllowed, bool bPaint);
-  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);
-  void OnVK_RIGHT(bool bShift, bool bCtrl);
-  void OnVK_HOME(bool bShift, bool bCtrl);
-  void OnVK_END(bool bShift, bool bCtrl);
-  void SetText(const CFX_WideString& sText);
-  bool InsertWord(uint16_t word, int32_t charset);
-  bool InsertReturn();
-  bool Backspace();
-  bool Delete();
-  bool Clear();
-  bool InsertText(const CFX_WideString& sText, int32_t charset);
-  bool Redo();
-  bool Undo();
-  int32_t WordPlaceToWordIndex(const CPVT_WordPlace& place) const;
-  CPVT_WordPlace WordIndexToWordPlace(int32_t index) 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_PointF GetScrollPos() const;
-  int32_t GetCharArray() const;
-  CFX_FloatRect GetContentRect() const;
-  CFX_WideString GetRangeText(const CPVT_WordRange& range) const;
-  int32_t GetHorzScale() const;
-  FX_FLOAT GetCharSpace() const;
-  int32_t GetTotalWords() const;
-  void SetSel(int32_t nStartChar, int32_t nEndChar);
-  void GetSel(int32_t& nStartChar, int32_t& nEndChar) const;
-  void SelectAll();
-  void SelectNone();
-  bool IsSelected() const;
-  void Paint();
-  void EnableRefresh(bool bRefresh);
-  void RefreshWordRange(const CPVT_WordRange& wr);
-  void SetCaret(int32_t nPos);
-  CPVT_WordRange GetWholeWordRange() const;
-  CPVT_WordRange GetSelectWordRange() const;
-  void EnableUndo(bool bUndo);
-  void EnableOprNotify(bool bNotify);
-  bool IsTextFull() const;
-  bool IsTextOverflow() const;
-  bool CanUndo() const;
-  bool CanRedo() const;
-  CPVT_WordRange GetVisibleWordRange() const;
-
-  bool Empty();
-
-  CPVT_WordPlace DoInsertText(const CPVT_WordPlace& place,
-                              const CFX_WideString& sText,
-                              int32_t charset);
-  int32_t GetCharSetFromUnicode(uint16_t word, int32_t nOldCharset);
-
-  int32_t GetTotalLines() const;
-
- private:
-  friend class CFX_Edit_Iterator;
-  friend class CFXEU_InsertWord;
-  friend class CFXEU_InsertReturn;
-  friend class CFXEU_Backspace;
-  friend class CFXEU_Delete;
-  friend class CFXEU_Clear;
-  friend class CFXEU_InsertText;
-
-  void SetSel(const CPVT_WordPlace& begin, const CPVT_WordPlace& end);
-
-  void RearrangeAll();
-  void RearrangePart(const CPVT_WordRange& range);
-  void ScrollToCaret();
-  void SetScrollInfo();
-  void SetScrollPosX(FX_FLOAT fx);
-  void SetScrollPosY(FX_FLOAT fy);
-  void SetScrollLimit();
-  void SetContentChanged();
-
-  bool InsertWord(uint16_t word,
-                  int32_t charset,
-                  const CPVT_WordProps* pWordProps,
-                  bool bAddUndo,
-                  bool bPaint);
-  bool InsertReturn(const CPVT_SecProps* pSecProps,
-                    const CPVT_WordProps* pWordProps,
-                    bool bAddUndo,
-                    bool bPaint);
-  bool Backspace(bool bAddUndo, bool bPaint);
-  bool Delete(bool bAddUndo, bool bPaint);
-  bool Clear(bool bAddUndo, bool bPaint);
-  bool InsertText(const CFX_WideString& sText,
-                  int32_t charset,
-                  bool bAddUndo,
-                  bool bPaint);
-  void PaintInsertText(const CPVT_WordPlace& wpOld,
-                       const CPVT_WordPlace& wpNew);
-
-  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();
-  void RefreshPushLineRects(const CPVT_WordRange& wr);
-
-  void SetCaret(const CPVT_WordPlace& place);
-  void SetCaretInfo();
-  void SetCaretOrigin();
-
-  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_PointF m_ptScrollPos;
-  CFX_PointF m_ptRefreshScrollPos;
-  bool m_bEnableScroll;
-  std::unique_ptr<CFX_Edit_Iterator> m_pIterator;
-  CFX_Edit_Refresh m_Refresh;
-  CFX_PointF m_ptCaret;
-  CFX_Edit_Undo m_Undo;
-  int32_t m_nAlignment;
-  bool m_bNotifyFlag;
-  bool m_bEnableOverflow;
-  bool m_bEnableRefresh;
-  CFX_FloatRect m_rcOldContent;
-  bool m_bEnableUndo;
-  bool m_bOprNotify;
-  CFX_Edit_GroupUndoItem* m_pGroupUndoItem;
-};
-
-class CFX_Edit_Iterator {
- public:
-  CFX_Edit_Iterator(CFX_Edit* pEdit, CPDF_VariableText::Iterator* pVTIterator);
-  ~CFX_Edit_Iterator();
-
-  bool NextWord();
-  bool PrevWord();
-  bool GetWord(CPVT_Word& word) const;
-  bool GetLine(CPVT_Line& line) const;
-  bool GetSection(CPVT_Section& section) const;
-  void SetAt(int32_t nWordIndex);
-  void SetAt(const CPVT_WordPlace& place);
-  const CPVT_WordPlace& GetAt() const;
-
- private:
-  CFX_Edit* m_pEdit;
-  CPDF_VariableText::Iterator* m_pVTIterator;
-};
-
-class CFX_Edit_Provider : public CPDF_VariableText::Provider {
- public:
-  explicit CFX_Edit_Provider(IPVT_FontMap* pFontMap);
-  ~CFX_Edit_Provider() override;
-
-  IPVT_FontMap* GetFontMap();
-
-  // CPDF_VariableText::Provider:
-  int32_t GetCharWidth(int32_t nFontIndex, uint16_t word) override;
-  int32_t GetTypeAscent(int32_t nFontIndex) override;
-  int32_t GetTypeDescent(int32_t nFontIndex) override;
-  int32_t GetWordFontIndex(uint16_t word,
-                           int32_t charset,
-                           int32_t nFontIndex) override;
-  int32_t GetDefaultFontIndex() override;
-  bool IsLatinWord(uint16_t word) override;
-
- private:
-  IPVT_FontMap* m_pFontMap;
-};
-
-#endif  // FPDFSDK_FXEDIT_FXET_EDIT_H_
diff --git a/fpdfsdk/fxedit/fxet_list.cpp b/fpdfsdk/fxedit/fxet_list.cpp
deleted file mode 100644
index 39877c9..0000000
--- a/fpdfsdk/fxedit/fxet_list.cpp
+++ /dev/null
@@ -1,784 +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/fxedit/fxet_list.h"
-
-#include "core/fpdfdoc/cpvt_word.h"
-#include "fpdfsdk/fxedit/fxet_edit.h"
-#include "fpdfsdk/pdfwindow/PWL_ListBox.h"
-
-CFX_ListItem::CFX_ListItem()
-    : m_pEdit(new CFX_Edit),
-      m_bSelected(false),
-      m_rcListItem(0.0f, 0.0f, 0.0f, 0.0f) {
-  m_pEdit->SetAlignmentV(1, true);
-  m_pEdit->Initialize();
-}
-
-CFX_ListItem::~CFX_ListItem() {
-}
-
-void CFX_ListItem::SetFontMap(IPVT_FontMap* pFontMap) {
-  m_pEdit->SetFontMap(pFontMap);
-}
-
-CFX_Edit* CFX_ListItem::GetEdit() const {
-  return m_pEdit.get();
-}
-
-CFX_Edit_Iterator* CFX_ListItem::GetIterator() const {
-  return m_pEdit->GetIterator();
-}
-
-void CFX_ListItem::SetRect(const CLST_Rect& rect) {
-  m_rcListItem = rect;
-}
-
-CLST_Rect CFX_ListItem::GetRect() const {
-  return m_rcListItem;
-}
-
-bool CFX_ListItem::IsSelected() const {
-  return m_bSelected;
-}
-
-void CFX_ListItem::SetSelect(bool bSelected) {
-  m_bSelected = bSelected;
-}
-
-void CFX_ListItem::SetText(const CFX_WideString& text) {
-  m_pEdit->SetText(text);
-}
-
-void CFX_ListItem::SetFontSize(FX_FLOAT fFontSize) {
-  m_pEdit->SetFontSize(fFontSize);
-}
-
-FX_FLOAT CFX_ListItem::GetItemHeight() const {
-  return m_pEdit->GetContentRect().Height();
-}
-
-uint16_t CFX_ListItem::GetFirstChar() const {
-  CPVT_Word word;
-  CFX_Edit_Iterator* pIterator = GetIterator();
-  pIterator->SetAt(1);
-  pIterator->GetWord(word);
-  return word.Word;
-}
-
-CFX_WideString CFX_ListItem::GetText() const {
-  return m_pEdit->GetText();
-}
-
-CFX_ListContainer::CFX_ListContainer() {}
-
-CFX_ListContainer::~CFX_ListContainer() {}
-
-void CFX_ListContainer::SetPlateRect(const CFX_FloatRect& rect) {
-  m_rcPlate = rect;
-}
-
-CPLST_Select::CPLST_Select() {}
-
-CPLST_Select::~CPLST_Select() {
-  for (int32_t i = 0, sz = m_aItems.GetSize(); i < sz; i++)
-    delete m_aItems.GetAt(i);
-
-  m_aItems.RemoveAll();
-}
-
-void CPLST_Select::Add(int32_t nItemIndex) {
-  int32_t nIndex = Find(nItemIndex);
-
-  if (nIndex < 0) {
-    m_aItems.Add(new CPLST_Select_Item(nItemIndex, 1));
-  } else {
-    if (CPLST_Select_Item* pItem = m_aItems.GetAt(nIndex)) {
-      pItem->nState = 1;
-    }
-  }
-}
-
-void CPLST_Select::Add(int32_t nBeginIndex, int32_t nEndIndex) {
-  if (nBeginIndex > nEndIndex) {
-    int32_t nTemp = nEndIndex;
-    nEndIndex = nBeginIndex;
-    nBeginIndex = nTemp;
-  }
-
-  for (int32_t i = nBeginIndex; i <= nEndIndex; i++)
-    Add(i);
-}
-
-void CPLST_Select::Sub(int32_t nItemIndex) {
-  for (int32_t i = m_aItems.GetSize() - 1; i >= 0; i--) {
-    if (CPLST_Select_Item* pItem = m_aItems.GetAt(i))
-      if (pItem->nItemIndex == nItemIndex)
-        pItem->nState = -1;
-  }
-}
-
-void CPLST_Select::Sub(int32_t nBeginIndex, int32_t nEndIndex) {
-  if (nBeginIndex > nEndIndex) {
-    int32_t nTemp = nEndIndex;
-    nEndIndex = nBeginIndex;
-    nBeginIndex = nTemp;
-  }
-
-  for (int32_t i = nBeginIndex; i <= nEndIndex; i++)
-    Sub(i);
-}
-
-int32_t CPLST_Select::Find(int32_t nItemIndex) const {
-  for (int32_t i = 0, sz = m_aItems.GetSize(); i < sz; i++) {
-    if (CPLST_Select_Item* pItem = m_aItems.GetAt(i)) {
-      if (pItem->nItemIndex == nItemIndex)
-        return i;
-    }
-  }
-
-  return -1;
-}
-
-bool CPLST_Select::IsExist(int32_t nItemIndex) const {
-  return Find(nItemIndex) >= 0;
-}
-
-int32_t CPLST_Select::GetCount() const {
-  return m_aItems.GetSize();
-}
-
-int32_t CPLST_Select::GetItemIndex(int32_t nIndex) const {
-  if (nIndex >= 0 && nIndex < m_aItems.GetSize())
-    if (CPLST_Select_Item* pItem = m_aItems.GetAt(nIndex))
-      return pItem->nItemIndex;
-
-  return -1;
-}
-
-int32_t CPLST_Select::GetState(int32_t nIndex) const {
-  if (nIndex >= 0 && nIndex < m_aItems.GetSize())
-    if (CPLST_Select_Item* pItem = m_aItems.GetAt(nIndex))
-      return pItem->nState;
-
-  return 0;
-}
-
-void CPLST_Select::DeselectAll() {
-  for (int32_t i = 0, sz = m_aItems.GetSize(); i < sz; i++) {
-    if (CPLST_Select_Item* pItem = m_aItems.GetAt(i)) {
-      pItem->nState = -1;
-    }
-  }
-}
-
-void CPLST_Select::Done() {
-  for (int32_t i = m_aItems.GetSize() - 1; i >= 0; i--) {
-    if (CPLST_Select_Item* pItem = m_aItems.GetAt(i)) {
-      if (pItem->nState == -1) {
-        delete pItem;
-        m_aItems.RemoveAt(i);
-      } else {
-        pItem->nState = 0;
-      }
-    }
-  }
-}
-
-CFX_ListCtrl::CFX_ListCtrl()
-    : m_pNotify(nullptr),
-      m_bNotifyFlag(false),
-      m_nSelItem(-1),
-      m_nFootIndex(-1),
-      m_bCtrlSel(false),
-      m_nCaretIndex(-1),
-      m_fFontSize(0.0f),
-      m_pFontMap(nullptr),
-      m_bMultiple(false) {}
-
-CFX_ListCtrl::~CFX_ListCtrl() {
-  Empty();
-}
-
-void CFX_ListCtrl::SetNotify(CPWL_List_Notify* pNotify) {
-  m_pNotify = pNotify;
-}
-
-CFX_PointF CFX_ListCtrl::InToOut(const CFX_PointF& point) const {
-  CFX_FloatRect rcPlate = GetPlateRect();
-  return CFX_PointF(point.x - (m_ptScrollPos.x - rcPlate.left),
-                    point.y - (m_ptScrollPos.y - rcPlate.top));
-}
-
-CFX_PointF CFX_ListCtrl::OutToIn(const CFX_PointF& point) const {
-  CFX_FloatRect rcPlate = GetPlateRect();
-  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_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_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_PointF& point,
-                               bool bShift,
-                               bool bCtrl) {
-  int32_t nHitIndex = GetItemIndex(point);
-
-  if (IsMultipleSel()) {
-    if (bCtrl) {
-      if (IsItemSelected(nHitIndex)) {
-        m_aSelItems.Sub(nHitIndex);
-        SelectItems();
-        m_bCtrlSel = false;
-      } else {
-        m_aSelItems.Add(nHitIndex);
-        SelectItems();
-        m_bCtrlSel = true;
-      }
-
-      m_nFootIndex = nHitIndex;
-    } else if (bShift) {
-      m_aSelItems.DeselectAll();
-      m_aSelItems.Add(m_nFootIndex, nHitIndex);
-      SelectItems();
-    } else {
-      m_aSelItems.DeselectAll();
-      m_aSelItems.Add(nHitIndex);
-      SelectItems();
-
-      m_nFootIndex = nHitIndex;
-    }
-
-    SetCaret(nHitIndex);
-  } else {
-    SetSingleSelect(nHitIndex);
-  }
-
-  if (!IsItemVisible(nHitIndex))
-    ScrollToListItem(nHitIndex);
-}
-
-void CFX_ListCtrl::OnMouseMove(const CFX_PointF& point,
-                               bool bShift,
-                               bool bCtrl) {
-  int32_t nHitIndex = GetItemIndex(point);
-
-  if (IsMultipleSel()) {
-    if (bCtrl) {
-      if (m_bCtrlSel)
-        m_aSelItems.Add(m_nFootIndex, nHitIndex);
-      else
-        m_aSelItems.Sub(m_nFootIndex, nHitIndex);
-
-      SelectItems();
-    } else {
-      m_aSelItems.DeselectAll();
-      m_aSelItems.Add(m_nFootIndex, nHitIndex);
-      SelectItems();
-    }
-
-    SetCaret(nHitIndex);
-  } else {
-    SetSingleSelect(nHitIndex);
-  }
-
-  if (!IsItemVisible(nHitIndex))
-    ScrollToListItem(nHitIndex);
-}
-
-void CFX_ListCtrl::OnVK(int32_t nItemIndex, bool bShift, bool bCtrl) {
-  if (IsMultipleSel()) {
-    if (nItemIndex >= 0 && nItemIndex < GetCount()) {
-      if (bCtrl) {
-      } else if (bShift) {
-        m_aSelItems.DeselectAll();
-        m_aSelItems.Add(m_nFootIndex, nItemIndex);
-        SelectItems();
-      } else {
-        m_aSelItems.DeselectAll();
-        m_aSelItems.Add(nItemIndex);
-        SelectItems();
-        m_nFootIndex = nItemIndex;
-      }
-
-      SetCaret(nItemIndex);
-    }
-  } else {
-    SetSingleSelect(nItemIndex);
-  }
-
-  if (!IsItemVisible(nItemIndex))
-    ScrollToListItem(nItemIndex);
-}
-
-void CFX_ListCtrl::OnVK_UP(bool bShift, bool bCtrl) {
-  OnVK(IsMultipleSel() ? GetCaret() - 1 : GetSelect() - 1, bShift, bCtrl);
-}
-
-void CFX_ListCtrl::OnVK_DOWN(bool bShift, bool bCtrl) {
-  OnVK(IsMultipleSel() ? GetCaret() + 1 : GetSelect() + 1, bShift, bCtrl);
-}
-
-void CFX_ListCtrl::OnVK_LEFT(bool bShift, bool bCtrl) {
-  OnVK(0, bShift, bCtrl);
-}
-
-void CFX_ListCtrl::OnVK_RIGHT(bool bShift, bool bCtrl) {
-  OnVK(GetCount() - 1, bShift, bCtrl);
-}
-
-void CFX_ListCtrl::OnVK_HOME(bool bShift, bool bCtrl) {
-  OnVK(0, bShift, bCtrl);
-}
-
-void CFX_ListCtrl::OnVK_END(bool bShift, bool bCtrl) {
-  OnVK(GetCount() - 1, bShift, bCtrl);
-}
-
-bool CFX_ListCtrl::OnChar(uint16_t nChar, bool bShift, bool bCtrl) {
-  int32_t nIndex = GetLastSelected();
-  int32_t nFindIndex = FindNext(nIndex, nChar);
-
-  if (nFindIndex != nIndex) {
-    OnVK(nFindIndex, bShift, bCtrl);
-    return true;
-  }
-  return false;
-}
-
-void CFX_ListCtrl::SetPlateRect(const CFX_FloatRect& rect) {
-  CFX_ListContainer::SetPlateRect(rect);
-  m_ptScrollPos.x = rect.left;
-  SetScrollPos(CFX_PointF(rect.left, rect.top));
-  ReArrange(0);
-  InvalidateItem(-1);
-}
-
-CFX_FloatRect CFX_ListCtrl::GetItemRect(int32_t nIndex) const {
-  return InToOut(GetItemRectInternal(nIndex));
-}
-
-CFX_FloatRect CFX_ListCtrl::GetItemRectInternal(int32_t nIndex) const {
-  if (CFX_ListItem* pListItem = m_aListItems.GetAt(nIndex)) {
-    CFX_FloatRect rcItem = pListItem->GetRect();
-    rcItem.left = 0.0f;
-    rcItem.right = GetPlateRect().Width();
-    return InnerToOuter(CLST_Rect(rcItem));
-  }
-
-  return CFX_FloatRect();
-}
-
-int32_t CFX_ListCtrl::GetCaret() const {
-  return m_nCaretIndex;
-}
-
-int32_t CFX_ListCtrl::GetSelect() const {
-  return m_nSelItem;
-}
-
-void CFX_ListCtrl::AddString(const CFX_WideString& str) {
-  AddItem(str);
-  ReArrange(GetCount() - 1);
-}
-
-void CFX_ListCtrl::SetMultipleSelect(int32_t nItemIndex, bool bSelected) {
-  if (!IsValid(nItemIndex))
-    return;
-
-  if (bSelected != IsItemSelected(nItemIndex)) {
-    if (bSelected) {
-      SetItemSelect(nItemIndex, true);
-      InvalidateItem(nItemIndex);
-    } else {
-      SetItemSelect(nItemIndex, false);
-      InvalidateItem(nItemIndex);
-    }
-  }
-}
-
-void CFX_ListCtrl::SetSingleSelect(int32_t nItemIndex) {
-  if (!IsValid(nItemIndex))
-    return;
-
-  if (m_nSelItem != nItemIndex) {
-    if (m_nSelItem >= 0) {
-      SetItemSelect(m_nSelItem, false);
-      InvalidateItem(m_nSelItem);
-    }
-
-    SetItemSelect(nItemIndex, true);
-    InvalidateItem(nItemIndex);
-    m_nSelItem = nItemIndex;
-  }
-}
-
-void CFX_ListCtrl::SetCaret(int32_t nItemIndex) {
-  if (!IsValid(nItemIndex))
-    return;
-
-  if (IsMultipleSel()) {
-    int32_t nOldIndex = m_nCaretIndex;
-
-    if (nOldIndex != nItemIndex) {
-      m_nCaretIndex = nItemIndex;
-      InvalidateItem(nOldIndex);
-      InvalidateItem(nItemIndex);
-    }
-  }
-}
-
-void CFX_ListCtrl::InvalidateItem(int32_t nItemIndex) {
-  if (m_pNotify) {
-    if (nItemIndex == -1) {
-      if (!m_bNotifyFlag) {
-        m_bNotifyFlag = true;
-        CFX_FloatRect rcRefresh = GetPlateRect();
-        m_pNotify->IOnInvalidateRect(&rcRefresh);
-        m_bNotifyFlag = false;
-      }
-    } else {
-      if (!m_bNotifyFlag) {
-        m_bNotifyFlag = true;
-        CFX_FloatRect rcRefresh = GetItemRect(nItemIndex);
-        rcRefresh.left -= 1.0f;
-        rcRefresh.right += 1.0f;
-        rcRefresh.bottom -= 1.0f;
-        rcRefresh.top += 1.0f;
-
-        m_pNotify->IOnInvalidateRect(&rcRefresh);
-        m_bNotifyFlag = false;
-      }
-    }
-  }
-}
-
-void CFX_ListCtrl::SelectItems() {
-  for (int32_t i = 0, sz = m_aSelItems.GetCount(); i < sz; i++) {
-    int32_t nItemIndex = m_aSelItems.GetItemIndex(i);
-    int32_t nState = m_aSelItems.GetState(i);
-
-    switch (nState) {
-      case 1:
-        SetMultipleSelect(nItemIndex, true);
-        break;
-      case -1:
-        SetMultipleSelect(nItemIndex, false);
-        break;
-    }
-  }
-
-  m_aSelItems.Done();
-}
-
-void CFX_ListCtrl::Select(int32_t nItemIndex) {
-  if (!IsValid(nItemIndex))
-    return;
-
-  if (IsMultipleSel()) {
-    m_aSelItems.Add(nItemIndex);
-    SelectItems();
-  } else {
-    SetSingleSelect(nItemIndex);
-  }
-}
-
-bool CFX_ListCtrl::IsItemVisible(int32_t nItemIndex) const {
-  CFX_FloatRect rcPlate = GetPlateRect();
-  CFX_FloatRect rcItem = GetItemRect(nItemIndex);
-
-  return rcItem.bottom >= rcPlate.bottom && rcItem.top <= rcPlate.top;
-}
-
-void CFX_ListCtrl::ScrollToListItem(int32_t nItemIndex) {
-  if (!IsValid(nItemIndex))
-    return;
-
-  CFX_FloatRect rcPlate = GetPlateRect();
-  CFX_FloatRect rcItem = GetItemRectInternal(nItemIndex);
-  CFX_FloatRect rcItemCtrl = GetItemRect(nItemIndex);
-
-  if (IsFloatSmaller(rcItemCtrl.bottom, rcPlate.bottom)) {
-    if (IsFloatSmaller(rcItemCtrl.top, rcPlate.top)) {
-      SetScrollPosY(rcItem.bottom + rcPlate.Height());
-    }
-  } else if (IsFloatBigger(rcItemCtrl.top, rcPlate.top)) {
-    if (IsFloatBigger(rcItemCtrl.bottom, rcPlate.bottom)) {
-      SetScrollPosY(rcItem.top);
-    }
-  }
-}
-
-void CFX_ListCtrl::SetScrollInfo() {
-  if (m_pNotify) {
-    CFX_FloatRect rcPlate = GetPlateRect();
-    CFX_FloatRect rcContent = GetContentRectInternal();
-
-    if (!m_bNotifyFlag) {
-      m_bNotifyFlag = true;
-      m_pNotify->IOnSetScrollInfoY(rcPlate.bottom, rcPlate.top,
-                                   rcContent.bottom, rcContent.top,
-                                   GetFirstHeight(), rcPlate.Height());
-      m_bNotifyFlag = false;
-    }
-  }
-}
-
-void CFX_ListCtrl::SetScrollPos(const CFX_PointF& point) {
-  SetScrollPosY(point.y);
-}
-
-void CFX_ListCtrl::SetScrollPosY(FX_FLOAT fy) {
-  if (!IsFloatEqual(m_ptScrollPos.y, fy)) {
-    CFX_FloatRect rcPlate = GetPlateRect();
-    CFX_FloatRect rcContent = GetContentRectInternal();
-
-    if (rcPlate.Height() > rcContent.Height()) {
-      fy = rcPlate.top;
-    } else {
-      if (IsFloatSmaller(fy - rcPlate.Height(), rcContent.bottom)) {
-        fy = rcContent.bottom + rcPlate.Height();
-      } else if (IsFloatBigger(fy, rcContent.top)) {
-        fy = rcContent.top;
-      }
-    }
-
-    m_ptScrollPos.y = fy;
-    InvalidateItem(-1);
-
-    if (m_pNotify) {
-      if (!m_bNotifyFlag) {
-        m_bNotifyFlag = true;
-        m_pNotify->IOnSetScrollPosY(fy);
-        m_bNotifyFlag = false;
-      }
-    }
-  }
-}
-
-CFX_FloatRect CFX_ListCtrl::GetContentRectInternal() const {
-  return InnerToOuter(CFX_ListContainer::GetContentRect());
-}
-
-CFX_FloatRect CFX_ListCtrl::GetContentRect() const {
-  return InToOut(GetContentRectInternal());
-}
-
-void CFX_ListCtrl::ReArrange(int32_t nItemIndex) {
-  FX_FLOAT fPosY = 0.0f;
-
-  if (CFX_ListItem* pPrevItem = m_aListItems.GetAt(nItemIndex - 1))
-    fPosY = pPrevItem->GetRect().bottom;
-
-  for (int32_t i = nItemIndex, sz = m_aListItems.GetSize(); i < sz; i++) {
-    if (CFX_ListItem* pListItem = m_aListItems.GetAt(i)) {
-      FX_FLOAT fListItemHeight = pListItem->GetItemHeight();
-      pListItem->SetRect(CLST_Rect(0.0f, fPosY, 0.0f, fPosY + fListItemHeight));
-      fPosY += fListItemHeight;
-    }
-  }
-
-  SetContentRect(CLST_Rect(0.0f, 0.0f, 0.0f, fPosY));
-  SetScrollInfo();
-}
-
-void CFX_ListCtrl::SetTopItem(int32_t nIndex) {
-  if (IsValid(nIndex)) {
-    GetPlateRect();
-    CFX_FloatRect rcItem = GetItemRectInternal(nIndex);
-    SetScrollPosY(rcItem.top);
-  }
-}
-
-int32_t CFX_ListCtrl::GetTopItem() const {
-  int32_t nItemIndex = GetItemIndex(GetBTPoint());
-
-  if (!IsItemVisible(nItemIndex) && IsItemVisible(nItemIndex + 1))
-    nItemIndex += 1;
-
-  return nItemIndex;
-}
-
-void CFX_ListCtrl::Empty() {
-  for (int32_t i = 0, sz = m_aListItems.GetSize(); i < sz; i++)
-    delete m_aListItems.GetAt(i);
-
-  m_aListItems.RemoveAll();
-
-  InvalidateItem(-1);
-}
-
-void CFX_ListCtrl::Cancel() {
-  m_aSelItems.DeselectAll();
-}
-
-int32_t CFX_ListCtrl::GetItemIndex(const CFX_PointF& point) const {
-  CFX_PointF pt = OuterToInner(OutToIn(point));
-
-  bool bFirst = true;
-  bool bLast = true;
-
-  for (int32_t i = 0, sz = m_aListItems.GetSize(); i < sz; i++) {
-    if (CFX_ListItem* pListItem = m_aListItems.GetAt(i)) {
-      CLST_Rect rcListItem = pListItem->GetRect();
-
-      if (IsFloatBigger(pt.y, rcListItem.top)) {
-        bFirst = false;
-      }
-
-      if (IsFloatSmaller(pt.y, rcListItem.bottom)) {
-        bLast = false;
-      }
-
-      if (pt.y >= rcListItem.top && pt.y < rcListItem.bottom) {
-        return i;
-      }
-    }
-  }
-
-  if (bFirst)
-    return 0;
-  if (bLast)
-    return m_aListItems.GetSize() - 1;
-
-  return -1;
-}
-
-CFX_WideString CFX_ListCtrl::GetText() const {
-  if (IsMultipleSel())
-    return GetItemText(m_nCaretIndex);
-  return GetItemText(m_nSelItem);
-}
-
-void CFX_ListCtrl::SetFontMap(IPVT_FontMap* pFontMap) {
-  m_pFontMap = pFontMap;
-}
-
-void CFX_ListCtrl::SetFontSize(FX_FLOAT fFontSize) {
-  m_fFontSize = fFontSize;
-}
-
-void CFX_ListCtrl::AddItem(const CFX_WideString& str) {
-  CFX_ListItem* pListItem = new CFX_ListItem();
-  pListItem->SetFontMap(m_pFontMap);
-  pListItem->SetFontSize(m_fFontSize);
-  pListItem->SetText(str);
-  m_aListItems.Add(pListItem);
-}
-
-CFX_Edit* CFX_ListCtrl::GetItemEdit(int32_t nIndex) const {
-  if (CFX_ListItem* pListItem = m_aListItems.GetAt(nIndex)) {
-    return pListItem->GetEdit();
-  }
-
-  return nullptr;
-}
-
-int32_t CFX_ListCtrl::GetCount() const {
-  return m_aListItems.GetSize();
-}
-
-CFX_FloatRect CFX_ListCtrl::GetPlateRect() const {
-  return CFX_ListContainer::GetPlateRect();
-}
-
-FX_FLOAT CFX_ListCtrl::GetFontSize() const {
-  return m_fFontSize;
-}
-
-FX_FLOAT CFX_ListCtrl::GetFirstHeight() const {
-  if (CFX_ListItem* pListItem = m_aListItems.GetAt(0)) {
-    return pListItem->GetItemHeight();
-  }
-
-  return 1.0f;
-}
-
-int32_t CFX_ListCtrl::GetFirstSelected() const {
-  for (int32_t i = 0, sz = m_aListItems.GetSize(); i < sz; i++) {
-    if (CFX_ListItem* pListItem = m_aListItems.GetAt(i)) {
-      if (pListItem->IsSelected())
-        return i;
-    }
-  }
-  return -1;
-}
-
-int32_t CFX_ListCtrl::GetLastSelected() const {
-  for (int32_t i = m_aListItems.GetSize() - 1; i >= 0; i--) {
-    if (CFX_ListItem* pListItem = m_aListItems.GetAt(i)) {
-      if (pListItem->IsSelected())
-        return i;
-    }
-  }
-  return -1;
-}
-
-FX_WCHAR CFX_ListCtrl::Toupper(FX_WCHAR c) const {
-  if ((c >= 'a') && (c <= 'z'))
-    c = c - ('a' - 'A');
-  return c;
-}
-
-int32_t CFX_ListCtrl::FindNext(int32_t nIndex, FX_WCHAR nChar) const {
-  int32_t nCircleIndex = nIndex;
-
-  for (int32_t i = 0, sz = m_aListItems.GetSize(); i < sz; i++) {
-    nCircleIndex++;
-    if (nCircleIndex >= sz)
-      nCircleIndex = 0;
-
-    if (CFX_ListItem* pListItem = m_aListItems.GetAt(nCircleIndex)) {
-      if (Toupper(pListItem->GetFirstChar()) == Toupper(nChar))
-        return nCircleIndex;
-    }
-  }
-
-  return nCircleIndex;
-}
-
-bool CFX_ListCtrl::IsItemSelected(int32_t nIndex) const {
-  if (CFX_ListItem* pListItem = m_aListItems.GetAt(nIndex))
-    return pListItem->IsSelected();
-  return false;
-}
-
-void CFX_ListCtrl::SetItemSelect(int32_t nItemIndex, bool bSelected) {
-  if (CFX_ListItem* pListItem = m_aListItems.GetAt(nItemIndex)) {
-    pListItem->SetSelect(bSelected);
-  }
-}
-
-void CFX_ListCtrl::SetMultipleSel(bool bMultiple) {
-  m_bMultiple = bMultiple;
-}
-
-bool CFX_ListCtrl::IsMultipleSel() const {
-  return m_bMultiple;
-}
-
-bool CFX_ListCtrl::IsValid(int32_t nItemIndex) const {
-  return nItemIndex >= 0 && nItemIndex < m_aListItems.GetSize();
-}
-
-CFX_WideString CFX_ListCtrl::GetItemText(int32_t nIndex) const {
-  if (CFX_ListItem* pListItem = m_aListItems.GetAt(nIndex)) {
-    return pListItem->GetText();
-  }
-
-  return L"";
-}
diff --git a/fpdfsdk/fxedit/fxet_list.h b/fpdfsdk/fxedit/fxet_list.h
deleted file mode 100644
index 01e18bc..0000000
--- a/fpdfsdk/fxedit/fxet_list.h
+++ /dev/null
@@ -1,304 +0,0 @@
-// Copyright 2014 PDFium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
-
-#ifndef FPDFSDK_FXEDIT_FXET_LIST_H_
-#define FPDFSDK_FXEDIT_FXET_LIST_H_
-
-#include <memory>
-
-#include "core/fxcrt/fx_coordinates.h"
-#include "fpdfsdk/fxedit/fx_edit.h"
-
-class CFX_Edit;
-class CFX_Edit_Iterator;
-class CPWL_List_Notify;
-
-class CLST_Rect : public CFX_FloatRect {
- public:
-  CLST_Rect() { left = top = right = bottom = 0.0f; }
-
-  CLST_Rect(FX_FLOAT other_left,
-            FX_FLOAT other_top,
-            FX_FLOAT other_right,
-            FX_FLOAT other_bottom) {
-    left = other_left;
-    top = other_top;
-    right = other_right;
-    bottom = other_bottom;
-  }
-
-  explicit CLST_Rect(const CFX_FloatRect& rect) {
-    left = rect.left;
-    top = rect.top;
-    right = rect.right;
-    bottom = rect.bottom;
-  }
-
-  ~CLST_Rect() {}
-
-  void Default() { left = top = right = bottom = 0.0f; }
-
-  const CLST_Rect operator=(const CFX_FloatRect& rect) {
-    left = rect.left;
-    top = rect.top;
-    right = rect.right;
-    bottom = rect.bottom;
-
-    return *this;
-  }
-
-  bool operator==(const CLST_Rect& rect) const {
-    return FXSYS_memcmp(this, &rect, sizeof(CLST_Rect)) == 0;
-  }
-
-  bool operator!=(const CLST_Rect& rect) const { return !(*this == rect); }
-
-  FX_FLOAT Width() const { return right - left; }
-
-  FX_FLOAT Height() const {
-    if (top > bottom)
-      return top - bottom;
-    return bottom - top;
-  }
-
-  CFX_PointF LeftTop() const { return CFX_PointF(left, top); }
-
-  CFX_PointF RightBottom() const { return CFX_PointF(right, bottom); }
-
-  const CLST_Rect operator+=(const CFX_PointF& point) {
-    left += point.x;
-    right += point.x;
-    top += point.y;
-    bottom += point.y;
-
-    return *this;
-  }
-
-  const CLST_Rect operator-=(const CFX_PointF& point) {
-    left -= point.x;
-    right -= point.x;
-    top -= point.y;
-    bottom -= point.y;
-
-    return *this;
-  }
-
-  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_PointF& point) const {
-    return CLST_Rect(left - point.x, top - point.y, right - point.x,
-                     bottom - point.y);
-  }
-};
-
-class CFX_ListItem final {
- public:
-  CFX_ListItem();
-  ~CFX_ListItem();
-
-  void SetFontMap(IPVT_FontMap* pFontMap);
-  CFX_Edit* GetEdit() const;
-
-  void SetRect(const CLST_Rect& rect);
-  void SetSelect(bool bSelected);
-  void SetText(const CFX_WideString& text);
-  void SetFontSize(FX_FLOAT fFontSize);
-  CFX_WideString GetText() const;
-
-  CLST_Rect GetRect() const;
-  bool IsSelected() const;
-  FX_FLOAT GetItemHeight() const;
-  uint16_t GetFirstChar() const;
-
- private:
-  CFX_Edit_Iterator* GetIterator() const;
-
-  std::unique_ptr<CFX_Edit> m_pEdit;
-  bool m_bSelected;
-  CLST_Rect m_rcListItem;
-};
-
-class CFX_ListContainer {
- public:
-  CFX_ListContainer();
-  virtual ~CFX_ListContainer();
-
-  virtual void SetPlateRect(const CFX_FloatRect& rect);
-
-  CFX_FloatRect GetPlateRect() const { return m_rcPlate; }
-  void SetContentRect(const CLST_Rect& rect) { m_rcContent = rect; }
-  CLST_Rect GetContentRect() const { return m_rcContent; }
-  CFX_PointF GetBTPoint() const {
-    return CFX_PointF(m_rcPlate.left, m_rcPlate.top);
-  }
-  CFX_PointF GetETPoint() const {
-    return CFX_PointF(m_rcPlate.right, m_rcPlate.bottom);
-  }
-
- public:
-  CFX_PointF InnerToOuter(const CFX_PointF& point) const {
-    return CFX_PointF(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_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_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);
-  }
-
- private:
-  CFX_FloatRect m_rcPlate;
-  CLST_Rect m_rcContent;  // positive forever!
-};
-
-template <class TYPE>
-class CLST_ArrayTemplate : public CFX_ArrayTemplate<TYPE> {
- public:
-  bool IsEmpty() { return CFX_ArrayTemplate<TYPE>::GetSize() <= 0; }
-  TYPE GetAt(int32_t nIndex) const {
-    if (nIndex >= 0 && nIndex < CFX_ArrayTemplate<TYPE>::GetSize())
-      return CFX_ArrayTemplate<TYPE>::GetAt(nIndex);
-    return nullptr;
-  }
-  void RemoveAt(int32_t nIndex) {
-    if (nIndex >= 0 && nIndex < CFX_ArrayTemplate<TYPE>::GetSize())
-      CFX_ArrayTemplate<TYPE>::RemoveAt(nIndex);
-  }
-};
-
-struct CPLST_Select_Item {
-  CPLST_Select_Item(int32_t other_nItemIndex, int32_t other_nState) {
-    nItemIndex = other_nItemIndex;
-    nState = other_nState;
-  }
-
-  int32_t nItemIndex;
-  int32_t nState;  // 0:normal select -1:to deselect 1: to select
-};
-
-class CPLST_Select {
- public:
-  CPLST_Select();
-  virtual ~CPLST_Select();
-
- public:
-  void Add(int32_t nItemIndex);
-  void Add(int32_t nBeginIndex, int32_t nEndIndex);
-  void Sub(int32_t nItemIndex);
-  void Sub(int32_t nBeginIndex, int32_t nEndIndex);
-  bool IsExist(int32_t nItemIndex) const;
-  int32_t Find(int32_t nItemIndex) const;
-  int32_t GetCount() const;
-  int32_t GetItemIndex(int32_t nIndex) const;
-  int32_t GetState(int32_t nIndex) const;
-  void Done();
-  void DeselectAll();
-
- private:
-  CFX_ArrayTemplate<CPLST_Select_Item*> m_aItems;
-};
-
-class CFX_ListCtrl : protected CFX_ListContainer {
- public:
-  CFX_ListCtrl();
-  ~CFX_ListCtrl() override;
-
-  // CFX_ListContainer
-  void SetPlateRect(const CFX_FloatRect& rect) override;
-
-  void SetNotify(CPWL_List_Notify* pNotify);
-  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);
-  void OnVK_RIGHT(bool bShift, bool bCtrl);
-  void OnVK_HOME(bool bShift, bool bCtrl);
-  void OnVK_END(bool bShift, bool bCtrl);
-  void OnVK(int32_t nItemIndex, bool bShift, bool bCtrl);
-  bool OnChar(uint16_t nChar, bool bShift, bool bCtrl);
-
-  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_PointF& point) const;
-  void AddString(const CFX_WideString& str);
-  void SetTopItem(int32_t nIndex);
-  void Select(int32_t nItemIndex);
-  void SetCaret(int32_t nItemIndex);
-  void Empty();
-  void Cancel();
-  CFX_WideString GetText() const;
-
-  void SetFontMap(IPVT_FontMap* pFontMap);
-  void SetFontSize(FX_FLOAT fFontSize);
-  CFX_FloatRect GetPlateRect() const;
-  FX_FLOAT GetFontSize() const;
-  CFX_Edit* GetItemEdit(int32_t nIndex) const;
-  int32_t GetCount() const;
-  bool IsItemSelected(int32_t nIndex) const;
-  FX_FLOAT GetFirstHeight() const;
-  void SetMultipleSel(bool bMultiple);
-  bool IsMultipleSel() const;
-  bool IsValid(int32_t nItemIndex) const;
-  int32_t FindNext(int32_t nIndex, FX_WCHAR nChar) const;
-  int32_t GetFirstSelected() 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;
-
- private:
-  void ReArrange(int32_t nItemIndex);
-  CFX_FloatRect GetItemRectInternal(int32_t nIndex) const;
-  CFX_FloatRect GetContentRectInternal() const;
-  void SetMultipleSelect(int32_t nItemIndex, bool bSelected);
-  void SetSingleSelect(int32_t nItemIndex);
-  void InvalidateItem(int32_t nItemIndex);
-  void SelectItems();
-  bool IsItemVisible(int32_t nItemIndex) const;
-  void SetScrollInfo();
-  void SetScrollPosY(FX_FLOAT fy);
-  void AddItem(const CFX_WideString& str);
-  CFX_WideString GetItemText(int32_t nIndex) const;
-  void SetItemSelect(int32_t nItemIndex, bool bSelected);
-  int32_t GetLastSelected() const;
-  FX_WCHAR Toupper(FX_WCHAR c) const;
-
-  CPWL_List_Notify* m_pNotify;
-  bool m_bNotifyFlag;
-  CFX_PointF m_ptScrollPos;
-  CPLST_Select m_aSelItems;  // for multiple
-  int32_t m_nSelItem;        // for single
-  int32_t m_nFootIndex;      // for multiple
-  bool m_bCtrlSel;           // for multiple
-  int32_t m_nCaretIndex;     // for multiple
-  CLST_ArrayTemplate<CFX_ListItem*> m_aListItems;
-  FX_FLOAT m_fFontSize;
-  IPVT_FontMap* m_pFontMap;
-  bool m_bMultiple;
-};
-
-#endif  // FPDFSDK_FXEDIT_FXET_LIST_H_
diff --git a/fpdfsdk/ipdfsdk_annothandler.h b/fpdfsdk/ipdfsdk_annothandler.h
index 636d161..bffeac6 100644
--- a/fpdfsdk/ipdfsdk_annothandler.h
+++ b/fpdfsdk/ipdfsdk_annothandler.h
@@ -7,7 +7,6 @@
 #ifndef FPDFSDK_IPDFSDK_ANNOTHANDLER_H_
 #define FPDFSDK_IPDFSDK_ANNOTHANDLER_H_
 
-#include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "fpdfsdk/cpdfsdk_annot.h"
 
@@ -36,6 +35,9 @@
   virtual void ReleaseAnnot(CPDFSDK_Annot* pAnnot) = 0;
   virtual CFX_FloatRect GetViewBBox(CPDFSDK_PageView* pPageView,
                                     CPDFSDK_Annot* pAnnot) = 0;
+  virtual WideString GetSelectedText(CPDFSDK_Annot* pAnnot) = 0;
+  virtual void ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                                const WideString& text) = 0;
   virtual bool HitTest(CPDFSDK_PageView* pPageView,
                        CPDFSDK_Annot* pAnnot,
                        const CFX_PointF& point) = 0;
diff --git a/fpdfsdk/javascript/Annot.cpp b/fpdfsdk/javascript/Annot.cpp
deleted file mode 100644
index 41c71ec..0000000
--- a/fpdfsdk/javascript/Annot.cpp
+++ /dev/null
@@ -1,115 +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 "fpdfsdk/javascript/Annot.h"
-
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_Object.h"
-#include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/cjs_event_context.h"
-
-namespace {
-
-CPDFSDK_BAAnnot* ToBAAnnot(CPDFSDK_Annot* annot) {
-  return static_cast<CPDFSDK_BAAnnot*>(annot);
-}
-
-}  // namespace
-
-JSConstSpec CJS_Annot::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
-
-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}};
-
-JSMethodSpec CJS_Annot::MethodSpecs[] = {{0, 0}};
-
-IMPLEMENT_JS_CLASS(CJS_Annot, Annot)
-
-Annot::Annot(CJS_Object* pJSObject) : CJS_EmbedObj(pJSObject) {}
-
-Annot::~Annot() {}
-
-bool Annot::hidden(CJS_Runtime* pRuntime,
-                   CJS_PropValue& vp,
-                   CFX_WideString& sError) {
-  if (vp.IsGetting()) {
-    if (!m_pAnnot) {
-      sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-      return false;
-    }
-    CPDF_Annot* pPDFAnnot = ToBAAnnot(m_pAnnot.Get())->GetPDFAnnot();
-    vp << CPDF_Annot::IsAnnotationHidden(pPDFAnnot->GetAnnotDict());
-    return true;
-  }
-
-  bool bHidden;
-  vp >> bHidden;  // May invalidate m_pAnnot.
-  if (!m_pAnnot) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-
-  uint32_t flags = ToBAAnnot(m_pAnnot.Get())->GetFlags();
-  if (bHidden) {
-    flags |= ANNOTFLAG_HIDDEN;
-    flags |= ANNOTFLAG_INVISIBLE;
-    flags |= ANNOTFLAG_NOVIEW;
-    flags &= ~ANNOTFLAG_PRINT;
-  } else {
-    flags &= ~ANNOTFLAG_HIDDEN;
-    flags &= ~ANNOTFLAG_INVISIBLE;
-    flags &= ~ANNOTFLAG_NOVIEW;
-    flags |= ANNOTFLAG_PRINT;
-  }
-  ToBAAnnot(m_pAnnot.Get())->SetFlags(flags);
-  return true;
-}
-
-bool Annot::name(CJS_Runtime* pRuntime,
-                 CJS_PropValue& vp,
-                 CFX_WideString& sError) {
-  if (vp.IsGetting()) {
-    if (!m_pAnnot) {
-      sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-      return false;
-    }
-    vp << ToBAAnnot(m_pAnnot.Get())->GetAnnotName();
-    return true;
-  }
-
-  CFX_WideString annotName;
-  vp >> annotName;  // May invalidate m_pAnnot.
-  if (!m_pAnnot) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-
-  ToBAAnnot(m_pAnnot.Get())->SetAnnotName(annotName);
-  return true;
-}
-
-bool Annot::type(CJS_Runtime* pRuntime,
-                 CJS_PropValue& vp,
-                 CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
-    return false;
-  }
-  if (!m_pAnnot) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  vp << CPDF_Annot::AnnotSubtypeToString(
-      ToBAAnnot(m_pAnnot.Get())->GetAnnotSubtype());
-  return true;
-}
-
-void Annot::SetSDKAnnot(CPDFSDK_BAAnnot* annot) {
-  m_pAnnot.Reset(annot);
-}
diff --git a/fpdfsdk/javascript/Annot.h b/fpdfsdk/javascript/Annot.h
deleted file mode 100644
index d9757fa..0000000
--- a/fpdfsdk/javascript/Annot.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2016 PDFium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
-
-#ifndef FPDFSDK_JAVASCRIPT_ANNOT_H_
-#define FPDFSDK_JAVASCRIPT_ANNOT_H_
-
-#include <memory>
-
-#include "fpdfsdk/cpdfsdk_baannot.h"
-#include "fpdfsdk/javascript/JS_Define.h"
-
-class Annot : public CJS_EmbedObj {
- public:
-  explicit Annot(CJS_Object* pJSObject);
-  ~Annot() override;
-
-  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);
-
- private:
-  CPDFSDK_Annot::ObservedPtr m_pAnnot;
-};
-
-class CJS_Annot : public CJS_Object {
- public:
-  explicit CJS_Annot(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Annot() override {}
-
-  DECLARE_JS_CLASS();
-  JS_STATIC_PROP(hidden, Annot);
-  JS_STATIC_PROP(name, Annot);
-  JS_STATIC_PROP(type, Annot);
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_ANNOT_H_
diff --git a/fpdfsdk/javascript/Consts.cpp b/fpdfsdk/javascript/Consts.cpp
deleted file mode 100644
index 82f9b4c..0000000
--- a/fpdfsdk/javascript/Consts.cpp
+++ /dev/null
@@ -1,204 +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/Consts.h"
-
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_Object.h"
-#include "fpdfsdk/javascript/JS_Value.h"
-
-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)
-
-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)
-
-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)
-
-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)
-
-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)
-
-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)
-
-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)
-
-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)
-
-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)                                \
-  (rt)->DefineGlobalConst(                                            \
-      (name), [](const v8::FunctionCallbackInfo<v8::Value>& info) {   \
-        info.GetReturnValue().Set(                                    \
-            CFXJS_Engine::CurrentEngineFromIsolate(info.GetIsolate()) \
-                ->NewString(value));                                  \
-      })
-
-void CJS_GlobalConsts::DefineJSObjects(CJS_Runtime* pRuntime) {
-  GLOBAL_STRING(pRuntime, L"IDS_GREATER_THAN",
-                L"Invalid value: must be greater than or equal to % s.");
-
-  GLOBAL_STRING(pRuntime, L"IDS_GT_AND_LT",
-                L"Invalid value: must be greater than or equal to % s "
-                L"and less than or equal to % s.");
-
-  GLOBAL_STRING(pRuntime, L"IDS_LESS_THAN",
-                L"Invalid value: must be less than or equal to % s.");
-
-  GLOBAL_STRING(pRuntime, L"IDS_INVALID_MONTH", L"**Invalid**");
-  GLOBAL_STRING(
-      pRuntime, L"IDS_INVALID_DATE",
-      L"Invalid date / time: please ensure that the date / time exists.Field");
-
-  GLOBAL_STRING(pRuntime, L"IDS_INVALID_VALUE",
-                L"The value entered does not match the format of the field");
-
-  GLOBAL_STRING(pRuntime, L"IDS_AM", L"am");
-  GLOBAL_STRING(pRuntime, L"IDS_PM", L"pm");
-  GLOBAL_STRING(pRuntime, L"IDS_MONTH_INFO",
-                L"January[1] February[2] March[3] April[4] May[5] "
-                L"June[6] July[7] August[8] September[9] October[10] "
-                L"November[11] December[12] Sept[9] Jan[1] Feb[2] Mar[3] "
-                L"Apr[4] Jun[6] Jul[7] Aug[8] Sep[9] Oct[10] Nov[11] "
-                L"Dec[12]");
-
-  GLOBAL_STRING(pRuntime, L"IDS_STARTUP_CONSOLE_MSG", L"** ^ _ ^ **");
-}
-
-#define GLOBAL_ARRAY(rt, name, ...)                                          \
-  {                                                                          \
-    const FX_WCHAR* values[] = {__VA_ARGS__};                                \
-    v8::Local<v8::Array> array = (rt)->NewArray();                           \
-    for (size_t i = 0; i < FX_ArraySize(values); ++i)                        \
-      array->Set(i, (rt)->NewString(values[i]));                             \
-    (rt)->SetConstArray((name), array);                                      \
-    (rt)->DefineGlobalConst(                                                 \
-        (name), [](const v8::FunctionCallbackInfo<v8::Value>& info) {        \
-          CJS_Runtime* pCurrentRuntime =                                     \
-              CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());     \
-          if (pCurrentRuntime)                                               \
-            info.GetReturnValue().Set(pCurrentRuntime->GetConstArray(name)); \
-        });                                                                  \
-  }
-
-void CJS_GlobalArrays::DefineJSObjects(CJS_Runtime* pRuntime) {
-  GLOBAL_ARRAY(pRuntime, L"RE_NUMBER_ENTRY_DOT_SEP", L"[+-]?\\d*\\.?\\d*");
-  GLOBAL_ARRAY(pRuntime, L"RE_NUMBER_COMMIT_DOT_SEP",
-               L"[+-]?\\d+(\\.\\d+)?",  // -1.0 or -1
-               L"[+-]?\\.\\d+",         // -.1
-               L"[+-]?\\d+\\.");        // -1.
-
-  GLOBAL_ARRAY(pRuntime, L"RE_NUMBER_ENTRY_COMMA_SEP", L"[+-]?\\d*,?\\d*");
-  GLOBAL_ARRAY(pRuntime, L"RE_NUMBER_COMMIT_COMMA_SEP",
-               L"[+-]?\\d+([.,]\\d+)?",  // -1,0 or -1
-               L"[+-]?[.,]\\d+",         // -,1
-               L"[+-]?\\d+[.,]");        // -1,
-
-  GLOBAL_ARRAY(pRuntime, L"RE_ZIP_ENTRY", L"\\d{0,5}");
-  GLOBAL_ARRAY(pRuntime, L"RE_ZIP_COMMIT", L"\\d{5}");
-  GLOBAL_ARRAY(pRuntime, L"RE_ZIP4_ENTRY", L"\\d{0,5}(\\.|[- ])?\\d{0,4}");
-  GLOBAL_ARRAY(pRuntime, L"RE_ZIP4_COMMIT", L"\\d{5}(\\.|[- ])?\\d{4}");
-  GLOBAL_ARRAY(pRuntime, L"RE_PHONE_ENTRY",
-               // 555-1234 or 408 555-1234
-               L"\\d{0,3}(\\.|[- ])?\\d{0,3}(\\.|[- ])?\\d{0,4}",
-
-               // (408
-               L"\\(\\d{0,3}",
-
-               // (408) 555-1234
-               // (allow the addition of parens as an afterthought)
-               L"\\(\\d{0,3}\\)(\\.|[- ])?\\d{0,3}(\\.|[- ])?\\d{0,4}",
-
-               // (408 555-1234
-               L"\\(\\d{0,3}(\\.|[- ])?\\d{0,3}(\\.|[- ])?\\d{0,4}",
-
-               // 408) 555-1234
-               L"\\d{0,3}\\)(\\.|[- ])?\\d{0,3}(\\.|[- ])?\\d{0,4}",
-
-               // international
-               L"011(\\.|[- \\d])*");
-
-  GLOBAL_ARRAY(
-      pRuntime, L"RE_PHONE_COMMIT", L"\\d{3}(\\.|[- ])?\\d{4}",  // 555-1234
-      L"\\d{3}(\\.|[- ])?\\d{3}(\\.|[- ])?\\d{4}",               // 408 555-1234
-      L"\\(\\d{3}\\)(\\.|[- ])?\\d{3}(\\.|[- ])?\\d{4}",  // (408) 555-1234
-      L"011(\\.|[- \\d])*");                              // international
-
-  GLOBAL_ARRAY(pRuntime, L"RE_SSN_ENTRY",
-               L"\\d{0,3}(\\.|[- ])?\\d{0,2}(\\.|[- ])?\\d{0,4}");
-
-  GLOBAL_ARRAY(pRuntime, L"RE_SSN_COMMIT",
-               L"\\d{3}(\\.|[- ])?\\d{2}(\\.|[- ])?\\d{4}");
-}
diff --git a/fpdfsdk/javascript/Consts.h b/fpdfsdk/javascript/Consts.h
deleted file mode 100644
index e358cb9..0000000
--- a/fpdfsdk/javascript/Consts.h
+++ /dev/null
@@ -1,94 +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 FPDFSDK_JAVASCRIPT_CONSTS_H_
-#define FPDFSDK_JAVASCRIPT_CONSTS_H_
-
-#include "fpdfsdk/javascript/JS_Define.h"
-
-class CJS_Border : public CJS_Object {
- public:
-  explicit CJS_Border(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Border() override {}
-
-  DECLARE_JS_CLASS_CONST();
-};
-
-class CJS_Display : public CJS_Object {
- public:
-  explicit CJS_Display(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Display() override {}
-
-  DECLARE_JS_CLASS_CONST();
-};
-
-class CJS_Font : public CJS_Object {
- public:
-  explicit CJS_Font(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Font() override {}
-
-  DECLARE_JS_CLASS_CONST();
-};
-
-class CJS_Highlight : public CJS_Object {
- public:
-  explicit CJS_Highlight(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Highlight() override {}
-
-  DECLARE_JS_CLASS_CONST();
-};
-
-class CJS_Position : public CJS_Object {
- public:
-  explicit CJS_Position(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Position() override {}
-
-  DECLARE_JS_CLASS_CONST();
-};
-
-class CJS_ScaleHow : public CJS_Object {
- public:
-  explicit CJS_ScaleHow(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_ScaleHow() override {}
-
-  DECLARE_JS_CLASS_CONST();
-};
-
-class CJS_ScaleWhen : public CJS_Object {
- public:
-  explicit CJS_ScaleWhen(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_ScaleWhen() override {}
-
-  DECLARE_JS_CLASS_CONST();
-};
-
-class CJS_Style : public CJS_Object {
- public:
-  explicit CJS_Style(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Style() override {}
-
-  DECLARE_JS_CLASS_CONST();
-};
-
-class CJS_Zoomtype : public CJS_Object {
- public:
-  explicit CJS_Zoomtype(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Zoomtype() override {}
-
-  DECLARE_JS_CLASS_CONST();
-};
-
-class CJS_GlobalConsts : public CJS_Object {
- public:
-  static void DefineJSObjects(CJS_Runtime* pRuntime);
-};
-
-class CJS_GlobalArrays : public CJS_Object {
- public:
-  static void DefineJSObjects(CJS_Runtime* pRuntmie);
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_CONSTS_H_
diff --git a/fpdfsdk/javascript/DEPS b/fpdfsdk/javascript/DEPS
deleted file mode 100644
index 36a51aa..0000000
--- a/fpdfsdk/javascript/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  '+fxjs'
-]
diff --git a/fpdfsdk/javascript/Document.cpp b/fpdfsdk/javascript/Document.cpp
deleted file mode 100644
index a45b8b9..0000000
--- a/fpdfsdk/javascript/Document.cpp
+++ /dev/null
@@ -1,1658 +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/Document.h"
-
-#include <algorithm>
-#include <utility>
-#include <vector>
-
-#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_document.h"
-#include "core/fpdfapi/parser/cpdf_string.h"
-#include "core/fpdfapi/parser/fpdf_parser_decode.h"
-#include "core/fpdfdoc/cpdf_interform.h"
-#include "core/fpdfdoc/cpdf_nametree.h"
-#include "fpdfsdk/cpdfsdk_annotiteration.h"
-#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
-#include "fpdfsdk/cpdfsdk_interform.h"
-#include "fpdfsdk/cpdfsdk_pageview.h"
-#include "fpdfsdk/cpdfsdk_widget.h"
-#include "fpdfsdk/javascript/Annot.h"
-#include "fpdfsdk/javascript/Field.h"
-#include "fpdfsdk/javascript/Icon.h"
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_EventHandler.h"
-#include "fpdfsdk/javascript/JS_Object.h"
-#include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/app.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"
-
-JSConstSpec CJS_PrintParamsObj::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
-
-JSPropertySpec CJS_PrintParamsObj::PropertySpecs[] = {{0, 0, 0}};
-
-JSMethodSpec CJS_PrintParamsObj::MethodSpecs[] = {{0, 0}};
-
-IMPLEMENT_JS_CLASS(CJS_PrintParamsObj, PrintParamsObj)
-
-PrintParamsObj::PrintParamsObj(CJS_Object* pJSObject)
-    : CJS_EmbedObj(pJSObject) {
-  bUI = true;
-  nStart = 0;
-  nEnd = 0;
-  bSilent = false;
-  bShrinkToFit = false;
-  bPrintAsImage = false;
-  bReverse = false;
-  bAnnotations = true;
-}
-
-#define MINWIDTH 5.0f
-#define MINHEIGHT 5.0f
-
-JSConstSpec CJS_Document::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
-
-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}};
-
-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)
-
-void CJS_Document::InitInstance(IJS_Runtime* pIRuntime) {
-  CJS_Runtime* pRuntime = static_cast<CJS_Runtime*>(pIRuntime);
-  Document* pDoc = static_cast<Document*>(GetEmbedObject());
-  pDoc->SetFormFillEnv(pRuntime->GetFormFillEnv());
-}
-
-Document::Document(CJS_Object* pJSObject)
-    : CJS_EmbedObj(pJSObject),
-      m_pFormFillEnv(nullptr),
-      m_cwBaseURL(L""),
-      m_bDelay(false) {}
-
-Document::~Document() {
-}
-
-// the total number of fileds in document.
-bool Document::numFields(CJS_Runtime* pRuntime,
-                         CJS_PropValue& vp,
-                         CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
-    return false;
-  }
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
-  CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
-  vp << static_cast<int>(pPDFForm->CountFields(CFX_WideString()));
-  return true;
-}
-
-bool Document::dirty(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  if (vp.IsGetting()) {
-    vp << !!m_pFormFillEnv->GetChangeMark();
-    return true;
-  }
-  bool bChanged = false;
-  vp >> bChanged;
-  if (bChanged)
-    m_pFormFillEnv->SetChangeMark();
-  else
-    m_pFormFillEnv->ClearChangeMark();
-
-  return true;
-}
-
-bool Document::ADBE(CJS_Runtime* pRuntime,
-                    CJS_PropValue& vp,
-                    CFX_WideString& sError) {
-  if (vp.IsGetting())
-    vp.GetJSValue()->SetNull(pRuntime);
-
-  return true;
-}
-
-bool Document::pageNum(CJS_Runtime* pRuntime,
-                       CJS_PropValue& vp,
-                       CFX_WideString& sError) {
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  if (vp.IsGetting()) {
-    if (CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetCurrentView())
-      vp << pPageView->GetPageIndex();
-    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(CJS_Runtime* pRuntime,
-                        const std::vector<CJS_Value>& params,
-                        CJS_Value& vRet,
-                        CFX_WideString& sError) {
-  // Not supported.
-  return true;
-}
-
-bool Document::addField(CJS_Runtime* pRuntime,
-                        const std::vector<CJS_Value>& params,
-                        CJS_Value& vRet,
-                        CFX_WideString& sError) {
-  // Not supported.
-  return true;
-}
-
-bool Document::exportAsText(CJS_Runtime* pRuntime,
-                            const std::vector<CJS_Value>& params,
-                            CJS_Value& vRet,
-                            CFX_WideString& sError) {
-  // Unsafe, not supported.
-  return true;
-}
-
-bool Document::exportAsFDF(CJS_Runtime* pRuntime,
-                           const std::vector<CJS_Value>& params,
-                           CJS_Value& vRet,
-                           CFX_WideString& sError) {
-  // Unsafe, not supported.
-  return true;
-}
-
-bool Document::exportAsXFDF(CJS_Runtime* pRuntime,
-                            const std::vector<CJS_Value>& params,
-                            CJS_Value& vRet,
-                            CFX_WideString& sError) {
-  // Unsafe, not supported.
-  return true;
-}
-
-// Maps a field object in PDF document to a JavaScript variable
-// comment:
-// 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(CJS_Runtime* pRuntime,
-                        const std::vector<CJS_Value>& params,
-                        CJS_Value& vRet,
-                        CFX_WideString& sError) {
-  if (params.size() < 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  CFX_WideString wideName = params[0].ToCFXWideString(pRuntime);
-  CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
-  CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
-  if (pPDFForm->CountFields(wideName) <= 0) {
-    vRet.SetNull(pRuntime);
-    return true;
-  }
-
-  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(CJS_Runtime* pRuntime,
-                               const std::vector<CJS_Value>& params,
-                               CJS_Value& vRet,
-                               CFX_WideString& sError) {
-  if (params.size() != 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  int nIndex = params[0].ToInt(pRuntime);
-  if (nIndex < 0) {
-    sError = JSGetStringFromID(IDS_STRING_JSVALUEERROR);
-    return false;
-  }
-  CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
-  CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
-  CPDF_FormField* pField = pPDFForm->GetField(nIndex, CFX_WideString());
-  if (!pField)
-    return false;
-
-  vRet = CJS_Value(pRuntime, pField->GetFullName().c_str());
-  return true;
-}
-
-bool Document::importAnFDF(CJS_Runtime* pRuntime,
-                           const std::vector<CJS_Value>& params,
-                           CJS_Value& vRet,
-                           CFX_WideString& sError) {
-  // Unsafe, not supported.
-  return true;
-}
-
-bool Document::importAnXFDF(CJS_Runtime* pRuntime,
-                            const std::vector<CJS_Value>& params,
-                            CJS_Value& vRet,
-                            CFX_WideString& sError) {
-  // Unsafe, not supported.
-  return true;
-}
-
-bool Document::importTextData(CJS_Runtime* pRuntime,
-                              const std::vector<CJS_Value>& params,
-                              CJS_Value& vRet,
-                              CFX_WideString& sError) {
-  // Unsafe, not supported.
-  return true;
-}
-
-// exports the form data and mails the resulting fdf file as an attachment to
-// all recipients.
-// comment: need reader supports
-bool Document::mailForm(CJS_Runtime* pRuntime,
-                        const std::vector<CJS_Value>& params,
-                        CJS_Value& vRet,
-                        CFX_WideString& sError) {
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  if (!m_pFormFillEnv->GetPermissions(FPDFPERM_EXTRACT_ACCESS)) {
-    sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
-    return false;
-  }
-  int iLength = params.size();
-  bool bUI = iLength > 0 ? params[0].ToBool(pRuntime) : true;
-  CFX_WideString cTo = iLength > 1 ? params[1].ToCFXWideString(pRuntime) : L"";
-  CFX_WideString cCc = iLength > 2 ? params[2].ToCFXWideString(pRuntime) : L"";
-  CFX_WideString cBcc = iLength > 3 ? params[3].ToCFXWideString(pRuntime) : L"";
-  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 = 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());
-  pRuntime->EndBlock();
-  return true;
-}
-
-bool Document::print(CJS_Runtime* pRuntime,
-                     const std::vector<CJS_Value>& params,
-                     CJS_Value& vRet,
-                     CFX_WideString& sError) {
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  bool bUI = true;
-  int nStart = 0;
-  int nEnd = 0;
-  bool bSilent = false;
-  bool bShrinkToFit = false;
-  bool bPrintAsImage = false;
-  bool bReverse = false;
-  bool bAnnotations = false;
-  int nlength = params.size();
-  if (nlength == 9) {
-    if (params[8].GetType() == CJS_Value::VT_object) {
-      v8::Local<v8::Object> pObj = params[8].ToV8Object(pRuntime);
-      if (CFXJS_Engine::GetObjDefnID(pObj) ==
-          CJS_PrintParamsObj::g_nObjDefnID) {
-        if (CJS_Object* pJSObj = params[8].ToCJSObject(pRuntime)) {
-          if (PrintParamsObj* pprintparamsObj =
-                  static_cast<PrintParamsObj*>(pJSObj->GetEmbedObject())) {
-            bUI = pprintparamsObj->bUI;
-            nStart = pprintparamsObj->nStart;
-            nEnd = pprintparamsObj->nEnd;
-            bSilent = pprintparamsObj->bSilent;
-            bShrinkToFit = pprintparamsObj->bShrinkToFit;
-            bPrintAsImage = pprintparamsObj->bPrintAsImage;
-            bReverse = pprintparamsObj->bReverse;
-            bAnnotations = pprintparamsObj->bAnnotations;
-          }
-        }
-      }
-    }
-  } else {
-    if (nlength >= 1)
-      bUI = params[0].ToBool(pRuntime);
-    if (nlength >= 2)
-      nStart = params[1].ToInt(pRuntime);
-    if (nlength >= 3)
-      nEnd = params[2].ToInt(pRuntime);
-    if (nlength >= 4)
-      bSilent = params[3].ToBool(pRuntime);
-    if (nlength >= 5)
-      bShrinkToFit = params[4].ToBool(pRuntime);
-    if (nlength >= 6)
-      bPrintAsImage = params[5].ToBool(pRuntime);
-    if (nlength >= 7)
-      bReverse = params[6].ToBool(pRuntime);
-    if (nlength >= 8)
-      bAnnotations = params[7].ToBool(pRuntime);
-  }
-
-  if (m_pFormFillEnv) {
-    m_pFormFillEnv->JS_docprint(bUI, nStart, nEnd, bSilent, bShrinkToFit,
-                                bPrintAsImage, bReverse, bAnnotations);
-    return true;
-  }
-  return false;
-}
-
-// removes the specified field from the document.
-// comment:
-// note: if the filed name is not rational, adobe is dumb for it.
-
-bool Document::removeField(CJS_Runtime* pRuntime,
-                           const std::vector<CJS_Value>& params,
-                           CJS_Value& vRet,
-                           CFX_WideString& sError) {
-  if (params.size() != 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  if (!(m_pFormFillEnv->GetPermissions(FPDFPERM_MODIFY) ||
-        m_pFormFillEnv->GetPermissions(FPDFPERM_ANNOT_FORM))) {
-    sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
-    return false;
-  }
-  CFX_WideString sFieldName = params[0].ToCFXWideString(pRuntime);
-  CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
-  std::vector<CPDFSDK_Annot::ObservedPtr> widgets;
-  pInterForm->GetWidgets(sFieldName, &widgets);
-  if (widgets.empty())
-    return true;
-
-  for (const auto& pAnnot : widgets) {
-    CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot.Get());
-    if (!pWidget)
-      continue;
-
-    CFX_FloatRect rcAnnot = pWidget->GetRect();
-    --rcAnnot.left;
-    --rcAnnot.bottom;
-    ++rcAnnot.right;
-    ++rcAnnot.top;
-
-    std::vector<CFX_FloatRect> aRefresh(1, rcAnnot);
-    UnderlyingPageType* pPage = pWidget->GetUnderlyingPage();
-    ASSERT(pPage);
-
-    // If there is currently no pageview associated with the page being used
-    // do not create one. We may be in the process of tearing down the document
-    // and creating a new pageview at this point will cause bad things.
-    CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetPageView(pPage, false);
-    if (pPageView) {
-#if PDF_ENABLE_XFA
-      pPageView->DeleteAnnot(pWidget);
-#endif  // PDF_ENABLE_XFA
-      pPageView->UpdateRects(aRefresh);
-    }
-  }
-  m_pFormFillEnv->SetChangeMark();
-
-  return true;
-}
-
-// reset filed values within a document.
-// comment:
-// note: if the fields names r not rational, aodbe is dumb for it.
-
-bool Document::resetForm(CJS_Runtime* pRuntime,
-                         const std::vector<CJS_Value>& params,
-                         CJS_Value& vRet,
-                         CFX_WideString& sError) {
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  if (!(m_pFormFillEnv->GetPermissions(FPDFPERM_MODIFY) ||
-        m_pFormFillEnv->GetPermissions(FPDFPERM_ANNOT_FORM) ||
-        m_pFormFillEnv->GetPermissions(FPDFPERM_FILL_FORM))) {
-    sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
-    return false;
-  }
-
-  CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
-  CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
-  CJS_Array aName;
-
-  if (params.empty()) {
-    pPDFForm->ResetForm(true);
-    m_pFormFillEnv->SetChangeMark();
-    return true;
-  }
-
-  switch (params[0].GetType()) {
-    default:
-      aName.Attach(params[0].ToV8Array(pRuntime));
-      break;
-    case CJS_Value::VT_string:
-      aName.SetElement(pRuntime, 0, params[0]);
-      break;
-  }
-
-  std::vector<CPDF_FormField*> aFields;
-  for (int i = 0, isz = aName.GetLength(pRuntime); i < isz; ++i) {
-    CJS_Value valElement(pRuntime);
-    aName.GetElement(pRuntime, i, valElement);
-    CFX_WideString swVal = valElement.ToCFXWideString(pRuntime);
-    for (int j = 0, jsz = pPDFForm->CountFields(swVal); j < jsz; ++j)
-      aFields.push_back(pPDFForm->GetField(j, swVal));
-  }
-
-  if (!aFields.empty()) {
-    pPDFForm->ResetForm(aFields, true, true);
-    m_pFormFillEnv->SetChangeMark();
-  }
-
-  return true;
-}
-
-bool Document::saveAs(CJS_Runtime* pRuntime,
-                      const std::vector<CJS_Value>& params,
-                      CJS_Value& vRet,
-                      CFX_WideString& sError) {
-  // Unsafe, not supported.
-  return true;
-}
-
-bool Document::syncAnnotScan(CJS_Runtime* pRuntime,
-                             const std::vector<CJS_Value>& params,
-                             CJS_Value& vRet,
-                             CFX_WideString& sError) {
-  return true;
-}
-
-bool Document::submitForm(CJS_Runtime* pRuntime,
-                          const std::vector<CJS_Value>& params,
-                          CJS_Value& vRet,
-                          CFX_WideString& sError) {
-  int nSize = params.size();
-  if (nSize < 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-
-  CJS_Array aFields;
-  CFX_WideString strURL;
-  bool bFDF = true;
-  bool bEmpty = false;
-  CJS_Value v = params[0];
-  if (v.GetType() == CJS_Value::VT_string) {
-    strURL = params[0].ToCFXWideString(pRuntime);
-    if (nSize > 1)
-      bFDF = params[1].ToBool(pRuntime);
-    if (nSize > 2)
-      bEmpty = params[2].ToBool(pRuntime);
-    if (nSize > 3)
-      aFields.Attach(params[3].ToV8Array(pRuntime));
-  } else if (v.GetType() == CJS_Value::VT_object) {
-    v8::Local<v8::Object> pObj = params[0].ToV8Object(pRuntime);
-    v8::Local<v8::Value> pValue = pRuntime->GetObjectProperty(pObj, L"cURL");
-    if (!pValue.IsEmpty())
-      strURL = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
-
-    pValue = pRuntime->GetObjectProperty(pObj, L"bFDF");
-    bFDF = CJS_Value(pRuntime, pValue).ToBool(pRuntime);
-
-    pValue = pRuntime->GetObjectProperty(pObj, L"bEmpty");
-    bEmpty = CJS_Value(pRuntime, pValue).ToBool(pRuntime);
-
-    pValue = pRuntime->GetObjectProperty(pObj, L"aFields");
-    aFields.Attach(CJS_Value(pRuntime, pValue).ToV8Array(pRuntime));
-  }
-
-  CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
-  CPDF_InterForm* pPDFInterForm = pInterForm->GetInterForm();
-  if (aFields.GetLength(pRuntime) == 0 && bEmpty) {
-    if (pPDFInterForm->CheckRequiredFields(nullptr, true)) {
-      pRuntime->BeginBlock();
-      pInterForm->SubmitForm(strURL, false);
-      pRuntime->EndBlock();
-    }
-    return true;
-  }
-
-  std::vector<CPDF_FormField*> fieldObjects;
-  for (int i = 0, sz = aFields.GetLength(pRuntime); i < sz; ++i) {
-    CJS_Value valName(pRuntime);
-    aFields.GetElement(pRuntime, i, valName);
-
-    CFX_WideString sName = valName.ToCFXWideString(pRuntime);
-    CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
-    for (int j = 0, jsz = pPDFForm->CountFields(sName); j < jsz; ++j) {
-      CPDF_FormField* pField = pPDFForm->GetField(j, sName);
-      if (!bEmpty && pField->GetValue().IsEmpty())
-        continue;
-
-      fieldObjects.push_back(pField);
-    }
-  }
-
-  if (pPDFInterForm->CheckRequiredFields(&fieldObjects, true)) {
-    pRuntime->BeginBlock();
-    pInterForm->SubmitFields(strURL, fieldObjects, true, !bFDF);
-    pRuntime->EndBlock();
-  }
-  return true;
-}
-
-void Document::SetFormFillEnv(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  m_pFormFillEnv.Reset(pFormFillEnv);
-}
-
-bool Document::bookmarkRoot(CJS_Runtime* pRuntime,
-                            CJS_PropValue& vp,
-                            CFX_WideString& sError) {
-  return true;
-}
-
-bool Document::mailDoc(CJS_Runtime* pRuntime,
-                       const std::vector<CJS_Value>& params,
-                       CJS_Value& vRet,
-                       CFX_WideString& sError) {
-  // TODO(tsepez): Check maximum number of allowed params.
-  bool bUI = true;
-  CFX_WideString cTo = L"";
-  CFX_WideString cCc = L"";
-  CFX_WideString cBcc = L"";
-  CFX_WideString cSubject = L"";
-  CFX_WideString cMsg = L"";
-
-  if (params.size() >= 1)
-    bUI = params[0].ToBool(pRuntime);
-  if (params.size() >= 2)
-    cTo = params[1].ToCFXWideString(pRuntime);
-  if (params.size() >= 3)
-    cCc = params[2].ToCFXWideString(pRuntime);
-  if (params.size() >= 4)
-    cBcc = params[3].ToCFXWideString(pRuntime);
-  if (params.size() >= 5)
-    cSubject = params[4].ToCFXWideString(pRuntime);
-  if (params.size() >= 6)
-    cMsg = params[5].ToCFXWideString(pRuntime);
-
-  if (params.size() >= 1 && params[0].GetType() == CJS_Value::VT_object) {
-    v8::Local<v8::Object> pObj = params[0].ToV8Object(pRuntime);
-
-    v8::Local<v8::Value> pValue = pRuntime->GetObjectProperty(pObj, L"bUI");
-    bUI = CJS_Value(pRuntime, pValue).ToBool(pRuntime);
-
-    pValue = pRuntime->GetObjectProperty(pObj, L"cTo");
-    cTo = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
-
-    pValue = pRuntime->GetObjectProperty(pObj, L"cCc");
-    cCc = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
-
-    pValue = pRuntime->GetObjectProperty(pObj, L"cBcc");
-    cBcc = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
-
-    pValue = pRuntime->GetObjectProperty(pObj, L"cSubject");
-    cSubject = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
-
-    pValue = pRuntime->GetObjectProperty(pObj, L"cMsg");
-    cMsg = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
-  }
-
-  pRuntime->BeginBlock();
-  CPDFSDK_FormFillEnvironment* pFormFillEnv = pRuntime->GetFormFillEnv();
-  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(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError) {
-  return getPropertyInternal(pRuntime, vp, "Author", sError);
-}
-
-bool Document::info(CJS_Runtime* pRuntime,
-                    CJS_PropValue& vp,
-                    CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
-    return false;
-  }
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  CPDF_Dictionary* pDictionary = m_pFormFillEnv->GetPDFDocument()->GetInfo();
-  if (!pDictionary)
-    return false;
-
-  CFX_WideString cwAuthor = pDictionary->GetUnicodeTextFor("Author");
-  CFX_WideString cwTitle = pDictionary->GetUnicodeTextFor("Title");
-  CFX_WideString cwSubject = pDictionary->GetUnicodeTextFor("Subject");
-  CFX_WideString cwKeywords = pDictionary->GetUnicodeTextFor("Keywords");
-  CFX_WideString cwCreator = pDictionary->GetUnicodeTextFor("Creator");
-  CFX_WideString cwProducer = pDictionary->GetUnicodeTextFor("Producer");
-  CFX_WideString cwCreationDate =
-      pDictionary->GetUnicodeTextFor("CreationDate");
-  CFX_WideString cwModDate = pDictionary->GetUnicodeTextFor("ModDate");
-  CFX_WideString cwTrapped = pDictionary->GetUnicodeTextFor("Trapped");
-
-  v8::Local<v8::Object> pObj = pRuntime->NewFxDynamicObj(-1);
-  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.AsStringC()));
-  pRuntime->PutObjectProperty(pObj, L"Creator",
-                              pRuntime->NewString(cwCreator.AsStringC()));
-  pRuntime->PutObjectProperty(pObj, L"Producer",
-                              pRuntime->NewString(cwProducer.AsStringC()));
-  pRuntime->PutObjectProperty(pObj, L"CreationDate",
-                              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) {
-    const CFX_ByteString& bsKey = it.first;
-    CPDF_Object* pValueObj = it.second.get();
-    CFX_WideString wsKey = CFX_WideString::FromUTF8(bsKey.AsStringC());
-    if (pValueObj->IsString() || pValueObj->IsName()) {
-      pRuntime->PutObjectProperty(
-          pObj, wsKey,
-          pRuntime->NewString(pValueObj->GetUnicodeText().AsStringC()));
-    } else if (pValueObj->IsNumber()) {
-      pRuntime->PutObjectProperty(pObj, wsKey,
-                                  pRuntime->NewNumber(pValueObj->GetNumber()));
-    } else if (pValueObj->IsBoolean()) {
-      pRuntime->PutObjectProperty(
-          pObj, wsKey, pRuntime->NewBoolean(!!pValueObj->GetInteger()));
-    }
-  }
-  vp << pObj;
-  return true;
-}
-
-bool Document::getPropertyInternal(CJS_Runtime* pRuntime,
-                                   CJS_PropValue& vp,
-                                   const CFX_ByteString& propName,
-                                   CFX_WideString& sError) {
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  CPDF_Dictionary* pDictionary = m_pFormFillEnv->GetPDFDocument()->GetInfo();
-  if (!pDictionary)
-    return false;
-
-  if (vp.IsGetting()) {
-    vp << pDictionary->GetUnicodeTextFor(propName);
-  } else {
-    if (!m_pFormFillEnv->GetPermissions(FPDFPERM_MODIFY)) {
-      sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
-      return false;
-    }
-    CFX_WideString csProperty;
-    vp >> csProperty;
-    pDictionary->SetNewFor<CPDF_String>(propName, PDF_EncodeText(csProperty),
-                                        false);
-    m_pFormFillEnv->SetChangeMark();
-  }
-  return true;
-}
-
-bool Document::creationDate(CJS_Runtime* pRuntime,
-                            CJS_PropValue& vp,
-                            CFX_WideString& sError) {
-  return getPropertyInternal(pRuntime, vp, "CreationDate", sError);
-}
-
-bool Document::creator(CJS_Runtime* pRuntime,
-                       CJS_PropValue& vp,
-                       CFX_WideString& sError) {
-  return getPropertyInternal(pRuntime, vp, "Creator", sError);
-}
-
-bool Document::delay(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  if (vp.IsGetting()) {
-    vp << m_bDelay;
-    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(CJS_Runtime* pRuntime,
-                        CJS_PropValue& vp,
-                        CFX_WideString& sError) {
-  return getPropertyInternal(pRuntime, vp, "Keywords", sError);
-}
-
-bool Document::modDate(CJS_Runtime* pRuntime,
-                       CJS_PropValue& vp,
-                       CFX_WideString& sError) {
-  return getPropertyInternal(pRuntime, vp, "ModDate", sError);
-}
-
-bool Document::producer(CJS_Runtime* pRuntime,
-                        CJS_PropValue& vp,
-                        CFX_WideString& sError) {
-  return getPropertyInternal(pRuntime, vp, "Producer", sError);
-}
-
-bool Document::subject(CJS_Runtime* pRuntime,
-                       CJS_PropValue& vp,
-                       CFX_WideString& sError) {
-  return getPropertyInternal(pRuntime, vp, "Subject", sError);
-}
-
-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(pRuntime, vp, "Title", sError);
-}
-
-bool Document::numPages(CJS_Runtime* pRuntime,
-                        CJS_PropValue& vp,
-                        CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
-    return false;
-  }
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  vp << m_pFormFillEnv->GetPageCount();
-  return true;
-}
-
-bool Document::external(CJS_Runtime* pRuntime,
-                        CJS_PropValue& vp,
-                        CFX_WideString& sError) {
-  // In Chrome case, should always return true.
-  if (vp.IsGetting()) {
-    vp << true;
-  }
-  return true;
-}
-
-bool Document::filesize(CJS_Runtime* pRuntime,
-                        CJS_PropValue& vp,
-                        CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
-    return false;
-  }
-  vp << 0;
-  return true;
-}
-
-bool Document::mouseX(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError) {
-  return true;
-}
-
-bool Document::mouseY(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError) {
-  return true;
-}
-
-bool Document::URL(CJS_Runtime* pRuntime,
-                   CJS_PropValue& vp,
-                   CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
-    return false;
-  }
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  vp << m_pFormFillEnv->JS_docGetFilePath();
-  return true;
-}
-
-bool Document::baseURL(CJS_Runtime* pRuntime,
-                       CJS_PropValue& vp,
-                       CFX_WideString& sError) {
-  if (vp.IsGetting()) {
-    vp << m_cwBaseURL;
-  } else {
-    vp >> m_cwBaseURL;
-  }
-  return true;
-}
-
-bool Document::calculate(CJS_Runtime* pRuntime,
-                         CJS_PropValue& vp,
-                         CFX_WideString& sError) {
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
-  if (vp.IsGetting()) {
-    vp << !!pInterForm->IsCalculateEnabled();
-    return true;
-  }
-  bool bCalculate;
-  vp >> bCalculate;
-  pInterForm->EnableCalculate(bCalculate);
-  return true;
-}
-
-bool Document::documentFileName(CJS_Runtime* pRuntime,
-                                CJS_PropValue& vp,
-                                CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
-    return false;
-  }
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  CFX_WideString wsFilePath = m_pFormFillEnv->JS_docGetFilePath();
-  int32_t i = wsFilePath.GetLength() - 1;
-  for (; i >= 0; i--) {
-    if (wsFilePath.GetAt(i) == L'\\' || wsFilePath.GetAt(i) == L'/')
-      break;
-  }
-  if (i >= 0 && i < wsFilePath.GetLength() - 1) {
-    vp << (wsFilePath.GetBuffer(wsFilePath.GetLength()) + i + 1);
-  } else {
-    vp << L"";
-  }
-  return true;
-}
-
-bool Document::path(CJS_Runtime* pRuntime,
-                    CJS_PropValue& vp,
-                    CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
-    return false;
-  }
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  vp << app::SysPathToPDFPath(m_pFormFillEnv->JS_docGetFilePath());
-  return true;
-}
-
-bool Document::pageWindowRect(CJS_Runtime* pRuntime,
-                              CJS_PropValue& vp,
-                              CFX_WideString& sError) {
-  return true;
-}
-
-bool Document::layout(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError) {
-  return true;
-}
-
-bool Document::addLink(CJS_Runtime* pRuntime,
-                       const std::vector<CJS_Value>& params,
-                       CJS_Value& vRet,
-                       CFX_WideString& sError) {
-  return true;
-}
-
-bool Document::closeDoc(CJS_Runtime* pRuntime,
-                        const std::vector<CJS_Value>& params,
-                        CJS_Value& vRet,
-                        CFX_WideString& sError) {
-  return true;
-}
-
-bool Document::getPageBox(CJS_Runtime* pRuntime,
-                          const std::vector<CJS_Value>& params,
-                          CJS_Value& vRet,
-                          CFX_WideString& sError) {
-  return true;
-}
-
-bool Document::getAnnot(CJS_Runtime* pRuntime,
-                        const std::vector<CJS_Value>& params,
-                        CJS_Value& vRet,
-                        CFX_WideString& sError) {
-  if (params.size() != 2) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  int nPageNo = params[0].ToInt(pRuntime);
-  CFX_WideString swAnnotName = params[1].ToCFXWideString(pRuntime);
-  CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetPageView(nPageNo);
-  if (!pPageView)
-    return false;
-
-  CPDFSDK_AnnotIteration annotIteration(pPageView, false);
-  CPDFSDK_BAAnnot* pSDKBAAnnot = nullptr;
-  for (const auto& pSDKAnnotCur : annotIteration) {
-    CPDFSDK_BAAnnot* pBAAnnot =
-        static_cast<CPDFSDK_BAAnnot*>(pSDKAnnotCur.Get());
-    if (pBAAnnot && pBAAnnot->GetAnnotName() == swAnnotName) {
-      pSDKBAAnnot = pBAAnnot;
-      break;
-    }
-  }
-  if (!pSDKBAAnnot)
-    return false;
-
-  v8::Local<v8::Object> pObj =
-      pRuntime->NewFxDynamicObj(CJS_Annot::g_nObjDefnID);
-  if (pObj.IsEmpty())
-    return false;
-
-  CJS_Annot* pJS_Annot =
-      static_cast<CJS_Annot*>(pRuntime->GetObjectPrivate(pObj));
-  Annot* pAnnot = static_cast<Annot*>(pJS_Annot->GetEmbedObject());
-  pAnnot->SetSDKAnnot(pSDKBAAnnot);
-  vRet = CJS_Value(pRuntime, pJS_Annot);
-  return true;
-}
-
-bool Document::getAnnots(CJS_Runtime* pRuntime,
-                         const std::vector<CJS_Value>& params,
-                         CJS_Value& vRet,
-                         CFX_WideString& sError) {
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  // TODO(tonikitoo): Add support supported parameters as per
-  // the PDF spec.
-
-  int nPageNo = m_pFormFillEnv->GetPageCount();
-  CJS_Array annots;
-
-  for (int i = 0; i < nPageNo; ++i) {
-    CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetPageView(i);
-    if (!pPageView)
-      return false;
-
-    CPDFSDK_AnnotIteration annotIteration(pPageView, false);
-    for (const auto& pSDKAnnotCur : annotIteration) {
-      if (!pSDKAnnotCur) {
-        sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-        return false;
-      }
-      v8::Local<v8::Object> pObj =
-          pRuntime->NewFxDynamicObj(CJS_Annot::g_nObjDefnID);
-      if (pObj.IsEmpty())
-        return false;
-
-      CJS_Annot* pJS_Annot =
-          static_cast<CJS_Annot*>(pRuntime->GetObjectPrivate(pObj));
-      Annot* pAnnot = static_cast<Annot*>(pJS_Annot->GetEmbedObject());
-      pAnnot->SetSDKAnnot(static_cast<CPDFSDK_BAAnnot*>(pSDKAnnotCur.Get()));
-      annots.SetElement(pRuntime, i, CJS_Value(pRuntime, pJS_Annot));
-    }
-  }
-  vRet = CJS_Value(pRuntime, annots);
-  return true;
-}
-
-bool Document::getAnnot3D(CJS_Runtime* pRuntime,
-                          const std::vector<CJS_Value>& params,
-                          CJS_Value& vRet,
-                          CFX_WideString& sError) {
-  vRet.SetNull(pRuntime);
-  return true;
-}
-
-bool Document::getAnnots3D(CJS_Runtime* pRuntime,
-                           const std::vector<CJS_Value>& params,
-                           CJS_Value& vRet,
-                           CFX_WideString& sError) {
-  return true;
-}
-
-bool Document::getOCGs(CJS_Runtime* pRuntime,
-                       const std::vector<CJS_Value>& params,
-                       CJS_Value& vRet,
-                       CFX_WideString& sError) {
-  return true;
-}
-
-bool Document::getLinks(CJS_Runtime* pRuntime,
-                        const std::vector<CJS_Value>& params,
-                        CJS_Value& vRet,
-                        CFX_WideString& sError) {
-  return true;
-}
-
-bool Document::IsEnclosedInRect(CFX_FloatRect rect, CFX_FloatRect LinkRect) {
-  return (rect.left <= LinkRect.left && rect.top <= LinkRect.top &&
-          rect.right >= LinkRect.right && rect.bottom >= LinkRect.bottom);
-}
-
-bool Document::addIcon(CJS_Runtime* pRuntime,
-                       const std::vector<CJS_Value>& params,
-                       CJS_Value& vRet,
-                       CFX_WideString& sError) {
-  if (params.size() != 2) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  CFX_WideString swIconName = params[0].ToCFXWideString(pRuntime);
-  if (params[1].GetType() != CJS_Value::VT_object) {
-    sError = JSGetStringFromID(IDS_STRING_JSTYPEERROR);
-    return false;
-  }
-
-  v8::Local<v8::Object> pJSIcon = params[1].ToV8Object(pRuntime);
-  if (pRuntime->GetObjDefnID(pJSIcon) != CJS_Icon::g_nObjDefnID) {
-    sError = JSGetStringFromID(IDS_STRING_JSTYPEERROR);
-    return false;
-  }
-
-  if (!params[1].ToCJSObject(pRuntime)->GetEmbedObject()) {
-    sError = JSGetStringFromID(IDS_STRING_JSTYPEERROR);
-    return false;
-  }
-
-  m_IconNames.push_back(swIconName);
-  return true;
-}
-
-bool Document::icons(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
-    return false;
-  }
-  if (m_IconNames.empty()) {
-    vp.GetJSValue()->SetNull(pRuntime);
-    return true;
-  }
-
-  CJS_Array Icons;
-  int i = 0;
-  for (const auto& name : m_IconNames) {
-    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));
-    Icon* pIcon = static_cast<Icon*>(pJS_Icon->GetEmbedObject());
-    pIcon->SetIconName(name);
-    Icons.SetElement(pRuntime, i++, CJS_Value(pRuntime, pJS_Icon));
-  }
-
-  vp << Icons;
-  return true;
-}
-
-bool Document::getIcon(CJS_Runtime* pRuntime,
-                       const std::vector<CJS_Value>& params,
-                       CJS_Value& vRet,
-                       CFX_WideString& sError) {
-  if (params.size() != 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  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;
-
-  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));
-  Icon* pIcon = static_cast<Icon*>(pJS_Icon->GetEmbedObject());
-  pIcon->SetIconName(*it);
-  vRet = CJS_Value(pRuntime, pJS_Icon);
-  return true;
-}
-
-bool Document::removeIcon(CJS_Runtime* pRuntime,
-                          const std::vector<CJS_Value>& params,
-                          CJS_Value& vRet,
-                          CFX_WideString& sError) {
-  // Unsafe, no supported.
-  return true;
-}
-
-bool Document::createDataObject(CJS_Runtime* pRuntime,
-                                const std::vector<CJS_Value>& params,
-                                CJS_Value& vRet,
-                                CFX_WideString& sError) {
-  // Unsafe, not implemented.
-  return true;
-}
-
-bool Document::media(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  return true;
-}
-
-bool Document::calculateNow(CJS_Runtime* pRuntime,
-                            const std::vector<CJS_Value>& params,
-                            CJS_Value& vRet,
-                            CFX_WideString& sError) {
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  if (!(m_pFormFillEnv->GetPermissions(FPDFPERM_MODIFY) ||
-        m_pFormFillEnv->GetPermissions(FPDFPERM_ANNOT_FORM) ||
-        m_pFormFillEnv->GetPermissions(FPDFPERM_FILL_FORM))) {
-    sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
-    return false;
-  }
-  m_pFormFillEnv->GetInterForm()->OnCalculate();
-  return true;
-}
-
-bool Document::Collab(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError) {
-  return true;
-}
-
-bool Document::getPageNthWord(CJS_Runtime* pRuntime,
-                              const std::vector<CJS_Value>& params,
-                              CJS_Value& vRet,
-                              CFX_WideString& sError) {
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  if (!m_pFormFillEnv->GetPermissions(FPDFPERM_EXTRACT_ACCESS)) {
-    sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
-    return false;
-  }
-
-  // TODO(tsepez): check maximum allowable params.
-
-  int nPageNo = params.size() > 0 ? params[0].ToInt(pRuntime) : 0;
-  int nWordNo = params.size() > 1 ? params[1].ToInt(pRuntime) : 0;
-  bool bStrip = params.size() > 2 ? params[2].ToBool(pRuntime) : true;
-
-  CPDF_Document* pDocument = m_pFormFillEnv->GetPDFDocument();
-  if (!pDocument)
-    return false;
-
-  if (nPageNo < 0 || nPageNo >= pDocument->GetPageCount()) {
-    sError = JSGetStringFromID(IDS_STRING_JSVALUEERROR);
-    return false;
-  }
-
-  CPDF_Dictionary* pPageDict = pDocument->GetPage(nPageNo);
-  if (!pPageDict)
-    return false;
-
-  CPDF_Page page(pDocument, pPageDict, true);
-  page.ParseContent();
-
-  int nWords = 0;
-  CFX_WideString swRet;
-  for (auto& pPageObj : *page.GetPageObjectList()) {
-    if (pPageObj->IsText()) {
-      CPDF_TextObject* pTextObj = pPageObj->AsText();
-      int nObjWords = CountWords(pTextObj);
-      if (nWords + nObjWords >= nWordNo) {
-        swRet = GetObjWordStr(pTextObj, nWordNo - nWords);
-        break;
-      }
-      nWords += nObjWords;
-    }
-  }
-
-  if (bStrip) {
-    swRet.TrimLeft();
-    swRet.TrimRight();
-  }
-
-  vRet = CJS_Value(pRuntime, swRet.c_str());
-  return true;
-}
-
-bool Document::getPageNthWordQuads(CJS_Runtime* pRuntime,
-                                   const std::vector<CJS_Value>& params,
-                                   CJS_Value& vRet,
-                                   CFX_WideString& sError) {
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  if (!m_pFormFillEnv->GetPermissions(FPDFPERM_EXTRACT_ACCESS)) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  return false;
-}
-
-bool Document::getPageNumWords(CJS_Runtime* pRuntime,
-                               const std::vector<CJS_Value>& params,
-                               CJS_Value& vRet,
-                               CFX_WideString& sError) {
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  if (!m_pFormFillEnv->GetPermissions(FPDFPERM_EXTRACT_ACCESS)) {
-    sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
-    return false;
-  }
-  int nPageNo = params.size() > 0 ? params[0].ToInt(pRuntime) : 0;
-  CPDF_Document* pDocument = m_pFormFillEnv->GetPDFDocument();
-  if (nPageNo < 0 || nPageNo >= pDocument->GetPageCount()) {
-    sError = JSGetStringFromID(IDS_STRING_JSVALUEERROR);
-    return false;
-  }
-
-  CPDF_Dictionary* pPageDict = pDocument->GetPage(nPageNo);
-  if (!pPageDict)
-    return false;
-
-  CPDF_Page page(pDocument, pPageDict, true);
-  page.ParseContent();
-
-  int nWords = 0;
-  for (auto& pPageObj : *page.GetPageObjectList()) {
-    if (pPageObj->IsText())
-      nWords += CountWords(pPageObj->AsText());
-  }
-
-  vRet = CJS_Value(pRuntime, nWords);
-  return true;
-}
-
-bool Document::getPrintParams(CJS_Runtime* pRuntime,
-                              const std::vector<CJS_Value>& params,
-                              CJS_Value& vRet,
-                              CFX_WideString& sError) {
-  v8::Local<v8::Object> pRetObj =
-      pRuntime->NewFxDynamicObj(CJS_PrintParamsObj::g_nObjDefnID);
-  if (pRetObj.IsEmpty())
-    return false;
-
-  // Not implemented yet.
-
-  vRet = CJS_Value(pRuntime, pRetObj);
-  return true;
-}
-
-#define ISLATINWORD(u) (u != 0x20 && u <= 0x28FF)
-
-int Document::CountWords(CPDF_TextObject* pTextObj) {
-  if (!pTextObj)
-    return 0;
-
-  int nWords = 0;
-
-  CPDF_Font* pFont = pTextObj->GetFont();
-  if (!pFont)
-    return 0;
-
-  bool bIsLatin = false;
-
-  for (int i = 0, sz = pTextObj->CountChars(); i < sz; i++) {
-    uint32_t charcode = CPDF_Font::kInvalidCharCode;
-    FX_FLOAT kerning;
-
-    pTextObj->GetCharInfo(i, &charcode, &kerning);
-    CFX_WideString swUnicode = pFont->UnicodeFromCharCode(charcode);
-
-    uint16_t unicode = 0;
-    if (swUnicode.GetLength() > 0)
-      unicode = swUnicode[0];
-
-    if (ISLATINWORD(unicode) && bIsLatin)
-      continue;
-
-    bIsLatin = ISLATINWORD(unicode);
-    if (unicode != 0x20)
-      nWords++;
-  }
-
-  return nWords;
-}
-
-CFX_WideString Document::GetObjWordStr(CPDF_TextObject* pTextObj,
-                                       int nWordIndex) {
-  CFX_WideString swRet;
-
-  CPDF_Font* pFont = pTextObj->GetFont();
-  if (!pFont)
-    return L"";
-
-  int nWords = 0;
-  bool bIsLatin = false;
-
-  for (int i = 0, sz = pTextObj->CountChars(); i < sz; i++) {
-    uint32_t charcode = CPDF_Font::kInvalidCharCode;
-    FX_FLOAT kerning;
-
-    pTextObj->GetCharInfo(i, &charcode, &kerning);
-    CFX_WideString swUnicode = pFont->UnicodeFromCharCode(charcode);
-
-    uint16_t unicode = 0;
-    if (swUnicode.GetLength() > 0)
-      unicode = swUnicode[0];
-
-    if (ISLATINWORD(unicode) && bIsLatin) {
-    } else {
-      bIsLatin = ISLATINWORD(unicode);
-      if (unicode != 0x20)
-        nWords++;
-    }
-
-    if (nWords - 1 == nWordIndex)
-      swRet += unicode;
-  }
-
-  return swRet;
-}
-
-bool Document::zoom(CJS_Runtime* pRuntime,
-                    CJS_PropValue& vp,
-                    CFX_WideString& sError) {
-  return true;
-}
-
-/**
-(none,  NoVary)
-(fitP,  FitPage)
-(fitW,  FitWidth)
-(fitH,  FitHeight)
-(fitV,  FitVisibleWidth)
-(pref,  Preferred)
-(refW,  ReflowWidth)
-*/
-
-bool Document::zoomType(CJS_Runtime* pRuntime,
-                        CJS_PropValue& vp,
-                        CFX_WideString& sError) {
-  return true;
-}
-
-bool Document::deletePages(CJS_Runtime* pRuntime,
-                           const std::vector<CJS_Value>& params,
-                           CJS_Value& vRet,
-                           CFX_WideString& sError) {
-  // Unsafe, no supported.
-  return true;
-}
-
-bool Document::extractPages(CJS_Runtime* pRuntime,
-                            const std::vector<CJS_Value>& params,
-                            CJS_Value& vRet,
-                            CFX_WideString& sError) {
-  // Unsafe, not supported.
-  return true;
-}
-
-bool Document::insertPages(CJS_Runtime* pRuntime,
-                           const std::vector<CJS_Value>& params,
-                           CJS_Value& vRet,
-                           CFX_WideString& sError) {
-  // Unsafe, not supported.
-  return true;
-}
-
-bool Document::replacePages(CJS_Runtime* pRuntime,
-                            const std::vector<CJS_Value>& params,
-                            CJS_Value& vRet,
-                            CFX_WideString& sError) {
-  // Unsafe, not supported.
-  return true;
-}
-
-bool Document::getURL(CJS_Runtime* pRuntime,
-                      const std::vector<CJS_Value>& params,
-                      CJS_Value& vRet,
-                      CFX_WideString& sError) {
-  // Unsafe, not supported.
-  return true;
-}
-
-bool Document::gotoNamedDest(CJS_Runtime* pRuntime,
-                             const std::vector<CJS_Value>& params,
-                             CJS_Value& vRet,
-                             CFX_WideString& sError) {
-  if (params.size() != 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-  if (!m_pFormFillEnv) {
-    sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-    return false;
-  }
-  CFX_WideString wideName = params[0].ToCFXWideString(pRuntime);
-  CFX_ByteString utf8Name = wideName.UTF8Encode();
-  CPDF_Document* pDocument = m_pFormFillEnv->GetPDFDocument();
-  if (!pDocument)
-    return false;
-
-  CPDF_NameTree nameTree(pDocument, "Dests");
-  CPDF_Array* destArray = nameTree.LookupNamedDest(pDocument, utf8Name);
-  if (!destArray)
-    return false;
-
-  CPDF_Dest dest(destArray);
-  const CPDF_Array* arrayObject = ToArray(dest.GetObject());
-
-  std::unique_ptr<float[]> scrollPositionArray;
-  int scrollPositionArraySize = 0;
-
-  if (arrayObject) {
-    scrollPositionArray.reset(new float[arrayObject->GetCount()]);
-    int j = 0;
-    for (size_t i = 2; i < arrayObject->GetCount(); i++)
-      scrollPositionArray[j++] = arrayObject->GetFloatAt(i);
-    scrollPositionArraySize = j;
-  }
-
-  pRuntime->BeginBlock();
-  m_pFormFillEnv->DoGoToAction(dest.GetPageIndex(pDocument), dest.GetZoomMode(),
-                               scrollPositionArray.get(),
-                               scrollPositionArraySize);
-  pRuntime->EndBlock();
-
-  return true;
-}
-
-void Document::AddDelayData(CJS_DelayData* pData) {
-  m_DelayData.push_back(std::unique_ptr<CJS_DelayData>(pData));
-}
-
-void Document::DoFieldDelay(const CFX_WideString& sFieldName,
-                            int nControlIndex) {
-  std::vector<std::unique_ptr<CJS_DelayData>> DelayDataForFieldAndControlIndex;
-  auto iter = m_DelayData.begin();
-  while (iter != m_DelayData.end()) {
-    auto old = iter++;
-    if ((*old)->sFieldName == sFieldName &&
-        (*old)->nControlIndex == nControlIndex) {
-      DelayDataForFieldAndControlIndex.push_back(std::move(*old));
-      m_DelayData.erase(old);
-    }
-  }
-
-  for (const auto& pData : DelayDataForFieldAndControlIndex)
-    Field::DoDelay(m_pFormFillEnv.Get(), pData.get());
-}
-
-CJS_Document* Document::GetCJSDoc() const {
-  return static_cast<CJS_Document*>(m_pJSObject);
-}
diff --git a/fpdfsdk/javascript/Document.h b/fpdfsdk/javascript/Document.h
deleted file mode 100644
index 91ca778..0000000
--- a/fpdfsdk/javascript/Document.h
+++ /dev/null
@@ -1,402 +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 FPDFSDK_JAVASCRIPT_DOCUMENT_H_
-#define FPDFSDK_JAVASCRIPT_DOCUMENT_H_
-
-#include <list>
-#include <memory>
-#include <vector>
-
-#include "core/fpdfapi/page/cpdf_pageobject.h"
-#include "core/fpdfapi/page/cpdf_textobject.h"
-#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
-#include "fpdfsdk/javascript/JS_Define.h"
-
-class PrintParamsObj : public CJS_EmbedObj {
- public:
-  explicit PrintParamsObj(CJS_Object* pJSObject);
-  ~PrintParamsObj() override {}
-
- public:
-  bool bUI;
-  int nStart;
-  int nEnd;
-  bool bSilent;
-  bool bShrinkToFit;
-  bool bPrintAsImage;
-  bool bReverse;
-  bool bAnnotations;
-};
-
-class CJS_PrintParamsObj : public CJS_Object {
- public:
-  explicit CJS_PrintParamsObj(v8::Local<v8::Object> pObject)
-      : CJS_Object(pObject) {}
-  ~CJS_PrintParamsObj() override {}
-
-  DECLARE_JS_CLASS();
-};
-
-struct CJS_AnnotObj;
-struct CJS_DelayAnnot;
-struct CJS_DelayData;
-
-class Document : public CJS_EmbedObj {
- public:
-  explicit Document(CJS_Object* pJSObject);
-  ~Document() override;
-
-  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(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(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(CJS_Runtime* pRuntime,
-                const std::vector<CJS_Value>& params,
-                CJS_Value& vRet,
-                CFX_WideString& sError);
-  bool addField(CJS_Runtime* pRuntime,
-                const std::vector<CJS_Value>& params,
-                CJS_Value& vRet,
-                CFX_WideString& sError);
-  bool addLink(CJS_Runtime* pRuntime,
-               const std::vector<CJS_Value>& params,
-               CJS_Value& vRet,
-               CFX_WideString& sError);
-  bool addIcon(CJS_Runtime* pRuntime,
-               const std::vector<CJS_Value>& params,
-               CJS_Value& vRet,
-               CFX_WideString& sError);
-  bool calculateNow(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError);
-  bool closeDoc(CJS_Runtime* pRuntime,
-                const std::vector<CJS_Value>& params,
-                CJS_Value& vRet,
-                CFX_WideString& sError);
-  bool createDataObject(CJS_Runtime* pRuntime,
-                        const std::vector<CJS_Value>& params,
-                        CJS_Value& vRet,
-                        CFX_WideString& sError);
-  bool deletePages(CJS_Runtime* pRuntime,
-                   const std::vector<CJS_Value>& params,
-                   CJS_Value& vRet,
-                   CFX_WideString& sError);
-  bool exportAsText(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError);
-  bool exportAsFDF(CJS_Runtime* pRuntime,
-                   const std::vector<CJS_Value>& params,
-                   CJS_Value& vRet,
-                   CFX_WideString& sError);
-  bool exportAsXFDF(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError);
-  bool extractPages(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError);
-  bool getAnnot(CJS_Runtime* pRuntime,
-                const std::vector<CJS_Value>& params,
-                CJS_Value& vRet,
-                CFX_WideString& sError);
-  bool getAnnots(CJS_Runtime* pRuntime,
-                 const std::vector<CJS_Value>& params,
-                 CJS_Value& vRet,
-                 CFX_WideString& sError);
-  bool getAnnot3D(CJS_Runtime* pRuntime,
-                  const std::vector<CJS_Value>& params,
-                  CJS_Value& vRet,
-                  CFX_WideString& sError);
-  bool getAnnots3D(CJS_Runtime* pRuntime,
-                   const std::vector<CJS_Value>& params,
-                   CJS_Value& vRet,
-                   CFX_WideString& sError);
-  bool getField(CJS_Runtime* pRuntime,
-                const std::vector<CJS_Value>& params,
-                CJS_Value& vRet,
-                CFX_WideString& sError);
-  bool getIcon(CJS_Runtime* pRuntime,
-               const std::vector<CJS_Value>& params,
-               CJS_Value& vRet,
-               CFX_WideString& sError);
-  bool getLinks(CJS_Runtime* pRuntime,
-                const std::vector<CJS_Value>& params,
-                CJS_Value& vRet,
-                CFX_WideString& sError);
-  bool getNthFieldName(CJS_Runtime* pRuntime,
-                       const std::vector<CJS_Value>& params,
-                       CJS_Value& vRet,
-                       CFX_WideString& sError);
-  bool getOCGs(CJS_Runtime* pRuntime,
-               const std::vector<CJS_Value>& params,
-               CJS_Value& vRet,
-               CFX_WideString& sError);
-  bool getPageBox(CJS_Runtime* pRuntime,
-                  const std::vector<CJS_Value>& params,
-                  CJS_Value& vRet,
-                  CFX_WideString& sError);
-  bool getPageNthWord(CJS_Runtime* pRuntime,
-                      const std::vector<CJS_Value>& params,
-                      CJS_Value& vRet,
-                      CFX_WideString& sError);
-  bool getPageNthWordQuads(CJS_Runtime* pRuntime,
-                           const std::vector<CJS_Value>& params,
-                           CJS_Value& vRet,
-                           CFX_WideString& sError);
-  bool getPageNumWords(CJS_Runtime* pRuntime,
-                       const std::vector<CJS_Value>& params,
-                       CJS_Value& vRet,
-                       CFX_WideString& sError);
-  bool getPrintParams(CJS_Runtime* pRuntime,
-                      const std::vector<CJS_Value>& params,
-                      CJS_Value& vRet,
-                      CFX_WideString& sError);
-  bool getURL(CJS_Runtime* pRuntime,
-              const std::vector<CJS_Value>& params,
-              CJS_Value& vRet,
-              CFX_WideString& sError);
-  bool gotoNamedDest(CJS_Runtime* pRuntime,
-                     const std::vector<CJS_Value>& params,
-                     CJS_Value& vRet,
-                     CFX_WideString& sError);
-  bool importAnFDF(CJS_Runtime* pRuntime,
-                   const std::vector<CJS_Value>& params,
-                   CJS_Value& vRet,
-                   CFX_WideString& sError);
-  bool importAnXFDF(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError);
-  bool importTextData(CJS_Runtime* pRuntime,
-                      const std::vector<CJS_Value>& params,
-                      CJS_Value& vRet,
-                      CFX_WideString& sError);
-  bool insertPages(CJS_Runtime* pRuntime,
-                   const std::vector<CJS_Value>& params,
-                   CJS_Value& vRet,
-                   CFX_WideString& sError);
-  bool mailForm(CJS_Runtime* pRuntime,
-                const std::vector<CJS_Value>& params,
-                CJS_Value& vRet,
-                CFX_WideString& sError);
-  bool print(CJS_Runtime* pRuntime,
-             const std::vector<CJS_Value>& params,
-             CJS_Value& vRet,
-             CFX_WideString& sError);
-  bool removeField(CJS_Runtime* pRuntime,
-                   const std::vector<CJS_Value>& params,
-                   CJS_Value& vRet,
-                   CFX_WideString& sError);
-  bool replacePages(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError);
-  bool resetForm(CJS_Runtime* pRuntime,
-                 const std::vector<CJS_Value>& params,
-                 CJS_Value& vRet,
-                 CFX_WideString& sError);
-  bool saveAs(CJS_Runtime* pRuntime,
-              const std::vector<CJS_Value>& params,
-              CJS_Value& vRet,
-              CFX_WideString& sError);
-  bool submitForm(CJS_Runtime* pRuntime,
-                  const std::vector<CJS_Value>& params,
-                  CJS_Value& vRet,
-                  CFX_WideString& sError);
-  bool syncAnnotScan(CJS_Runtime* pRuntime,
-                     const std::vector<CJS_Value>& params,
-                     CJS_Value& vRet,
-                     CFX_WideString& sError);
-  bool mailDoc(CJS_Runtime* pRuntime,
-               const std::vector<CJS_Value>& params,
-               CJS_Value& vRet,
-               CFX_WideString& sError);
-  bool removeIcon(CJS_Runtime* pRuntime,
-                  const std::vector<CJS_Value>& params,
-                  CJS_Value& vRet,
-                  CFX_WideString& sError);
-  bool URL(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
-
-  void SetFormFillEnv(CPDFSDK_FormFillEnvironment* pFormFillEnv);
-  CPDFSDK_FormFillEnvironment* GetFormFillEnv() const {
-    return m_pFormFillEnv.Get();
-  }
-  void AddDelayData(CJS_DelayData* pData);
-  void DoFieldDelay(const CFX_WideString& sFieldName, int nControlIndex);
-  CJS_Document* GetCJSDoc() const;
-
- private:
-  bool IsEnclosedInRect(CFX_FloatRect rect, CFX_FloatRect LinkRect);
-  int CountWords(CPDF_TextObject* pTextObj);
-  CFX_WideString GetObjWordStr(CPDF_TextObject* pTextObj, int nWordIndex);
-
-  bool getPropertyInternal(CJS_Runtime* pRuntime,
-                           CJS_PropValue& vp,
-                           const CFX_ByteString& propName,
-                           CFX_WideString& sError);
-
-  CPDFSDK_FormFillEnvironment::ObservedPtr m_pFormFillEnv;
-  CFX_WideString m_cwBaseURL;
-  std::list<std::unique_ptr<CJS_DelayData>> m_DelayData;
-  // Needs to be a std::list for iterator stability.
-  std::list<CFX_WideString> m_IconNames;
-  bool m_bDelay;
-};
-
-class CJS_Document : public CJS_Object {
- public:
-  explicit CJS_Document(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Document() override {}
-
-  // CJS_Object
-  void InitInstance(IJS_Runtime* pIRuntime) override;
-
-  DECLARE_JS_CLASS();
-
-  JS_STATIC_PROP(ADBE, Document);
-  JS_STATIC_PROP(author, Document);
-  JS_STATIC_PROP(baseURL, Document);
-  JS_STATIC_PROP(bookmarkRoot, Document);
-  JS_STATIC_PROP(calculate, Document);
-  JS_STATIC_PROP(Collab, Document);
-  JS_STATIC_PROP(creationDate, Document);
-  JS_STATIC_PROP(creator, Document);
-  JS_STATIC_PROP(delay, Document);
-  JS_STATIC_PROP(dirty, Document);
-  JS_STATIC_PROP(documentFileName, Document);
-  JS_STATIC_PROP(external, Document);
-  JS_STATIC_PROP(filesize, Document);
-  JS_STATIC_PROP(icons, Document);
-  JS_STATIC_PROP(info, Document);
-  JS_STATIC_PROP(keywords, Document);
-  JS_STATIC_PROP(layout, Document);
-  JS_STATIC_PROP(media, Document);
-  JS_STATIC_PROP(modDate, Document);
-  JS_STATIC_PROP(mouseX, Document);
-  JS_STATIC_PROP(mouseY, Document);
-  JS_STATIC_PROP(numFields, Document);
-  JS_STATIC_PROP(numPages, Document);
-  JS_STATIC_PROP(pageNum, Document);
-  JS_STATIC_PROP(pageWindowRect, Document);
-  JS_STATIC_PROP(path, Document);
-  JS_STATIC_PROP(producer, Document);
-  JS_STATIC_PROP(subject, Document);
-  JS_STATIC_PROP(title, Document);
-  JS_STATIC_PROP(URL, Document);
-  JS_STATIC_PROP(zoom, Document);
-  JS_STATIC_PROP(zoomType, Document);
-
-  JS_STATIC_METHOD(addAnnot, Document);
-  JS_STATIC_METHOD(addField, Document);
-  JS_STATIC_METHOD(addLink, Document);
-  JS_STATIC_METHOD(addIcon, Document);
-  JS_STATIC_METHOD(calculateNow, Document);
-  JS_STATIC_METHOD(closeDoc, Document);
-  JS_STATIC_METHOD(createDataObject, Document);
-  JS_STATIC_METHOD(deletePages, Document);
-  JS_STATIC_METHOD(exportAsText, Document);
-  JS_STATIC_METHOD(exportAsFDF, Document);
-  JS_STATIC_METHOD(exportAsXFDF, Document);
-  JS_STATIC_METHOD(extractPages, Document);
-  JS_STATIC_METHOD(getAnnot, Document);
-  JS_STATIC_METHOD(getAnnots, Document);
-  JS_STATIC_METHOD(getAnnot3D, Document);
-  JS_STATIC_METHOD(getAnnots3D, Document);
-  JS_STATIC_METHOD(getField, Document);
-  JS_STATIC_METHOD(getIcon, Document);
-  JS_STATIC_METHOD(getLinks, Document);
-  JS_STATIC_METHOD(getNthFieldName, Document);
-  JS_STATIC_METHOD(getOCGs, Document);
-  JS_STATIC_METHOD(getPageBox, Document);
-  JS_STATIC_METHOD(getPageNthWord, Document);
-  JS_STATIC_METHOD(getPageNthWordQuads, Document);
-  JS_STATIC_METHOD(getPageNumWords, Document);
-  JS_STATIC_METHOD(getPrintParams, Document);
-  JS_STATIC_METHOD(getURL, Document);
-  JS_STATIC_METHOD(gotoNamedDest, Document);
-  JS_STATIC_METHOD(importAnFDF, Document);
-  JS_STATIC_METHOD(importAnXFDF, Document);
-  JS_STATIC_METHOD(importTextData, Document);
-  JS_STATIC_METHOD(insertPages, Document);
-  JS_STATIC_METHOD(mailForm, Document);
-  JS_STATIC_METHOD(print, Document);
-  JS_STATIC_METHOD(removeField, Document);
-  JS_STATIC_METHOD(replacePages, Document);
-  JS_STATIC_METHOD(removeIcon, Document);
-  JS_STATIC_METHOD(resetForm, Document);
-  JS_STATIC_METHOD(saveAs, Document);
-  JS_STATIC_METHOD(submitForm, Document);
-  JS_STATIC_METHOD(syncAnnotScan, Document);
-  JS_STATIC_METHOD(mailDoc, Document);
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_DOCUMENT_H_
diff --git a/fpdfsdk/javascript/Field.cpp b/fpdfsdk/javascript/Field.cpp
deleted file mode 100644
index f37b3d4..0000000
--- a/fpdfsdk/javascript/Field.cpp
+++ /dev/null
@@ -1,3405 +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/Field.h"
-
-#include <algorithm>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "core/fpdfapi/font/cpdf_font.h"
-#include "core/fpdfapi/page/cpdf_page.h"
-#include "core/fpdfapi/parser/cpdf_document.h"
-#include "core/fpdfdoc/cpdf_interform.h"
-#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
-#include "fpdfsdk/cpdfsdk_interform.h"
-#include "fpdfsdk/cpdfsdk_pageview.h"
-#include "fpdfsdk/cpdfsdk_widget.h"
-#include "fpdfsdk/javascript/Document.h"
-#include "fpdfsdk/javascript/Icon.h"
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_EventHandler.h"
-#include "fpdfsdk/javascript/JS_Object.h"
-#include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/PublicMethods.h"
-#include "fpdfsdk/javascript/cjs_event_context.h"
-#include "fpdfsdk/javascript/cjs_runtime.h"
-#include "fpdfsdk/javascript/color.h"
-
-namespace {
-
-bool SetWidgetDisplayStatus(CPDFSDK_Widget* pWidget, int value) {
-  if (!pWidget)
-    return false;
-
-  uint32_t dwFlag = pWidget->GetFlags();
-  switch (value) {
-    case 0:
-      dwFlag &= ~ANNOTFLAG_INVISIBLE;
-      dwFlag &= ~ANNOTFLAG_HIDDEN;
-      dwFlag &= ~ANNOTFLAG_NOVIEW;
-      dwFlag |= ANNOTFLAG_PRINT;
-      break;
-    case 1:
-      dwFlag &= ~ANNOTFLAG_INVISIBLE;
-      dwFlag &= ~ANNOTFLAG_NOVIEW;
-      dwFlag |= (ANNOTFLAG_HIDDEN | ANNOTFLAG_PRINT);
-      break;
-    case 2:
-      dwFlag &= ~ANNOTFLAG_INVISIBLE;
-      dwFlag &= ~ANNOTFLAG_PRINT;
-      dwFlag &= ~ANNOTFLAG_HIDDEN;
-      dwFlag &= ~ANNOTFLAG_NOVIEW;
-      break;
-    case 3:
-      dwFlag |= ANNOTFLAG_NOVIEW;
-      dwFlag |= ANNOTFLAG_PRINT;
-      dwFlag &= ~ANNOTFLAG_HIDDEN;
-      break;
-  }
-
-  if (dwFlag != pWidget->GetFlags()) {
-    pWidget->SetFlags(dwFlag);
-    return true;
-  }
-
-  return false;
-}
-
-}  // namespace
-
-JSConstSpec CJS_Field::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
-
-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}};
-
-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)
-
-CJS_DelayData::CJS_DelayData(FIELD_PROP prop,
-                             int idx,
-                             const CFX_WideString& name)
-    : eProp(prop), nControlIndex(idx), sFieldName(name) {}
-
-CJS_DelayData::~CJS_DelayData() {}
-
-void CJS_Field::InitInstance(IJS_Runtime* pIRuntime) {
-}
-
-Field::Field(CJS_Object* pJSObject)
-    : CJS_EmbedObj(pJSObject),
-      m_pJSDoc(nullptr),
-      m_pFormFillEnv(nullptr),
-      m_nFormControlIndex(-1),
-      m_bCanSet(false),
-      m_bDelay(false) {}
-
-Field::~Field() {}
-
-// note: iControlNo = -1, means not a widget.
-void Field::ParseFieldName(const std::wstring& strFieldNameParsed,
-                           std::wstring& strFieldName,
-                           int& iControlNo) {
-  int iStart = strFieldNameParsed.find_last_of(L'.');
-  if (iStart == -1) {
-    strFieldName = strFieldNameParsed;
-    iControlNo = -1;
-    return;
-  }
-  std::wstring suffixal = strFieldNameParsed.substr(iStart + 1);
-  iControlNo = FXSYS_wtoi(suffixal.c_str());
-  if (iControlNo == 0) {
-    int iSpaceStart;
-    while ((iSpaceStart = suffixal.find_last_of(L" ")) != -1) {
-      suffixal.erase(iSpaceStart, 1);
-    }
-
-    if (suffixal.compare(L"0") != 0) {
-      strFieldName = strFieldNameParsed;
-      iControlNo = -1;
-      return;
-    }
-  }
-  strFieldName = strFieldNameParsed.substr(0, iStart);
-}
-
-bool Field::AttachField(Document* pDocument,
-                        const CFX_WideString& csFieldName) {
-  m_pJSDoc = pDocument;
-  m_pFormFillEnv.Reset(pDocument->GetFormFillEnv());
-  m_bCanSet = m_pFormFillEnv->GetPermissions(FPDFPERM_FILL_FORM) ||
-              m_pFormFillEnv->GetPermissions(FPDFPERM_ANNOT_FORM) ||
-              m_pFormFillEnv->GetPermissions(FPDFPERM_MODIFY);
-
-  CPDFSDK_InterForm* pRDInterForm = m_pFormFillEnv->GetInterForm();
-  CPDF_InterForm* pInterForm = pRDInterForm->GetInterForm();
-  CFX_WideString swFieldNameTemp = csFieldName;
-  swFieldNameTemp.Replace(L"..", L".");
-
-  if (pInterForm->CountFields(swFieldNameTemp) <= 0) {
-    std::wstring strFieldName;
-    int iControlNo = -1;
-    ParseFieldName(swFieldNameTemp.c_str(), strFieldName, iControlNo);
-    if (iControlNo == -1)
-      return false;
-
-    m_FieldName = strFieldName.c_str();
-    m_nFormControlIndex = iControlNo;
-    return true;
-  }
-
-  m_FieldName = swFieldNameTemp;
-  m_nFormControlIndex = -1;
-
-  return true;
-}
-
-std::vector<CPDF_FormField*> Field::GetFormFields(
-    CPDFSDK_FormFillEnvironment* pFormFillEnv,
-    const CFX_WideString& csFieldName) {
-  std::vector<CPDF_FormField*> fields;
-  CPDFSDK_InterForm* pReaderInterForm = pFormFillEnv->GetInterForm();
-  CPDF_InterForm* pInterForm = pReaderInterForm->GetInterForm();
-  for (int i = 0, sz = pInterForm->CountFields(csFieldName); i < sz; ++i) {
-    if (CPDF_FormField* pFormField = pInterForm->GetField(i, csFieldName))
-      fields.push_back(pFormField);
-  }
-  return fields;
-}
-
-std::vector<CPDF_FormField*> Field::GetFormFields(
-    const CFX_WideString& csFieldName) const {
-  return Field::GetFormFields(m_pFormFillEnv.Get(), csFieldName);
-}
-
-void Field::UpdateFormField(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                            CPDF_FormField* pFormField,
-                            bool bChangeMark,
-                            bool bResetAP,
-                            bool bRefresh) {
-  CPDFSDK_InterForm* pInterForm = pFormFillEnv->GetInterForm();
-
-  if (bResetAP) {
-    std::vector<CPDFSDK_Annot::ObservedPtr> widgets;
-    pInterForm->GetWidgets(pFormField, &widgets);
-
-    int nFieldType = pFormField->GetFieldType();
-    if (nFieldType == FIELDTYPE_COMBOBOX || nFieldType == FIELDTYPE_TEXTFIELD) {
-      for (auto& pObserved : widgets) {
-        if (pObserved) {
-          bool bFormatted = false;
-          CFX_WideString sValue = static_cast<CPDFSDK_Widget*>(pObserved.Get())
-                                      ->OnFormat(bFormatted);
-          if (pObserved) {  // Not redundant, may be clobbered by OnFormat.
-            static_cast<CPDFSDK_Widget*>(pObserved.Get())
-                ->ResetAppearance(bFormatted ? &sValue : nullptr, false);
-          }
-        }
-      }
-    } else {
-      for (auto& pObserved : widgets) {
-        if (pObserved) {
-          static_cast<CPDFSDK_Widget*>(pObserved.Get())
-              ->ResetAppearance(nullptr, false);
-        }
-      }
-    }
-  }
-
-  if (bRefresh) {
-    // Refresh the widget list. The calls in |bResetAP| may have caused widgets
-    // to be removed from the list. We need to call |GetWidgets| again to be
-    // sure none of the widgets have been deleted.
-    std::vector<CPDFSDK_Annot::ObservedPtr> widgets;
-    pInterForm->GetWidgets(pFormField, &widgets);
-
-    // TODO(dsinclair): Determine if all widgets share the same
-    // CPDFSDK_InterForm. If that's the case, we can move the code to
-    // |GetFormFillEnv| out of the loop.
-    for (auto& pObserved : widgets) {
-      if (pObserved) {
-        CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pObserved.Get());
-        pWidget->GetInterForm()->GetFormFillEnv()->UpdateAllViews(nullptr,
-                                                                  pWidget);
-      }
-    }
-  }
-
-  if (bChangeMark)
-    pFormFillEnv->SetChangeMark();
-}
-
-void Field::UpdateFormControl(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                              CPDF_FormControl* pFormControl,
-                              bool bChangeMark,
-                              bool bResetAP,
-                              bool bRefresh) {
-  ASSERT(pFormControl);
-
-  CPDFSDK_InterForm* pForm = pFormFillEnv->GetInterForm();
-  CPDFSDK_Widget* pWidget = pForm->GetWidget(pFormControl);
-
-  if (pWidget) {
-    if (bResetAP) {
-      int nFieldType = pWidget->GetFieldType();
-      if (nFieldType == FIELDTYPE_COMBOBOX ||
-          nFieldType == FIELDTYPE_TEXTFIELD) {
-        bool bFormatted = false;
-        CFX_WideString sValue = pWidget->OnFormat(bFormatted);
-        pWidget->ResetAppearance(bFormatted ? &sValue : nullptr, false);
-      } else {
-        pWidget->ResetAppearance(nullptr, false);
-      }
-    }
-
-    if (bRefresh) {
-      CPDFSDK_InterForm* pInterForm = pWidget->GetInterForm();
-      pInterForm->GetFormFillEnv()->UpdateAllViews(nullptr, pWidget);
-    }
-  }
-
-  if (bChangeMark)
-    pFormFillEnv->SetChangeMark();
-}
-
-CPDFSDK_Widget* Field::GetWidget(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                 CPDF_FormControl* pFormControl) {
-  CPDFSDK_InterForm* pInterForm =
-      static_cast<CPDFSDK_InterForm*>(pFormFillEnv->GetInterForm());
-  return pInterForm ? pInterForm->GetWidget(pFormControl) : nullptr;
-}
-
-bool Field::ValueIsOccur(CPDF_FormField* pFormField,
-                         CFX_WideString csOptLabel) {
-  for (int i = 0, sz = pFormField->CountOptions(); i < sz; i++) {
-    if (csOptLabel.Compare(pFormField->GetOptionLabel(i)) == 0)
-      return true;
-  }
-
-  return false;
-}
-
-CPDF_FormControl* Field::GetSmartFieldControl(CPDF_FormField* pFormField) {
-  if (!pFormField->CountControls() ||
-      m_nFormControlIndex >= pFormField->CountControls())
-    return nullptr;
-
-  if (m_nFormControlIndex < 0)
-    return pFormField->GetControl(0);
-
-  return pFormField->GetControl(m_nFormControlIndex);
-}
-
-bool Field::alignment(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    CFX_ByteString alignStr;
-    vp >> alignStr;
-
-    if (m_bDelay) {
-      AddDelay_String(FP_ALIGNMENT, alignStr);
-    } else {
-      Field::SetAlignment(m_pFormFillEnv.Get(), m_FieldName,
-                          m_nFormControlIndex, alignStr);
-    }
-  } 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;
-
-    CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-    if (!pFormControl)
-      return false;
-
-    switch (pFormControl->GetControlAlignment()) {
-      case 1:
-        vp << L"center";
-        break;
-      case 0:
-        vp << L"left";
-        break;
-      case 2:
-        vp << L"right";
-        break;
-      default:
-        vp << L"";
-    }
-  }
-
-  return true;
-}
-
-void Field::SetAlignment(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                         const CFX_WideString& swFieldName,
-                         int nControlIndex,
-                         const CFX_ByteString& string) {
-  // Not supported.
-}
-
-bool Field::borderStyle(CJS_Runtime* pRuntime,
-                        CJS_PropValue& vp,
-                        CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    CFX_ByteString strType = "";
-    vp >> strType;
-
-    if (m_bDelay) {
-      AddDelay_String(FP_BORDERSTYLE, strType);
-    } else {
-      Field::SetBorderStyle(m_pFormFillEnv.Get(), m_FieldName,
-                            m_nFormControlIndex, strType);
-    }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    if (!pFormField)
-      return false;
-
-    CPDFSDK_Widget* pWidget =
-        GetWidget(m_pFormFillEnv.Get(), GetSmartFieldControl(pFormField));
-    if (!pWidget)
-      return false;
-
-    switch (pWidget->GetBorderStyle()) {
-      case BorderStyle::SOLID:
-        vp << L"solid";
-        break;
-      case BorderStyle::DASH:
-        vp << L"dashed";
-        break;
-      case BorderStyle::BEVELED:
-        vp << L"beveled";
-        break;
-      case BorderStyle::INSET:
-        vp << L"inset";
-        break;
-      case BorderStyle::UNDERLINE:
-        vp << L"underline";
-        break;
-      default:
-        vp << L"";
-        break;
-    }
-  }
-
-  return true;
-}
-
-void Field::SetBorderStyle(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                           const CFX_WideString& swFieldName,
-                           int nControlIndex,
-                           const CFX_ByteString& string) {
-  ASSERT(pFormFillEnv);
-
-  BorderStyle nBorderStyle = BorderStyle::SOLID;
-  if (string == "solid")
-    nBorderStyle = BorderStyle::SOLID;
-  else if (string == "beveled")
-    nBorderStyle = BorderStyle::BEVELED;
-  else if (string == "dashed")
-    nBorderStyle = BorderStyle::DASH;
-  else if (string == "inset")
-    nBorderStyle = BorderStyle::INSET;
-  else if (string == "underline")
-    nBorderStyle = BorderStyle::UNDERLINE;
-  else
-    return;
-
-  std::vector<CPDF_FormField*> FieldArray =
-      GetFormFields(pFormFillEnv, swFieldName);
-  for (CPDF_FormField* pFormField : FieldArray) {
-    if (nControlIndex < 0) {
-      bool bSet = false;
-      for (int i = 0, sz = pFormField->CountControls(); i < sz; ++i) {
-        if (CPDFSDK_Widget* pWidget =
-                GetWidget(pFormFillEnv, pFormField->GetControl(i))) {
-          if (pWidget->GetBorderStyle() != nBorderStyle) {
-            pWidget->SetBorderStyle(nBorderStyle);
-            bSet = true;
-          }
-        }
-      }
-      if (bSet)
-        UpdateFormField(pFormFillEnv, pFormField, true, true, true);
-    } else {
-      if (nControlIndex >= pFormField->CountControls())
-        return;
-      if (CPDF_FormControl* pFormControl =
-              pFormField->GetControl(nControlIndex)) {
-        if (CPDFSDK_Widget* pWidget = GetWidget(pFormFillEnv, pFormControl)) {
-          if (pWidget->GetBorderStyle() != nBorderStyle) {
-            pWidget->SetBorderStyle(nBorderStyle);
-            UpdateFormControl(pFormFillEnv, pFormControl, true, true, true);
-          }
-        }
-      }
-    }
-  }
-}
-
-bool Field::buttonAlignX(CJS_Runtime* pRuntime,
-                         CJS_PropValue& vp,
-                         CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    int nVP;
-    vp >> nVP;
-
-    if (m_bDelay) {
-      AddDelay_Int(FP_BUTTONALIGNX, nVP);
-    } else {
-      Field::SetButtonAlignX(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];
-    if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON)
-      return false;
-
-    CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-    if (!pFormControl)
-      return false;
-
-    CPDF_IconFit IconFit = pFormControl->GetIconFit();
-
-    FX_FLOAT fLeft, fBottom;
-    IconFit.GetIconPosition(fLeft, fBottom);
-
-    vp << (int32_t)fLeft;
-  }
-
-  return true;
-}
-
-void Field::SetButtonAlignX(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                            const CFX_WideString& swFieldName,
-                            int nControlIndex,
-                            int number) {
-  // Not supported.
-}
-
-bool Field::buttonAlignY(CJS_Runtime* pRuntime,
-                         CJS_PropValue& vp,
-                         CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    int nVP;
-    vp >> nVP;
-
-    if (m_bDelay) {
-      AddDelay_Int(FP_BUTTONALIGNY, nVP);
-    } else {
-      Field::SetButtonAlignY(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];
-    if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON)
-      return false;
-
-    CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-    if (!pFormControl)
-      return false;
-
-    CPDF_IconFit IconFit = pFormControl->GetIconFit();
-
-    FX_FLOAT fLeft, fBottom;
-    IconFit.GetIconPosition(fLeft, fBottom);
-
-    vp << (int32_t)fBottom;
-  }
-
-  return true;
-}
-
-void Field::SetButtonAlignY(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                            const CFX_WideString& swFieldName,
-                            int nControlIndex,
-                            int number) {
-  // Not supported.
-}
-
-bool Field::buttonFitBounds(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_BUTTONFITBOUNDS, bVP);
-    } else {
-      Field::SetButtonFitBounds(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_PUSHBUTTON)
-      return false;
-
-    CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-    if (!pFormControl)
-      return false;
-
-    vp << pFormControl->GetIconFit().GetFittingBounds();
-  }
-
-  return true;
-}
-
-void Field::SetButtonFitBounds(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                               const CFX_WideString& swFieldName,
-                               int nControlIndex,
-                               bool b) {
-  // Not supported.
-}
-
-bool Field::buttonPosition(CJS_Runtime* pRuntime,
-                           CJS_PropValue& vp,
-                           CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    int nVP;
-    vp >> nVP;
-
-    if (m_bDelay) {
-      AddDelay_Int(FP_BUTTONPOSITION, nVP);
-    } else {
-      Field::SetButtonPosition(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];
-    if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON)
-      return false;
-
-    CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-    if (!pFormControl)
-      return false;
-
-    vp << pFormControl->GetTextPosition();
-  }
-  return true;
-}
-
-void Field::SetButtonPosition(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                              const CFX_WideString& swFieldName,
-                              int nControlIndex,
-                              int number) {
-  // Not supported.
-}
-
-bool Field::buttonScaleHow(CJS_Runtime* pRuntime,
-                           CJS_PropValue& vp,
-                           CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    int nVP;
-    vp >> nVP;
-
-    if (m_bDelay) {
-      AddDelay_Int(FP_BUTTONSCALEHOW, nVP);
-    } else {
-      Field::SetButtonScaleHow(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];
-    if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON)
-      return false;
-
-    CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-    if (!pFormControl)
-      return false;
-
-    CPDF_IconFit IconFit = pFormControl->GetIconFit();
-    if (IconFit.IsProportionalScale())
-      vp << (int32_t)0;
-    else
-      vp << (int32_t)1;
-  }
-
-  return true;
-}
-
-void Field::SetButtonScaleHow(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                              const CFX_WideString& swFieldName,
-                              int nControlIndex,
-                              int number) {
-  // Not supported.
-}
-
-bool Field::buttonScaleWhen(CJS_Runtime* pRuntime,
-                            CJS_PropValue& vp,
-                            CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    int nVP;
-    vp >> nVP;
-
-    if (m_bDelay) {
-      AddDelay_Int(FP_BUTTONSCALEWHEN, nVP);
-    } else {
-      Field::SetButtonScaleWhen(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];
-    if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON)
-      return false;
-
-    CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-    if (!pFormControl)
-      return false;
-
-    CPDF_IconFit IconFit = pFormControl->GetIconFit();
-    int ScaleM = IconFit.GetScaleMethod();
-    switch (ScaleM) {
-      case CPDF_IconFit::Always:
-        vp << (int32_t)CPDF_IconFit::Always;
-        break;
-      case CPDF_IconFit::Bigger:
-        vp << (int32_t)CPDF_IconFit::Bigger;
-        break;
-      case CPDF_IconFit::Never:
-        vp << (int32_t)CPDF_IconFit::Never;
-        break;
-      case CPDF_IconFit::Smaller:
-        vp << (int32_t)CPDF_IconFit::Smaller;
-        break;
-    }
-  }
-
-  return true;
-}
-
-void Field::SetButtonScaleWhen(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                               const CFX_WideString& swFieldName,
-                               int nControlIndex,
-                               int number) {
-  // Not supported.
-}
-
-bool Field::calcOrderIndex(CJS_Runtime* pRuntime,
-                           CJS_PropValue& vp,
-                           CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    int nVP;
-    vp >> nVP;
-
-    if (m_bDelay) {
-      AddDelay_Int(FP_CALCORDERINDEX, nVP);
-    } else {
-      Field::SetCalcOrderIndex(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];
-    if (pFormField->GetFieldType() != FIELDTYPE_COMBOBOX &&
-        pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD) {
-      return false;
-    }
-
-    CPDFSDK_InterForm* pRDInterForm = m_pFormFillEnv->GetInterForm();
-    CPDF_InterForm* pInterForm = pRDInterForm->GetInterForm();
-    vp << (int32_t)pInterForm->FindFieldInCalculationOrder(pFormField);
-  }
-
-  return true;
-}
-
-void Field::SetCalcOrderIndex(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                              const CFX_WideString& swFieldName,
-                              int nControlIndex,
-                              int number) {
-  // Not supported.
-}
-
-bool Field::charLimit(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    int nVP;
-    vp >> nVP;
-
-    if (m_bDelay) {
-      AddDelay_Int(FP_CHARLIMIT, nVP);
-    } else {
-      Field::SetCharLimit(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];
-    if (pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD)
-      return false;
-
-    vp << (int32_t)pFormField->GetMaxLen();
-  }
-  return true;
-}
-
-void Field::SetCharLimit(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                         const CFX_WideString& swFieldName,
-                         int nControlIndex,
-                         int number) {
-  // Not supported.
-}
-
-bool Field::comb(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_COMB, bVP);
-    } else {
-      Field::SetComb(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_COMB)
-      vp << true;
-    else
-      vp << false;
-  }
-
-  return true;
-}
-
-void Field::SetComb(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                    const CFX_WideString& swFieldName,
-                    int nControlIndex,
-                    bool b) {
-  // Not supported.
-}
-
-bool Field::commitOnSelChange(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_COMMITONSELCHANGE, bVP);
-    } else {
-      Field::SetCommitOnSelChange(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_COMBOBOX &&
-        pFormField->GetFieldType() != FIELDTYPE_LISTBOX) {
-      return false;
-    }
-
-    if (pFormField->GetFieldFlags() & FIELDFLAG_COMMITONSELCHANGE)
-      vp << true;
-    else
-      vp << false;
-  }
-
-  return true;
-}
-
-void Field::SetCommitOnSelChange(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                 const CFX_WideString& swFieldName,
-                                 int nControlIndex,
-                                 bool b) {
-  // Not supported.
-}
-
-bool Field::currentValueIndices(CJS_Runtime* pRuntime,
-                                CJS_PropValue& vp,
-                                CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    std::vector<uint32_t> array;
-    if (vp.GetJSValue()->GetType() == CJS_Value::VT_number) {
-      int iSelecting = 0;
-      vp >> iSelecting;
-      array.push_back(iSelecting);
-    } else if (vp.GetJSValue()->IsArrayObject()) {
-      CJS_Array SelArray;
-      CJS_Value SelValue(pRuntime);
-      int iSelecting;
-      vp >> SelArray;
-      for (int i = 0, sz = SelArray.GetLength(pRuntime); i < sz; i++) {
-        SelArray.GetElement(pRuntime, i, SelValue);
-        iSelecting = SelValue.ToInt(pRuntime);
-        array.push_back(iSelecting);
-      }
-    }
-
-    if (m_bDelay) {
-      AddDelay_WordArray(FP_CURRENTVALUEINDICES, array);
-    } else {
-      Field::SetCurrentValueIndices(m_pFormFillEnv.Get(), m_FieldName,
-                                    m_nFormControlIndex, array);
-    }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    if (pFormField->GetFieldType() != FIELDTYPE_COMBOBOX &&
-        pFormField->GetFieldType() != FIELDTYPE_LISTBOX) {
-      return false;
-    }
-
-    if (pFormField->CountSelectedItems() == 1) {
-      vp << pFormField->GetSelectedIndex(0);
-    } else if (pFormField->CountSelectedItems() > 1) {
-      CJS_Array SelArray;
-      for (int i = 0, sz = pFormField->CountSelectedItems(); i < sz; i++) {
-        SelArray.SetElement(
-            pRuntime, i, CJS_Value(pRuntime, pFormField->GetSelectedIndex(i)));
-      }
-      vp << SelArray;
-    } else {
-      vp << -1;
-    }
-  }
-
-  return true;
-}
-
-void Field::SetCurrentValueIndices(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                   const CFX_WideString& swFieldName,
-                                   int nControlIndex,
-                                   const std::vector<uint32_t>& array) {
-  ASSERT(pFormFillEnv);
-  std::vector<CPDF_FormField*> FieldArray =
-      GetFormFields(pFormFillEnv, swFieldName);
-
-  for (CPDF_FormField* pFormField : FieldArray) {
-    int nFieldType = pFormField->GetFieldType();
-    if (nFieldType == FIELDTYPE_COMBOBOX || nFieldType == FIELDTYPE_LISTBOX) {
-      uint32_t dwFieldFlags = pFormField->GetFieldFlags();
-      pFormField->ClearSelection(true);
-      for (size_t i = 0; i < array.size(); ++i) {
-        if (i != 0 && !(dwFieldFlags & (1 << 21)))
-          break;
-        if (array[i] < static_cast<uint32_t>(pFormField->CountOptions()) &&
-            !pFormField->IsItemSelected(array[i])) {
-          pFormField->SetItemSelection(array[i], true);
-        }
-      }
-      UpdateFormField(pFormFillEnv, pFormField, true, true, true);
-    }
-  }
-}
-
-bool Field::defaultStyle(CJS_Runtime* pRuntime,
-                         CJS_PropValue& vp,
-                         CFX_WideString& sError) {
-  return false;
-}
-
-void Field::SetDefaultStyle(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                            const CFX_WideString& swFieldName,
-                            int nControlIndex) {
-  // Not supported.
-}
-
-bool Field::defaultValue(CJS_Runtime* pRuntime,
-                         CJS_PropValue& vp,
-                         CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    CFX_WideString WideStr;
-    vp >> WideStr;
-
-    if (m_bDelay) {
-      AddDelay_WideString(FP_DEFAULTVALUE, WideStr);
-    } else {
-      Field::SetDefaultValue(m_pFormFillEnv.Get(), m_FieldName,
-                             m_nFormControlIndex, WideStr);
-    }
-  } else {
-    std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-    if (FieldArray.empty())
-      return false;
-
-    CPDF_FormField* pFormField = FieldArray[0];
-    if (pFormField->GetFieldType() == FIELDTYPE_PUSHBUTTON ||
-        pFormField->GetFieldType() == FIELDTYPE_SIGNATURE) {
-      return false;
-    }
-
-    vp << pFormField->GetDefaultValue();
-  }
-  return true;
-}
-
-void Field::SetDefaultValue(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                            const CFX_WideString& swFieldName,
-                            int nControlIndex,
-                            const CFX_WideString& string) {
-  // Not supported.
-}
-
-bool Field::doNotScroll(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_DONOTSCROLL, bVP);
-    } else {
-      Field::SetDoNotScroll(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_DONOTSCROLL)
-      vp << true;
-    else
-      vp << false;
-  }
-
-  return true;
-}
-
-void Field::SetDoNotScroll(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                           const CFX_WideString& swFieldName,
-                           int nControlIndex,
-                           bool b) {
-  // Not supported.
-}
-
-bool Field::doNotSpellCheck(CJS_Runtime* pRuntime,
-                            CJS_PropValue& vp,
-                            CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    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_TEXTFIELD &&
-        pFormField->GetFieldType() != FIELDTYPE_COMBOBOX) {
-      return false;
-    }
-
-    if (pFormField->GetFieldFlags() & FIELDFLAG_DONOTSPELLCHECK)
-      vp << true;
-    else
-      vp << false;
-  }
-
-  return true;
-}
-
-void Field::SetDelay(bool bDelay) {
-  m_bDelay = bDelay;
-
-  if (!m_bDelay) {
-    if (m_pJSDoc)
-      m_pJSDoc->DoFieldDelay(m_FieldName, m_nFormControlIndex);
-  }
-}
-
-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(CJS_Runtime* pRuntime,
-                    CJS_PropValue& vp,
-                    CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    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 {
-    if (ANNOTFLAG_PRINT & dwFlag) {
-      if (ANNOTFLAG_NOVIEW & dwFlag) {
-        vp << (int32_t)3;
-      } else {
-        vp << (int32_t)0;
-      }
-    } else {
-      vp << (int32_t)2;
-    }
-  }
-  return true;
-}
-
-void Field::SetDisplay(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                       const CFX_WideString& swFieldName,
-                       int nControlIndex,
-                       int number) {
-  CPDFSDK_InterForm* pInterForm = pFormFillEnv->GetInterForm();
-  std::vector<CPDF_FormField*> FieldArray =
-      GetFormFields(pFormFillEnv, swFieldName);
-  for (CPDF_FormField* pFormField : FieldArray) {
-    if (nControlIndex < 0) {
-      bool bAnySet = false;
-      for (int i = 0, sz = pFormField->CountControls(); i < sz; ++i) {
-        CPDF_FormControl* pFormControl = pFormField->GetControl(i);
-        ASSERT(pFormControl);
-
-        CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormControl);
-        if (SetWidgetDisplayStatus(pWidget, number))
-          bAnySet = true;
-      }
-
-      if (bAnySet)
-        UpdateFormField(pFormFillEnv, pFormField, true, false, true);
-    } else {
-      if (nControlIndex >= pFormField->CountControls())
-        return;
-
-      CPDF_FormControl* pFormControl = pFormField->GetControl(nControlIndex);
-      if (!pFormControl)
-        return;
-
-      CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormControl);
-      if (SetWidgetDisplayStatus(pWidget, number))
-        UpdateFormControl(pFormFillEnv, pFormControl, true, false, true);
-    }
-  }
-}
-
-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(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    bool bVP;
-    vp >> bVP;
-    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(CJS_Runtime* pRuntime,
-                         CJS_PropValue& vp,
-                         CFX_WideString& sError) {
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  CPDF_FormField* pFormField = FieldArray[0];
-  if (pFormField->GetFieldType() != FIELDTYPE_CHECKBOX &&
-      pFormField->GetFieldType() != FIELDTYPE_RADIOBUTTON) {
-    return false;
-  }
-  if (vp.IsSetting())
-    return m_bCanSet && vp.GetJSValue()->IsArrayObject();
-
-  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;
-
-    ExportValusArray.SetElement(
-        pRuntime, 0,
-        CJS_Value(pRuntime, pFormControl->GetExportValue().c_str()));
-  }
-  vp << ExportValusArray;
-  return true;
-}
-
-bool Field::fileSelect(CJS_Runtime* pRuntime,
-                       CJS_PropValue& vp,
-                       CFX_WideString& sError) {
-  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 (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    bool bVP;
-    vp >> bVP;
-    return true;
-  }
-  vp << !!(pFormField->GetFieldFlags() & FIELDFLAG_FILESELECT);
-  return true;
-}
-
-bool Field::fillColor(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError) {
-  CJS_Array crArray;
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    if (!vp.GetJSValue()->IsArrayObject())
-      return false;
-
-    vp >> crArray;
-
-    CPWL_Color color;
-    color::ConvertArrayToPWLColor(pRuntime, crArray, &color);
-    if (m_bDelay) {
-      AddDelay_Color(FP_FILLCOLOR, color);
-    } else {
-      Field::SetFillColor(m_pFormFillEnv.Get(), m_FieldName,
-                          m_nFormControlIndex, color);
-    }
-    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;
-}
-
-void Field::SetFillColor(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                         const CFX_WideString& swFieldName,
-                         int nControlIndex,
-                         const CPWL_Color& color) {
-  // Not supported.
-}
-
-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);
-    }
-    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;
-}
-
-void Field::SetHidden(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                      const CFX_WideString& swFieldName,
-                      int nControlIndex,
-                      bool b) {
-  int display = b ? 1 /*Hidden*/ : 0 /*Visible*/;
-  SetDisplay(pFormFillEnv, swFieldName, nControlIndex, display);
-}
-
-bool Field::highlight(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    CFX_ByteString strMode;
-    vp >> strMode;
-
-    if (m_bDelay) {
-      AddDelay_String(FP_HIGHLIGHT, strMode);
-    } else {
-      Field::SetHighlight(m_pFormFillEnv.Get(), m_FieldName,
-                          m_nFormControlIndex, strMode);
-    }
-    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;
-}
-
-void Field::SetHighlight(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                         const CFX_WideString& swFieldName,
-                         int nControlIndex,
-                         const CFX_ByteString& string) {
-  // Not supported.
-}
-
-bool Field::lineWidth(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    int iWidth;
-    vp >> iWidth;
-
-    if (m_bDelay) {
-      AddDelay_Int(FP_LINEWIDTH, iWidth);
-    } else {
-      Field::SetLineWidth(m_pFormFillEnv.Get(), m_FieldName,
-                          m_nFormControlIndex, iWidth);
-    }
-    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;
-}
-
-void Field::SetLineWidth(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                         const CFX_WideString& swFieldName,
-                         int nControlIndex,
-                         int number) {
-  CPDFSDK_InterForm* pInterForm = pFormFillEnv->GetInterForm();
-  std::vector<CPDF_FormField*> FieldArray =
-      GetFormFields(pFormFillEnv, swFieldName);
-  for (CPDF_FormField* pFormField : FieldArray) {
-    if (nControlIndex < 0) {
-      bool bSet = false;
-      for (int i = 0, sz = pFormField->CountControls(); i < sz; ++i) {
-        CPDF_FormControl* pFormControl = pFormField->GetControl(i);
-        ASSERT(pFormControl);
-
-        if (CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormControl)) {
-          if (number != pWidget->GetBorderWidth()) {
-            pWidget->SetBorderWidth(number);
-            bSet = true;
-          }
-        }
-      }
-      if (bSet)
-        UpdateFormField(pFormFillEnv, pFormField, true, true, true);
-    } else {
-      if (nControlIndex >= pFormField->CountControls())
-        return;
-      if (CPDF_FormControl* pFormControl =
-              pFormField->GetControl(nControlIndex)) {
-        if (CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormControl)) {
-          if (number != pWidget->GetBorderWidth()) {
-            pWidget->SetBorderWidth(number);
-            UpdateFormControl(pFormFillEnv, pFormControl, true, true, true);
-          }
-        }
-      }
-    }
-  }
-}
-
-bool Field::multiline(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_MULTILINE, bVP);
-    } else {
-      Field::SetMultiline(m_pFormFillEnv.Get(), m_FieldName,
-                          m_nFormControlIndex, bVP);
-    }
-    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;
-}
-
-void Field::SetMultiline(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                         const CFX_WideString& swFieldName,
-                         int nControlIndex,
-                         bool b) {
-  // Not supported.
-}
-
-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);
-    }
-    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;
-}
-
-void Field::SetMultipleSelection(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                 const CFX_WideString& swFieldName,
-                                 int nControlIndex,
-                                 bool b) {
-  // Not supported.
-}
-
-bool Field::name(CJS_Runtime* pRuntime,
-                 CJS_PropValue& vp,
-                 CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  vp << m_FieldName;
-  return true;
-}
-
-bool Field::numItems(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  CPDF_FormField* pFormField = FieldArray[0];
-  if (pFormField->GetFieldType() != FIELDTYPE_COMBOBOX &&
-      pFormField->GetFieldType() != FIELDTYPE_LISTBOX) {
-    return false;
-  }
-
-  vp << (int32_t)pFormField->CountOptions();
-  return true;
-}
-
-bool Field::page(CJS_Runtime* pRuntime,
-                 CJS_PropValue& vp,
-                 CFX_WideString& sError) {
-  if (!vp.IsGetting()) {
-    sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
-    return false;
-  }
-
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  CPDF_FormField* pFormField = FieldArray[0];
-  if (!pFormField)
-    return false;
-
-  std::vector<CPDFSDK_Annot::ObservedPtr> widgets;
-  m_pFormFillEnv->GetInterForm()->GetWidgets(pFormField, &widgets);
-  if (widgets.empty()) {
-    vp << (int32_t)-1;
-    return true;
-  }
-
-  CJS_Array PageArray;
-  int i = 0;
-  for (const auto& pObserved : widgets) {
-    if (!pObserved) {
-      sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
-      return false;
-    }
-
-    auto pWidget = static_cast<CPDFSDK_Widget*>(pObserved.Get());
-    CPDFSDK_PageView* pPageView = pWidget->GetPageView();
-    if (!pPageView)
-      return false;
-
-    PageArray.SetElement(
-        pRuntime, i, CJS_Value(pRuntime, (int32_t)pPageView->GetPageIndex()));
-    ++i;
-  }
-
-  vp << PageArray;
-  return true;
-}
-
-bool Field::password(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_PASSWORD, bVP);
-    } else {
-      Field::SetPassword(m_pFormFillEnv.Get(), m_FieldName, m_nFormControlIndex,
-                         bVP);
-    }
-    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;
-}
-
-void Field::SetPassword(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                        const CFX_WideString& swFieldName,
-                        int nControlIndex,
-                        bool b) {
-  // Not supported.
-}
-
-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())
-    return false;
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    bool bVP;
-    vp >> bVP;
-
-    for (CPDF_FormField* pFormField : FieldArray) {
-      if (m_nFormControlIndex < 0) {
-        bool bSet = false;
-        for (int i = 0, sz = pFormField->CountControls(); i < sz; ++i) {
-          if (CPDFSDK_Widget* pWidget =
-                  pInterForm->GetWidget(pFormField->GetControl(i))) {
-            uint32_t dwFlags = pWidget->GetFlags();
-            if (bVP)
-              dwFlags |= ANNOTFLAG_PRINT;
-            else
-              dwFlags &= ~ANNOTFLAG_PRINT;
-
-            if (dwFlags != pWidget->GetFlags()) {
-              pWidget->SetFlags(dwFlags);
-              bSet = true;
-            }
-          }
-        }
-
-        if (bSet)
-          UpdateFormField(m_pFormFillEnv.Get(), pFormField, true, false, true);
-      } else {
-        if (m_nFormControlIndex >= pFormField->CountControls())
-          return false;
-        if (CPDF_FormControl* pFormControl =
-                pFormField->GetControl(m_nFormControlIndex)) {
-          if (CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormControl)) {
-            uint32_t dwFlags = pWidget->GetFlags();
-            if (bVP)
-              dwFlags |= ANNOTFLAG_PRINT;
-            else
-              dwFlags &= ~ANNOTFLAG_PRINT;
-
-            if (dwFlags != pWidget->GetFlags()) {
-              pWidget->SetFlags(dwFlags);
-              UpdateFormControl(m_pFormFillEnv.Get(),
-                                pFormField->GetControl(m_nFormControlIndex),
-                                true, false, true);
-            }
-          }
-        }
-      }
-    }
-    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(CJS_Runtime* pRuntime,
-                           CJS_PropValue& vp,
-                           CFX_WideString& sError) {
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    bool bVP;
-    vp >> bVP;
-    return true;
-  }
-  CPDF_FormField* pFormField = FieldArray[0];
-  if (pFormField->GetFieldType() != FIELDTYPE_RADIOBUTTON)
-    return false;
-
-  vp << !!(pFormField->GetFieldFlags() & FIELDFLAG_RADIOSINUNISON);
-  return true;
-}
-
-bool Field::readonly(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    bool bVP;
-    vp >> bVP;
-    return true;
-  }
-  vp << !!(FieldArray[0]->GetFieldFlags() & FIELDFLAG_READONLY);
-  return true;
-}
-
-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);
-  CJS_Value Lower_Righty(pRuntime);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-    if (!vp.GetJSValue()->IsArrayObject())
-      return false;
-
-    CJS_Array rcArray;
-    vp >> rcArray;
-    rcArray.GetElement(pRuntime, 0, Upper_Leftx);
-    rcArray.GetElement(pRuntime, 1, Upper_Lefty);
-    rcArray.GetElement(pRuntime, 2, Lower_Rightx);
-    rcArray.GetElement(pRuntime, 3, Lower_Righty);
-
-    FX_FLOAT pArray[4] = {0.0f, 0.0f, 0.0f, 0.0f};
-    pArray[0] = static_cast<FX_FLOAT>(Upper_Leftx.ToInt(pRuntime));
-    pArray[1] = static_cast<FX_FLOAT>(Lower_Righty.ToInt(pRuntime));
-    pArray[2] = static_cast<FX_FLOAT>(Lower_Rightx.ToInt(pRuntime));
-    pArray[3] = static_cast<FX_FLOAT>(Upper_Lefty.ToInt(pRuntime));
-
-    CFX_FloatRect crRect(pArray);
-    if (m_bDelay) {
-      AddDelay_Rect(FP_RECT, crRect);
-    } else {
-      Field::SetRect(m_pFormFillEnv.Get(), m_FieldName, m_nFormControlIndex,
-                     crRect);
-    }
-    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;
-}
-
-void Field::SetRect(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                    const CFX_WideString& swFieldName,
-                    int nControlIndex,
-                    const CFX_FloatRect& rect) {
-  CPDFSDK_InterForm* pInterForm = pFormFillEnv->GetInterForm();
-  std::vector<CPDF_FormField*> FieldArray =
-      GetFormFields(pFormFillEnv, swFieldName);
-  for (CPDF_FormField* pFormField : FieldArray) {
-    if (nControlIndex < 0) {
-      bool bSet = false;
-      for (int i = 0, sz = pFormField->CountControls(); i < sz; ++i) {
-        CPDF_FormControl* pFormControl = pFormField->GetControl(i);
-        ASSERT(pFormControl);
-
-        if (CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormControl)) {
-          CFX_FloatRect crRect = rect;
-
-          CPDF_Page* pPDFPage = pWidget->GetPDFPage();
-          crRect.Intersect(pPDFPage->GetPageBBox());
-
-          if (!crRect.IsEmpty()) {
-            CFX_FloatRect rcOld = pWidget->GetRect();
-            if (crRect.left != rcOld.left || crRect.right != rcOld.right ||
-                crRect.top != rcOld.top || crRect.bottom != rcOld.bottom) {
-              pWidget->SetRect(crRect);
-              bSet = true;
-            }
-          }
-        }
-      }
-
-      if (bSet)
-        UpdateFormField(pFormFillEnv, pFormField, true, true, true);
-    } else {
-      if (nControlIndex >= pFormField->CountControls())
-        return;
-      if (CPDF_FormControl* pFormControl =
-              pFormField->GetControl(nControlIndex)) {
-        if (CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormControl)) {
-          CFX_FloatRect crRect = rect;
-
-          CPDF_Page* pPDFPage = pWidget->GetPDFPage();
-          crRect.Intersect(pPDFPage->GetPageBBox());
-
-          if (!crRect.IsEmpty()) {
-            CFX_FloatRect rcOld = pWidget->GetRect();
-            if (crRect.left != rcOld.left || crRect.right != rcOld.right ||
-                crRect.top != rcOld.top || crRect.bottom != rcOld.bottom) {
-              pWidget->SetRect(crRect);
-              UpdateFormControl(pFormFillEnv, pFormControl, true, true, true);
-            }
-          }
-        }
-      }
-    }
-  }
-}
-
-bool Field::required(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    bool bVP;
-    vp >> bVP;
-    return true;
-  }
-  CPDF_FormField* pFormField = FieldArray[0];
-  if (pFormField->GetFieldType() == FIELDTYPE_PUSHBUTTON)
-    return false;
-
-  vp << !!(pFormField->GetFieldFlags() & FIELDFLAG_REQUIRED);
-  return true;
-}
-
-bool Field::richText(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_RICHTEXT, bVP);
-
-    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(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError) {
-  return true;
-}
-
-bool Field::rotation(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    int nVP;
-    vp >> nVP;
-    if (m_bDelay) {
-      AddDelay_Int(FP_ROTATION, nVP);
-    } else {
-      Field::SetRotation(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];
-  CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-  if (!pFormControl)
-    return false;
-
-  vp << (int32_t)pFormControl->GetRotation();
-  return true;
-}
-
-void Field::SetRotation(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                        const CFX_WideString& swFieldName,
-                        int nControlIndex,
-                        int number) {
-  // Not supported.
-}
-
-bool Field::strokeColor(CJS_Runtime* pRuntime,
-                        CJS_PropValue& vp,
-                        CFX_WideString& sError) {
-  CJS_Array crArray;
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    if (!vp.GetJSValue()->IsArrayObject())
-      return false;
-
-    vp >> crArray;
-
-    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);
-    }
-    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;
-}
-
-void Field::SetStrokeColor(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                           const CFX_WideString& swFieldName,
-                           int nControlIndex,
-                           const CPWL_Color& color) {
-  // Not supported.
-}
-
-bool Field::style(CJS_Runtime* pRuntime,
-                  CJS_PropValue& vp,
-                  CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    CFX_ByteString csBCaption;
-    vp >> csBCaption;
-
-    if (m_bDelay) {
-      AddDelay_String(FP_STYLE, csBCaption);
-    } else {
-      Field::SetStyle(m_pFormFillEnv.Get(), m_FieldName, m_nFormControlIndex,
-                      csBCaption);
-    }
-    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;
-  return true;
-}
-
-void Field::SetStyle(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                     const CFX_WideString& swFieldName,
-                     int nControlIndex,
-                     const CFX_ByteString& string) {
-  // Not supported.
-}
-
-bool Field::submitName(CJS_Runtime* pRuntime,
-                       CJS_PropValue& vp,
-                       CFX_WideString& sError) {
-  return true;
-}
-
-bool Field::textColor(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError) {
-  CJS_Array crArray;
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    if (!vp.GetJSValue()->IsArrayObject())
-      return false;
-
-    vp >> crArray;
-
-    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);
-    }
-    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;
-}
-
-void Field::SetTextColor(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                         const CFX_WideString& swFieldName,
-                         int nControlIndex,
-                         const CPWL_Color& color) {
-  // Not supported.
-}
-
-bool Field::textFont(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    CFX_ByteString csFontName;
-    vp >> csFontName;
-    if (csFontName.IsEmpty())
-      return false;
-
-    if (m_bDelay) {
-      AddDelay_String(FP_TEXTFONT, csFontName);
-    } else {
-      Field::SetTextFont(m_pFormFillEnv.Get(), m_FieldName, m_nFormControlIndex,
-                         csFontName);
-    }
-    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;
-}
-
-void Field::SetTextFont(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                        const CFX_WideString& swFieldName,
-                        int nControlIndex,
-                        const CFX_ByteString& string) {
-  // Not supported.
-}
-
-bool Field::textSize(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    int nVP;
-    vp >> nVP;
-    if (m_bDelay) {
-      AddDelay_Int(FP_TEXTSIZE, nVP);
-    } else {
-      Field::SetTextSize(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);
-  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;
-}
-
-void Field::SetTextSize(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                        const CFX_WideString& swFieldName,
-                        int nControlIndex,
-                        int number) {
-  // Not supported.
-}
-
-bool Field::type(CJS_Runtime* pRuntime,
-                 CJS_PropValue& vp,
-                 CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  CPDF_FormField* pFormField = FieldArray[0];
-  switch (pFormField->GetFieldType()) {
-    case FIELDTYPE_UNKNOWN:
-      vp << L"unknown";
-      break;
-    case FIELDTYPE_PUSHBUTTON:
-      vp << L"button";
-      break;
-    case FIELDTYPE_CHECKBOX:
-      vp << L"checkbox";
-      break;
-    case FIELDTYPE_RADIOBUTTON:
-      vp << L"radiobutton";
-      break;
-    case FIELDTYPE_COMBOBOX:
-      vp << L"combobox";
-      break;
-    case FIELDTYPE_LISTBOX:
-      vp << L"listbox";
-      break;
-    case FIELDTYPE_TEXTFIELD:
-      vp << L"text";
-      break;
-    case FIELDTYPE_SIGNATURE:
-      vp << L"signature";
-      break;
-    default:
-      vp << L"unknown";
-      break;
-  }
-  return true;
-}
-
-bool Field::userName(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  ASSERT(m_pFormFillEnv);
-
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    CFX_WideString swName;
-    vp >> swName;
-
-    if (m_bDelay) {
-      AddDelay_WideString(FP_USERNAME, swName);
-    } else {
-      Field::SetUserName(m_pFormFillEnv.Get(), m_FieldName, m_nFormControlIndex,
-                         swName);
-    }
-    return true;
-  }
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  vp << FieldArray[0]->GetAlternateName();
-  return true;
-}
-
-void Field::SetUserName(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                        const CFX_WideString& swFieldName,
-                        int nControlIndex,
-                        const CFX_WideString& string) {
-  // Not supported.
-}
-
-bool Field::value(CJS_Runtime* pRuntime,
-                  CJS_PropValue& vp,
-                  CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    if (!m_bCanSet)
-      return false;
-
-    std::vector<CFX_WideString> strArray;
-    if (vp.GetJSValue()->IsArrayObject()) {
-      CJS_Array ValueArray;
-      vp.GetJSValue()->ConvertToArray(pRuntime, ValueArray);
-      for (int i = 0, sz = ValueArray.GetLength(pRuntime); i < sz; i++) {
-        CJS_Value ElementValue(pRuntime);
-        ValueArray.GetElement(pRuntime, i, ElementValue);
-        strArray.push_back(ElementValue.ToCFXWideString(pRuntime));
-      }
-    } else {
-      CFX_WideString swValue;
-      vp >> swValue;
-      strArray.push_back(swValue);
-    }
-
-    if (m_bDelay) {
-      AddDelay_WideStringArray(FP_VALUE, strArray);
-    } else {
-      Field::SetValue(m_pFormFillEnv.Get(), m_FieldName, m_nFormControlIndex,
-                      strArray);
-    }
-    return true;
-  }
-
-  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->GetOptionLabel(iIndex).c_str());
-          }
-          ValueArray.SetElement(pRuntime, i, ElementValue);
-        }
-        vp << ValueArray;
-      } else {
-        vp << pFormField->GetValue();
-      }
-    } 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;
-}
-
-void Field::SetValue(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                     const CFX_WideString& swFieldName,
-                     int nControlIndex,
-                     const std::vector<CFX_WideString>& strArray) {
-  ASSERT(pFormFillEnv);
-  if (strArray.empty())
-    return;
-
-  std::vector<CPDF_FormField*> FieldArray =
-      GetFormFields(pFormFillEnv, swFieldName);
-
-  for (CPDF_FormField* pFormField : FieldArray) {
-    if (pFormField->GetFullName().Compare(swFieldName) != 0)
-      continue;
-
-    switch (pFormField->GetFieldType()) {
-      case FIELDTYPE_TEXTFIELD:
-      case FIELDTYPE_COMBOBOX:
-        if (pFormField->GetValue() != strArray[0]) {
-          pFormField->SetValue(strArray[0], true);
-          UpdateFormField(pFormFillEnv, pFormField, true, false, true);
-        }
-        break;
-      case FIELDTYPE_CHECKBOX:
-      case FIELDTYPE_RADIOBUTTON: {
-        if (pFormField->GetValue() != strArray[0]) {
-          pFormField->SetValue(strArray[0], true);
-          UpdateFormField(pFormFillEnv, pFormField, true, false, true);
-        }
-      } break;
-      case FIELDTYPE_LISTBOX: {
-        bool bModified = false;
-        for (const auto& str : strArray) {
-          if (!pFormField->IsItemSelected(pFormField->FindOption(str))) {
-            bModified = true;
-            break;
-          }
-        }
-        if (bModified) {
-          pFormField->ClearSelection(true);
-          for (const auto& str : strArray) {
-            int index = pFormField->FindOption(str);
-            if (!pFormField->IsItemSelected(index))
-              pFormField->SetItemSelection(index, true, true);
-          }
-          UpdateFormField(pFormFillEnv, pFormField, true, false, true);
-        }
-      } break;
-      default:
-        break;
-    }
-  }
-}
-
-bool Field::valueAsString(CJS_Runtime* pRuntime,
-                          CJS_PropValue& vp,
-                          CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  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;
-
-  if (pFormField->GetFieldType() == FIELDTYPE_CHECKBOX) {
-    if (!pFormField->CountControls())
-      return false;
-
-    if (pFormField->GetControl(0)->IsChecked())
-      vp << L"Yes";
-    else
-      vp << L"Off";
-  } else if (pFormField->GetFieldType() == FIELDTYPE_RADIOBUTTON &&
-             !(pFormField->GetFieldFlags() & FIELDFLAG_RADIOSINUNISON)) {
-    for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
-      if (pFormField->GetControl(i)->IsChecked()) {
-        vp << pFormField->GetControl(i)->GetExportValue().c_str();
-        break;
-      } else {
-        vp << L"Off";
-      }
-    }
-  } else if (pFormField->GetFieldType() == FIELDTYPE_LISTBOX &&
-             (pFormField->CountSelectedItems() > 1)) {
-    vp << L"";
-  } else {
-    vp << pFormField->GetValue().c_str();
-  }
-
-  return true;
-}
-
-bool Field::browseForFileToSubmit(CJS_Runtime* pRuntime,
-                                  const std::vector<CJS_Value>& params,
-                                  CJS_Value& vRet,
-                                  CFX_WideString& sError) {
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  CPDF_FormField* pFormField = FieldArray[0];
-  if ((pFormField->GetFieldFlags() & FIELDFLAG_FILESELECT) &&
-      (pFormField->GetFieldType() == FIELDTYPE_TEXTFIELD)) {
-    CFX_WideString wsFileName = m_pFormFillEnv->JS_fieldBrowse();
-    if (!wsFileName.IsEmpty()) {
-      pFormField->SetValue(wsFileName);
-      UpdateFormField(m_pFormFillEnv.Get(), pFormField, true, true, true);
-    }
-    return true;
-  }
-  return false;
-}
-
-bool Field::buttonGetCaption(CJS_Runtime* pRuntime,
-                             const std::vector<CJS_Value>& params,
-                             CJS_Value& vRet,
-                             CFX_WideString& sError) {
-  int nface = 0;
-  int iSize = params.size();
-  if (iSize >= 1)
-    nface = params[0].ToInt(pRuntime);
-
-  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;
-
-  if (nface == 0)
-    vRet = CJS_Value(pRuntime, pFormControl->GetNormalCaption().c_str());
-  else if (nface == 1)
-    vRet = CJS_Value(pRuntime, pFormControl->GetDownCaption().c_str());
-  else if (nface == 2)
-    vRet = CJS_Value(pRuntime, pFormControl->GetRolloverCaption().c_str());
-  else
-    return false;
-
-  return true;
-}
-
-bool Field::buttonGetIcon(CJS_Runtime* pRuntime,
-                          const std::vector<CJS_Value>& params,
-                          CJS_Value& vRet,
-                          CFX_WideString& sError) {
-  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())
-    return false;
-
-  CPDF_FormField* pFormField = FieldArray[0];
-  if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON)
-    return false;
-
-  CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField);
-  if (!pFormControl)
-    return false;
-
-  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));
-  vRet = CJS_Value(pRuntime, pJS_Icon);
-  return true;
-}
-
-bool Field::buttonImportIcon(CJS_Runtime* pRuntime,
-                             const std::vector<CJS_Value>& params,
-                             CJS_Value& vRet,
-                             CFX_WideString& sError) {
-  return true;
-}
-
-bool Field::buttonSetCaption(CJS_Runtime* pRuntime,
-                             const std::vector<CJS_Value>& params,
-                             CJS_Value& vRet,
-                             CFX_WideString& sError) {
-  return false;
-}
-
-bool Field::buttonSetIcon(CJS_Runtime* pRuntime,
-                          const std::vector<CJS_Value>& params,
-                          CJS_Value& vRet,
-                          CFX_WideString& sError) {
-  return false;
-}
-
-bool Field::checkThisBox(CJS_Runtime* pRuntime,
-                         const std::vector<CJS_Value>& params,
-                         CJS_Value& vRet,
-                         CFX_WideString& sError) {
-  int iSize = params.size();
-  if (iSize < 1)
-    return false;
-
-  if (!m_bCanSet)
-    return false;
-
-  int nWidget = params[0].ToInt(pRuntime);
-  bool bCheckit = true;
-  if (iSize >= 2)
-    bCheckit = params[1].ToBool(pRuntime);
-
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  CPDF_FormField* pFormField = FieldArray[0];
-  if (pFormField->GetFieldType() != FIELDTYPE_CHECKBOX &&
-      pFormField->GetFieldType() != FIELDTYPE_RADIOBUTTON)
-    return false;
-  if (nWidget < 0 || nWidget >= pFormField->CountControls())
-    return false;
-  // TODO(weili): Check whether anything special needed for radio button,
-  // otherwise merge these branches.
-  if (pFormField->GetFieldType() == FIELDTYPE_RADIOBUTTON)
-    pFormField->CheckControl(nWidget, bCheckit, true);
-  else
-    pFormField->CheckControl(nWidget, bCheckit, true);
-
-  UpdateFormField(m_pFormFillEnv.Get(), pFormField, true, true, true);
-  return true;
-}
-
-bool Field::clearItems(CJS_Runtime* pRuntime,
-                       const std::vector<CJS_Value>& params,
-                       CJS_Value& vRet,
-                       CFX_WideString& sError) {
-  return true;
-}
-
-bool Field::defaultIsChecked(CJS_Runtime* pRuntime,
-                             const std::vector<CJS_Value>& params,
-                             CJS_Value& vRet,
-                             CFX_WideString& sError) {
-  if (!m_bCanSet)
-    return false;
-
-  int iSize = params.size();
-  if (iSize < 1)
-    return false;
-
-  int nWidget = params[0].ToInt(pRuntime);
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  CPDF_FormField* pFormField = FieldArray[0];
-  if (nWidget < 0 || nWidget >= pFormField->CountControls())
-    return false;
-
-  vRet = CJS_Value(pRuntime,
-                   pFormField->GetFieldType() == FIELDTYPE_CHECKBOX ||
-                       pFormField->GetFieldType() == FIELDTYPE_RADIOBUTTON);
-
-  return true;
-}
-
-bool Field::deleteItemAt(CJS_Runtime* pRuntime,
-                         const std::vector<CJS_Value>& params,
-                         CJS_Value& vRet,
-                         CFX_WideString& sError) {
-  return true;
-}
-
-bool Field::getArray(CJS_Runtime* pRuntime,
-                     const std::vector<CJS_Value>& params,
-                     CJS_Value& vRet,
-                     CFX_WideString& sError) {
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  std::vector<std::unique_ptr<CFX_WideString>> swSort;
-  for (CPDF_FormField* pFormField : FieldArray) {
-    swSort.push_back(std::unique_ptr<CFX_WideString>(
-        new CFX_WideString(pFormField->GetFullName())));
-  }
-
-  std::sort(
-      swSort.begin(), swSort.end(),
-      [](const std::unique_ptr<CFX_WideString>& p1,
-         const std::unique_ptr<CFX_WideString>& p2) { return *p1 < *p2; });
-
-  CJS_Array FormFieldArray;
-
-  int j = 0;
-  for (const auto& pStr : swSort) {
-    v8::Local<v8::Object> pObj =
-        pRuntime->NewFxDynamicObj(CJS_Field::g_nObjDefnID);
-    if (pObj.IsEmpty())
-      return false;
-
-    CJS_Field* pJSField =
-        static_cast<CJS_Field*>(pRuntime->GetObjectPrivate(pObj));
-    Field* pField = static_cast<Field*>(pJSField->GetEmbedObject());
-    pField->AttachField(m_pJSDoc, *pStr);
-    FormFieldArray.SetElement(pRuntime, j++, CJS_Value(pRuntime, pJSField));
-  }
-
-  vRet = CJS_Value(pRuntime, FormFieldArray);
-  return true;
-}
-
-bool Field::getItemAt(CJS_Runtime* pRuntime,
-                      const std::vector<CJS_Value>& params,
-                      CJS_Value& vRet,
-                      CFX_WideString& sError) {
-  int iSize = params.size();
-  int nIdx = -1;
-  if (iSize >= 1)
-    nIdx = params[0].ToInt(pRuntime);
-
-  bool bExport = true;
-  if (iSize >= 2)
-    bExport = params[1].ToBool(pRuntime);
-
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  CPDF_FormField* pFormField = FieldArray[0];
-  if ((pFormField->GetFieldType() == FIELDTYPE_LISTBOX) ||
-      (pFormField->GetFieldType() == FIELDTYPE_COMBOBOX)) {
-    if (nIdx == -1 || nIdx > pFormField->CountOptions())
-      nIdx = pFormField->CountOptions() - 1;
-    if (bExport) {
-      CFX_WideString strval = pFormField->GetOptionValue(nIdx);
-      if (strval.IsEmpty())
-        vRet = CJS_Value(pRuntime, pFormField->GetOptionLabel(nIdx).c_str());
-      else
-        vRet = CJS_Value(pRuntime, strval.c_str());
-    } else {
-      vRet = CJS_Value(pRuntime, pFormField->GetOptionLabel(nIdx).c_str());
-    }
-  } else {
-    return false;
-  }
-
-  return true;
-}
-
-bool Field::getLock(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError) {
-  return false;
-}
-
-bool Field::insertItemAt(CJS_Runtime* pRuntime,
-                         const std::vector<CJS_Value>& params,
-                         CJS_Value& vRet,
-                         CFX_WideString& sError) {
-  return true;
-}
-
-bool Field::isBoxChecked(CJS_Runtime* pRuntime,
-                         const std::vector<CJS_Value>& params,
-                         CJS_Value& vRet,
-                         CFX_WideString& sError) {
-  int nIndex = -1;
-  if (params.size() >= 1)
-    nIndex = params[0].ToInt(pRuntime);
-
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  CPDF_FormField* pFormField = FieldArray[0];
-  if (nIndex < 0 || nIndex >= pFormField->CountControls()) {
-    return false;
-  }
-
-  vRet = CJS_Value(pRuntime,
-                   ((pFormField->GetFieldType() == FIELDTYPE_CHECKBOX ||
-                     pFormField->GetFieldType() == FIELDTYPE_RADIOBUTTON) &&
-                    pFormField->GetControl(nIndex)->IsChecked() != 0));
-  return true;
-}
-
-bool Field::isDefaultChecked(CJS_Runtime* pRuntime,
-                             const std::vector<CJS_Value>& params,
-                             CJS_Value& vRet,
-                             CFX_WideString& sError) {
-  int nIndex = -1;
-  if (params.size() >= 1)
-    nIndex = params[0].ToInt(pRuntime);
-
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  CPDF_FormField* pFormField = FieldArray[0];
-  if (nIndex < 0 || nIndex >= pFormField->CountControls())
-    return false;
-
-  vRet = CJS_Value(pRuntime,
-                   ((pFormField->GetFieldType() == FIELDTYPE_CHECKBOX ||
-                     pFormField->GetFieldType() == FIELDTYPE_RADIOBUTTON) &&
-                    pFormField->GetControl(nIndex)->IsDefaultChecked() != 0));
-  return true;
-}
-
-bool Field::setAction(CJS_Runtime* pRuntime,
-                      const std::vector<CJS_Value>& params,
-                      CJS_Value& vRet,
-                      CFX_WideString& sError) {
-  return true;
-}
-
-bool Field::setFocus(CJS_Runtime* pRuntime,
-                     const std::vector<CJS_Value>& params,
-                     CJS_Value& vRet,
-                     CFX_WideString& sError) {
-  std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
-  if (FieldArray.empty())
-    return false;
-
-  CPDF_FormField* pFormField = FieldArray[0];
-  int32_t nCount = pFormField->CountControls();
-  if (nCount < 1)
-    return false;
-
-  CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
-  CPDFSDK_Widget* pWidget = nullptr;
-  if (nCount == 1) {
-    pWidget = pInterForm->GetWidget(pFormField->GetControl(0));
-  } else {
-    UnderlyingPageType* pPage =
-        UnderlyingFromFPDFPage(m_pFormFillEnv->GetCurrentPage(
-            m_pFormFillEnv->GetUnderlyingDocument()));
-    if (!pPage)
-      return false;
-    if (CPDFSDK_PageView* pCurPageView =
-            m_pFormFillEnv->GetPageView(pPage, true)) {
-      for (int32_t i = 0; i < nCount; i++) {
-        if (CPDFSDK_Widget* pTempWidget =
-                pInterForm->GetWidget(pFormField->GetControl(i))) {
-          if (pTempWidget->GetPDFPage() == pCurPageView->GetPDFPage()) {
-            pWidget = pTempWidget;
-            break;
-          }
-        }
-      }
-    }
-  }
-
-  if (pWidget) {
-    CPDFSDK_Annot::ObservedPtr pObserved(pWidget);
-    m_pFormFillEnv->SetFocusAnnot(&pObserved);
-  }
-
-  return true;
-}
-
-bool Field::setItems(CJS_Runtime* pRuntime,
-                     const std::vector<CJS_Value>& params,
-                     CJS_Value& vRet,
-                     CFX_WideString& sError) {
-  return true;
-}
-
-bool Field::setLock(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError) {
-  return false;
-}
-
-bool Field::signatureGetModifications(CJS_Runtime* pRuntime,
-                                      const std::vector<CJS_Value>& params,
-                                      CJS_Value& vRet,
-                                      CFX_WideString& sError) {
-  return false;
-}
-
-bool Field::signatureGetSeedValue(CJS_Runtime* pRuntime,
-                                  const std::vector<CJS_Value>& params,
-                                  CJS_Value& vRet,
-                                  CFX_WideString& sError) {
-  return false;
-}
-
-bool Field::signatureInfo(CJS_Runtime* pRuntime,
-                          const std::vector<CJS_Value>& params,
-                          CJS_Value& vRet,
-                          CFX_WideString& sError) {
-  return false;
-}
-
-bool Field::signatureSetSeedValue(CJS_Runtime* pRuntime,
-                                  const std::vector<CJS_Value>& params,
-                                  CJS_Value& vRet,
-                                  CFX_WideString& sError) {
-  return false;
-}
-
-bool Field::signatureSign(CJS_Runtime* pRuntime,
-                          const std::vector<CJS_Value>& params,
-                          CJS_Value& vRet,
-                          CFX_WideString& sError) {
-  return false;
-}
-
-bool Field::signatureValidate(CJS_Runtime* pRuntime,
-                              const std::vector<CJS_Value>& params,
-                              CJS_Value& vRet,
-                              CFX_WideString& sError) {
-  return false;
-}
-
-bool Field::source(CJS_Runtime* pRuntime,
-                   CJS_PropValue& vp,
-                   CFX_WideString& sError) {
-  if (vp.IsGetting()) {
-    vp << (CJS_Object*)nullptr;
-  }
-
-  return true;
-}
-
-void Field::AddDelay_Int(FIELD_PROP prop, int32_t n) {
-  CJS_DelayData* pNewData =
-      new CJS_DelayData(prop, m_nFormControlIndex, m_FieldName);
-  pNewData->num = n;
-  m_pJSDoc->AddDelayData(pNewData);
-}
-
-void Field::AddDelay_Bool(FIELD_PROP prop, bool b) {
-  CJS_DelayData* pNewData =
-      new CJS_DelayData(prop, m_nFormControlIndex, m_FieldName);
-  pNewData->b = b;
-  m_pJSDoc->AddDelayData(pNewData);
-}
-
-void Field::AddDelay_String(FIELD_PROP prop, const CFX_ByteString& string) {
-  CJS_DelayData* pNewData =
-      new CJS_DelayData(prop, m_nFormControlIndex, m_FieldName);
-  pNewData->string = string;
-  m_pJSDoc->AddDelayData(pNewData);
-}
-
-void Field::AddDelay_WideString(FIELD_PROP prop, const CFX_WideString& string) {
-  CJS_DelayData* pNewData =
-      new CJS_DelayData(prop, m_nFormControlIndex, m_FieldName);
-  pNewData->widestring = string;
-  m_pJSDoc->AddDelayData(pNewData);
-}
-
-void Field::AddDelay_Rect(FIELD_PROP prop, const CFX_FloatRect& rect) {
-  CJS_DelayData* pNewData =
-      new CJS_DelayData(prop, m_nFormControlIndex, m_FieldName);
-  pNewData->rect = rect;
-  m_pJSDoc->AddDelayData(pNewData);
-}
-
-void Field::AddDelay_Color(FIELD_PROP prop, const CPWL_Color& color) {
-  CJS_DelayData* pNewData =
-      new CJS_DelayData(prop, m_nFormControlIndex, m_FieldName);
-  pNewData->color = color;
-  m_pJSDoc->AddDelayData(pNewData);
-}
-
-void Field::AddDelay_WordArray(FIELD_PROP prop,
-                               const std::vector<uint32_t>& array) {
-  CJS_DelayData* pNewData =
-      new CJS_DelayData(prop, m_nFormControlIndex, m_FieldName);
-  pNewData->wordarray = array;
-  m_pJSDoc->AddDelayData(pNewData);
-}
-
-void Field::AddDelay_WideStringArray(FIELD_PROP prop,
-                                     const std::vector<CFX_WideString>& array) {
-  CJS_DelayData* pNewData =
-      new CJS_DelayData(prop, m_nFormControlIndex, m_FieldName);
-  pNewData->widestringarray = array;
-  m_pJSDoc->AddDelayData(pNewData);
-}
-
-void Field::DoDelay(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                    CJS_DelayData* pData) {
-  ASSERT(pFormFillEnv);
-  switch (pData->eProp) {
-    case FP_ALIGNMENT:
-      Field::SetAlignment(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                          pData->string);
-      break;
-    case FP_BORDERSTYLE:
-      Field::SetBorderStyle(pFormFillEnv, pData->sFieldName,
-                            pData->nControlIndex, pData->string);
-      break;
-    case FP_BUTTONALIGNX:
-      Field::SetButtonAlignX(pFormFillEnv, pData->sFieldName,
-                             pData->nControlIndex, pData->num);
-      break;
-    case FP_BUTTONALIGNY:
-      Field::SetButtonAlignY(pFormFillEnv, pData->sFieldName,
-                             pData->nControlIndex, pData->num);
-      break;
-    case FP_BUTTONFITBOUNDS:
-      Field::SetButtonFitBounds(pFormFillEnv, pData->sFieldName,
-                                pData->nControlIndex, pData->b);
-      break;
-    case FP_BUTTONPOSITION:
-      Field::SetButtonPosition(pFormFillEnv, pData->sFieldName,
-                               pData->nControlIndex, pData->num);
-      break;
-    case FP_BUTTONSCALEHOW:
-      Field::SetButtonScaleHow(pFormFillEnv, pData->sFieldName,
-                               pData->nControlIndex, pData->num);
-      break;
-    case FP_BUTTONSCALEWHEN:
-      Field::SetButtonScaleWhen(pFormFillEnv, pData->sFieldName,
-                                pData->nControlIndex, pData->num);
-      break;
-    case FP_CALCORDERINDEX:
-      Field::SetCalcOrderIndex(pFormFillEnv, pData->sFieldName,
-                               pData->nControlIndex, pData->num);
-      break;
-    case FP_CHARLIMIT:
-      Field::SetCharLimit(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                          pData->num);
-      break;
-    case FP_COMB:
-      Field::SetComb(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                     pData->b);
-      break;
-    case FP_COMMITONSELCHANGE:
-      Field::SetCommitOnSelChange(pFormFillEnv, pData->sFieldName,
-                                  pData->nControlIndex, pData->b);
-      break;
-    case FP_CURRENTVALUEINDICES:
-      Field::SetCurrentValueIndices(pFormFillEnv, pData->sFieldName,
-                                    pData->nControlIndex, pData->wordarray);
-      break;
-    case FP_DEFAULTVALUE:
-      Field::SetDefaultValue(pFormFillEnv, pData->sFieldName,
-                             pData->nControlIndex, pData->widestring);
-      break;
-    case FP_DONOTSCROLL:
-      Field::SetDoNotScroll(pFormFillEnv, pData->sFieldName,
-                            pData->nControlIndex, pData->b);
-      break;
-    case FP_DISPLAY:
-      Field::SetDisplay(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                        pData->num);
-      break;
-    case FP_FILLCOLOR:
-      Field::SetFillColor(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                          pData->color);
-      break;
-    case FP_HIDDEN:
-      Field::SetHidden(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                       pData->b);
-      break;
-    case FP_HIGHLIGHT:
-      Field::SetHighlight(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                          pData->string);
-      break;
-    case FP_LINEWIDTH:
-      Field::SetLineWidth(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                          pData->num);
-      break;
-    case FP_MULTILINE:
-      Field::SetMultiline(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                          pData->b);
-      break;
-    case FP_MULTIPLESELECTION:
-      Field::SetMultipleSelection(pFormFillEnv, pData->sFieldName,
-                                  pData->nControlIndex, pData->b);
-      break;
-    case FP_PASSWORD:
-      Field::SetPassword(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                         pData->b);
-      break;
-    case FP_RECT:
-      Field::SetRect(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                     pData->rect);
-      break;
-    case FP_RICHTEXT:
-      // Not supported.
-      break;
-    case FP_RICHVALUE:
-      break;
-    case FP_ROTATION:
-      Field::SetRotation(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                         pData->num);
-      break;
-    case FP_STROKECOLOR:
-      Field::SetStrokeColor(pFormFillEnv, pData->sFieldName,
-                            pData->nControlIndex, pData->color);
-      break;
-    case FP_STYLE:
-      Field::SetStyle(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                      pData->string);
-      break;
-    case FP_TEXTCOLOR:
-      Field::SetTextColor(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                          pData->color);
-      break;
-    case FP_TEXTFONT:
-      Field::SetTextFont(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                         pData->string);
-      break;
-    case FP_TEXTSIZE:
-      Field::SetTextSize(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                         pData->num);
-      break;
-    case FP_USERNAME:
-      Field::SetUserName(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                         pData->widestring);
-      break;
-    case FP_VALUE:
-      Field::SetValue(pFormFillEnv, pData->sFieldName, pData->nControlIndex,
-                      pData->widestringarray);
-      break;
-  }
-}
-
-void Field::AddField(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                     int nPageIndex,
-                     int nFieldType,
-                     const CFX_WideString& sName,
-                     const CFX_FloatRect& rcCoords) {
-  // Not supported.
-}
diff --git a/fpdfsdk/javascript/Field.h b/fpdfsdk/javascript/Field.h
deleted file mode 100644
index 462c127..0000000
--- a/fpdfsdk/javascript/Field.h
+++ /dev/null
@@ -1,598 +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 FPDFSDK_JAVASCRIPT_FIELD_H_
-#define FPDFSDK_JAVASCRIPT_FIELD_H_
-
-#include <string>
-#include <vector>
-
-#include "core/fxcrt/cfx_observable.h"
-#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"  // For CPWL_Color.
-
-class CPDFSDK_Widget;
-class Document;
-
-enum FIELD_PROP {
-  FP_ALIGNMENT,
-  FP_BORDERSTYLE,
-  FP_BUTTONALIGNX,
-  FP_BUTTONALIGNY,
-  FP_BUTTONFITBOUNDS,
-  FP_BUTTONPOSITION,
-  FP_BUTTONSCALEHOW,
-  FP_BUTTONSCALEWHEN,
-  FP_CALCORDERINDEX,
-  FP_CHARLIMIT,
-  FP_COMB,
-  FP_COMMITONSELCHANGE,
-  FP_CURRENTVALUEINDICES,
-  FP_DEFAULTVALUE,
-  FP_DONOTSCROLL,
-  FP_DISPLAY,
-  FP_FILLCOLOR,
-  FP_HIDDEN,
-  FP_HIGHLIGHT,
-  FP_LINEWIDTH,
-  FP_MULTILINE,
-  FP_MULTIPLESELECTION,
-  FP_PASSWORD,
-  FP_RECT,
-  FP_RICHTEXT,
-  FP_RICHVALUE,
-  FP_ROTATION,
-  FP_STROKECOLOR,
-  FP_STYLE,
-  FP_TEXTCOLOR,
-  FP_TEXTFONT,
-  FP_TEXTSIZE,
-  FP_USERNAME,
-  FP_VALUE
-};
-
-struct CJS_DelayData {
-  CJS_DelayData(FIELD_PROP prop, int idx, const CFX_WideString& name);
-  ~CJS_DelayData();
-
-  FIELD_PROP eProp;
-  int nControlIndex;
-  CFX_WideString sFieldName;
-  int32_t num;
-  bool b;
-  CFX_ByteString string;
-  CFX_WideString widestring;
-  CFX_FloatRect rect;
-  CPWL_Color color;
-  std::vector<uint32_t> wordarray;
-  std::vector<CFX_WideString> widestringarray;
-};
-
-class Field : public CJS_EmbedObj {
- public:
-  explicit Field(CJS_Object* pJSObject);
-  ~Field() override;
-
-  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(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError);
-  bool buttonScaleHow(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError);
-  bool buttonScaleWhen(CJS_Runtime* pRuntime,
-                       CJS_PropValue& vp,
-                       CFX_WideString& sError);
-  bool calcOrderIndex(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError);
-  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(CJS_Runtime* pRuntime,
-                           CJS_PropValue& vp,
-                           CFX_WideString& sError);
-  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(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(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(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(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError);
-
-  bool browseForFileToSubmit(CJS_Runtime* pRuntime,
-                             const std::vector<CJS_Value>& params,
-                             CJS_Value& vRet,
-                             CFX_WideString& sError);
-  bool buttonGetCaption(CJS_Runtime* pRuntime,
-                        const std::vector<CJS_Value>& params,
-                        CJS_Value& vRet,
-                        CFX_WideString& sError);
-  bool buttonGetIcon(CJS_Runtime* pRuntime,
-                     const std::vector<CJS_Value>& params,
-                     CJS_Value& vRet,
-                     CFX_WideString& sError);
-  bool buttonImportIcon(CJS_Runtime* pRuntime,
-                        const std::vector<CJS_Value>& params,
-                        CJS_Value& vRet,
-                        CFX_WideString& sError);
-  bool buttonSetCaption(CJS_Runtime* pRuntime,
-                        const std::vector<CJS_Value>& params,
-                        CJS_Value& vRet,
-                        CFX_WideString& sError);
-  bool buttonSetIcon(CJS_Runtime* pRuntime,
-                     const std::vector<CJS_Value>& params,
-                     CJS_Value& vRet,
-                     CFX_WideString& sError);
-  bool checkThisBox(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError);
-  bool clearItems(CJS_Runtime* pRuntime,
-                  const std::vector<CJS_Value>& params,
-                  CJS_Value& vRet,
-                  CFX_WideString& sError);
-  bool defaultIsChecked(CJS_Runtime* pRuntime,
-                        const std::vector<CJS_Value>& params,
-                        CJS_Value& vRet,
-                        CFX_WideString& sError);
-  bool deleteItemAt(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError);
-  bool getArray(CJS_Runtime* pRuntime,
-                const std::vector<CJS_Value>& params,
-                CJS_Value& vRet,
-                CFX_WideString& sError);
-  bool getItemAt(CJS_Runtime* pRuntime,
-                 const std::vector<CJS_Value>& params,
-                 CJS_Value& vRet,
-                 CFX_WideString& sError);
-  bool getLock(CJS_Runtime* pRuntime,
-               const std::vector<CJS_Value>& params,
-               CJS_Value& vRet,
-               CFX_WideString& sError);
-  bool insertItemAt(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError);
-  bool isBoxChecked(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError);
-  bool isDefaultChecked(CJS_Runtime* pRuntime,
-                        const std::vector<CJS_Value>& params,
-                        CJS_Value& vRet,
-                        CFX_WideString& sError);
-  bool setAction(CJS_Runtime* pRuntime,
-                 const std::vector<CJS_Value>& params,
-                 CJS_Value& vRet,
-                 CFX_WideString& sError);
-  bool setFocus(CJS_Runtime* pRuntime,
-                const std::vector<CJS_Value>& params,
-                CJS_Value& vRet,
-                CFX_WideString& sError);
-  bool setItems(CJS_Runtime* pRuntime,
-                const std::vector<CJS_Value>& params,
-                CJS_Value& vRet,
-                CFX_WideString& sError);
-  bool setLock(CJS_Runtime* pRuntime,
-               const std::vector<CJS_Value>& params,
-               CJS_Value& vRet,
-               CFX_WideString& sError);
-  bool signatureGetModifications(CJS_Runtime* pRuntime,
-                                 const std::vector<CJS_Value>& params,
-                                 CJS_Value& vRet,
-                                 CFX_WideString& sError);
-  bool signatureGetSeedValue(CJS_Runtime* pRuntime,
-                             const std::vector<CJS_Value>& params,
-                             CJS_Value& vRet,
-                             CFX_WideString& sError);
-  bool signatureInfo(CJS_Runtime* pRuntime,
-                     const std::vector<CJS_Value>& params,
-                     CJS_Value& vRet,
-                     CFX_WideString& sError);
-  bool signatureSetSeedValue(CJS_Runtime* pRuntime,
-                             const std::vector<CJS_Value>& params,
-                             CJS_Value& vRet,
-                             CFX_WideString& sError);
-  bool signatureSign(CJS_Runtime* pRuntime,
-                     const std::vector<CJS_Value>& params,
-                     CJS_Value& vRet,
-                     CFX_WideString& sError);
-  bool signatureValidate(CJS_Runtime* pRuntime,
-                         const std::vector<CJS_Value>& params,
-                         CJS_Value& vRet,
-                         CFX_WideString& sError);
-
-  static void SetAlignment(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                           const CFX_WideString& swFieldName,
-                           int nControlIndex,
-                           const CFX_ByteString& string);
-  static void SetBorderStyle(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                             const CFX_WideString& swFieldName,
-                             int nControlIndex,
-                             const CFX_ByteString& string);
-  static void SetButtonAlignX(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                              const CFX_WideString& swFieldName,
-                              int nControlIndex,
-                              int number);
-  static void SetButtonAlignY(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                              const CFX_WideString& swFieldName,
-                              int nControlIndex,
-                              int number);
-  static void SetButtonFitBounds(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                 const CFX_WideString& swFieldName,
-                                 int nControlIndex,
-                                 bool b);
-  static void SetButtonPosition(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                const CFX_WideString& swFieldName,
-                                int nControlIndex,
-                                int number);
-  static void SetButtonScaleHow(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                const CFX_WideString& swFieldName,
-                                int nControlIndex,
-                                int number);
-  static void SetButtonScaleWhen(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                 const CFX_WideString& swFieldName,
-                                 int nControlIndex,
-                                 int number);
-  static void SetCalcOrderIndex(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                const CFX_WideString& swFieldName,
-                                int nControlIndex,
-                                int number);
-  static void SetCharLimit(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                           const CFX_WideString& swFieldName,
-                           int nControlIndex,
-                           int number);
-  static void SetComb(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                      const CFX_WideString& swFieldName,
-                      int nControlIndex,
-                      bool b);
-  static void SetCommitOnSelChange(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                   const CFX_WideString& swFieldName,
-                                   int nControlIndex,
-                                   bool b);
-  static void SetCurrentValueIndices(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                     const CFX_WideString& swFieldName,
-                                     int nControlIndex,
-                                     const std::vector<uint32_t>& array);
-  static void SetDefaultStyle(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                              const CFX_WideString& swFieldName,
-                              int nControlIndex);
-  static void SetDefaultValue(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                              const CFX_WideString& swFieldName,
-                              int nControlIndex,
-                              const CFX_WideString& string);
-  static void SetDoNotScroll(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                             const CFX_WideString& swFieldName,
-                             int nControlIndex,
-                             bool b);
-  static void SetDisplay(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                         const CFX_WideString& swFieldName,
-                         int nControlIndex,
-                         int number);
-  static void SetFillColor(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                           const CFX_WideString& swFieldName,
-                           int nControlIndex,
-                           const CPWL_Color& color);
-  static void SetHidden(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                        const CFX_WideString& swFieldName,
-                        int nControlIndex,
-                        bool b);
-  static void SetHighlight(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                           const CFX_WideString& swFieldName,
-                           int nControlIndex,
-                           const CFX_ByteString& string);
-  static void SetLineWidth(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                           const CFX_WideString& swFieldName,
-                           int nControlIndex,
-                           int number);
-  static void SetMultiline(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                           const CFX_WideString& swFieldName,
-                           int nControlIndex,
-                           bool b);
-  static void SetMultipleSelection(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                   const CFX_WideString& swFieldName,
-                                   int nControlIndex,
-                                   bool b);
-  static void SetPassword(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                          const CFX_WideString& swFieldName,
-                          int nControlIndex,
-                          bool b);
-  static void SetRect(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                      const CFX_WideString& swFieldName,
-                      int nControlIndex,
-                      const CFX_FloatRect& rect);
-  static void SetRotation(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                          const CFX_WideString& swFieldName,
-                          int nControlIndex,
-                          int number);
-  static void SetStrokeColor(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                             const CFX_WideString& swFieldName,
-                             int nControlIndex,
-                             const CPWL_Color& color);
-  static void SetStyle(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                       const CFX_WideString& swFieldName,
-                       int nControlIndex,
-                       const CFX_ByteString& string);
-  static void SetTextColor(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                           const CFX_WideString& swFieldName,
-                           int nControlIndex,
-                           const CPWL_Color& color);
-  static void SetTextFont(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                          const CFX_WideString& swFieldName,
-                          int nControlIndex,
-                          const CFX_ByteString& string);
-  static void SetTextSize(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                          const CFX_WideString& swFieldName,
-                          int nControlIndex,
-                          int number);
-  static void SetUserName(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                          const CFX_WideString& swFieldName,
-                          int nControlIndex,
-                          const CFX_WideString& string);
-  static void SetValue(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                       const CFX_WideString& swFieldName,
-                       int nControlIndex,
-                       const std::vector<CFX_WideString>& strArray);
-
-  static void AddField(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                       int nPageIndex,
-                       int nFieldType,
-                       const CFX_WideString& sName,
-                       const CFX_FloatRect& rcCoords);
-
-  static void UpdateFormField(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                              CPDF_FormField* pFormField,
-                              bool bChangeMark,
-                              bool bResetAP,
-                              bool bRefresh);
-  static void UpdateFormControl(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                CPDF_FormControl* pFormControl,
-                                bool bChangeMark,
-                                bool bResetAP,
-                                bool bRefresh);
-
-  static CPDFSDK_Widget* GetWidget(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                   CPDF_FormControl* pFormControl);
-  static std::vector<CPDF_FormField*> GetFormFields(
-      CPDFSDK_FormFillEnvironment* pFormFillEnv,
-      const CFX_WideString& csFieldName);
-
-  static void DoDelay(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                      CJS_DelayData* pData);
-
-  bool AttachField(Document* pDocument, const CFX_WideString& csFieldName);
-  void SetDelay(bool bDelay);
-
- protected:
-  void ParseFieldName(const std::wstring& strFieldNameParsed,
-                      std::wstring& strFieldName,
-                      int& iControlNo);
-  std::vector<CPDF_FormField*> GetFormFields(
-      const CFX_WideString& csFieldName) const;
-  CPDF_FormControl* GetSmartFieldControl(CPDF_FormField* pFormField);
-  bool ValueIsOccur(CPDF_FormField* pFormField, CFX_WideString csOptLabel);
-
-  void AddDelay_Int(FIELD_PROP prop, int32_t n);
-  void AddDelay_Bool(FIELD_PROP prop, bool b);
-  void AddDelay_String(FIELD_PROP prop, const CFX_ByteString& string);
-  void AddDelay_WideString(FIELD_PROP prop, const CFX_WideString& string);
-  void AddDelay_Rect(FIELD_PROP prop, const CFX_FloatRect& rect);
-  void AddDelay_Color(FIELD_PROP prop, const CPWL_Color& color);
-  void AddDelay_WordArray(FIELD_PROP prop, const std::vector<uint32_t>& array);
-  void AddDelay_WideStringArray(FIELD_PROP prop,
-                                const std::vector<CFX_WideString>& array);
-
-  void DoDelay();
-
- public:
-  Document* m_pJSDoc;
-  CPDFSDK_FormFillEnvironment::ObservedPtr m_pFormFillEnv;
-  CFX_WideString m_FieldName;
-  int m_nFormControlIndex;
-  bool m_bCanSet;
-  bool m_bDelay;
-};
-
-class CJS_Field : public CJS_Object {
- public:
-  explicit CJS_Field(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Field() override {}
-
-  void InitInstance(IJS_Runtime* pIRuntime) override;
-
-  DECLARE_JS_CLASS();
-  JS_STATIC_PROP(alignment, Field);
-  JS_STATIC_PROP(borderStyle, Field);
-  JS_STATIC_PROP(buttonAlignX, Field);
-  JS_STATIC_PROP(buttonAlignY, Field);
-  JS_STATIC_PROP(buttonFitBounds, Field);
-  JS_STATIC_PROP(buttonPosition, Field);
-  JS_STATIC_PROP(buttonScaleHow, Field);
-  JS_STATIC_PROP(buttonScaleWhen, Field);
-  JS_STATIC_PROP(calcOrderIndex, Field);
-  JS_STATIC_PROP(charLimit, Field);
-  JS_STATIC_PROP(comb, Field);
-  JS_STATIC_PROP(commitOnSelChange, Field);
-  JS_STATIC_PROP(currentValueIndices, Field);
-  JS_STATIC_PROP(defaultStyle, Field);
-  JS_STATIC_PROP(defaultValue, Field);
-  JS_STATIC_PROP(doNotScroll, Field);
-  JS_STATIC_PROP(doNotSpellCheck, Field);
-  JS_STATIC_PROP(delay, Field);
-  JS_STATIC_PROP(display, Field);
-  JS_STATIC_PROP(doc, Field);
-  JS_STATIC_PROP(editable, Field);
-  JS_STATIC_PROP(exportValues, Field);
-  JS_STATIC_PROP(fileSelect, Field);
-  JS_STATIC_PROP(fillColor, Field);
-  JS_STATIC_PROP(hidden, Field);
-  JS_STATIC_PROP(highlight, Field);
-  JS_STATIC_PROP(lineWidth, Field);
-  JS_STATIC_PROP(multiline, Field);
-  JS_STATIC_PROP(multipleSelection, Field);
-  JS_STATIC_PROP(name, Field);
-  JS_STATIC_PROP(numItems, Field);
-  JS_STATIC_PROP(page, Field);
-  JS_STATIC_PROP(password, Field);
-  JS_STATIC_PROP(print, Field);
-  JS_STATIC_PROP(radiosInUnison, Field);
-  JS_STATIC_PROP(readonly, Field);
-  JS_STATIC_PROP(rect, Field);
-  JS_STATIC_PROP(required, Field);
-  JS_STATIC_PROP(richText, Field);
-  JS_STATIC_PROP(richValue, Field);
-  JS_STATIC_PROP(rotation, Field);
-  JS_STATIC_PROP(strokeColor, Field);
-  JS_STATIC_PROP(style, Field);
-  JS_STATIC_PROP(submitName, Field);
-  JS_STATIC_PROP(textColor, Field);
-  JS_STATIC_PROP(textFont, Field);
-  JS_STATIC_PROP(textSize, Field);
-  JS_STATIC_PROP(type, Field);
-  JS_STATIC_PROP(userName, Field);
-  JS_STATIC_PROP(value, Field);
-  JS_STATIC_PROP(valueAsString, Field);
-  JS_STATIC_PROP(source, Field);
-
-  JS_STATIC_METHOD(browseForFileToSubmit, Field);
-  JS_STATIC_METHOD(buttonGetCaption, Field);
-  JS_STATIC_METHOD(buttonGetIcon, Field);
-  JS_STATIC_METHOD(buttonImportIcon, Field);
-  JS_STATIC_METHOD(buttonSetCaption, Field);
-  JS_STATIC_METHOD(buttonSetIcon, Field);
-  JS_STATIC_METHOD(checkThisBox, Field);
-  JS_STATIC_METHOD(clearItems, Field);
-  JS_STATIC_METHOD(defaultIsChecked, Field);
-  JS_STATIC_METHOD(deleteItemAt, Field);
-  JS_STATIC_METHOD(getArray, Field);
-  JS_STATIC_METHOD(getItemAt, Field);
-  JS_STATIC_METHOD(getLock, Field);
-  JS_STATIC_METHOD(insertItemAt, Field);
-  JS_STATIC_METHOD(isBoxChecked, Field);
-  JS_STATIC_METHOD(isDefaultChecked, Field);
-  JS_STATIC_METHOD(setAction, Field);
-  JS_STATIC_METHOD(setFocus, Field);
-  JS_STATIC_METHOD(setItems, Field);
-  JS_STATIC_METHOD(setLock, Field);
-  JS_STATIC_METHOD(signatureGetModifications, Field);
-  JS_STATIC_METHOD(signatureGetSeedValue, Field);
-  JS_STATIC_METHOD(signatureInfo, Field);
-  JS_STATIC_METHOD(signatureSetSeedValue, Field);
-  JS_STATIC_METHOD(signatureSign, Field);
-  JS_STATIC_METHOD(signatureValidate, Field);
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_FIELD_H_
diff --git a/fpdfsdk/javascript/Icon.cpp b/fpdfsdk/javascript/Icon.cpp
deleted file mode 100644
index fa2f92f..0000000
--- a/fpdfsdk/javascript/Icon.cpp
+++ /dev/null
@@ -1,36 +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/Icon.h"
-
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_Object.h"
-#include "fpdfsdk/javascript/JS_Value.h"
-
-JSConstSpec CJS_Icon::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
-
-JSPropertySpec CJS_Icon::PropertySpecs[] = {
-    {"name", get_name_static, set_name_static},
-    {0, 0, 0}};
-
-JSMethodSpec CJS_Icon::MethodSpecs[] = {{0, 0}};
-
-IMPLEMENT_JS_CLASS(CJS_Icon, Icon)
-
-Icon::Icon(CJS_Object* pJSObject)
-    : CJS_EmbedObj(pJSObject), m_swIconName(L"") {}
-
-Icon::~Icon() {}
-
-bool Icon::name(CJS_Runtime* pRuntime,
-                CJS_PropValue& vp,
-                CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  vp << m_swIconName;
-  return true;
-}
diff --git a/fpdfsdk/javascript/Icon.h b/fpdfsdk/javascript/Icon.h
deleted file mode 100644
index 5580678..0000000
--- a/fpdfsdk/javascript/Icon.h
+++ /dev/null
@@ -1,36 +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 FPDFSDK_JAVASCRIPT_ICON_H_
-#define FPDFSDK_JAVASCRIPT_ICON_H_
-
-#include "fpdfsdk/javascript/JS_Define.h"
-
-class CPDF_Stream;
-
-class Icon : public CJS_EmbedObj {
- public:
-  explicit Icon(CJS_Object* pJSObject);
-  ~Icon() override;
-
-  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:
-  CFX_WideString m_swIconName;
-};
-
-class CJS_Icon : public CJS_Object {
- public:
-  explicit CJS_Icon(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Icon() override {}
-
-  DECLARE_JS_CLASS();
-  JS_STATIC_PROP(name, Icon);
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_ICON_H_
diff --git a/fpdfsdk/javascript/JS_Define.h b/fpdfsdk/javascript/JS_Define.h
deleted file mode 100644
index 375ca3a..0000000
--- a/fpdfsdk/javascript/JS_Define.h
+++ /dev/null
@@ -1,456 +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 FPDFSDK_JAVASCRIPT_JS_DEFINE_H_
-#define FPDFSDK_JAVASCRIPT_JS_DEFINE_H_
-
-#include <vector>
-
-#include "fpdfsdk/javascript/JS_Object.h"
-#include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/resource.h"
-#include "fxjs/fxjs_v8.h"
-
-struct JSConstSpec {
-  enum Type { Number = 0, String = 1 };
-
-  const char* pName;
-  Type eType;
-  double number;
-  const char* pStr;
-};
-
-struct JSPropertySpec {
-  const char* pName;
-  v8::AccessorGetterCallback pPropGet;
-  v8::AccessorSetterCallback pPropPut;
-};
-
-struct JSMethodSpec {
-  const char* pName;
-  v8::FunctionCallback pMethodCall;
-};
-
-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,
-                  const v8::PropertyCallbackInfo<v8::Value>& 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;
-  C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject());
-  CFX_WideString sError;
-  CJS_PropValue value(pRuntime);
-  value.StartGetting();
-  if (!(pObj->*M)(pRuntime, value, sError)) {
-    pRuntime->Error(
-        JSFormatErrorString(class_name_string, prop_name_string, sError));
-    return;
-  }
-  info.GetReturnValue().Set(value.GetJSValue()->ToV8Value(pRuntime));
-}
-
-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,
-                  v8::Local<v8::Value> value,
-                  const v8::PropertyCallbackInfo<void>& 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;
-  C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject());
-  CFX_WideString sError;
-  CJS_PropValue propValue(pRuntime, CJS_Value(pRuntime, value));
-  propValue.StartSetting();
-  if (!(pObj->*M)(pRuntime, propValue, sError)) {
-    pRuntime->Error(
-        JSFormatErrorString(class_name_string, prop_name_string, sError));
-  }
-}
-
-#define JS_STATIC_PROP(prop_name, class_name)                                 \
-  static void get_##prop_name##_static(                                       \
-      v8::Local<v8::String> property,                                         \
-      const v8::PropertyCallbackInfo<v8::Value>& info) {                      \
-    JSPropGetter<class_name, &class_name::prop_name>(#prop_name, #class_name, \
-                                                     property, info);         \
-  }                                                                           \
-  static void set_##prop_name##_static(                                       \
-      v8::Local<v8::String> property, v8::Local<v8::Value> value,             \
-      const v8::PropertyCallbackInfo<void>& info) {                           \
-    JSPropSetter<class_name, &class_name::prop_name>(#prop_name, #class_name, \
-                                                     property, value, info);  \
-  }
-
-template <class C,
-          bool (C::*M)(CJS_Runtime*,
-                       const std::vector<CJS_Value>&,
-                       CJS_Value&,
-                       CFX_WideString&)>
-void JSMethod(const char* method_name_string,
-              const char* class_name_string,
-              const v8::FunctionCallbackInfo<v8::Value>& info) {
-  CJS_Runtime* pRuntime =
-      CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
-  if (!pRuntime)
-    return;
-  std::vector<CJS_Value> parameters;
-  for (unsigned int i = 0; i < (unsigned int)info.Length(); i++) {
-    parameters.push_back(CJS_Value(pRuntime, info[i]));
-  }
-  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, parameters, valueRes, sError)) {
-    pRuntime->Error(
-        JSFormatErrorString(class_name_string, method_name_string, sError));
-    return;
-  }
-  info.GetReturnValue().Set(valueRes.ToV8Value(pRuntime));
-}
-
-#define JS_STATIC_METHOD(method_name, class_name)                             \
-  static void method_name##_static(                                           \
-      const v8::FunctionCallbackInfo<v8::Value>& info) {                      \
-    JSMethod<class_name, &class_name::method_name>(#method_name, #class_name, \
-                                                   info);                     \
-  }
-
-#define JS_SPECIAL_STATIC_METHOD(method_name, class_alternate, class_name) \
-  static void method_name##_static(                                        \
-      const v8::FunctionCallbackInfo<v8::Value>& info) {                   \
-    JSMethod<class_alternate, &class_alternate::method_name>(              \
-        #method_name, #class_name, info);                                  \
-  }
-
-// 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 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 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.
-#define DECLARE_JS_CLASS_CONST() \
-  DECLARE_JS_CLASS_BASE_PART()   \
-  DECLARE_JS_CLASS_CONST_PART()
-
-#define IMPLEMENT_JS_CLASS_CONST(js_class_name, class_name)                  \
-  IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name)                    \
-  IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)                   \
-  void js_class_name::DefineJSObjects(CFXJS_Engine* pEngine,                 \
-                                      FXJSOBJTYPE eObjType) {                \
-    g_nObjDefnID = pEngine->DefineObj(js_class_name::g_pClassName, eObjType, \
-                                      nullptr, nullptr);                     \
-    DefineConsts(pEngine);                                                   \
-  }
-
-#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(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.
-#define DECLARE_JS_CLASS() DECLARE_JS_CLASS_RICH()
-#define IMPLEMENT_JS_CLASS(js_class_name, class_name) \
-  IMPLEMENT_JS_CLASS_RICH(js_class_name, class_name, class_name)
-
-// Rich JS classes provide constants, methods, properties, and the ability
-// to construct native object state.
-#define DECLARE_JS_CLASS_RICH() \
-  DECLARE_JS_CLASS_BASE_PART()  \
-  DECLARE_JS_CLASS_CONST_PART() \
-  DECLARE_JS_CLASS_RICH_PART()
-
-#define IMPLEMENT_JS_CLASS_RICH(js_class_name, class_alternate, class_name)  \
-  IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name)                    \
-  IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)                   \
-  IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate, class_name)   \
-  void js_class_name::DefineJSObjects(CFXJS_Engine* pEngine,                 \
-                                      FXJSOBJTYPE eObjType) {                \
-    g_nObjDefnID = pEngine->DefineObj(js_class_name::g_pClassName, eObjType, \
-                                      JSConstructor, JSDestructor);          \
-    DefineConsts(pEngine);                                                   \
-    DefineProps(pEngine);                                                    \
-    DefineMethods(pEngine);                                                  \
-  }
-
-#define DECLARE_JS_CLASS_RICH_PART()                                           \
-  static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj); \
-  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 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) {         \
-    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.
-#define DECLARE_SPECIAL_JS_CLASS() \
-  DECLARE_JS_CLASS_BASE_PART()     \
-  DECLARE_JS_CLASS_CONST_PART()    \
-  DECLARE_JS_CLASS_RICH_PART()     \
-  DECLARE_SPECIAL_JS_CLASS_PART()
-
-#define IMPLEMENT_SPECIAL_JS_CLASS(js_class_name, class_alternate, class_name) \
-  IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name)                      \
-  IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)                     \
-  IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate, class_name)     \
-  IMPLEMENT_SPECIAL_JS_CLASS_PART(js_class_name, class_alternate, class_name)  \
-  void js_class_name::DefineJSObjects(CFXJS_Engine* pEngine,                   \
-                                      FXJSOBJTYPE eObjType) {                  \
-    g_nObjDefnID = pEngine->DefineObj(js_class_name::g_pClassName, eObjType,   \
-                                      JSConstructor, JSDestructor);            \
-    DefineConsts(pEngine);                                                     \
-    DefineProps(pEngine);                                                      \
-    DefineMethods(pEngine);                                                    \
-    DefineAllProperties(pEngine);                                              \
-  }
-
-#define DECLARE_SPECIAL_JS_CLASS_PART()                                        \
-  static void queryprop_static(                                                \
-      v8::Local<v8::String> property,                                          \
-      const v8::PropertyCallbackInfo<v8::Integer>& info);                      \
-  static void getprop_static(v8::Local<v8::String> property,                   \
-                             const v8::PropertyCallbackInfo<v8::Value>& info); \
-  static void putprop_static(v8::Local<v8::String> property,                   \
-                             v8::Local<v8::Value> value,                       \
-                             const v8::PropertyCallbackInfo<v8::Value>& info); \
-  static void delprop_static(                                                  \
-      v8::Local<v8::String> property,                                          \
-      const v8::PropertyCallbackInfo<v8::Boolean>& info);                      \
-  static void DefineAllProperties(CFXJS_Engine* pEngine);
-
-#define IMPLEMENT_SPECIAL_JS_CLASS_PART(js_class_name, class_alternate,    \
-                                        class_name)                        \
-  void js_class_name::queryprop_static(                                    \
-      v8::Local<v8::String> property,                                      \
-      const v8::PropertyCallbackInfo<v8::Integer>& info) {                 \
-    JSSpecialPropQuery<class_alternate>(#class_name, property, info);      \
-  }                                                                        \
-  void js_class_name::getprop_static(                                      \
-      v8::Local<v8::String> property,                                      \
-      const v8::PropertyCallbackInfo<v8::Value>& info) {                   \
-    JSSpecialPropGet<class_alternate>(#class_name, property, info);        \
-  }                                                                        \
-  void js_class_name::putprop_static(                                      \
-      v8::Local<v8::String> property, v8::Local<v8::Value> value,          \
-      const v8::PropertyCallbackInfo<v8::Value>& info) {                   \
-    JSSpecialPropPut<class_alternate>(#class_name, property, value, info); \
-  }                                                                        \
-  void js_class_name::delprop_static(                                      \
-      v8::Local<v8::String> property,                                      \
-      const v8::PropertyCallbackInfo<v8::Boolean>& info) {                 \
-    JSSpecialPropDel<class_alternate>(#class_name, property, info);        \
-  }                                                                        \
-  void js_class_name::DefineAllProperties(CFXJS_Engine* pEngine) {         \
-    pEngine->DefineObjAllProperties(                                       \
-        g_nObjDefnID, js_class_name::queryprop_static,                     \
-        js_class_name::getprop_static, js_class_name::putprop_static,      \
-        js_class_name::delprop_static);                                    \
-  }
-
-template <class Alt>
-void JSSpecialPropQuery(const char*,
-                        v8::Local<v8::String> property,
-                        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()));
-  bool bRet = pObj->QueryProperty(propname.c_str());
-  info.GetReturnValue().Set(bRet ? 4 : 0);
-}
-
-template <class Alt>
-void JSSpecialPropGet(const char* class_name,
-                      v8::Local<v8::String> property,
-                      const v8::PropertyCallbackInfo<v8::Value>& 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()));
-  CFX_WideString sError;
-  CJS_PropValue value(pRuntime);
-  value.StartGetting();
-  if (!pObj->DoProperty(pRuntime, propname.c_str(), value, sError)) {
-    pRuntime->Error(JSFormatErrorString(class_name, "GetProperty", sError));
-    return;
-  }
-  info.GetReturnValue().Set(value.GetJSValue()->ToV8Value(pRuntime));
-}
-
-template <class Alt>
-void JSSpecialPropPut(const char* class_name,
-                      v8::Local<v8::String> property,
-                      v8::Local<v8::Value> value,
-                      const v8::PropertyCallbackInfo<v8::Value>& 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()));
-  CFX_WideString sError;
-  CJS_PropValue PropValue(pRuntime, CJS_Value(pRuntime, value));
-  PropValue.StartSetting();
-  if (!pObj->DoProperty(pRuntime, propname.c_str(), PropValue, sError)) {
-    pRuntime->Error(JSFormatErrorString(class_name, "PutProperty", sError));
-  }
-}
-
-template <class Alt>
-void JSSpecialPropDel(const char* class_name,
-                      v8::Local<v8::String> property,
-                      const v8::PropertyCallbackInfo<v8::Boolean>& 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()));
-  CFX_WideString 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)(CJS_Runtime*,
-                    const std::vector<CJS_Value>&,
-                    CJS_Value&,
-                    CFX_WideString&)>
-void JSGlobalFunc(const char* func_name_string,
-                  const v8::FunctionCallbackInfo<v8::Value>& info) {
-  CJS_Runtime* pRuntime =
-      CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
-  if (!pRuntime)
-    return;
-  std::vector<CJS_Value> parameters;
-  for (unsigned int i = 0; i < (unsigned int)info.Length(); i++) {
-    parameters.push_back(CJS_Value(pRuntime, info[i]));
-  }
-  CJS_Value valueRes(pRuntime);
-  CFX_WideString sError;
-  if (!(*F)(pRuntime, parameters, valueRes, sError)) {
-    pRuntime->Error(JSFormatErrorString(func_name_string, nullptr, sError));
-    return;
-  }
-  info.GetReturnValue().Set(valueRes.ToV8Value(pRuntime));
-}
-
-#define JS_STATIC_GLOBAL_FUN(fun_name)                   \
-  static void fun_name##_static(                         \
-      const v8::FunctionCallbackInfo<v8::Value>& info) { \
-    JSGlobalFunc<fun_name>(#fun_name, info);             \
-  }
-
-#define JS_STATIC_DECLARE_GLOBAL_FUN()       \
-  static JSMethodSpec GlobalFunctionSpecs[]; \
-  static void DefineJSObjects(CFXJS_Engine* pEngine)
-
-#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
deleted file mode 100644
index bd1c8e2..0000000
--- a/fpdfsdk/javascript/JS_EventHandler.cpp
+++ /dev/null
@@ -1,653 +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/JS_EventHandler.h"
-
-#include "fpdfsdk/javascript/Document.h"
-#include "fpdfsdk/javascript/Field.h"
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_Object.h"
-#include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/cjs_event_context.h"
-#include "fpdfsdk/javascript/cjs_runtime.h"
-
-CJS_EventHandler::CJS_EventHandler(CJS_EventContext* pContext)
-    : m_pJSEventContext(pContext),
-      m_eEventType(JET_UNKNOWN),
-      m_bValid(false),
-      m_pWideStrChange(nullptr),
-      m_nCommitKey(-1),
-      m_bKeyDown(false),
-      m_bModifier(false),
-      m_bShift(false),
-      m_pISelEnd(nullptr),
-      m_nSelEndDu(0),
-      m_pISelStart(nullptr),
-      m_nSelStartDu(0),
-      m_bWillCommit(false),
-      m_pValue(nullptr),
-      m_bFieldFull(false),
-      m_pbRc(nullptr),
-      m_bRcDu(false),
-      m_pTargetBookMark(nullptr),
-      m_pTargetFormFillEnv(nullptr),
-      m_pTargetAnnot(nullptr) {}
-
-CJS_EventHandler::~CJS_EventHandler() {}
-
-void CJS_EventHandler::OnApp_Init() {
-  Initial(JET_APP_INIT);
-}
-
-void CJS_EventHandler::OnDoc_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                  const CFX_WideString& strTargetName) {
-  Initial(JET_DOC_OPEN);
-  m_pTargetFormFillEnv.Reset(pFormFillEnv);
-  m_strTargetName = strTargetName;
-}
-
-void CJS_EventHandler::OnDoc_WillPrint(
-    CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  Initial(JET_DOC_WILLPRINT);
-  m_pTargetFormFillEnv.Reset(pFormFillEnv);
-}
-
-void CJS_EventHandler::OnDoc_DidPrint(
-    CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  Initial(JET_DOC_DIDPRINT);
-  m_pTargetFormFillEnv.Reset(pFormFillEnv);
-}
-
-void CJS_EventHandler::OnDoc_WillSave(
-    CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  Initial(JET_DOC_WILLSAVE);
-  m_pTargetFormFillEnv.Reset(pFormFillEnv);
-}
-
-void CJS_EventHandler::OnDoc_DidSave(
-    CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  Initial(JET_DOC_DIDSAVE);
-  m_pTargetFormFillEnv.Reset(pFormFillEnv);
-}
-
-void CJS_EventHandler::OnDoc_WillClose(
-    CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  Initial(JET_DOC_WILLCLOSE);
-  m_pTargetFormFillEnv.Reset(pFormFillEnv);
-}
-
-void CJS_EventHandler::OnPage_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  Initial(JET_PAGE_OPEN);
-  m_pTargetFormFillEnv.Reset(pFormFillEnv);
-}
-
-void CJS_EventHandler::OnPage_Close(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  Initial(JET_PAGE_CLOSE);
-  m_pTargetFormFillEnv.Reset(pFormFillEnv);
-}
-
-void CJS_EventHandler::OnPage_InView(
-    CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  Initial(JET_PAGE_INVIEW);
-  m_pTargetFormFillEnv.Reset(pFormFillEnv);
-}
-
-void CJS_EventHandler::OnPage_OutView(
-    CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  Initial(JET_PAGE_OUTVIEW);
-  m_pTargetFormFillEnv.Reset(pFormFillEnv);
-}
-
-void CJS_EventHandler::OnField_MouseEnter(bool bModifier,
-                                          bool bShift,
-                                          CPDF_FormField* pTarget) {
-  Initial(JET_FIELD_MOUSEENTER);
-
-  m_bModifier = bModifier;
-  m_bShift = bShift;
-
-  m_strTargetName = pTarget->GetFullName();
-}
-
-void CJS_EventHandler::OnField_MouseExit(bool bModifier,
-                                         bool bShift,
-                                         CPDF_FormField* pTarget) {
-  Initial(JET_FIELD_MOUSEEXIT);
-
-  m_bModifier = bModifier;
-  m_bShift = bShift;
-  m_strTargetName = pTarget->GetFullName();
-}
-
-void CJS_EventHandler::OnField_MouseDown(bool bModifier,
-                                         bool bShift,
-                                         CPDF_FormField* pTarget) {
-  Initial(JET_FIELD_MOUSEDOWN);
-  m_eEventType = JET_FIELD_MOUSEDOWN;
-
-  m_bModifier = bModifier;
-  m_bShift = bShift;
-  m_strTargetName = pTarget->GetFullName();
-}
-
-void CJS_EventHandler::OnField_MouseUp(bool bModifier,
-                                       bool bShift,
-                                       CPDF_FormField* pTarget) {
-  Initial(JET_FIELD_MOUSEUP);
-
-  m_bModifier = bModifier;
-  m_bShift = bShift;
-  m_strTargetName = pTarget->GetFullName();
-}
-
-void CJS_EventHandler::OnField_Focus(bool bModifier,
-                                     bool bShift,
-                                     CPDF_FormField* pTarget,
-                                     const CFX_WideString& Value) {
-  Initial(JET_FIELD_FOCUS);
-
-  m_bModifier = bModifier;
-  m_bShift = bShift;
-  m_strTargetName = pTarget->GetFullName();
-  m_pValue = (CFX_WideString*)&Value;
-}
-
-void CJS_EventHandler::OnField_Blur(bool bModifier,
-                                    bool bShift,
-                                    CPDF_FormField* pTarget,
-                                    const CFX_WideString& Value) {
-  Initial(JET_FIELD_BLUR);
-
-  m_bModifier = bModifier;
-  m_bShift = bShift;
-  m_strTargetName = pTarget->GetFullName();
-  m_pValue = (CFX_WideString*)&Value;
-}
-
-void CJS_EventHandler::OnField_Keystroke(CFX_WideString& strChange,
-                                         const CFX_WideString& strChangeEx,
-                                         bool KeyDown,
-                                         bool bModifier,
-                                         int& nSelEnd,
-                                         int& nSelStart,
-                                         bool bShift,
-                                         CPDF_FormField* pTarget,
-                                         CFX_WideString& Value,
-                                         bool bWillCommit,
-                                         bool bFieldFull,
-                                         bool& bRc) {
-  Initial(JET_FIELD_KEYSTROKE);
-
-  m_nCommitKey = 0;
-  m_pWideStrChange = &strChange;
-  m_WideStrChangeEx = strChangeEx;
-  m_bKeyDown = KeyDown;
-  m_bModifier = bModifier;
-  m_pISelEnd = &nSelEnd;
-  m_pISelStart = &nSelStart;
-  m_bShift = bShift;
-  m_strTargetName = pTarget->GetFullName();
-  m_pValue = &Value;
-  m_bWillCommit = bWillCommit;
-  m_pbRc = &bRc;
-  m_bFieldFull = bFieldFull;
-}
-
-void CJS_EventHandler::OnField_Validate(CFX_WideString& strChange,
-                                        const CFX_WideString& strChangeEx,
-                                        bool bKeyDown,
-                                        bool bModifier,
-                                        bool bShift,
-                                        CPDF_FormField* pTarget,
-                                        CFX_WideString& Value,
-                                        bool& bRc) {
-  Initial(JET_FIELD_VALIDATE);
-
-  m_pWideStrChange = &strChange;
-  m_WideStrChangeEx = strChangeEx;
-  m_bKeyDown = bKeyDown;
-  m_bModifier = bModifier;
-  m_bShift = bShift;
-  m_strTargetName = pTarget->GetFullName();
-  m_pValue = &Value;
-  m_pbRc = &bRc;
-}
-
-void CJS_EventHandler::OnField_Calculate(CPDF_FormField* pSource,
-                                         CPDF_FormField* pTarget,
-                                         CFX_WideString& Value,
-                                         bool& bRc) {
-  Initial(JET_FIELD_CALCULATE);
-
-  if (pSource)
-    m_strSourceName = pSource->GetFullName();
-  m_strTargetName = pTarget->GetFullName();
-  m_pValue = &Value;
-  m_pbRc = &bRc;
-}
-
-void CJS_EventHandler::OnField_Format(CPDF_FormField* pTarget,
-                                      CFX_WideString& Value,
-                                      bool bWillCommit) {
-  Initial(JET_FIELD_FORMAT);
-
-  m_nCommitKey = 0;
-  m_strTargetName = pTarget->GetFullName();
-  m_pValue = &Value;
-  m_bWillCommit = bWillCommit;
-}
-
-void CJS_EventHandler::OnScreen_Focus(bool bModifier,
-                                      bool bShift,
-                                      CPDFSDK_Annot* pScreen) {
-  Initial(JET_SCREEN_FOCUS);
-
-  m_bModifier = bModifier;
-  m_bShift = bShift;
-  m_pTargetAnnot.Reset(pScreen);
-}
-
-void CJS_EventHandler::OnScreen_Blur(bool bModifier,
-                                     bool bShift,
-                                     CPDFSDK_Annot* pScreen) {
-  Initial(JET_SCREEN_BLUR);
-
-  m_bModifier = bModifier;
-  m_bShift = bShift;
-  m_pTargetAnnot.Reset(pScreen);
-}
-
-void CJS_EventHandler::OnScreen_Open(bool bModifier,
-                                     bool bShift,
-                                     CPDFSDK_Annot* pScreen) {
-  Initial(JET_SCREEN_OPEN);
-
-  m_bModifier = bModifier;
-  m_bShift = bShift;
-  m_pTargetAnnot.Reset(pScreen);
-}
-
-void CJS_EventHandler::OnScreen_Close(bool bModifier,
-                                      bool bShift,
-                                      CPDFSDK_Annot* pScreen) {
-  Initial(JET_SCREEN_CLOSE);
-
-  m_bModifier = bModifier;
-  m_bShift = bShift;
-  m_pTargetAnnot.Reset(pScreen);
-}
-
-void CJS_EventHandler::OnScreen_MouseDown(bool bModifier,
-                                          bool bShift,
-                                          CPDFSDK_Annot* pScreen) {
-  Initial(JET_SCREEN_MOUSEDOWN);
-
-  m_bModifier = bModifier;
-  m_bShift = bShift;
-  m_pTargetAnnot.Reset(pScreen);
-}
-
-void CJS_EventHandler::OnScreen_MouseUp(bool bModifier,
-                                        bool bShift,
-                                        CPDFSDK_Annot* pScreen) {
-  Initial(JET_SCREEN_MOUSEUP);
-
-  m_bModifier = bModifier;
-  m_bShift = bShift;
-  m_pTargetAnnot.Reset(pScreen);
-}
-
-void CJS_EventHandler::OnScreen_MouseEnter(bool bModifier,
-                                           bool bShift,
-                                           CPDFSDK_Annot* pScreen) {
-  Initial(JET_SCREEN_MOUSEENTER);
-
-  m_bModifier = bModifier;
-  m_bShift = bShift;
-  m_pTargetAnnot.Reset(pScreen);
-}
-
-void CJS_EventHandler::OnScreen_MouseExit(bool bModifier,
-                                          bool bShift,
-                                          CPDFSDK_Annot* pScreen) {
-  Initial(JET_SCREEN_MOUSEEXIT);
-
-  m_bModifier = bModifier;
-  m_bShift = bShift;
-  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.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.Reset(pScreen);
-}
-
-void CJS_EventHandler::OnLink_MouseUp(
-    CPDFSDK_FormFillEnvironment* pTargetFormFillEnv) {
-  Initial(JET_LINK_MOUSEUP);
-  m_pTargetFormFillEnv.Reset(pTargetFormFillEnv);
-}
-
-void CJS_EventHandler::OnBookmark_MouseUp(CPDF_Bookmark* pBookMark) {
-  Initial(JET_BOOKMARK_MOUSEUP);
-  m_pTargetBookMark = pBookMark;
-}
-
-void CJS_EventHandler::OnMenu_Exec(
-    CPDFSDK_FormFillEnvironment* pTargetFormFillEnv,
-    const CFX_WideString& strTargetName) {
-  Initial(JET_MENU_EXEC);
-  m_pTargetFormFillEnv.Reset(pTargetFormFillEnv);
-  m_strTargetName = strTargetName;
-}
-
-void CJS_EventHandler::OnExternal_Exec() {
-  Initial(JET_EXTERNAL_EXEC);
-}
-
-void CJS_EventHandler::OnBatchExec(
-    CPDFSDK_FormFillEnvironment* pTargetFormFillEnv) {
-  Initial(JET_BATCH_EXEC);
-  m_pTargetFormFillEnv.Reset(pTargetFormFillEnv);
-}
-
-void CJS_EventHandler::OnConsole_Exec() {
-  Initial(JET_CONSOLE_EXEC);
-}
-
-void CJS_EventHandler::Initial(JS_EVENT_T type) {
-  m_eEventType = type;
-
-  m_strTargetName = L"";
-  m_strSourceName = L"";
-  m_pWideStrChange = nullptr;
-  m_WideStrChangeDu = L"";
-  m_WideStrChangeEx = L"";
-  m_nCommitKey = -1;
-  m_bKeyDown = false;
-  m_bModifier = false;
-  m_bShift = false;
-  m_pISelEnd = nullptr;
-  m_nSelEndDu = 0;
-  m_pISelStart = nullptr;
-  m_nSelStartDu = 0;
-  m_bWillCommit = false;
-  m_pValue = nullptr;
-  m_bFieldFull = false;
-  m_pbRc = nullptr;
-  m_bRcDu = false;
-
-  m_pTargetBookMark = nullptr;
-  m_pTargetFormFillEnv.Reset();
-  m_pTargetAnnot.Reset();
-
-  m_bValid = true;
-}
-
-void CJS_EventHandler::Destroy() {
-  m_bValid = false;
-}
-
-bool CJS_EventHandler::IsValid() {
-  return m_bValid;
-}
-
-CFX_WideString& CJS_EventHandler::Change() {
-  if (m_pWideStrChange) {
-    return *m_pWideStrChange;
-  }
-  return m_WideStrChangeDu;
-}
-
-CFX_WideString CJS_EventHandler::ChangeEx() {
-  return m_WideStrChangeEx;
-}
-
-int CJS_EventHandler::CommitKey() {
-  return m_nCommitKey;
-}
-
-bool CJS_EventHandler::FieldFull() {
-  return m_bFieldFull;
-}
-
-bool CJS_EventHandler::KeyDown() {
-  return m_bKeyDown;
-}
-
-bool CJS_EventHandler::Modifier() {
-  return m_bModifier;
-}
-
-const FX_WCHAR* CJS_EventHandler::Name() {
-  switch (m_eEventType) {
-    case JET_APP_INIT:
-      return L"Init";
-    case JET_BATCH_EXEC:
-      return L"Exec";
-    case JET_BOOKMARK_MOUSEUP:
-      return L"Mouse Up";
-    case JET_CONSOLE_EXEC:
-      return L"Exec";
-    case JET_DOC_DIDPRINT:
-      return L"DidPrint";
-    case JET_DOC_DIDSAVE:
-      return L"DidSave";
-    case JET_DOC_OPEN:
-      return L"Open";
-    case JET_DOC_WILLCLOSE:
-      return L"WillClose";
-    case JET_DOC_WILLPRINT:
-      return L"WillPrint";
-    case JET_DOC_WILLSAVE:
-      return L"WillSave";
-    case JET_EXTERNAL_EXEC:
-      return L"Exec";
-    case JET_FIELD_FOCUS:
-    case JET_SCREEN_FOCUS:
-      return L"Focus";
-    case JET_FIELD_BLUR:
-    case JET_SCREEN_BLUR:
-      return L"Blur";
-    case JET_FIELD_MOUSEDOWN:
-    case JET_SCREEN_MOUSEDOWN:
-      return L"Mouse Down";
-    case JET_FIELD_MOUSEUP:
-    case JET_SCREEN_MOUSEUP:
-      return L"Mouse Up";
-    case JET_FIELD_MOUSEENTER:
-    case JET_SCREEN_MOUSEENTER:
-      return L"Mouse Enter";
-    case JET_FIELD_MOUSEEXIT:
-    case JET_SCREEN_MOUSEEXIT:
-      return L"Mouse Exit";
-    case JET_FIELD_CALCULATE:
-      return L"Calculate";
-    case JET_FIELD_FORMAT:
-      return L"Format";
-    case JET_FIELD_KEYSTROKE:
-      return L"Keystroke";
-    case JET_FIELD_VALIDATE:
-      return L"Validate";
-    case JET_LINK_MOUSEUP:
-      return L"Mouse Up";
-    case JET_MENU_EXEC:
-      return L"Exec";
-    case JET_PAGE_OPEN:
-    case JET_SCREEN_OPEN:
-      return L"Open";
-    case JET_PAGE_CLOSE:
-    case JET_SCREEN_CLOSE:
-      return L"Close";
-    case JET_SCREEN_INVIEW:
-    case JET_PAGE_INVIEW:
-      return L"InView";
-    case JET_PAGE_OUTVIEW:
-    case JET_SCREEN_OUTVIEW:
-      return L"OutView";
-    default:
-      return L"";
-  }
-}
-
-const FX_WCHAR* CJS_EventHandler::Type() {
-  switch (m_eEventType) {
-    case JET_APP_INIT:
-      return L"App";
-    case JET_BATCH_EXEC:
-      return L"Batch";
-    case JET_BOOKMARK_MOUSEUP:
-      return L"BookMark";
-    case JET_CONSOLE_EXEC:
-      return L"Console";
-    case JET_DOC_DIDPRINT:
-    case JET_DOC_DIDSAVE:
-    case JET_DOC_OPEN:
-    case JET_DOC_WILLCLOSE:
-    case JET_DOC_WILLPRINT:
-    case JET_DOC_WILLSAVE:
-      return L"Doc";
-    case JET_EXTERNAL_EXEC:
-      return L"External";
-    case JET_FIELD_BLUR:
-    case JET_FIELD_FOCUS:
-    case JET_FIELD_MOUSEDOWN:
-    case JET_FIELD_MOUSEENTER:
-    case JET_FIELD_MOUSEEXIT:
-    case JET_FIELD_MOUSEUP:
-    case JET_FIELD_CALCULATE:
-    case JET_FIELD_FORMAT:
-    case JET_FIELD_KEYSTROKE:
-    case JET_FIELD_VALIDATE:
-      return L"Field";
-    case JET_SCREEN_FOCUS:
-    case JET_SCREEN_BLUR:
-    case JET_SCREEN_OPEN:
-    case JET_SCREEN_CLOSE:
-    case JET_SCREEN_MOUSEDOWN:
-    case JET_SCREEN_MOUSEUP:
-    case JET_SCREEN_MOUSEENTER:
-    case JET_SCREEN_MOUSEEXIT:
-    case JET_SCREEN_INVIEW:
-    case JET_SCREEN_OUTVIEW:
-      return L"Screen";
-    case JET_LINK_MOUSEUP:
-      return L"Link";
-    case JET_MENU_EXEC:
-      return L"Menu";
-    case JET_PAGE_OPEN:
-    case JET_PAGE_CLOSE:
-    case JET_PAGE_INVIEW:
-    case JET_PAGE_OUTVIEW:
-      return L"Page";
-    default:
-      return L"";
-  }
-}
-
-bool& CJS_EventHandler::Rc() {
-  if (m_pbRc) {
-    return *m_pbRc;
-  }
-  return m_bRcDu;
-}
-
-int& CJS_EventHandler::SelEnd() {
-  if (m_pISelEnd) {
-    return *m_pISelEnd;
-  }
-  return m_nSelEndDu;
-}
-
-int& CJS_EventHandler::SelStart() {
-  if (m_pISelStart) {
-    return *m_pISelStart;
-  }
-  return m_nSelStartDu;
-}
-
-bool CJS_EventHandler::Shift() {
-  return m_bShift;
-}
-
-Field* CJS_EventHandler::Source() {
-  CJS_Runtime* pRuntime = m_pJSEventContext->GetJSRuntime();
-  v8::Local<v8::Object> pDocObj =
-      pRuntime->NewFxDynamicObj(CJS_Document::g_nObjDefnID);
-  if (pDocObj.IsEmpty())
-    return nullptr;
-
-  v8::Local<v8::Object> pFieldObj =
-      pRuntime->NewFxDynamicObj(CJS_Field::g_nObjDefnID);
-  if (pFieldObj.IsEmpty())
-    return nullptr;
-
-  CJS_Document* pJSDocument =
-      static_cast<CJS_Document*>(pRuntime->GetObjectPrivate(pDocObj));
-  CJS_Field* pJSField =
-      static_cast<CJS_Field*>(pRuntime->GetObjectPrivate(pFieldObj));
-
-  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_pJSEventContext->GetJSRuntime();
-  v8::Local<v8::Object> pDocObj =
-      pRuntime->NewFxDynamicObj(CJS_Document::g_nObjDefnID);
-  if (pDocObj.IsEmpty())
-    return nullptr;
-
-  v8::Local<v8::Object> pFieldObj =
-      pRuntime->NewFxDynamicObj(CJS_Field::g_nObjDefnID);
-  if (pFieldObj.IsEmpty())
-    return nullptr;
-
-  CJS_Document* pJSDocument =
-      static_cast<CJS_Document*>(pRuntime->GetObjectPrivate(pDocObj));
-  CJS_Field* pJSField =
-      static_cast<CJS_Field*>(pRuntime->GetObjectPrivate(pFieldObj));
-
-  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;
-}
-
-CFX_WideString& CJS_EventHandler::Value() {
-  return *m_pValue;
-}
-
-bool CJS_EventHandler::WillCommit() {
-  return m_bWillCommit;
-}
-
-CFX_WideString CJS_EventHandler::TargetName() {
-  return m_strTargetName;
-}
diff --git a/fpdfsdk/javascript/JS_EventHandler.h b/fpdfsdk/javascript/JS_EventHandler.h
deleted file mode 100644
index b9836b0..0000000
--- a/fpdfsdk/javascript/JS_EventHandler.h
+++ /dev/null
@@ -1,196 +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 FPDFSDK_JAVASCRIPT_JS_EVENTHANDLER_H_
-#define FPDFSDK_JAVASCRIPT_JS_EVENTHANDLER_H_
-
-#include "core/fxcrt/fx_string.h"
-#include "core/fxcrt/fx_system.h"
-#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
-
-class CJS_EventContext;
-class CPDFSDK_Annot;
-class CPDF_Bookmark;
-class CPDF_FormField;
-class Field;
-
-enum JS_EVENT_T {
-  JET_UNKNOWN,
-  JET_APP_INIT,
-  JET_DOC_OPEN,
-  JET_DOC_WILLPRINT,
-  JET_DOC_DIDPRINT,
-  JET_DOC_WILLSAVE,
-  JET_DOC_DIDSAVE,
-  JET_DOC_WILLCLOSE,
-  JET_PAGE_OPEN,
-  JET_PAGE_CLOSE,
-  JET_PAGE_INVIEW,
-  JET_PAGE_OUTVIEW,
-  JET_FIELD_MOUSEDOWN,
-  JET_FIELD_MOUSEUP,
-  JET_FIELD_MOUSEENTER,
-  JET_FIELD_MOUSEEXIT,
-  JET_FIELD_FOCUS,
-  JET_FIELD_BLUR,
-  JET_FIELD_KEYSTROKE,
-  JET_FIELD_VALIDATE,
-  JET_FIELD_CALCULATE,
-  JET_FIELD_FORMAT,
-  JET_SCREEN_FOCUS,
-  JET_SCREEN_BLUR,
-  JET_SCREEN_OPEN,
-  JET_SCREEN_CLOSE,
-  JET_SCREEN_MOUSEDOWN,
-  JET_SCREEN_MOUSEUP,
-  JET_SCREEN_MOUSEENTER,
-  JET_SCREEN_MOUSEEXIT,
-  JET_SCREEN_INVIEW,
-  JET_SCREEN_OUTVIEW,
-  JET_BATCH_EXEC,
-  JET_MENU_EXEC,
-  JET_CONSOLE_EXEC,
-  JET_EXTERNAL_EXEC,
-  JET_BOOKMARK_MOUSEUP,
-  JET_LINK_MOUSEUP
-};
-
-class CJS_EventHandler {
- public:
-  explicit CJS_EventHandler(CJS_EventContext* pContext);
-  virtual ~CJS_EventHandler();
-
-  void OnApp_Init();
-
-  void OnDoc_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                  const CFX_WideString& strTargetName);
-  void OnDoc_WillPrint(CPDFSDK_FormFillEnvironment* pFormFillEnv);
-  void OnDoc_DidPrint(CPDFSDK_FormFillEnvironment* pFormFillEnv);
-  void OnDoc_WillSave(CPDFSDK_FormFillEnvironment* pFormFillEnv);
-  void OnDoc_DidSave(CPDFSDK_FormFillEnvironment* pFormFillEnv);
-  void OnDoc_WillClose(CPDFSDK_FormFillEnvironment* pFormFillEnv);
-
-  void OnPage_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv);
-  void OnPage_Close(CPDFSDK_FormFillEnvironment* pFormFillEnv);
-  void OnPage_InView(CPDFSDK_FormFillEnvironment* pFormFillEnv);
-  void OnPage_OutView(CPDFSDK_FormFillEnvironment* pFormFillEnv);
-
-  void OnField_Calculate(CPDF_FormField* pSource,
-                         CPDF_FormField* pTarget,
-                         CFX_WideString& Value,
-                         bool& bRc);
-  void OnField_Format(CPDF_FormField* pTarget,
-                      CFX_WideString& Value,
-                      bool bWillCommit);
-  void OnField_Keystroke(CFX_WideString& strChange,
-                         const CFX_WideString& strChangeEx,
-                         bool KeyDown,
-                         bool bModifier,
-                         int& nSelEnd,
-                         int& nSelStart,
-                         bool bShift,
-                         CPDF_FormField* pTarget,
-                         CFX_WideString& Value,
-                         bool bWillCommit,
-                         bool bFieldFull,
-                         bool& bRc);
-  void OnField_Validate(CFX_WideString& strChange,
-                        const CFX_WideString& strChangeEx,
-                        bool bKeyDown,
-                        bool bModifier,
-                        bool bShift,
-                        CPDF_FormField* pTarget,
-                        CFX_WideString& Value,
-                        bool& bRc);
-
-  void OnField_MouseDown(bool bModifier, bool bShift, CPDF_FormField* pTarget);
-  void OnField_MouseEnter(bool bModifier, bool bShift, CPDF_FormField* pTarget);
-  void OnField_MouseExit(bool bModifier, bool bShift, CPDF_FormField* pTarget);
-  void OnField_MouseUp(bool bModifier, bool bShift, CPDF_FormField* pTarget);
-  void OnField_Blur(bool bModifier,
-                    bool bShift,
-                    CPDF_FormField* pTarget,
-                    const CFX_WideString& Value);
-  void OnField_Focus(bool bModifier,
-                     bool bShift,
-                     CPDF_FormField* pTarget,
-                     const CFX_WideString& Value);
-
-  void OnScreen_Focus(bool bModifier, bool bShift, CPDFSDK_Annot* pScreen);
-  void OnScreen_Blur(bool bModifier, bool bShift, CPDFSDK_Annot* pScreen);
-  void OnScreen_Open(bool bModifier, bool bShift, CPDFSDK_Annot* pScreen);
-  void OnScreen_Close(bool bModifier, bool bShift, CPDFSDK_Annot* pScreen);
-  void OnScreen_MouseDown(bool bModifier, bool bShift, CPDFSDK_Annot* pScreen);
-  void OnScreen_MouseUp(bool bModifier, bool bShift, CPDFSDK_Annot* pScreen);
-  void OnScreen_MouseEnter(bool bModifier, bool bShift, CPDFSDK_Annot* pScreen);
-  void OnScreen_MouseExit(bool bModifier, bool bShift, CPDFSDK_Annot* pScreen);
-  void OnScreen_InView(bool bModifier, bool bShift, CPDFSDK_Annot* pScreen);
-  void OnScreen_OutView(bool bModifier, bool bShift, CPDFSDK_Annot* pScreen);
-
-  void OnBookmark_MouseUp(CPDF_Bookmark* pBookMark);
-  void OnLink_MouseUp(CPDFSDK_FormFillEnvironment* pFormFillEnv);
-
-  void OnMenu_Exec(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                   const CFX_WideString& strTargetName);
-  void OnBatchExec(CPDFSDK_FormFillEnvironment* pFormFillEnv);
-  void OnConsole_Exec();
-  void OnExternal_Exec();
-
- public:
-  void Initial(JS_EVENT_T type);
-  void Destroy();
-  bool IsValid();
-
-  CFX_WideString& Change();
-  CFX_WideString ChangeEx();
-  int CommitKey();
-  bool FieldFull();
-  bool KeyDown();
-  bool Modifier();
-  const FX_WCHAR* Name();
-  const FX_WCHAR* Type();
-  bool& Rc();
-  int& SelEnd();
-  int& SelStart();
-  bool Shift();
-  Field* Source();
-  Field* Target_Field();
-  CFX_WideString& Value();
-  bool WillCommit();
-  CFX_WideString TargetName();
-
-  JS_EVENT_T EventType() { return m_eEventType; }
-
- public:
-  CJS_EventContext* const m_pJSEventContext;  // Not Owned.
-  JS_EVENT_T m_eEventType;
-  bool m_bValid;
-
-  CFX_WideString m_strTargetName;
-  CFX_WideString m_strSourceName;
-  CFX_WideString* m_pWideStrChange;
-  CFX_WideString m_WideStrChangeDu;
-  CFX_WideString m_WideStrChangeEx;
-  int m_nCommitKey;
-  bool m_bKeyDown;
-  bool m_bModifier;
-  bool m_bShift;
-  int* m_pISelEnd;
-  int m_nSelEndDu;
-  int* m_pISelStart;
-  int m_nSelStartDu;
-  bool m_bWillCommit;
-  CFX_WideString* m_pValue;
-  bool m_bFieldFull;
-  bool* m_pbRc;
-  bool m_bRcDu;
-
-  CPDF_Bookmark* m_pTargetBookMark;
-  CPDFSDK_FormFillEnvironment::ObservedPtr m_pTargetFormFillEnv;
-  CPDFSDK_Annot::ObservedPtr m_pTargetAnnot;
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_JS_EVENTHANDLER_H_
diff --git a/fpdfsdk/javascript/JS_GlobalData.cpp b/fpdfsdk/javascript/JS_GlobalData.cpp
deleted file mode 100644
index 68d929f..0000000
--- a/fpdfsdk/javascript/JS_GlobalData.cpp
+++ /dev/null
@@ -1,396 +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/JS_GlobalData.h"
-
-#include <utility>
-
-#include "core/fdrm/crypto/fx_crypt.h"
-#include "third_party/base/stl_util.h"
-
-#define JS_MAXGLOBALDATA (1024 * 4 - 8)
-
-#define READER_JS_GLOBALDATA_FILENAME L"Reader_JsGlobal.Data"
-#define PHANTOM_JS_GLOBALDATA_FILENAME L"Phantom_JsGlobal.Data"
-#define SDK_JS_GLOBALDATA_FILENAME L"SDK_JsGlobal.Data"
-
-namespace {
-
-const uint8_t JS_RC4KEY[] = {
-    0x19, 0xa8, 0xe8, 0x01, 0xf6, 0xa8, 0xb6, 0x4d, 0x82, 0x04, 0x45, 0x6d,
-    0xb4, 0xcf, 0xd7, 0x77, 0x67, 0xf9, 0x75, 0x9f, 0xf0, 0xe0, 0x1e, 0x51,
-    0xee, 0x46, 0xfd, 0x0b, 0xc9, 0x93, 0x25, 0x55, 0x4a, 0xee, 0xe0, 0x16,
-    0xd0, 0xdf, 0x8c, 0xfa, 0x2a, 0xa9, 0x49, 0xfd, 0x97, 0x1c, 0x0e, 0x22,
-    0x13, 0x28, 0x7c, 0xaf, 0xc4, 0xfc, 0x9c, 0x12, 0x65, 0x8c, 0x4e, 0x5b,
-    0x04, 0x75, 0x89, 0xc9, 0xb1, 0xed, 0x50, 0xca, 0x96, 0x6f, 0x1a, 0x7a,
-    0xfe, 0x58, 0x5d, 0xec, 0x19, 0x4a, 0xf6, 0x35, 0x6a, 0x97, 0x14, 0x00,
-    0x0e, 0xd0, 0x6b, 0xbb, 0xd5, 0x75, 0x55, 0x8b, 0x6e, 0x6b, 0x19, 0xa0,
-    0xf8, 0x77, 0xd5, 0xa3};
-
-// Returns true if non-empty, setting sPropName
-bool TrimPropName(CFX_ByteString* sPropName) {
-  sPropName->TrimLeft();
-  sPropName->TrimRight();
-  return sPropName->GetLength() != 0;
-}
-
-CJS_GlobalData* g_pInstance = nullptr;
-
-}  // namespace
-
-// static
-CJS_GlobalData* CJS_GlobalData::GetRetainedInstance(
-    CPDFSDK_FormFillEnvironment* pApp) {
-  if (!g_pInstance) {
-    g_pInstance = new CJS_GlobalData();
-  }
-  ++g_pInstance->m_RefCount;
-  return g_pInstance;
-}
-
-void CJS_GlobalData::Release() {
-  if (!--m_RefCount) {
-    delete g_pInstance;
-    g_pInstance = nullptr;
-  }
-}
-
-CJS_GlobalData::CJS_GlobalData()
-    : m_RefCount(0), m_sFilePath(SDK_JS_GLOBALDATA_FILENAME) {
-  LoadGlobalPersistentVariables();
-}
-
-CJS_GlobalData::~CJS_GlobalData() {
-  SaveGlobalPersisitentVariables();
-}
-
-CJS_GlobalData::iterator CJS_GlobalData::FindGlobalVariable(
-    const CFX_ByteString& propname) {
-  for (auto it = m_arrayGlobalData.begin(); it != m_arrayGlobalData.end();
-       ++it) {
-    if ((*it)->data.sKey == propname)
-      return it;
-  }
-  return m_arrayGlobalData.end();
-}
-
-CJS_GlobalData::const_iterator CJS_GlobalData::FindGlobalVariable(
-    const CFX_ByteString& propname) const {
-  for (auto it = m_arrayGlobalData.begin(); it != m_arrayGlobalData.end();
-       ++it) {
-    if ((*it)->data.sKey == propname)
-      return it;
-  }
-  return m_arrayGlobalData.end();
-}
-
-CJS_GlobalData_Element* CJS_GlobalData::GetGlobalVariable(
-    const CFX_ByteString& propname) {
-  auto iter = FindGlobalVariable(propname);
-  return iter != m_arrayGlobalData.end() ? iter->get() : nullptr;
-}
-
-void CJS_GlobalData::SetGlobalVariableNumber(const CFX_ByteString& propname,
-                                             double dData) {
-  CFX_ByteString sPropName(propname);
-  if (!TrimPropName(&sPropName))
-    return;
-
-  if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) {
-    pData->data.nType = JS_GlobalDataType::NUMBER;
-    pData->data.dData = dData;
-    return;
-  }
-  std::unique_ptr<CJS_GlobalData_Element> pNewData(new CJS_GlobalData_Element);
-  pNewData->data.sKey = sPropName;
-  pNewData->data.nType = JS_GlobalDataType::NUMBER;
-  pNewData->data.dData = dData;
-  m_arrayGlobalData.push_back(std::move(pNewData));
-}
-
-void CJS_GlobalData::SetGlobalVariableBoolean(const CFX_ByteString& propname,
-                                              bool bData) {
-  CFX_ByteString sPropName(propname);
-  if (!TrimPropName(&sPropName))
-    return;
-
-  if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) {
-    pData->data.nType = JS_GlobalDataType::BOOLEAN;
-    pData->data.bData = bData;
-    return;
-  }
-  std::unique_ptr<CJS_GlobalData_Element> pNewData(new CJS_GlobalData_Element);
-  pNewData->data.sKey = sPropName;
-  pNewData->data.nType = JS_GlobalDataType::BOOLEAN;
-  pNewData->data.bData = bData;
-  m_arrayGlobalData.push_back(std::move(pNewData));
-}
-
-void CJS_GlobalData::SetGlobalVariableString(const CFX_ByteString& propname,
-                                             const CFX_ByteString& sData) {
-  CFX_ByteString sPropName(propname);
-  if (!TrimPropName(&sPropName))
-    return;
-
-  if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) {
-    pData->data.nType = JS_GlobalDataType::STRING;
-    pData->data.sData = sData;
-    return;
-  }
-  std::unique_ptr<CJS_GlobalData_Element> pNewData(new CJS_GlobalData_Element);
-  pNewData->data.sKey = sPropName;
-  pNewData->data.nType = JS_GlobalDataType::STRING;
-  pNewData->data.sData = sData;
-  m_arrayGlobalData.push_back(std::move(pNewData));
-}
-
-void CJS_GlobalData::SetGlobalVariableObject(
-    const CFX_ByteString& propname,
-    const CJS_GlobalVariableArray& array) {
-  CFX_ByteString sPropName(propname);
-  if (!TrimPropName(&sPropName))
-    return;
-
-  if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) {
-    pData->data.nType = JS_GlobalDataType::OBJECT;
-    pData->data.objData.Copy(array);
-    return;
-  }
-  std::unique_ptr<CJS_GlobalData_Element> pNewData(new CJS_GlobalData_Element);
-  pNewData->data.sKey = sPropName;
-  pNewData->data.nType = JS_GlobalDataType::OBJECT;
-  pNewData->data.objData.Copy(array);
-  m_arrayGlobalData.push_back(std::move(pNewData));
-}
-
-void CJS_GlobalData::SetGlobalVariableNull(const CFX_ByteString& propname) {
-  CFX_ByteString sPropName(propname);
-  if (!TrimPropName(&sPropName))
-    return;
-
-  if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) {
-    pData->data.nType = JS_GlobalDataType::NULLOBJ;
-    return;
-  }
-  std::unique_ptr<CJS_GlobalData_Element> pNewData(new CJS_GlobalData_Element);
-  pNewData->data.sKey = sPropName;
-  pNewData->data.nType = JS_GlobalDataType::NULLOBJ;
-  m_arrayGlobalData.push_back(std::move(pNewData));
-}
-
-bool CJS_GlobalData::SetGlobalVariablePersistent(const CFX_ByteString& propname,
-                                                 bool bPersistent) {
-  CFX_ByteString sPropName(propname);
-  if (!TrimPropName(&sPropName))
-    return false;
-
-  CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName);
-  if (!pData)
-    return false;
-
-  pData->bPersistent = bPersistent;
-  return true;
-}
-
-bool CJS_GlobalData::DeleteGlobalVariable(const CFX_ByteString& propname) {
-  CFX_ByteString sPropName(propname);
-  if (!TrimPropName(&sPropName))
-    return false;
-
-  auto iter = FindGlobalVariable(sPropName);
-  if (iter == m_arrayGlobalData.end())
-    return false;
-
-  m_arrayGlobalData.erase(iter);
-  return true;
-}
-
-int32_t CJS_GlobalData::GetSize() const {
-  return pdfium::CollectionSize<int32_t>(m_arrayGlobalData);
-}
-
-CJS_GlobalData_Element* CJS_GlobalData::GetAt(int index) const {
-  if (index < 0 || index >= GetSize())
-    return nullptr;
-  return m_arrayGlobalData[index].get();
-}
-
-void CJS_GlobalData::LoadGlobalPersistentVariables() {
-  uint8_t* pBuffer = nullptr;
-  int32_t nLength = 0;
-
-  LoadFileBuffer(m_sFilePath.c_str(), pBuffer, nLength);
-  CRYPT_ArcFourCryptBlock(pBuffer, nLength, JS_RC4KEY, sizeof(JS_RC4KEY));
-
-  if (pBuffer) {
-    uint8_t* p = pBuffer;
-    uint16_t wType = *((uint16_t*)p);
-    p += sizeof(uint16_t);
-
-    if (wType == (uint16_t)(('X' << 8) | 'F')) {
-      uint16_t wVersion = *((uint16_t*)p);
-      p += sizeof(uint16_t);
-
-      ASSERT(wVersion <= 2);
-
-      uint32_t dwCount = *((uint32_t*)p);
-      p += sizeof(uint32_t);
-
-      uint32_t dwSize = *((uint32_t*)p);
-      p += sizeof(uint32_t);
-
-      if (dwSize == nLength - sizeof(uint16_t) * 2 - sizeof(uint32_t) * 2) {
-        for (int32_t i = 0, sz = dwCount; i < sz; i++) {
-          if (p > pBuffer + nLength)
-            break;
-
-          uint32_t dwNameLen = *((uint32_t*)p);
-          p += sizeof(uint32_t);
-
-          if (p + dwNameLen > pBuffer + nLength)
-            break;
-
-          CFX_ByteString sEntry = CFX_ByteString(p, dwNameLen);
-          p += sizeof(char) * dwNameLen;
-
-          JS_GlobalDataType wDataType =
-              static_cast<JS_GlobalDataType>(*((uint16_t*)p));
-          p += sizeof(uint16_t);
-
-          switch (wDataType) {
-            case JS_GlobalDataType::NUMBER: {
-              double dData = 0;
-              switch (wVersion) {
-                case 1: {
-                  uint32_t dwData = *((uint32_t*)p);
-                  p += sizeof(uint32_t);
-                  dData = dwData;
-                } break;
-                case 2: {
-                  dData = *((double*)p);
-                  p += sizeof(double);
-                } break;
-              }
-              SetGlobalVariableNumber(sEntry, dData);
-              SetGlobalVariablePersistent(sEntry, true);
-            } break;
-            case JS_GlobalDataType::BOOLEAN: {
-              uint16_t wData = *((uint16_t*)p);
-              p += sizeof(uint16_t);
-              SetGlobalVariableBoolean(sEntry, (bool)(wData == 1));
-              SetGlobalVariablePersistent(sEntry, true);
-            } break;
-            case JS_GlobalDataType::STRING: {
-              uint32_t dwLength = *((uint32_t*)p);
-              p += sizeof(uint32_t);
-
-              if (p + dwLength > pBuffer + nLength)
-                break;
-
-              SetGlobalVariableString(sEntry, CFX_ByteString(p, dwLength));
-              SetGlobalVariablePersistent(sEntry, true);
-              p += sizeof(char) * dwLength;
-            } break;
-            case JS_GlobalDataType::NULLOBJ: {
-              SetGlobalVariableNull(sEntry);
-              SetGlobalVariablePersistent(sEntry, true);
-            }
-            case JS_GlobalDataType::OBJECT:
-              break;
-          }
-        }
-      }
-    }
-    FX_Free(pBuffer);
-  }
-}
-
-void CJS_GlobalData::SaveGlobalPersisitentVariables() {
-  uint32_t nCount = 0;
-  CFX_BinaryBuf sData;
-  for (const auto& pElement : m_arrayGlobalData) {
-    if (pElement->bPersistent) {
-      CFX_BinaryBuf sElement;
-      MakeByteString(pElement->data.sKey, &pElement->data, sElement);
-      if (sData.GetSize() + sElement.GetSize() > JS_MAXGLOBALDATA)
-        break;
-
-      sData.AppendBlock(sElement.GetBuffer(), sElement.GetSize());
-      nCount++;
-    }
-  }
-
-  CFX_BinaryBuf sFile;
-  uint16_t wType = (uint16_t)(('X' << 8) | 'F');
-  sFile.AppendBlock(&wType, sizeof(uint16_t));
-  uint16_t wVersion = 2;
-  sFile.AppendBlock(&wVersion, sizeof(uint16_t));
-  sFile.AppendBlock(&nCount, sizeof(uint32_t));
-  uint32_t dwSize = sData.GetSize();
-  sFile.AppendBlock(&dwSize, sizeof(uint32_t));
-
-  sFile.AppendBlock(sData.GetBuffer(), sData.GetSize());
-
-  CRYPT_ArcFourCryptBlock(sFile.GetBuffer(), sFile.GetSize(), JS_RC4KEY,
-                          sizeof(JS_RC4KEY));
-  WriteFileBuffer(m_sFilePath.c_str(), (const FX_CHAR*)sFile.GetBuffer(),
-                  sFile.GetSize());
-}
-
-void CJS_GlobalData::LoadFileBuffer(const FX_WCHAR* sFilePath,
-                                    uint8_t*& pBuffer,
-                                    int32_t& nLength) {
-  // UnSupport.
-}
-
-void CJS_GlobalData::WriteFileBuffer(const FX_WCHAR* sFilePath,
-                                     const FX_CHAR* pBuffer,
-                                     int32_t nLength) {
-  // UnSupport.
-}
-
-void CJS_GlobalData::MakeByteString(const CFX_ByteString& name,
-                                    CJS_KeyValue* pData,
-                                    CFX_BinaryBuf& sData) {
-  switch (pData->nType) {
-    case JS_GlobalDataType::NUMBER: {
-      uint32_t dwNameLen = (uint32_t)name.GetLength();
-      sData.AppendBlock(&dwNameLen, sizeof(uint32_t));
-      sData.AppendString(name);
-      sData.AppendBlock(&pData->nType, sizeof(uint16_t));
-
-      double dData = pData->dData;
-      sData.AppendBlock(&dData, sizeof(double));
-    } break;
-    case JS_GlobalDataType::BOOLEAN: {
-      uint32_t dwNameLen = (uint32_t)name.GetLength();
-      sData.AppendBlock(&dwNameLen, sizeof(uint32_t));
-      sData.AppendString(name);
-      sData.AppendBlock(&pData->nType, sizeof(uint16_t));
-
-      uint16_t wData = (uint16_t)pData->bData;
-      sData.AppendBlock(&wData, sizeof(uint16_t));
-    } break;
-    case JS_GlobalDataType::STRING: {
-      uint32_t dwNameLen = (uint32_t)name.GetLength();
-      sData.AppendBlock(&dwNameLen, sizeof(uint32_t));
-      sData.AppendString(name);
-      sData.AppendBlock(&pData->nType, sizeof(uint16_t));
-
-      uint32_t dwDataLen = (uint32_t)pData->sData.GetLength();
-      sData.AppendBlock(&dwDataLen, sizeof(uint32_t));
-      sData.AppendString(pData->sData);
-    } break;
-    case JS_GlobalDataType::NULLOBJ: {
-      uint32_t dwNameLen = (uint32_t)name.GetLength();
-      sData.AppendBlock(&dwNameLen, sizeof(uint32_t));
-      sData.AppendString(name);
-      sData.AppendBlock(&pData->nType, sizeof(uint32_t));
-    } break;
-    default:
-      break;
-  }
-}
diff --git a/fpdfsdk/javascript/JS_GlobalData.h b/fpdfsdk/javascript/JS_GlobalData.h
deleted file mode 100644
index c8947cd..0000000
--- a/fpdfsdk/javascript/JS_GlobalData.h
+++ /dev/null
@@ -1,77 +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 FPDFSDK_JAVASCRIPT_JS_GLOBALDATA_H_
-#define FPDFSDK_JAVASCRIPT_JS_GLOBALDATA_H_
-
-#include <memory>
-#include <vector>
-
-#include "core/fxcrt/fx_basic.h"
-#include "fpdfsdk/javascript/JS_KeyValue.h"
-
-class CPDFSDK_FormFillEnvironment;
-
-class CJS_GlobalData_Element {
- public:
-  CJS_GlobalData_Element() {}
-  ~CJS_GlobalData_Element() {}
-
-  CJS_KeyValue data;
-  bool bPersistent;
-};
-
-class CJS_GlobalData {
- public:
-  static CJS_GlobalData* GetRetainedInstance(CPDFSDK_FormFillEnvironment* pApp);
-  void Release();
-
-  void SetGlobalVariableNumber(const CFX_ByteString& propname, double dData);
-  void SetGlobalVariableBoolean(const CFX_ByteString& propname, bool bData);
-  void SetGlobalVariableString(const CFX_ByteString& propname,
-                               const CFX_ByteString& sData);
-  void SetGlobalVariableObject(const CFX_ByteString& propname,
-                               const CJS_GlobalVariableArray& array);
-  void SetGlobalVariableNull(const CFX_ByteString& propname);
-  bool SetGlobalVariablePersistent(const CFX_ByteString& propname,
-                                   bool bPersistent);
-  bool DeleteGlobalVariable(const CFX_ByteString& propname);
-
-  int32_t GetSize() const;
-  CJS_GlobalData_Element* GetAt(int index) const;
-
- private:
-  using iterator =
-      std::vector<std::unique_ptr<CJS_GlobalData_Element>>::iterator;
-  using const_iterator =
-      std::vector<std::unique_ptr<CJS_GlobalData_Element>>::const_iterator;
-
-  CJS_GlobalData();
-  ~CJS_GlobalData();
-
-  void LoadGlobalPersistentVariables();
-  void SaveGlobalPersisitentVariables();
-
-  CJS_GlobalData_Element* GetGlobalVariable(const CFX_ByteString& sPropname);
-  iterator FindGlobalVariable(const CFX_ByteString& sPropname);
-  const_iterator FindGlobalVariable(const CFX_ByteString& sPropname) const;
-
-  void LoadFileBuffer(const FX_WCHAR* sFilePath,
-                      uint8_t*& pBuffer,
-                      int32_t& nLength);
-  void WriteFileBuffer(const FX_WCHAR* sFilePath,
-                       const FX_CHAR* pBuffer,
-                       int32_t nLength);
-  void MakeByteString(const CFX_ByteString& name,
-                      CJS_KeyValue* pData,
-                      CFX_BinaryBuf& sData);
-
-  size_t m_RefCount;
-  std::vector<std::unique_ptr<CJS_GlobalData_Element>> m_arrayGlobalData;
-  CFX_WideString m_sFilePath;
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_JS_GLOBALDATA_H_
diff --git a/fpdfsdk/javascript/JS_KeyValue.cpp b/fpdfsdk/javascript/JS_KeyValue.cpp
deleted file mode 100644
index 7d1e575..0000000
--- a/fpdfsdk/javascript/JS_KeyValue.cpp
+++ /dev/null
@@ -1,70 +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 "fpdfsdk/javascript/JS_KeyValue.h"
-
-CJS_GlobalVariableArray::CJS_GlobalVariableArray() {}
-
-CJS_GlobalVariableArray::~CJS_GlobalVariableArray() {}
-
-void CJS_GlobalVariableArray::Copy(const CJS_GlobalVariableArray& array) {
-  m_Array.clear();
-  for (int i = 0, sz = array.Count(); i < sz; i++) {
-    CJS_KeyValue* pOldObjData = array.GetAt(i);
-    switch (pOldObjData->nType) {
-      case JS_GlobalDataType::NUMBER: {
-        CJS_KeyValue* pNewObjData = new CJS_KeyValue;
-        pNewObjData->sKey = pOldObjData->sKey;
-        pNewObjData->nType = pOldObjData->nType;
-        pNewObjData->dData = pOldObjData->dData;
-        Add(pNewObjData);
-      } break;
-      case JS_GlobalDataType::BOOLEAN: {
-        CJS_KeyValue* pNewObjData = new CJS_KeyValue;
-        pNewObjData->sKey = pOldObjData->sKey;
-        pNewObjData->nType = pOldObjData->nType;
-        pNewObjData->bData = pOldObjData->bData;
-        Add(pNewObjData);
-      } break;
-      case JS_GlobalDataType::STRING: {
-        CJS_KeyValue* pNewObjData = new CJS_KeyValue;
-        pNewObjData->sKey = pOldObjData->sKey;
-        pNewObjData->nType = pOldObjData->nType;
-        pNewObjData->sData = pOldObjData->sData;
-        Add(pNewObjData);
-      } break;
-      case JS_GlobalDataType::OBJECT: {
-        CJS_KeyValue* pNewObjData = new CJS_KeyValue;
-        pNewObjData->sKey = pOldObjData->sKey;
-        pNewObjData->nType = pOldObjData->nType;
-        pNewObjData->objData.Copy(pOldObjData->objData);
-        Add(pNewObjData);
-      } break;
-      case JS_GlobalDataType::NULLOBJ: {
-        CJS_KeyValue* pNewObjData = new CJS_KeyValue;
-        pNewObjData->sKey = pOldObjData->sKey;
-        pNewObjData->nType = pOldObjData->nType;
-        Add(pNewObjData);
-      } break;
-    }
-  }
-}
-
-void CJS_GlobalVariableArray::Add(CJS_KeyValue* p) {
-  m_Array.push_back(std::unique_ptr<CJS_KeyValue>(p));
-}
-
-int CJS_GlobalVariableArray::Count() const {
-  return m_Array.size();
-}
-
-CJS_KeyValue* CJS_GlobalVariableArray::GetAt(int index) const {
-  return m_Array.at(index).get();
-}
-
-CJS_KeyValue::CJS_KeyValue() {}
-
-CJS_KeyValue::~CJS_KeyValue() {}
diff --git a/fpdfsdk/javascript/JS_KeyValue.h b/fpdfsdk/javascript/JS_KeyValue.h
deleted file mode 100644
index a571588..0000000
--- a/fpdfsdk/javascript/JS_KeyValue.h
+++ /dev/null
@@ -1,46 +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 FPDFSDK_JAVASCRIPT_JS_KEYVALUE_H_
-#define FPDFSDK_JAVASCRIPT_JS_KEYVALUE_H_
-
-#include <memory>
-#include <vector>
-
-#include "core/fxcrt/fx_basic.h"
-
-enum class JS_GlobalDataType { NUMBER = 0, BOOLEAN, STRING, OBJECT, NULLOBJ };
-
-class CJS_KeyValue;
-
-class CJS_GlobalVariableArray {
- public:
-  CJS_GlobalVariableArray();
-  ~CJS_GlobalVariableArray();
-
-  void Add(CJS_KeyValue* p);
-  int Count() const;
-  CJS_KeyValue* GetAt(int index) const;
-  void Copy(const CJS_GlobalVariableArray& array);
-
- private:
-  std::vector<std::unique_ptr<CJS_KeyValue>> m_Array;
-};
-
-class CJS_KeyValue {
- public:
-  CJS_KeyValue();
-  ~CJS_KeyValue();
-
-  CFX_ByteString sKey;
-  JS_GlobalDataType nType;
-  double dData;
-  bool bData;
-  CFX_ByteString sData;
-  CJS_GlobalVariableArray objData;
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_JS_KEYVALUE_H_
diff --git a/fpdfsdk/javascript/JS_Object.cpp b/fpdfsdk/javascript/JS_Object.cpp
deleted file mode 100644
index cd86889..0000000
--- a/fpdfsdk/javascript/JS_Object.cpp
+++ /dev/null
@@ -1,45 +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/JS_Object.h"
-
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/cjs_event_context.h"
-
-CJS_EmbedObj::CJS_EmbedObj(CJS_Object* pJSObject) : m_pJSObject(pJSObject) {}
-
-CJS_EmbedObj::~CJS_EmbedObj() {
-}
-
-void FreeObject(const v8::WeakCallbackInfo<CJS_Object>& data) {
-  CJS_Object* pJSObj = data.GetParameter();
-  delete pJSObj;
-  CFXJS_Engine::FreeObjectPrivate(data.GetInternalField(0));
-}
-
-void DisposeObject(const v8::WeakCallbackInfo<CJS_Object>& data) {
-  CJS_Object* pJSObj = data.GetParameter();
-  pJSObj->Dispose();
-  data.SetSecondPassCallback(FreeObject);
-}
-
-CJS_Object::CJS_Object(v8::Local<v8::Object> pObject) {
-  m_pIsolate = pObject->GetIsolate();
-  m_pV8Object.Reset(m_pIsolate, pObject);
-}
-
-CJS_Object::~CJS_Object() {}
-
-void CJS_Object::MakeWeak() {
-  m_pV8Object.SetWeak(this, DisposeObject,
-                      v8::WeakCallbackType::kInternalFields);
-}
-
-void CJS_Object::Dispose() {
-  m_pV8Object.Reset();
-}
-
-void CJS_Object::InitInstance(IJS_Runtime* pIRuntime) {}
diff --git a/fpdfsdk/javascript/JS_Object.h b/fpdfsdk/javascript/JS_Object.h
deleted file mode 100644
index 2e5c75c..0000000
--- a/fpdfsdk/javascript/JS_Object.h
+++ /dev/null
@@ -1,57 +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 FPDFSDK_JAVASCRIPT_JS_OBJECT_H_
-#define FPDFSDK_JAVASCRIPT_JS_OBJECT_H_
-
-#include <map>
-#include <memory>
-
-#include "fpdfsdk/fsdk_define.h"
-#include "fpdfsdk/javascript/cjs_runtime.h"
-#include "fxjs/fxjs_v8.h"
-
-class CJS_EventContext;
-class CJS_Object;
-class CPDFSDK_FormFillEnvironment;
-
-class CJS_EmbedObj {
- public:
-  explicit CJS_EmbedObj(CJS_Object* pJSObject);
-  virtual ~CJS_EmbedObj();
-
-  CJS_Object* GetJSObject() const { return m_pJSObject; }
-
- protected:
-  CJS_Object* const m_pJSObject;
-};
-
-class CJS_Object {
- public:
-  explicit CJS_Object(v8::Local<v8::Object> pObject);
-  virtual ~CJS_Object();
-
-  void MakeWeak();
-  void Dispose();
-
-  virtual void InitInstance(IJS_Runtime* pIRuntime);
-
-  v8::Local<v8::Object> ToV8Object() { return m_pV8Object.Get(m_pIsolate); }
-
-  // Takes ownership of |pObj|.
-  void SetEmbedObject(CJS_EmbedObj* pObj) { m_pEmbedObj.reset(pObj); }
-  CJS_EmbedObj* GetEmbedObject() const { return m_pEmbedObj.get(); }
-
-  v8::Isolate* GetIsolate() const { return m_pIsolate; }
-
- protected:
-  std::unique_ptr<CJS_EmbedObj> m_pEmbedObj;
-  v8::Global<v8::Object> m_pV8Object;
-  v8::Isolate* m_pIsolate;
-};
-
-
-#endif  // FPDFSDK_JAVASCRIPT_JS_OBJECT_H_
diff --git a/fpdfsdk/javascript/JS_Runtime_Stub.cpp b/fpdfsdk/javascript/JS_Runtime_Stub.cpp
deleted file mode 100644
index dcd8ceb..0000000
--- a/fpdfsdk/javascript/JS_Runtime_Stub.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright 2015 PDFium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
-
-#include <memory>
-
-#include "fpdfsdk/javascript/ijs_event_context.h"
-#include "fpdfsdk/javascript/ijs_runtime.h"
-#include "third_party/base/ptr_util.h"
-
-class CJS_EventContextStub final : public IJS_EventContext {
- public:
-  CJS_EventContextStub() {}
-  ~CJS_EventContextStub() override {}
-
-  // IJS_EventContext:
-  bool RunScript(const CFX_WideString& script, CFX_WideString* info) override {
-    return false;
-  }
-
-  void OnApp_Init() override {}
-  void OnDoc_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                  const CFX_WideString& strTargetName) override {}
-  void OnDoc_WillPrint(CPDFSDK_FormFillEnvironment* pFormFillEnv) override {}
-  void OnDoc_DidPrint(CPDFSDK_FormFillEnvironment* pFormFillEnv) override {}
-  void OnDoc_WillSave(CPDFSDK_FormFillEnvironment* pFormFillEnv) override {}
-  void OnDoc_DidSave(CPDFSDK_FormFillEnvironment* pFormFillEnv) override {}
-  void OnDoc_WillClose(CPDFSDK_FormFillEnvironment* pFormFillEnv) override {}
-  void OnPage_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv) override {}
-  void OnPage_Close(CPDFSDK_FormFillEnvironment* pFormFillEnv) override {}
-  void OnPage_InView(CPDFSDK_FormFillEnvironment* pFormFillEnv) override {}
-  void OnPage_OutView(CPDFSDK_FormFillEnvironment* pFormFillEnv) override {}
-  void OnField_MouseDown(bool bModifier,
-                         bool bShift,
-                         CPDF_FormField* pTarget) override {}
-  void OnField_MouseEnter(bool bModifier,
-                          bool bShift,
-                          CPDF_FormField* pTarget) override {}
-  void OnField_MouseExit(bool bModifier,
-                         bool bShift,
-                         CPDF_FormField* pTarget) override {}
-  void OnField_MouseUp(bool bModifier,
-                       bool bShift,
-                       CPDF_FormField* pTarget) override {}
-  void OnField_Focus(bool bModifier,
-                     bool bShift,
-                     CPDF_FormField* pTarget,
-                     const CFX_WideString& Value) override {}
-  void OnField_Blur(bool bModifier,
-                    bool bShift,
-                    CPDF_FormField* pTarget,
-                    const CFX_WideString& Value) override {}
-  void OnField_Calculate(CPDF_FormField* pSource,
-                         CPDF_FormField* pTarget,
-                         CFX_WideString& Value,
-                         bool& bRc) override {}
-  void OnField_Format(CPDF_FormField* pTarget,
-                      CFX_WideString& Value,
-                      bool bWillCommit) override {}
-  void OnField_Keystroke(CFX_WideString& strChange,
-                         const CFX_WideString& strChangeEx,
-                         bool KeyDown,
-                         bool bModifier,
-                         int& nSelEnd,
-                         int& nSelStart,
-                         bool bShift,
-                         CPDF_FormField* pTarget,
-                         CFX_WideString& Value,
-                         bool bWillCommit,
-                         bool bFieldFull,
-                         bool& bRc) override {}
-  void OnField_Validate(CFX_WideString& strChange,
-                        const CFX_WideString& strChangeEx,
-                        bool bKeyDown,
-                        bool bModifier,
-                        bool bShift,
-                        CPDF_FormField* pTarget,
-                        CFX_WideString& Value,
-                        bool& bRc) override {}
-  void OnScreen_Focus(bool bModifier,
-                      bool bShift,
-                      CPDFSDK_Annot* pScreen) override {}
-  void OnScreen_Blur(bool bModifier,
-                     bool bShift,
-                     CPDFSDK_Annot* pScreen) override {}
-  void OnScreen_Open(bool bModifier,
-                     bool bShift,
-                     CPDFSDK_Annot* pScreen) override {}
-  void OnScreen_Close(bool bModifier,
-                      bool bShift,
-                      CPDFSDK_Annot* pScreen) override {}
-  void OnScreen_MouseDown(bool bModifier,
-                          bool bShift,
-                          CPDFSDK_Annot* pScreen) override {}
-  void OnScreen_MouseUp(bool bModifier,
-                        bool bShift,
-                        CPDFSDK_Annot* pScreen) override {}
-  void OnScreen_MouseEnter(bool bModifier,
-                           bool bShift,
-                           CPDFSDK_Annot* pScreen) override {}
-  void OnScreen_MouseExit(bool bModifier,
-                          bool bShift,
-                          CPDFSDK_Annot* pScreen) override {}
-  void OnScreen_InView(bool bModifier,
-                       bool bShift,
-                       CPDFSDK_Annot* pScreen) override {}
-  void OnScreen_OutView(bool bModifier,
-                        bool bShift,
-                        CPDFSDK_Annot* pScreen) override {}
-  void OnBookmark_MouseUp(CPDF_Bookmark* pBookMark) override {}
-  void OnLink_MouseUp(CPDFSDK_FormFillEnvironment* pFormFillEnv) override {}
-  void OnMenu_Exec(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                   const CFX_WideString&) override {}
-  void OnBatchExec(CPDFSDK_FormFillEnvironment* pFormFillEnv) override {}
-  void OnConsole_Exec() override {}
-  void OnExternal_Exec() override {}
-};
-
-class CJS_RuntimeStub final : public IJS_Runtime {
- public:
-  explicit CJS_RuntimeStub(CPDFSDK_FormFillEnvironment* pFormFillEnv)
-      : m_pFormFillEnv(pFormFillEnv) {}
-  ~CJS_RuntimeStub() override {}
-
-  IJS_EventContext* NewEventContext() override {
-    if (!m_pContext)
-      m_pContext = pdfium::MakeUnique<CJS_EventContextStub>();
-    return m_pContext.get();
-  }
-
-  void ReleaseEventContext(IJS_EventContext* pContext) override {}
-
-  CPDFSDK_FormFillEnvironment* GetFormFillEnv() const override {
-    return m_pFormFillEnv;
-  }
-
-#ifdef PDF_ENABLE_XFA
-  bool GetValueByName(const CFX_ByteStringC&, CFXJSE_Value*) override {
-    return false;
-  }
-
-  bool SetValueByName(const CFX_ByteStringC&, CFXJSE_Value*) override {
-    return false;
-  }
-#endif  // PDF_ENABLE_XFA
-
-  int ExecuteScript(const CFX_WideString& script,
-                    CFX_WideString* info) override {
-    return 0;
-  }
-
- protected:
-  CPDFSDK_FormFillEnvironment* m_pFormFillEnv;
-  std::unique_ptr<CJS_EventContextStub> m_pContext;
-};
-
-// static
-void IJS_Runtime::Initialize(unsigned int slot, void* isolate) {}
-
-// static
-void IJS_Runtime::Destroy() {}
-
-// static
-IJS_Runtime* IJS_Runtime::Create(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  return new CJS_RuntimeStub(pFormFillEnv);
-}
diff --git a/fpdfsdk/javascript/JS_Value.cpp b/fpdfsdk/javascript/JS_Value.cpp
deleted file mode 100644
index b058847..0000000
--- a/fpdfsdk/javascript/JS_Value.cpp
+++ /dev/null
@@ -1,770 +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/JS_Value.h"
-
-#include <time.h>
-
-#include <algorithm>
-#include <cmath>
-#include <limits>
-#include <vector>
-
-#include "fpdfsdk/javascript/Document.h"
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_Object.h"
-
-namespace {
-
-const uint32_t g_nan[2] = {0, 0x7FF80000};
-
-double GetNan() {
-  return *(double*)g_nan;
-}
-
-double
-MakeDate(int year, int mon, int day, int hour, int min, int sec, int ms) {
-  return JS_MakeDate(JS_MakeDay(year, mon, day),
-                     JS_MakeTime(hour, min, sec, ms));
-}
-
-}  // namespace
-
-CJS_Value::CJS_Value(CJS_Runtime* pRuntime) {}
-
-CJS_Value::CJS_Value(CJS_Runtime* pRuntime, v8::Local<v8::Value> pValue)
-    : m_pValue(pValue) {}
-
-CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const int& iValue)
-    : m_pValue(pRuntime->NewNumber(iValue)) {}
-
-CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const bool& bValue)
-    : m_pValue(pRuntime->NewBoolean(bValue)) {}
-
-CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const float& fValue)
-    : m_pValue(pRuntime->NewNumber(fValue)) {}
-
-CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const double& dValue)
-    : m_pValue(pRuntime->NewNumber(dValue)) {}
-
-CJS_Value::CJS_Value(CJS_Runtime* pRuntime, CJS_Object* pObj) {
-  if (pObj)
-    m_pValue = pObj->ToV8Object();
-}
-
-CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const FX_WCHAR* pWstr)
-    : m_pValue(pRuntime->NewString(pWstr)) {}
-
-CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const FX_CHAR* pStr)
-    : m_pValue(pRuntime->NewString(CFX_WideString::FromLocal(pStr).c_str())) {}
-
-CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const CJS_Array& array)
-    : m_pValue(array.ToV8Array(pRuntime)) {}
-
-CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const CJS_Date& date)
-    : m_pValue(date.ToV8Date(pRuntime)) {}
-
-CJS_Value::~CJS_Value() {}
-
-CJS_Value::CJS_Value(const CJS_Value& other) = default;
-
-void CJS_Value::Attach(v8::Local<v8::Value> pValue) {
-  m_pValue = pValue;
-}
-
-void CJS_Value::Detach() {
-  m_pValue = v8::Local<v8::Value>();
-}
-
-int CJS_Value::ToInt(CJS_Runtime* pRuntime) const {
-  return pRuntime->ToInt32(m_pValue);
-}
-
-bool CJS_Value::ToBool(CJS_Runtime* pRuntime) const {
-  return pRuntime->ToBoolean(m_pValue);
-}
-
-double CJS_Value::ToDouble(CJS_Runtime* pRuntime) const {
-  return pRuntime->ToDouble(m_pValue);
-}
-
-float CJS_Value::ToFloat(CJS_Runtime* pRuntime) const {
-  return (float)ToDouble(pRuntime);
-}
-
-CJS_Object* CJS_Value::ToCJSObject(CJS_Runtime* pRuntime) const {
-  v8::Local<v8::Object> pObj = pRuntime->ToObject(m_pValue);
-  return static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(pObj));
-}
-
-v8::Local<v8::Object> CJS_Value::ToV8Object(CJS_Runtime* pRuntime) const {
-  return pRuntime->ToObject(m_pValue);
-}
-
-CFX_WideString CJS_Value::ToCFXWideString(CJS_Runtime* pRuntime) const {
-  return pRuntime->ToWideString(m_pValue);
-}
-
-CFX_ByteString CJS_Value::ToCFXByteString(CJS_Runtime* pRuntime) const {
-  return CFX_ByteString::FromUnicode(ToCFXWideString(pRuntime));
-}
-
-v8::Local<v8::Value> CJS_Value::ToV8Value(CJS_Runtime* pRuntime) const {
-  return m_pValue;
-}
-
-v8::Local<v8::Array> CJS_Value::ToV8Array(CJS_Runtime* pRuntime) const {
-  return pRuntime->ToArray(m_pValue);
-}
-
-void CJS_Value::SetNull(CJS_Runtime* pRuntime) {
-  m_pValue = pRuntime->NewNull();
-}
-
-void CJS_Value::MaybeCoerceToNumber(CJS_Runtime* pRuntime) {
-  bool bAllowNaN = false;
-  if (GetType() == VT_string) {
-    CFX_ByteString bstr = ToCFXByteString(pRuntime);
-    if (bstr.GetLength() == 0)
-      return;
-    if (bstr == "NaN")
-      bAllowNaN = true;
-  }
-  v8::Isolate* pIsolate = pRuntime->GetIsolate();
-  v8::TryCatch try_catch(pIsolate);
-  v8::MaybeLocal<v8::Number> maybeNum =
-      m_pValue->ToNumber(pIsolate->GetCurrentContext());
-  if (maybeNum.IsEmpty())
-    return;
-  v8::Local<v8::Number> num = maybeNum.ToLocalChecked();
-  if (std::isnan(num->Value()) && !bAllowNaN)
-    return;
-  m_pValue = num;
-}
-
-// static
-CJS_Value::Type CJS_Value::GetValueType(v8::Local<v8::Value> value) {
-  if (value.IsEmpty())
-    return VT_unknown;
-  if (value->IsString())
-    return VT_string;
-  if (value->IsNumber())
-    return VT_number;
-  if (value->IsBoolean())
-    return VT_boolean;
-  if (value->IsDate())
-    return VT_date;
-  if (value->IsObject())
-    return VT_object;
-  if (value->IsNull())
-    return VT_null;
-  if (value->IsUndefined())
-    return VT_undefined;
-  return VT_unknown;
-}
-
-bool CJS_Value::IsArrayObject() const {
-  return !m_pValue.IsEmpty() && m_pValue->IsArray();
-}
-
-bool CJS_Value::IsDateObject() const {
-  return !m_pValue.IsEmpty() && m_pValue->IsDate();
-}
-
-bool CJS_Value::ConvertToArray(CJS_Runtime* pRuntime, CJS_Array& array) const {
-  if (!IsArrayObject())
-    return false;
-  array.Attach(pRuntime->ToArray(m_pValue));
-  return true;
-}
-
-bool CJS_Value::ConvertToDate(CJS_Runtime* pRuntime, CJS_Date& date) const {
-  if (!IsDateObject())
-    return false;
-  v8::Local<v8::Value> mutable_value = m_pValue;
-  date.Attach(mutable_value.As<v8::Date>());
-  return true;
-}
-
-CJS_PropValue::CJS_PropValue(CJS_Runtime* pRuntime)
-    : m_bIsSetting(0), m_Value(pRuntime), m_pJSRuntime(pRuntime) {}
-
-CJS_PropValue::CJS_PropValue(CJS_Runtime* pRuntime, const CJS_Value& value)
-    : m_bIsSetting(0), m_Value(value), m_pJSRuntime(pRuntime) {}
-
-CJS_PropValue::~CJS_PropValue() {}
-
-void CJS_PropValue::operator<<(int iValue) {
-  ASSERT(!m_bIsSetting);
-  m_Value = CJS_Value(m_pJSRuntime, iValue);
-}
-
-void CJS_PropValue::operator>>(int& iValue) const {
-  ASSERT(m_bIsSetting);
-  iValue = m_Value.ToInt(m_pJSRuntime);
-}
-
-void CJS_PropValue::operator<<(bool bValue) {
-  ASSERT(!m_bIsSetting);
-  m_Value = CJS_Value(m_pJSRuntime, bValue);
-}
-
-void CJS_PropValue::operator>>(bool& bValue) const {
-  ASSERT(m_bIsSetting);
-  bValue = m_Value.ToBool(m_pJSRuntime);
-}
-
-void CJS_PropValue::operator<<(double dValue) {
-  ASSERT(!m_bIsSetting);
-  m_Value = CJS_Value(m_pJSRuntime, dValue);
-}
-
-void CJS_PropValue::operator>>(double& dValue) const {
-  ASSERT(m_bIsSetting);
-  dValue = m_Value.ToDouble(m_pJSRuntime);
-}
-
-void CJS_PropValue::operator<<(CJS_Object* pObj) {
-  ASSERT(!m_bIsSetting);
-  m_Value = CJS_Value(m_pJSRuntime, pObj);
-}
-
-void CJS_PropValue::operator>>(CJS_Object*& ppObj) const {
-  ASSERT(m_bIsSetting);
-  ppObj = m_Value.ToCJSObject(m_pJSRuntime);
-}
-
-void CJS_PropValue::operator<<(CJS_Document* pJsDoc) {
-  ASSERT(!m_bIsSetting);
-  m_Value = CJS_Value(m_pJSRuntime, pJsDoc);
-}
-
-void CJS_PropValue::operator>>(CJS_Document*& ppJsDoc) const {
-  ASSERT(m_bIsSetting);
-  ppJsDoc = static_cast<CJS_Document*>(m_Value.ToCJSObject(m_pJSRuntime));
-}
-
-void CJS_PropValue::operator<<(v8::Local<v8::Object> pObj) {
-  ASSERT(!m_bIsSetting);
-  m_Value = CJS_Value(m_pJSRuntime, pObj);
-}
-
-void CJS_PropValue::operator>>(v8::Local<v8::Object>& ppObj) const {
-  ASSERT(m_bIsSetting);
-  ppObj = m_Value.ToV8Object(m_pJSRuntime);
-}
-
-void CJS_PropValue::operator<<(CFX_ByteString str) {
-  ASSERT(!m_bIsSetting);
-  m_Value = CJS_Value(m_pJSRuntime, str.c_str());
-}
-
-void CJS_PropValue::operator>>(CFX_ByteString& str) const {
-  ASSERT(m_bIsSetting);
-  str = m_Value.ToCFXByteString(m_pJSRuntime);
-}
-
-void CJS_PropValue::operator<<(const FX_WCHAR* str) {
-  ASSERT(!m_bIsSetting);
-  m_Value = CJS_Value(m_pJSRuntime, str);
-}
-
-void CJS_PropValue::operator>>(CFX_WideString& wide_string) const {
-  ASSERT(m_bIsSetting);
-  wide_string = m_Value.ToCFXWideString(m_pJSRuntime);
-}
-
-void CJS_PropValue::operator<<(CFX_WideString wide_string) {
-  ASSERT(!m_bIsSetting);
-  m_Value = CJS_Value(m_pJSRuntime, wide_string.c_str());
-}
-
-void CJS_PropValue::operator>>(CJS_Array& array) const {
-  ASSERT(m_bIsSetting);
-  m_Value.ConvertToArray(m_pJSRuntime, array);
-}
-
-void CJS_PropValue::operator<<(CJS_Array& array) {
-  ASSERT(!m_bIsSetting);
-  m_Value = CJS_Value(m_pJSRuntime, array.ToV8Array(m_pJSRuntime));
-}
-
-void CJS_PropValue::operator>>(CJS_Date& date) const {
-  ASSERT(m_bIsSetting);
-  m_Value.ConvertToDate(m_pJSRuntime, date);
-}
-
-void CJS_PropValue::operator<<(CJS_Date& date) {
-  ASSERT(!m_bIsSetting);
-  m_Value = CJS_Value(m_pJSRuntime, date);
-}
-
-CJS_Array::CJS_Array() {}
-
-CJS_Array::CJS_Array(const CJS_Array& other) = default;
-
-CJS_Array::~CJS_Array() {}
-
-void CJS_Array::Attach(v8::Local<v8::Array> pArray) {
-  m_pArray = pArray;
-}
-
-void CJS_Array::GetElement(CJS_Runtime* pRuntime,
-                           unsigned index,
-                           CJS_Value& value) const {
-  if (!m_pArray.IsEmpty())
-    value.Attach(pRuntime->GetArrayElement(m_pArray, index));
-}
-
-void CJS_Array::SetElement(CJS_Runtime* pRuntime,
-                           unsigned index,
-                           const CJS_Value& value) {
-  if (m_pArray.IsEmpty())
-    m_pArray = pRuntime->NewArray();
-
-  pRuntime->PutArrayElement(m_pArray, index, value.ToV8Value(pRuntime));
-}
-
-int CJS_Array::GetLength(CJS_Runtime* pRuntime) const {
-  if (m_pArray.IsEmpty())
-    return 0;
-  return pRuntime->GetArrayLength(m_pArray);
-}
-
-v8::Local<v8::Array> CJS_Array::ToV8Array(CJS_Runtime* pRuntime) const {
-  if (m_pArray.IsEmpty())
-    m_pArray = pRuntime->NewArray();
-
-  return m_pArray;
-}
-
-CJS_Date::CJS_Date() {}
-
-CJS_Date::CJS_Date(CJS_Runtime* pRuntime, double dMsecTime)
-    : m_pDate(pRuntime->NewDate(dMsecTime)) {}
-
-CJS_Date::CJS_Date(CJS_Runtime* pRuntime,
-                   int year,
-                   int mon,
-                   int day,
-                   int hour,
-                   int min,
-                   int sec)
-    : m_pDate(pRuntime->NewDate(MakeDate(year, mon, day, hour, min, sec, 0))) {}
-
-CJS_Date::~CJS_Date() {}
-
-bool CJS_Date::IsValidDate(CJS_Runtime* pRuntime) const {
-  return !m_pDate.IsEmpty() && !JS_PortIsNan(pRuntime->ToDouble(m_pDate));
-}
-
-void CJS_Date::Attach(v8::Local<v8::Date> pDate) {
-  m_pDate = pDate;
-}
-
-int CJS_Date::GetYear(CJS_Runtime* pRuntime) const {
-  if (!IsValidDate(pRuntime))
-    return 0;
-
-  return JS_GetYearFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
-}
-
-void CJS_Date::SetYear(CJS_Runtime* pRuntime, int iYear) {
-  m_pDate = pRuntime->NewDate(
-      MakeDate(iYear, GetMonth(pRuntime), GetDay(pRuntime), GetHours(pRuntime),
-               GetMinutes(pRuntime), GetSeconds(pRuntime), 0));
-}
-
-int CJS_Date::GetMonth(CJS_Runtime* pRuntime) const {
-  if (!IsValidDate(pRuntime))
-    return 0;
-
-  return JS_GetMonthFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
-}
-
-void CJS_Date::SetMonth(CJS_Runtime* pRuntime, int iMonth) {
-  m_pDate = pRuntime->NewDate(
-      MakeDate(GetYear(pRuntime), iMonth, GetDay(pRuntime), GetHours(pRuntime),
-               GetMinutes(pRuntime), GetSeconds(pRuntime), 0));
-}
-
-int CJS_Date::GetDay(CJS_Runtime* pRuntime) const {
-  if (!IsValidDate(pRuntime))
-    return 0;
-
-  return JS_GetDayFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
-}
-
-void CJS_Date::SetDay(CJS_Runtime* pRuntime, int iDay) {
-  m_pDate = pRuntime->NewDate(
-      MakeDate(GetYear(pRuntime), GetMonth(pRuntime), iDay, GetHours(pRuntime),
-               GetMinutes(pRuntime), GetSeconds(pRuntime), 0));
-}
-
-int CJS_Date::GetHours(CJS_Runtime* pRuntime) const {
-  if (!IsValidDate(pRuntime))
-    return 0;
-
-  return JS_GetHourFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
-}
-
-void CJS_Date::SetHours(CJS_Runtime* pRuntime, int iHours) {
-  m_pDate = pRuntime->NewDate(
-      MakeDate(GetYear(pRuntime), GetMonth(pRuntime), GetDay(pRuntime), iHours,
-               GetMinutes(pRuntime), GetSeconds(pRuntime), 0));
-}
-
-int CJS_Date::GetMinutes(CJS_Runtime* pRuntime) const {
-  if (!IsValidDate(pRuntime))
-    return 0;
-
-  return JS_GetMinFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
-}
-
-void CJS_Date::SetMinutes(CJS_Runtime* pRuntime, int minutes) {
-  m_pDate = pRuntime->NewDate(MakeDate(GetYear(pRuntime), GetMonth(pRuntime),
-                                       GetDay(pRuntime), GetHours(pRuntime),
-                                       minutes, GetSeconds(pRuntime), 0));
-}
-
-int CJS_Date::GetSeconds(CJS_Runtime* pRuntime) const {
-  if (!IsValidDate(pRuntime))
-    return 0;
-
-  return JS_GetSecFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
-}
-
-void CJS_Date::SetSeconds(CJS_Runtime* pRuntime, int seconds) {
-  m_pDate = pRuntime->NewDate(MakeDate(GetYear(pRuntime), GetMonth(pRuntime),
-                                       GetDay(pRuntime), GetHours(pRuntime),
-                                       GetMinutes(pRuntime), seconds, 0));
-}
-
-double CJS_Date::ToDouble(CJS_Runtime* pRuntime) const {
-  return !m_pDate.IsEmpty() ? pRuntime->ToDouble(m_pDate) : 0.0;
-}
-
-CFX_WideString CJS_Date::ToString(CJS_Runtime* pRuntime) const {
-  return !m_pDate.IsEmpty() ? pRuntime->ToWideString(m_pDate)
-                            : CFX_WideString();
-}
-
-v8::Local<v8::Date> CJS_Date::ToV8Date(CJS_Runtime* pRuntime) const {
-  return m_pDate;
-}
-
-double _getLocalTZA() {
-  if (!FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
-    return 0;
-  time_t t = 0;
-  time(&t);
-  localtime(&t);
-#if _MSC_VER >= 1900
-  // In gcc and in Visual Studio prior to VS 2015 'timezone' is a global
-  // variable declared in time.h. That variable was deprecated and in VS 2015
-  // is removed, with _get_timezone replacing it.
-  long timezone = 0;
-  _get_timezone(&timezone);
-#endif
-  return (double)(-(timezone * 1000));
-}
-
-int _getDaylightSavingTA(double d) {
-  if (!FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
-    return 0;
-  time_t t = (time_t)(d / 1000);
-  struct tm* tmp = localtime(&t);
-  if (!tmp)
-    return 0;
-  if (tmp->tm_isdst > 0)
-    // One hour.
-    return (int)60 * 60 * 1000;
-  return 0;
-}
-
-double _Mod(double x, double y) {
-  double r = fmod(x, y);
-  if (r < 0)
-    r += y;
-  return r;
-}
-
-int _isfinite(double v) {
-#if _MSC_VER
-  return ::_finite(v);
-#else
-  return std::fabs(v) < std::numeric_limits<double>::max();
-#endif
-}
-
-double _toInteger(double n) {
-  return (n >= 0) ? FXSYS_floor(n) : -FXSYS_floor(-n);
-}
-
-bool _isLeapYear(int year) {
-  return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 != 0));
-}
-
-int _DayFromYear(int y) {
-  return (int)(365 * (y - 1970.0) + FXSYS_floor((y - 1969.0) / 4) -
-               FXSYS_floor((y - 1901.0) / 100) +
-               FXSYS_floor((y - 1601.0) / 400));
-}
-
-double _TimeFromYear(int y) {
-  return 86400000.0 * _DayFromYear(y);
-}
-
-static const uint16_t daysMonth[12] = {0,   31,  59,  90,  120, 151,
-                                       181, 212, 243, 273, 304, 334};
-static const uint16_t leapDaysMonth[12] = {0,   31,  60,  91,  121, 152,
-                                           182, 213, 244, 274, 305, 335};
-
-double _TimeFromYearMonth(int y, int m) {
-  const uint16_t* pMonth = _isLeapYear(y) ? leapDaysMonth : daysMonth;
-  return _TimeFromYear(y) + ((double)pMonth[m]) * 86400000;
-}
-
-int _Day(double t) {
-  return (int)FXSYS_floor(t / 86400000);
-}
-
-int _YearFromTime(double t) {
-  // estimate the time.
-  int y = 1970 + static_cast<int>(t / (365.2425 * 86400000));
-  if (_TimeFromYear(y) <= t) {
-    while (_TimeFromYear(y + 1) <= t)
-      y++;
-  } else {
-    while (_TimeFromYear(y) > t)
-      y--;
-  }
-  return y;
-}
-
-int _DayWithinYear(double t) {
-  int year = _YearFromTime(t);
-  int day = _Day(t);
-  return day - _DayFromYear(year);
-}
-
-int _MonthFromTime(double t) {
-  int day = _DayWithinYear(t);
-  int year = _YearFromTime(t);
-  if (0 <= day && day < 31)
-    return 0;
-  if (31 <= day && day < 59 + _isLeapYear(year))
-    return 1;
-  if ((59 + _isLeapYear(year)) <= day && day < (90 + _isLeapYear(year)))
-    return 2;
-  if ((90 + _isLeapYear(year)) <= day && day < (120 + _isLeapYear(year)))
-    return 3;
-  if ((120 + _isLeapYear(year)) <= day && day < (151 + _isLeapYear(year)))
-    return 4;
-  if ((151 + _isLeapYear(year)) <= day && day < (181 + _isLeapYear(year)))
-    return 5;
-  if ((181 + _isLeapYear(year)) <= day && day < (212 + _isLeapYear(year)))
-    return 6;
-  if ((212 + _isLeapYear(year)) <= day && day < (243 + _isLeapYear(year)))
-    return 7;
-  if ((243 + _isLeapYear(year)) <= day && day < (273 + _isLeapYear(year)))
-    return 8;
-  if ((273 + _isLeapYear(year)) <= day && day < (304 + _isLeapYear(year)))
-    return 9;
-  if ((304 + _isLeapYear(year)) <= day && day < (334 + _isLeapYear(year)))
-    return 10;
-  if ((334 + _isLeapYear(year)) <= day && day < (365 + _isLeapYear(year)))
-    return 11;
-
-  return -1;
-}
-
-int _DateFromTime(double t) {
-  int day = _DayWithinYear(t);
-  int year = _YearFromTime(t);
-  int leap = _isLeapYear(year);
-  int month = _MonthFromTime(t);
-  switch (month) {
-    case 0:
-      return day + 1;
-    case 1:
-      return day - 30;
-    case 2:
-      return day - 58 - leap;
-    case 3:
-      return day - 89 - leap;
-    case 4:
-      return day - 119 - leap;
-    case 5:
-      return day - 150 - leap;
-    case 6:
-      return day - 180 - leap;
-    case 7:
-      return day - 211 - leap;
-    case 8:
-      return day - 242 - leap;
-    case 9:
-      return day - 272 - leap;
-    case 10:
-      return day - 303 - leap;
-    case 11:
-      return day - 333 - leap;
-    default:
-      return 0;
-  }
-}
-
-double JS_GetDateTime() {
-  if (!FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
-    return 0;
-  time_t t = time(nullptr);
-  struct tm* pTm = localtime(&t);
-
-  int year = pTm->tm_year + 1900;
-  double t1 = _TimeFromYear(year);
-
-  return t1 + pTm->tm_yday * 86400000.0 + pTm->tm_hour * 3600000.0 +
-         pTm->tm_min * 60000.0 + pTm->tm_sec * 1000.0;
-}
-
-int JS_GetYearFromTime(double dt) {
-  return _YearFromTime(dt);
-}
-
-int JS_GetMonthFromTime(double dt) {
-  return _MonthFromTime(dt);
-}
-
-int JS_GetDayFromTime(double dt) {
-  return _DateFromTime(dt);
-}
-
-int JS_GetHourFromTime(double dt) {
-  return (int)_Mod(floor(dt / (60 * 60 * 1000)), 24);
-}
-
-int JS_GetMinFromTime(double dt) {
-  return (int)_Mod(floor(dt / (60 * 1000)), 60);
-}
-
-int JS_GetSecFromTime(double dt) {
-  return (int)_Mod(floor(dt / 1000), 60);
-}
-
-double JS_DateParse(const CFX_WideString& str) {
-  v8::Isolate* pIsolate = v8::Isolate::GetCurrent();
-  v8::Isolate::Scope isolate_scope(pIsolate);
-  v8::HandleScope scope(pIsolate);
-
-  v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
-
-  // Use the built-in object method.
-  v8::Local<v8::Value> v =
-      context->Global()
-          ->Get(context, v8::String::NewFromUtf8(pIsolate, "Date",
-                                                 v8::NewStringType::kNormal)
-                             .ToLocalChecked())
-          .ToLocalChecked();
-  if (v->IsObject()) {
-    v8::Local<v8::Object> o = v->ToObject(context).ToLocalChecked();
-    v = o->Get(context, v8::String::NewFromUtf8(pIsolate, "parse",
-                                                v8::NewStringType::kNormal)
-                            .ToLocalChecked())
-            .ToLocalChecked();
-    if (v->IsFunction()) {
-      v8::Local<v8::Function> funC = v8::Local<v8::Function>::Cast(v);
-      const int argc = 1;
-      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()) {
-        double date = v->ToNumber(context).ToLocalChecked()->Value();
-        if (!_isfinite(date))
-          return date;
-        return JS_LocalTime(date);
-      }
-    }
-  }
-  return 0;
-}
-
-double JS_MakeDay(int nYear, int nMonth, int nDate) {
-  if (!_isfinite(nYear) || !_isfinite(nMonth) || !_isfinite(nDate))
-    return GetNan();
-  double y = _toInteger(nYear);
-  double m = _toInteger(nMonth);
-  double dt = _toInteger(nDate);
-  double ym = y + FXSYS_floor((double)m / 12);
-  double mn = _Mod(m, 12);
-
-  double t = _TimeFromYearMonth((int)ym, (int)mn);
-
-  if (_YearFromTime(t) != ym || _MonthFromTime(t) != mn ||
-      _DateFromTime(t) != 1)
-    return GetNan();
-  return _Day(t) + dt - 1;
-}
-
-double JS_MakeTime(int nHour, int nMin, int nSec, int nMs) {
-  if (!_isfinite(nHour) || !_isfinite(nMin) || !_isfinite(nSec) ||
-      !_isfinite(nMs))
-    return GetNan();
-
-  double h = _toInteger(nHour);
-  double m = _toInteger(nMin);
-  double s = _toInteger(nSec);
-  double milli = _toInteger(nMs);
-
-  return h * 3600000 + m * 60000 + s * 1000 + milli;
-}
-
-double JS_MakeDate(double day, double time) {
-  if (!_isfinite(day) || !_isfinite(time))
-    return GetNan();
-
-  return day * 86400000 + time;
-}
-
-bool JS_PortIsNan(double d) {
-  return d != d;
-}
-
-double JS_LocalTime(double d) {
-  return d + _getLocalTZA() + _getDaylightSavingTA(d);
-}
-
-std::vector<CJS_Value> JS_ExpandKeywordParams(
-    CJS_Runtime* pRuntime,
-    const std::vector<CJS_Value>& originals,
-    size_t nKeywords,
-    ...) {
-  ASSERT(nKeywords);
-
-  std::vector<CJS_Value> result(nKeywords, CJS_Value(pRuntime));
-  size_t size = std::min(originals.size(), nKeywords);
-  for (size_t i = 0; i < size; ++i)
-    result[i] = originals[i];
-
-  if (originals.size() != 1 || originals[0].GetType() != CJS_Value::VT_object ||
-      originals[0].IsArrayObject()) {
-    return result;
-  }
-  v8::Local<v8::Object> pObj = originals[0].ToV8Object(pRuntime);
-  result[0] = CJS_Value(pRuntime);  // Make unknown.
-
-  va_list ap;
-  va_start(ap, nKeywords);
-  for (size_t i = 0; i < nKeywords; ++i) {
-    const wchar_t* property = va_arg(ap, const wchar_t*);
-    v8::Local<v8::Value> v8Value = pRuntime->GetObjectProperty(pObj, property);
-    if (!v8Value->IsUndefined())
-      result[i] = CJS_Value(pRuntime, v8Value);
-  }
-  va_end(ap);
-  return result;
-}
diff --git a/fpdfsdk/javascript/JS_Value.h b/fpdfsdk/javascript/JS_Value.h
deleted file mode 100644
index 313f0c3..0000000
--- a/fpdfsdk/javascript/JS_Value.h
+++ /dev/null
@@ -1,215 +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 FPDFSDK_JAVASCRIPT_JS_VALUE_H_
-#define FPDFSDK_JAVASCRIPT_JS_VALUE_H_
-
-#include <vector>
-
-#include "core/fxcrt/fx_basic.h"
-#include "fxjs/fxjs_v8.h"
-
-class CJS_Array;
-class CJS_Date;
-class CJS_Document;
-class CJS_Object;
-class CJS_Runtime;
-
-class CJS_Value {
- public:
-  enum Type {
-    VT_unknown,
-    VT_string,
-    VT_number,
-    VT_boolean,
-    VT_date,
-    VT_object,
-    VT_null,
-    VT_undefined
-  };
-
-  explicit CJS_Value(CJS_Runtime* pRuntime);
-  CJS_Value(CJS_Runtime* pRuntime, v8::Local<v8::Value> pValue);
-  CJS_Value(CJS_Runtime* pRuntime, const int& iValue);
-  CJS_Value(CJS_Runtime* pRuntime, const double& dValue);
-  CJS_Value(CJS_Runtime* pRuntime, const float& fValue);
-  CJS_Value(CJS_Runtime* pRuntime, const bool& bValue);
-  CJS_Value(CJS_Runtime* pRuntime, CJS_Object* pObj);
-  CJS_Value(CJS_Runtime* pRuntime, const FX_CHAR* pStr);
-  CJS_Value(CJS_Runtime* pRuntime, const FX_WCHAR* pWstr);
-  CJS_Value(CJS_Runtime* pRuntime, const CJS_Array& array);
-  CJS_Value(CJS_Runtime* pRuntime, const CJS_Date& date);
-  CJS_Value(CJS_Runtime* pRuntime, const CJS_Object* object);
-  CJS_Value(const CJS_Value& other);
-
-  ~CJS_Value();
-
-  void SetNull(CJS_Runtime* pRuntime);
-  void SetValue(const CJS_Value& other);
-  void Attach(v8::Local<v8::Value> pValue);
-  void Detach();
-
-  static Type GetValueType(v8::Local<v8::Value> value);
-  Type GetType() const { return GetValueType(m_pValue); }
-
-  int ToInt(CJS_Runtime* pRuntime) const;
-  bool ToBool(CJS_Runtime* pRuntime) const;
-  double ToDouble(CJS_Runtime* pRuntime) const;
-  float ToFloat(CJS_Runtime* pRuntime) const;
-  CJS_Object* ToCJSObject(CJS_Runtime* pRuntime) const;
-  CFX_WideString ToCFXWideString(CJS_Runtime* pRuntime) const;
-  CFX_ByteString ToCFXByteString(CJS_Runtime* pRuntime) const;
-  v8::Local<v8::Object> ToV8Object(CJS_Runtime* pRuntime) const;
-  v8::Local<v8::Array> ToV8Array(CJS_Runtime* pRuntime) const;
-  v8::Local<v8::Value> ToV8Value(CJS_Runtime* pRuntime) const;
-
-  // Replace the current |m_pValue| with a v8::Number if possible
-  // to make one from the current |m_pValue|.
-  void MaybeCoerceToNumber(CJS_Runtime* pRuntime);
-
-  bool IsArrayObject() const;
-  bool IsDateObject() const;
-  bool ConvertToArray(CJS_Runtime* pRuntime, CJS_Array&) const;
-  bool ConvertToDate(CJS_Runtime* pRuntime, CJS_Date&) const;
-
- protected:
-  v8::Local<v8::Value> m_pValue;
-};
-
-class CJS_PropValue {
- public:
-  explicit CJS_PropValue(CJS_Runtime* pRuntime);
-  CJS_PropValue(CJS_Runtime* pRuntime, const CJS_Value&);
-  ~CJS_PropValue();
-
-  void StartSetting() { m_bIsSetting = true; }
-  void StartGetting() { m_bIsSetting = false; }
-  bool IsSetting() const { return m_bIsSetting; }
-  bool IsGetting() const { return !m_bIsSetting; }
-  CJS_Runtime* GetJSRuntime() const { return m_pJSRuntime; }
-  CJS_Value* GetJSValue() { return &m_Value; }
-
-  // These calls may re-enter JS (and hence invalidate objects).
-  void operator<<(int val);
-  void operator>>(int&) const;
-  void operator<<(bool val);
-  void operator>>(bool&) const;
-  void operator<<(double val);
-  void operator>>(double&) const;
-  void operator<<(CJS_Object* pObj);
-  void operator>>(CJS_Object*& ppObj) const;
-  void operator<<(CJS_Document* pJsDoc);
-  void operator>>(CJS_Document*& ppJsDoc) const;
-  void operator<<(CFX_ByteString);
-  void operator>>(CFX_ByteString&) const;
-  void operator<<(CFX_WideString);
-  void operator>>(CFX_WideString&) const;
-  void operator<<(const FX_WCHAR* c_string);
-  void operator<<(v8::Local<v8::Object>);
-  void operator>>(v8::Local<v8::Object>&) const;
-  void operator>>(CJS_Array& array) const;
-  void operator<<(CJS_Array& array);
-  void operator<<(CJS_Date& date);
-  void operator>>(CJS_Date& date) const;
-
- private:
-  bool m_bIsSetting;
-  CJS_Value m_Value;
-  CJS_Runtime* const m_pJSRuntime;
-};
-
-class CJS_Array {
- public:
-  CJS_Array();
-  CJS_Array(const CJS_Array& other);
-  virtual ~CJS_Array();
-
-  void Attach(v8::Local<v8::Array> pArray);
-  int GetLength(CJS_Runtime* pRuntime) const;
-
-  // These two calls may re-enter JS (and hence invalidate objects).
-  void GetElement(CJS_Runtime* pRuntime,
-                  unsigned index,
-                  CJS_Value& value) const;
-  void SetElement(CJS_Runtime* pRuntime,
-                  unsigned index,
-                  const CJS_Value& value);
-
-  v8::Local<v8::Array> ToV8Array(CJS_Runtime* pRuntime) const;
-
- private:
-  mutable v8::Local<v8::Array> m_pArray;
-};
-
-class CJS_Date {
- public:
-  CJS_Date();
-  CJS_Date(CJS_Runtime* pRuntime, double dMsec_time);
-  CJS_Date(CJS_Runtime* pRuntime,
-           int year,
-           int mon,
-           int day,
-           int hour,
-           int min,
-           int sec);
-  virtual ~CJS_Date();
-
-  void Attach(v8::Local<v8::Date> pDate);
-  bool IsValidDate(CJS_Runtime* pRuntime) const;
-
-  int GetYear(CJS_Runtime* pRuntime) const;
-  void SetYear(CJS_Runtime* pRuntime, int iYear);
-
-  int GetMonth(CJS_Runtime* pRuntime) const;
-  void SetMonth(CJS_Runtime* pRuntime, int iMonth);
-
-  int GetDay(CJS_Runtime* pRuntime) const;
-  void SetDay(CJS_Runtime* pRuntime, int iDay);
-
-  int GetHours(CJS_Runtime* pRuntime) const;
-  void SetHours(CJS_Runtime* pRuntime, int iHours);
-
-  int GetMinutes(CJS_Runtime* pRuntime) const;
-  void SetMinutes(CJS_Runtime* pRuntime, int minutes);
-
-  int GetSeconds(CJS_Runtime* pRuntime) const;
-  void SetSeconds(CJS_Runtime* pRuntime, int seconds);
-
-  v8::Local<v8::Date> ToV8Date(CJS_Runtime* pRuntime) const;
-  double ToDouble(CJS_Runtime* pRuntime) const;
-  CFX_WideString ToString(CJS_Runtime* pRuntime) const;
-
- protected:
-  v8::Local<v8::Date> m_pDate;
-};
-
-double JS_GetDateTime();
-int JS_GetYearFromTime(double dt);
-int JS_GetMonthFromTime(double dt);
-int JS_GetDayFromTime(double dt);
-int JS_GetHourFromTime(double dt);
-int JS_GetMinFromTime(double dt);
-int JS_GetSecFromTime(double dt);
-double JS_DateParse(const CFX_WideString& str);
-double JS_MakeDay(int nYear, int nMonth, int nDay);
-double JS_MakeTime(int nHour, int nMin, int nSec, int nMs);
-double JS_MakeDate(double day, double time);
-bool JS_PortIsNan(double d);
-double JS_LocalTime(double d);
-
-// Some JS methods have the bizarre convention that they may also be called
-// with a single argument which is an object containing the actual arguments
-// as its properties. The varying arguments to this method are the property
-// names as wchar_t string literals corresponding to each positional argument.
-// The result will always contain |nKeywords| value, with unspecified ones
-// being set to type VT_unknown.
-std::vector<CJS_Value> JS_ExpandKeywordParams(
-    CJS_Runtime* pRuntime,
-    const std::vector<CJS_Value>& originals,
-    size_t nKeywords,
-    ...);
-
-#endif  // FPDFSDK_JAVASCRIPT_JS_VALUE_H_
diff --git a/fpdfsdk/javascript/PublicMethods.cpp b/fpdfsdk/javascript/PublicMethods.cpp
deleted file mode 100644
index 3bcbc34..0000000
--- a/fpdfsdk/javascript/PublicMethods.cpp
+++ /dev/null
@@ -1,1801 +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/PublicMethods.h"
-
-#include <algorithm>
-#include <iomanip>
-#include <limits>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include "core/fpdfdoc/cpdf_interform.h"
-#include "core/fxcrt/fx_ext.h"
-#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
-#include "fpdfsdk/cpdfsdk_interform.h"
-#include "fpdfsdk/javascript/Field.h"
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_EventHandler.h"
-#include "fpdfsdk/javascript/JS_Object.h"
-#include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/cjs_event_context.h"
-#include "fpdfsdk/javascript/cjs_runtime.h"
-#include "fpdfsdk/javascript/color.h"
-#include "fpdfsdk/javascript/resource.h"
-#include "fpdfsdk/javascript/util.h"
-
-#define DOUBLE_CORRECT 0.000000000000001
-
-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)
-
-namespace {
-
-const FX_WCHAR* const months[] = {L"Jan", L"Feb", L"Mar", L"Apr",
-                                  L"May", L"Jun", L"Jul", L"Aug",
-                                  L"Sep", L"Oct", L"Nov", L"Dec"};
-
-const FX_WCHAR* const fullmonths[] = {L"January", L"February", L"March",
-                                      L"April",   L"May",      L"June",
-                                      L"July",    L"August",   L"September",
-                                      L"October", L"November", L"December"};
-
-CFX_ByteString StrTrim(const CFX_ByteString& pStr) {
-  CFX_ByteString result(pStr);
-  result.TrimLeft(' ');
-  result.TrimRight(' ');
-  return result;
-}
-
-CFX_WideString StrTrim(const CFX_WideString& pStr) {
-  CFX_WideString result(pStr);
-  result.TrimLeft(' ');
-  result.TrimRight(' ');
-  return result;
-}
-
-void AlertIfPossible(CJS_EventContext* pContext, const FX_WCHAR* swMsg) {
-  CPDFSDK_FormFillEnvironment* pFormFillEnv = pContext->GetFormFillEnv();
-  if (pFormFillEnv)
-    pFormFillEnv->JS_appAlert(swMsg, nullptr, 0, 3);
-}
-
-#if _FX_OS_ != _FX_ANDROID_
-CFX_ByteString CalculateString(double dValue,
-                               int iDec,
-                               int* iDec2,
-                               bool* bNegative) {
-  *bNegative = dValue < 0;
-  if (*bNegative)
-    dValue = -dValue;
-
-  // Make sure the number of precision characters will fit.
-  if (iDec > std::numeric_limits<double>::digits10)
-    iDec = std::numeric_limits<double>::digits10;
-
-  std::stringstream ss;
-  ss << std::fixed << std::setprecision(iDec) << dValue;
-  std::string stringValue = ss.str();
-  size_t iDecimalPos = stringValue.find(".");
-  *iDec2 = iDecimalPos == std::string::npos ? stringValue.size()
-                                            : static_cast<int>(iDecimalPos);
-  return CFX_ByteString(stringValue.c_str());
-}
-#endif
-
-}  // namespace
-
-bool CJS_PublicMethods::IsNumber(const CFX_WideString& str) {
-  CFX_WideString sTrim = StrTrim(str);
-  const FX_WCHAR* pTrim = sTrim.c_str();
-  const FX_WCHAR* p = pTrim;
-  bool bDot = false;
-  bool bKXJS = false;
-
-  wchar_t c;
-  while ((c = *p) != L'\0') {
-    if (c == L'.' || c == L',') {
-      if (bDot)
-        return false;
-      bDot = true;
-    } else if (c == L'-' || c == L'+') {
-      if (p != pTrim)
-        return false;
-    } else if (c == L'e' || c == L'E') {
-      if (bKXJS)
-        return false;
-
-      p++;
-      c = *p;
-      if (c == L'+' || c == L'-') {
-        bKXJS = true;
-      } else {
-        return false;
-      }
-    } else if (!FXSYS_iswdigit(c)) {
-      return false;
-    }
-    p++;
-  }
-
-  return true;
-}
-
-bool CJS_PublicMethods::maskSatisfied(wchar_t c_Change, wchar_t c_Mask) {
-  switch (c_Mask) {
-    case L'9':
-      return FXSYS_iswdigit(c_Change);
-    case L'A':
-      return FXSYS_iswalpha(c_Change);
-    case L'O':
-      return FXSYS_iswalnum(c_Change);
-    case L'X':
-      return true;
-    default:
-      return (c_Change == c_Mask);
-  }
-}
-
-bool CJS_PublicMethods::isReservedMaskChar(wchar_t ch) {
-  return ch == L'9' || ch == L'A' || ch == L'O' || ch == L'X';
-}
-
-double CJS_PublicMethods::AF_Simple(const FX_WCHAR* sFuction,
-                                    double dValue1,
-                                    double dValue2) {
-  if (FXSYS_wcsicmp(sFuction, L"AVG") == 0 ||
-      FXSYS_wcsicmp(sFuction, L"SUM") == 0) {
-    return dValue1 + dValue2;
-  }
-  if (FXSYS_wcsicmp(sFuction, L"PRD") == 0) {
-    return dValue1 * dValue2;
-  }
-  if (FXSYS_wcsicmp(sFuction, L"MIN") == 0) {
-    return std::min(dValue1, dValue2);
-  }
-  if (FXSYS_wcsicmp(sFuction, L"MAX") == 0) {
-    return std::max(dValue1, dValue2);
-  }
-  return dValue1;
-}
-
-CJS_Array CJS_PublicMethods::AF_MakeArrayFromList(CJS_Runtime* pRuntime,
-                                                  CJS_Value val) {
-  CJS_Array StrArray;
-  if (val.IsArrayObject()) {
-    val.ConvertToArray(pRuntime, StrArray);
-    return StrArray;
-  }
-  CFX_WideString wsStr = val.ToCFXWideString(pRuntime);
-  CFX_ByteString t = CFX_ByteString::FromUnicode(wsStr);
-  const char* p = t.c_str();
-
-  int ch = ',';
-  int nIndex = 0;
-
-  while (*p) {
-    const char* pTemp = strchr(p, ch);
-    if (!pTemp) {
-      StrArray.SetElement(
-          pRuntime, nIndex,
-          CJS_Value(pRuntime, StrTrim(CFX_ByteString(p)).c_str()));
-      break;
-    }
-
-    char* pSub = new char[pTemp - p + 1];
-    strncpy(pSub, p, pTemp - p);
-    *(pSub + (pTemp - p)) = '\0';
-
-    StrArray.SetElement(
-        pRuntime, nIndex,
-        CJS_Value(pRuntime, StrTrim(CFX_ByteString(pSub)).c_str()));
-    delete[] pSub;
-
-    nIndex++;
-    p = ++pTemp;
-  }
-  return StrArray;
-}
-
-int CJS_PublicMethods::ParseStringInteger(const CFX_WideString& str,
-                                          int nStart,
-                                          int& nSkip,
-                                          int nMaxStep) {
-  int nRet = 0;
-  nSkip = 0;
-  for (int i = nStart, sz = str.GetLength(); i < sz; i++) {
-    if (i - nStart > 10)
-      break;
-
-    FX_WCHAR c = str.GetAt(i);
-    if (!FXSYS_iswdigit(c))
-      break;
-
-    nRet = nRet * 10 + FXSYS_toDecimalDigit(c);
-    nSkip = i - nStart + 1;
-    if (nSkip >= nMaxStep)
-      break;
-  }
-
-  return nRet;
-}
-
-CFX_WideString CJS_PublicMethods::ParseStringString(const CFX_WideString& str,
-                                                    int nStart,
-                                                    int& nSkip) {
-  CFX_WideString swRet;
-  nSkip = 0;
-  for (int i = nStart, sz = str.GetLength(); i < sz; i++) {
-    FX_WCHAR c = str.GetAt(i);
-    if (!FXSYS_iswdigit(c))
-      break;
-
-    swRet += c;
-    nSkip = i - nStart + 1;
-  }
-
-  return swRet;
-}
-
-double CJS_PublicMethods::ParseNormalDate(const CFX_WideString& value,
-                                          bool* bWrongFormat) {
-  double dt = JS_GetDateTime();
-
-  int nYear = JS_GetYearFromTime(dt);
-  int nMonth = JS_GetMonthFromTime(dt) + 1;
-  int nDay = JS_GetDayFromTime(dt);
-  int nHour = JS_GetHourFromTime(dt);
-  int nMin = JS_GetMinFromTime(dt);
-  int nSec = JS_GetSecFromTime(dt);
-
-  int number[3];
-
-  int nSkip = 0;
-  int nLen = value.GetLength();
-  int nIndex = 0;
-  int i = 0;
-  while (i < nLen) {
-    if (nIndex > 2)
-      break;
-
-    FX_WCHAR c = value.GetAt(i);
-    if (FXSYS_iswdigit(c)) {
-      number[nIndex++] = ParseStringInteger(value, i, nSkip, 4);
-      i += nSkip;
-    } else {
-      i++;
-    }
-  }
-
-  if (nIndex == 2) {
-    // case2: month/day
-    // case3: day/month
-    if ((number[0] >= 1 && number[0] <= 12) &&
-        (number[1] >= 1 && number[1] <= 31)) {
-      nMonth = number[0];
-      nDay = number[1];
-    } else if ((number[0] >= 1 && number[0] <= 31) &&
-               (number[1] >= 1 && number[1] <= 12)) {
-      nDay = number[0];
-      nMonth = number[1];
-    }
-
-    if (bWrongFormat)
-      *bWrongFormat = false;
-  } else if (nIndex == 3) {
-    // case1: year/month/day
-    // case2: month/day/year
-    // case3: day/month/year
-
-    if (number[0] > 12 && (number[1] >= 1 && number[1] <= 12) &&
-        (number[2] >= 1 && number[2] <= 31)) {
-      nYear = number[0];
-      nMonth = number[1];
-      nDay = number[2];
-    } else if ((number[0] >= 1 && number[0] <= 12) &&
-               (number[1] >= 1 && number[1] <= 31) && number[2] > 31) {
-      nMonth = number[0];
-      nDay = number[1];
-      nYear = number[2];
-    } else if ((number[0] >= 1 && number[0] <= 31) &&
-               (number[1] >= 1 && number[1] <= 12) && number[2] > 31) {
-      nDay = number[0];
-      nMonth = number[1];
-      nYear = number[2];
-    }
-
-    if (bWrongFormat)
-      *bWrongFormat = false;
-  } else {
-    if (bWrongFormat)
-      *bWrongFormat = true;
-    return dt;
-  }
-
-  CFX_WideString swTemp;
-  swTemp.Format(L"%d/%d/%d %d:%d:%d", nMonth, nDay, nYear, nHour, nMin, nSec);
-  return JS_DateParse(swTemp);
-}
-
-double CJS_PublicMethods::MakeRegularDate(const CFX_WideString& value,
-                                          const CFX_WideString& format,
-                                          bool* bWrongFormat) {
-  double dt = JS_GetDateTime();
-
-  if (format.IsEmpty() || value.IsEmpty())
-    return dt;
-
-  int nYear = JS_GetYearFromTime(dt);
-  int nMonth = JS_GetMonthFromTime(dt) + 1;
-  int nDay = JS_GetDayFromTime(dt);
-  int nHour = JS_GetHourFromTime(dt);
-  int nMin = JS_GetMinFromTime(dt);
-  int nSec = JS_GetSecFromTime(dt);
-
-  int nYearSub = 99;  // nYear - 2000;
-
-  bool bPm = false;
-  bool bExit = false;
-  bool bBadFormat = false;
-
-  int i = 0;
-  int j = 0;
-
-  while (i < format.GetLength()) {
-    if (bExit)
-      break;
-
-    FX_WCHAR c = format.GetAt(i);
-    switch (c) {
-      case ':':
-      case '.':
-      case '-':
-      case '\\':
-      case '/':
-        i++;
-        j++;
-        break;
-
-      case 'y':
-      case 'm':
-      case 'd':
-      case 'H':
-      case 'h':
-      case 'M':
-      case 's':
-      case 't': {
-        int oldj = j;
-        int nSkip = 0;
-        int remaining = format.GetLength() - i - 1;
-
-        if (remaining == 0 || format.GetAt(i + 1) != c) {
-          switch (c) {
-            case 'y':
-              i++;
-              j++;
-              break;
-            case 'm':
-              nMonth = ParseStringInteger(value, j, nSkip, 2);
-              i++;
-              j += nSkip;
-              break;
-            case 'd':
-              nDay = ParseStringInteger(value, j, nSkip, 2);
-              i++;
-              j += nSkip;
-              break;
-            case 'H':
-              nHour = ParseStringInteger(value, j, nSkip, 2);
-              i++;
-              j += nSkip;
-              break;
-            case 'h':
-              nHour = ParseStringInteger(value, j, nSkip, 2);
-              i++;
-              j += nSkip;
-              break;
-            case 'M':
-              nMin = ParseStringInteger(value, j, nSkip, 2);
-              i++;
-              j += nSkip;
-              break;
-            case 's':
-              nSec = ParseStringInteger(value, j, nSkip, 2);
-              i++;
-              j += nSkip;
-              break;
-            case 't':
-              bPm = (j < value.GetLength() && value.GetAt(j) == 'p');
-              i++;
-              j++;
-              break;
-          }
-        } else if (remaining == 1 || format.GetAt(i + 2) != c) {
-          switch (c) {
-            case 'y':
-              nYear = ParseStringInteger(value, j, nSkip, 4);
-              i += 2;
-              j += nSkip;
-              break;
-            case 'm':
-              nMonth = ParseStringInteger(value, j, nSkip, 2);
-              i += 2;
-              j += nSkip;
-              break;
-            case 'd':
-              nDay = ParseStringInteger(value, j, nSkip, 2);
-              i += 2;
-              j += nSkip;
-              break;
-            case 'H':
-              nHour = ParseStringInteger(value, j, nSkip, 2);
-              i += 2;
-              j += nSkip;
-              break;
-            case 'h':
-              nHour = ParseStringInteger(value, j, nSkip, 2);
-              i += 2;
-              j += nSkip;
-              break;
-            case 'M':
-              nMin = ParseStringInteger(value, j, nSkip, 2);
-              i += 2;
-              j += nSkip;
-              break;
-            case 's':
-              nSec = ParseStringInteger(value, j, nSkip, 2);
-              i += 2;
-              j += nSkip;
-              break;
-            case 't':
-              bPm = (j + 1 < value.GetLength() && value.GetAt(j) == 'p' &&
-                     value.GetAt(j + 1) == 'm');
-              i += 2;
-              j += 2;
-              break;
-          }
-        } else if (remaining == 2 || format.GetAt(i + 3) != c) {
-          switch (c) {
-            case 'm': {
-              CFX_WideString sMonth = ParseStringString(value, j, nSkip);
-              bool bFind = false;
-              for (int m = 0; m < 12; m++) {
-                if (sMonth.CompareNoCase(months[m]) == 0) {
-                  nMonth = m + 1;
-                  i += 3;
-                  j += nSkip;
-                  bFind = true;
-                  break;
-                }
-              }
-
-              if (!bFind) {
-                nMonth = ParseStringInteger(value, j, nSkip, 3);
-                i += 3;
-                j += nSkip;
-              }
-            } break;
-            case 'y':
-              break;
-            default:
-              i += 3;
-              j += 3;
-              break;
-          }
-        } else if (remaining == 3 || format.GetAt(i + 4) != c) {
-          switch (c) {
-            case 'y':
-              nYear = ParseStringInteger(value, j, nSkip, 4);
-              j += nSkip;
-              i += 4;
-              break;
-            case 'm': {
-              bool bFind = false;
-
-              CFX_WideString sMonth = ParseStringString(value, j, nSkip);
-              sMonth.MakeLower();
-
-              for (int m = 0; m < 12; m++) {
-                CFX_WideString sFullMonths = fullmonths[m];
-                sFullMonths.MakeLower();
-
-                if (sFullMonths.Find(sMonth.c_str(), 0) != -1) {
-                  nMonth = m + 1;
-                  i += 4;
-                  j += nSkip;
-                  bFind = true;
-                  break;
-                }
-              }
-
-              if (!bFind) {
-                nMonth = ParseStringInteger(value, j, nSkip, 4);
-                i += 4;
-                j += nSkip;
-              }
-            } break;
-            default:
-              i += 4;
-              j += 4;
-              break;
-          }
-        } else {
-          if (j >= value.GetLength() || format.GetAt(i) != value.GetAt(j)) {
-            bBadFormat = true;
-            bExit = true;
-          }
-          i++;
-          j++;
-        }
-
-        if (oldj == j) {
-          bBadFormat = true;
-          bExit = true;
-        }
-      }
-
-      break;
-      default:
-        if (value.GetLength() <= j) {
-          bExit = true;
-        } else if (format.GetAt(i) != value.GetAt(j)) {
-          bBadFormat = true;
-          bExit = true;
-        }
-
-        i++;
-        j++;
-        break;
-    }
-  }
-
-  if (bPm)
-    nHour += 12;
-
-  if (nYear >= 0 && nYear <= nYearSub)
-    nYear += 2000;
-
-  if (nMonth < 1 || nMonth > 12)
-    bBadFormat = true;
-
-  if (nDay < 1 || nDay > 31)
-    bBadFormat = true;
-
-  if (nHour < 0 || nHour > 24)
-    bBadFormat = true;
-
-  if (nMin < 0 || nMin > 60)
-    bBadFormat = true;
-
-  if (nSec < 0 || nSec > 60)
-    bBadFormat = true;
-
-  double dRet = 0;
-  if (bBadFormat) {
-    dRet = ParseNormalDate(value, &bBadFormat);
-  } else {
-    dRet = JS_MakeDate(JS_MakeDay(nYear, nMonth - 1, nDay),
-                       JS_MakeTime(nHour, nMin, nSec, 0));
-    if (JS_PortIsNan(dRet))
-      dRet = JS_DateParse(value);
-  }
-
-  if (JS_PortIsNan(dRet))
-    dRet = ParseNormalDate(value, &bBadFormat);
-
-  if (bWrongFormat)
-    *bWrongFormat = bBadFormat;
-
-  return dRet;
-}
-
-CFX_WideString CJS_PublicMethods::MakeFormatDate(double dDate,
-                                                 const CFX_WideString& format) {
-  CFX_WideString sRet = L"", sPart = L"";
-
-  int nYear = JS_GetYearFromTime(dDate);
-  int nMonth = JS_GetMonthFromTime(dDate) + 1;
-  int nDay = JS_GetDayFromTime(dDate);
-  int nHour = JS_GetHourFromTime(dDate);
-  int nMin = JS_GetMinFromTime(dDate);
-  int nSec = JS_GetSecFromTime(dDate);
-
-  int i = 0;
-  while (i < format.GetLength()) {
-    FX_WCHAR c = format.GetAt(i);
-    int remaining = format.GetLength() - i - 1;
-    sPart = L"";
-    switch (c) {
-      case 'y':
-      case 'm':
-      case 'd':
-      case 'H':
-      case 'h':
-      case 'M':
-      case 's':
-      case 't':
-        if (remaining == 0 || format.GetAt(i + 1) != c) {
-          switch (c) {
-            case 'y':
-              sPart += c;
-              break;
-            case 'm':
-              sPart.Format(L"%d", nMonth);
-              break;
-            case 'd':
-              sPart.Format(L"%d", nDay);
-              break;
-            case 'H':
-              sPart.Format(L"%d", nHour);
-              break;
-            case 'h':
-              sPart.Format(L"%d", nHour > 12 ? nHour - 12 : nHour);
-              break;
-            case 'M':
-              sPart.Format(L"%d", nMin);
-              break;
-            case 's':
-              sPart.Format(L"%d", nSec);
-              break;
-            case 't':
-              sPart += nHour > 12 ? 'p' : 'a';
-              break;
-          }
-          i++;
-        } else if (remaining == 1 || format.GetAt(i + 2) != c) {
-          switch (c) {
-            case 'y':
-              sPart.Format(L"%02d", nYear - (nYear / 100) * 100);
-              break;
-            case 'm':
-              sPart.Format(L"%02d", nMonth);
-              break;
-            case 'd':
-              sPart.Format(L"%02d", nDay);
-              break;
-            case 'H':
-              sPart.Format(L"%02d", nHour);
-              break;
-            case 'h':
-              sPart.Format(L"%02d", nHour > 12 ? nHour - 12 : nHour);
-              break;
-            case 'M':
-              sPart.Format(L"%02d", nMin);
-              break;
-            case 's':
-              sPart.Format(L"%02d", nSec);
-              break;
-            case 't':
-              sPart = nHour > 12 ? L"pm" : L"am";
-              break;
-          }
-          i += 2;
-        } else if (remaining == 2 || format.GetAt(i + 3) != c) {
-          switch (c) {
-            case 'm':
-              i += 3;
-              if (nMonth > 0 && nMonth <= 12)
-                sPart += months[nMonth - 1];
-              break;
-            default:
-              i += 3;
-              sPart += c;
-              sPart += c;
-              sPart += c;
-              break;
-          }
-        } else if (remaining == 3 || format.GetAt(i + 4) != c) {
-          switch (c) {
-            case 'y':
-              sPart.Format(L"%04d", nYear);
-              i += 4;
-              break;
-            case 'm':
-              i += 4;
-              if (nMonth > 0 && nMonth <= 12)
-                sPart += fullmonths[nMonth - 1];
-              break;
-            default:
-              i += 4;
-              sPart += c;
-              sPart += c;
-              sPart += c;
-              sPart += c;
-              break;
-          }
-        } else {
-          i++;
-          sPart += c;
-        }
-        break;
-      default:
-        i++;
-        sPart += c;
-        break;
-    }
-
-    sRet += sPart;
-  }
-
-  return sRet;
-}
-
-// function AFNumber_Format(nDec, sepStyle, negStyle, currStyle, strCurrency,
-// bCurrencyPrepend)
-bool CJS_PublicMethods::AFNumber_Format(CJS_Runtime* pRuntime,
-                                        const std::vector<CJS_Value>& params,
-                                        CJS_Value& vRet,
-                                        CFX_WideString& sError) {
-#if _FX_OS_ != _FX_ANDROID_
-  if (params.size() != 6) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  CJS_EventHandler* pEvent =
-      pRuntime->GetCurrentEventContext()->GetEventHandler();
-  if (!pEvent->m_pValue)
-    return false;
-
-  CFX_WideString& Value = pEvent->Value();
-  CFX_ByteString strValue = StrTrim(CFX_ByteString::FromUnicode(Value));
-  if (strValue.IsEmpty())
-    return true;
-
-  int iDec = params[0].ToInt(pRuntime);
-  int iSepStyle = params[1].ToInt(pRuntime);
-  int iNegStyle = params[2].ToInt(pRuntime);
-  // params[3] is iCurrStyle, it's not used.
-  CFX_WideString wstrCurrency = params[4].ToCFXWideString(pRuntime);
-  bool bCurrencyPrepend = params[5].ToBool(pRuntime);
-
-  if (iDec < 0)
-    iDec = -iDec;
-
-  if (iSepStyle < 0 || iSepStyle > 3)
-    iSepStyle = 0;
-
-  if (iNegStyle < 0 || iNegStyle > 3)
-    iNegStyle = 0;
-
-  // Processing decimal places
-  strValue.Replace(",", ".");
-  double dValue = atof(strValue.c_str());
-  if (iDec > 0)
-    dValue += DOUBLE_CORRECT;
-
-  // Calculating number string
-  bool bNegative;
-  int iDec2;
-  strValue = CalculateString(dValue, iDec, &iDec2, &bNegative);
-  if (strValue.IsEmpty()) {
-    dValue = 0;
-    strValue = CalculateString(dValue, iDec, &iDec2, &bNegative);
-    if (strValue.IsEmpty()) {
-      strValue = "0";
-      iDec2 = 1;
-    }
-  }
-
-  // Processing separator style
-  if (iDec2 < strValue.GetLength()) {
-    if (iSepStyle == 2 || iSepStyle == 3)
-      strValue.Replace(".", ",");
-
-    if (iDec2 == 0)
-      strValue.Insert(iDec2, '0');
-  }
-  if (iSepStyle == 0 || iSepStyle == 2) {
-    char cSeparator;
-    if (iSepStyle == 0)
-      cSeparator = ',';
-    else
-      cSeparator = '.';
-
-    for (int iDecPositive = iDec2 - 3; iDecPositive > 0; iDecPositive -= 3)
-      strValue.Insert(iDecPositive, cSeparator);
-  }
-
-  // Processing currency string
-  Value = CFX_WideString::FromLocal(strValue.AsStringC());
-
-  if (bCurrencyPrepend)
-    Value = wstrCurrency + Value;
-  else
-    Value = Value + wstrCurrency;
-
-  // Processing negative style
-  if (bNegative) {
-    if (iNegStyle == 0)
-      Value = L"-" + Value;
-    else if (iNegStyle == 2 || iNegStyle == 3)
-      Value = L"(" + Value + L")";
-    if (iNegStyle == 1 || iNegStyle == 3) {
-      if (Field* fTarget = pEvent->Target_Field()) {
-        CJS_Array arColor;
-        CJS_Value vColElm(pRuntime);
-        vColElm = CJS_Value(pRuntime, L"RGB");
-        arColor.SetElement(pRuntime, 0, vColElm);
-        vColElm = CJS_Value(pRuntime, 1);
-        arColor.SetElement(pRuntime, 1, vColElm);
-        vColElm = CJS_Value(pRuntime, 0);
-        arColor.SetElement(pRuntime, 2, vColElm);
-        arColor.SetElement(pRuntime, 3, vColElm);
-
-        CJS_PropValue vProp(pRuntime);
-        vProp.StartGetting();
-        vProp << arColor;
-        vProp.StartSetting();
-        fTarget->textColor(pRuntime, vProp, sError);  // red
-      }
-    }
-  } else {
-    if (iNegStyle == 1 || iNegStyle == 3) {
-      if (Field* fTarget = pEvent->Target_Field()) {
-        CJS_Array arColor;
-        CJS_Value vColElm(pRuntime);
-        vColElm = CJS_Value(pRuntime, L"RGB");
-        arColor.SetElement(pRuntime, 0, vColElm);
-        vColElm = CJS_Value(pRuntime, 0);
-        arColor.SetElement(pRuntime, 1, vColElm);
-        arColor.SetElement(pRuntime, 2, vColElm);
-        arColor.SetElement(pRuntime, 3, vColElm);
-
-        CJS_PropValue vProp(pRuntime);
-        vProp.StartGetting();
-        fTarget->textColor(pRuntime, vProp, sError);
-
-        CJS_Array aProp;
-        vProp.GetJSValue()->ConvertToArray(pRuntime, aProp);
-
-        CPWL_Color crProp;
-        CPWL_Color crColor;
-        color::ConvertArrayToPWLColor(pRuntime, aProp, &crProp);
-        color::ConvertArrayToPWLColor(pRuntime, arColor, &crColor);
-
-        if (crColor != crProp) {
-          CJS_PropValue vProp2(pRuntime);
-          vProp2.StartGetting();
-          vProp2 << arColor;
-          vProp2.StartSetting();
-          fTarget->textColor(pRuntime, vProp2, sError);
-        }
-      }
-    }
-  }
-#endif
-  return true;
-}
-
-// function AFNumber_Keystroke(nDec, sepStyle, negStyle, currStyle, strCurrency,
-// bCurrencyPrepend)
-bool CJS_PublicMethods::AFNumber_Keystroke(CJS_Runtime* pRuntime,
-                                           const std::vector<CJS_Value>& params,
-                                           CJS_Value& vRet,
-                                           CFX_WideString& sError) {
-  if (params.size() < 2)
-    return false;
-
-  CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
-  if (!pEvent->m_pValue)
-    return false;
-
-  CFX_WideString& val = pEvent->Value();
-  CFX_WideString& wstrChange = pEvent->Change();
-  CFX_WideString wstrValue = val;
-
-  if (pEvent->WillCommit()) {
-    CFX_WideString swTemp = StrTrim(wstrValue);
-    if (swTemp.IsEmpty())
-      return true;
-
-    swTemp.Replace(L",", L".");
-    if (!IsNumber(swTemp.c_str())) {
-      pEvent->Rc() = false;
-      sError = JSGetStringFromID(IDS_STRING_JSAFNUMBER_KEYSTROKE);
-      AlertIfPossible(pContext, sError.c_str());
-    }
-    return true;  // it happens after the last keystroke and before validating,
-  }
-
-  CFX_WideString wstrSelected;
-  if (pEvent->SelStart() != -1) {
-    wstrSelected = wstrValue.Mid(pEvent->SelStart(),
-                                 pEvent->SelEnd() - pEvent->SelStart());
-  }
-
-  bool bHasSign = wstrValue.Find(L'-') != -1 && wstrSelected.Find(L'-') == -1;
-  if (bHasSign) {
-    // can't insert "change" in front to sign postion.
-    if (pEvent->SelStart() == 0) {
-      bool& bRc = pEvent->Rc();
-      bRc = false;
-      return true;
-    }
-  }
-
-  int iSepStyle = params[1].ToInt(pRuntime);
-  if (iSepStyle < 0 || iSepStyle > 3)
-    iSepStyle = 0;
-  const FX_WCHAR cSep = iSepStyle < 2 ? L'.' : L',';
-
-  bool bHasSep = wstrValue.Find(cSep) != -1;
-  for (FX_STRSIZE i = 0; i < wstrChange.GetLength(); ++i) {
-    if (wstrChange[i] == cSep) {
-      if (bHasSep) {
-        bool& bRc = pEvent->Rc();
-        bRc = false;
-        return true;
-      }
-      bHasSep = true;
-      continue;
-    }
-    if (wstrChange[i] == L'-') {
-      if (bHasSign) {
-        bool& bRc = pEvent->Rc();
-        bRc = false;
-        return true;
-      }
-      // sign's position is not correct
-      if (i != 0) {
-        bool& bRc = pEvent->Rc();
-        bRc = false;
-        return true;
-      }
-      if (pEvent->SelStart() != 0) {
-        bool& bRc = pEvent->Rc();
-        bRc = false;
-        return true;
-      }
-      bHasSign = true;
-      continue;
-    }
-
-    if (!FXSYS_iswdigit(wstrChange[i])) {
-      bool& bRc = pEvent->Rc();
-      bRc = false;
-      return true;
-    }
-  }
-
-  CFX_WideString wprefix = wstrValue.Mid(0, pEvent->SelStart());
-  CFX_WideString wpostfix;
-  if (pEvent->SelEnd() < wstrValue.GetLength())
-    wpostfix = wstrValue.Mid(pEvent->SelEnd());
-  val = wprefix + wstrChange + wpostfix;
-  return true;
-}
-
-// function AFPercent_Format(nDec, sepStyle)
-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_
-  if (params.size() != 2) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  CJS_EventHandler* pEvent =
-      pRuntime->GetCurrentEventContext()->GetEventHandler();
-  if (!pEvent->m_pValue)
-    return false;
-
-  CFX_WideString& Value = pEvent->Value();
-  CFX_ByteString strValue = StrTrim(CFX_ByteString::FromUnicode(Value));
-  if (strValue.IsEmpty())
-    return true;
-
-  int iDec = params[0].ToInt(pRuntime);
-  if (iDec < 0)
-    iDec = -iDec;
-
-  int iSepStyle = params[1].ToInt(pRuntime);
-  if (iSepStyle < 0 || iSepStyle > 3)
-    iSepStyle = 0;
-
-  // for processing decimal places
-  double dValue = atof(strValue.c_str());
-  dValue *= 100;
-  if (iDec > 0)
-    dValue += DOUBLE_CORRECT;
-
-  int iDec2;
-  int iNegative = 0;
-  strValue = fcvt(dValue, iDec, &iDec2, &iNegative);
-  if (strValue.IsEmpty()) {
-    dValue = 0;
-    strValue = fcvt(dValue, iDec, &iDec2, &iNegative);
-  }
-
-  if (iDec2 < 0) {
-    for (int iNum = 0; iNum < abs(iDec2); iNum++) {
-      strValue = "0" + strValue;
-    }
-    iDec2 = 0;
-  }
-  int iMax = strValue.GetLength();
-  if (iDec2 > iMax) {
-    for (int iNum = 0; iNum <= iDec2 - iMax; iNum++) {
-      strValue += "0";
-    }
-    iMax = iDec2 + 1;
-  }
-
-  // for processing seperator style
-  if (iDec2 < iMax) {
-    if (iSepStyle == 0 || iSepStyle == 1) {
-      strValue.Insert(iDec2, '.');
-      iMax++;
-    } else if (iSepStyle == 2 || iSepStyle == 3) {
-      strValue.Insert(iDec2, ',');
-      iMax++;
-    }
-
-    if (iDec2 == 0)
-      strValue.Insert(iDec2, '0');
-  }
-  if (iSepStyle == 0 || iSepStyle == 2) {
-    char cSeperator;
-    if (iSepStyle == 0)
-      cSeperator = ',';
-    else
-      cSeperator = '.';
-
-    for (int iDecPositive = iDec2 - 3; iDecPositive > 0; iDecPositive -= 3) {
-      strValue.Insert(iDecPositive, cSeperator);
-      iMax++;
-    }
-  }
-
-  // negative mark
-  if (iNegative)
-    strValue = "-" + strValue;
-  strValue += "%";
-  Value = CFX_WideString::FromLocal(strValue.AsStringC());
-#endif
-  return true;
-}
-// AFPercent_Keystroke(nDec, sepStyle)
-bool CJS_PublicMethods::AFPercent_Keystroke(
-    CJS_Runtime* pRuntime,
-    const std::vector<CJS_Value>& params,
-    CJS_Value& vRet,
-    CFX_WideString& sError) {
-  return AFNumber_Keystroke(pRuntime, params, vRet, sError);
-}
-
-// function AFDate_FormatEx(cFormat)
-bool CJS_PublicMethods::AFDate_FormatEx(CJS_Runtime* pRuntime,
-                                        const std::vector<CJS_Value>& params,
-                                        CJS_Value& vRet,
-                                        CFX_WideString& sError) {
-  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;
-
-  CFX_WideString& val = pEvent->Value();
-  CFX_WideString strValue = val;
-  if (strValue.IsEmpty())
-    return true;
-
-  CFX_WideString sFormat = params[0].ToCFXWideString(pRuntime);
-  double dDate = 0.0f;
-
-  if (strValue.Find(L"GMT") != -1) {
-    // for GMT format time
-    // such as "Tue Aug 11 14:24:16 GMT+08002009"
-    dDate = MakeInterDate(strValue);
-  } else {
-    dDate = MakeRegularDate(strValue, sFormat, nullptr);
-  }
-
-  if (JS_PortIsNan(dDate)) {
-    CFX_WideString swMsg;
-    swMsg.Format(JSGetStringFromID(IDS_STRING_JSPARSEDATE).c_str(),
-                 sFormat.c_str());
-    AlertIfPossible(pContext, swMsg.c_str());
-    return false;
-  }
-
-  val = MakeFormatDate(dDate, sFormat);
-  return true;
-}
-
-double CJS_PublicMethods::MakeInterDate(const CFX_WideString& strValue) {
-  std::vector<CFX_WideString> wsArray;
-  CFX_WideString sTemp = L"";
-  for (int i = 0; i < strValue.GetLength(); ++i) {
-    FX_WCHAR c = strValue.GetAt(i);
-    if (c == L' ' || c == L':') {
-      wsArray.push_back(sTemp);
-      sTemp = L"";
-      continue;
-    }
-    sTemp += c;
-  }
-  wsArray.push_back(sTemp);
-  if (wsArray.size() != 8)
-    return 0;
-
-  int nMonth = 1;
-  sTemp = wsArray[1];
-  if (sTemp.Compare(L"Jan") == 0)
-    nMonth = 1;
-  else if (sTemp.Compare(L"Feb") == 0)
-    nMonth = 2;
-  else if (sTemp.Compare(L"Mar") == 0)
-    nMonth = 3;
-  else if (sTemp.Compare(L"Apr") == 0)
-    nMonth = 4;
-  else if (sTemp.Compare(L"May") == 0)
-    nMonth = 5;
-  else if (sTemp.Compare(L"Jun") == 0)
-    nMonth = 6;
-  else if (sTemp.Compare(L"Jul") == 0)
-    nMonth = 7;
-  else if (sTemp.Compare(L"Aug") == 0)
-    nMonth = 8;
-  else if (sTemp.Compare(L"Sep") == 0)
-    nMonth = 9;
-  else if (sTemp.Compare(L"Oct") == 0)
-    nMonth = 10;
-  else if (sTemp.Compare(L"Nov") == 0)
-    nMonth = 11;
-  else if (sTemp.Compare(L"Dec") == 0)
-    nMonth = 12;
-
-  int nDay = FX_atof(wsArray[2].AsStringC());
-  int nHour = FX_atof(wsArray[3].AsStringC());
-  int nMin = FX_atof(wsArray[4].AsStringC());
-  int nSec = FX_atof(wsArray[5].AsStringC());
-  int nYear = FX_atof(wsArray[7].AsStringC());
-  double dRet = JS_MakeDate(JS_MakeDay(nYear, nMonth - 1, nDay),
-                            JS_MakeTime(nHour, nMin, nSec, 0));
-  if (JS_PortIsNan(dRet))
-    dRet = JS_DateParse(strValue);
-
-  return dRet;
-}
-
-// AFDate_KeystrokeEx(cFormat)
-bool CJS_PublicMethods::AFDate_KeystrokeEx(CJS_Runtime* pRuntime,
-                                           const std::vector<CJS_Value>& params,
-                                           CJS_Value& vRet,
-                                           CFX_WideString& sError) {
-  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;
-
-    CFX_WideString sFormat = params[0].ToCFXWideString(pRuntime);
-    bool bWrongFormat = false;
-    double dRet = MakeRegularDate(strValue, sFormat, &bWrongFormat);
-    if (bWrongFormat || JS_PortIsNan(dRet)) {
-      CFX_WideString swMsg;
-      swMsg.Format(JSGetStringFromID(IDS_STRING_JSPARSEDATE).c_str(),
-                   sFormat.c_str());
-      AlertIfPossible(pContext, swMsg.c_str());
-      pEvent->Rc() = false;
-      return true;
-    }
-  }
-  return true;
-}
-
-bool CJS_PublicMethods::AFDate_Format(CJS_Runtime* pRuntime,
-                                      const std::vector<CJS_Value>& params,
-                                      CJS_Value& vRet,
-                                      CFX_WideString& sError) {
-  if (params.size() != 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  int iIndex = params[0].ToInt(pRuntime);
-  const FX_WCHAR* cFormats[] = {L"m/d",
-                                L"m/d/yy",
-                                L"mm/dd/yy",
-                                L"mm/yy",
-                                L"d-mmm",
-                                L"d-mmm-yy",
-                                L"dd-mmm-yy",
-                                L"yy-mm-dd",
-                                L"mmm-yy",
-                                L"mmmm-yy",
-                                L"mmm d, yyyy",
-                                L"mmmm d, yyyy",
-                                L"m/d/yy h:MM tt",
-                                L"m/d/yy HH:MM"};
-
-  if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats)))
-    iIndex = 0;
-
-  std::vector<CJS_Value> newParams;
-  newParams.push_back(CJS_Value(pRuntime, cFormats[iIndex]));
-  return AFDate_FormatEx(pRuntime, newParams, vRet, sError);
-}
-
-// AFDate_KeystrokeEx(cFormat)
-bool CJS_PublicMethods::AFDate_Keystroke(CJS_Runtime* pRuntime,
-                                         const std::vector<CJS_Value>& params,
-                                         CJS_Value& vRet,
-                                         CFX_WideString& sError) {
-  if (params.size() != 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  int iIndex = params[0].ToInt(pRuntime);
-  const FX_WCHAR* cFormats[] = {L"m/d",
-                                L"m/d/yy",
-                                L"mm/dd/yy",
-                                L"mm/yy",
-                                L"d-mmm",
-                                L"d-mmm-yy",
-                                L"dd-mmm-yy",
-                                L"yy-mm-dd",
-                                L"mmm-yy",
-                                L"mmmm-yy",
-                                L"mmm d, yyyy",
-                                L"mmmm d, yyyy",
-                                L"m/d/yy h:MM tt",
-                                L"m/d/yy HH:MM"};
-
-  if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats)))
-    iIndex = 0;
-
-  std::vector<CJS_Value> newParams;
-  newParams.push_back(CJS_Value(pRuntime, cFormats[iIndex]));
-  return AFDate_KeystrokeEx(pRuntime, newParams, vRet, sError);
-}
-
-// function AFTime_Format(ptf)
-bool CJS_PublicMethods::AFTime_Format(CJS_Runtime* pRuntime,
-                                      const std::vector<CJS_Value>& params,
-                                      CJS_Value& vRet,
-                                      CFX_WideString& sError) {
-  if (params.size() != 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  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"};
-
-  if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats)))
-    iIndex = 0;
-
-  std::vector<CJS_Value> newParams;
-  newParams.push_back(CJS_Value(pRuntime, cFormats[iIndex]));
-  return AFDate_FormatEx(pRuntime, newParams, vRet, sError);
-}
-
-bool CJS_PublicMethods::AFTime_Keystroke(CJS_Runtime* pRuntime,
-                                         const std::vector<CJS_Value>& params,
-                                         CJS_Value& vRet,
-                                         CFX_WideString& sError) {
-  if (params.size() != 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  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"};
-
-  if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats)))
-    iIndex = 0;
-
-  std::vector<CJS_Value> newParams;
-  newParams.push_back(CJS_Value(pRuntime, cFormats[iIndex]));
-  return AFDate_KeystrokeEx(pRuntime, newParams, vRet, sError);
-}
-
-bool CJS_PublicMethods::AFTime_FormatEx(CJS_Runtime* pRuntime,
-                                        const std::vector<CJS_Value>& params,
-                                        CJS_Value& vRet,
-                                        CFX_WideString& sError) {
-  return AFDate_FormatEx(pRuntime, params, vRet, sError);
-}
-
-bool CJS_PublicMethods::AFTime_KeystrokeEx(CJS_Runtime* pRuntime,
-                                           const std::vector<CJS_Value>& params,
-                                           CJS_Value& vRet,
-                                           CFX_WideString& sError) {
-  return AFDate_KeystrokeEx(pRuntime, params, vRet, sError);
-}
-
-// function AFSpecial_Format(psf)
-bool CJS_PublicMethods::AFSpecial_Format(CJS_Runtime* pRuntime,
-                                         const std::vector<CJS_Value>& params,
-                                         CJS_Value& vRet,
-                                         CFX_WideString& sError) {
-  if (params.size() != 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  CJS_EventHandler* pEvent =
-      pRuntime->GetCurrentEventContext()->GetEventHandler();
-  if (!pEvent->m_pValue)
-    return false;
-
-  CFX_WideString wsSource = pEvent->Value();
-  CFX_WideString wsFormat;
-  switch (params[0].ToInt(pRuntime)) {
-    case 0:
-      wsFormat = L"99999";
-      break;
-    case 1:
-      wsFormat = L"99999-9999";
-      break;
-    case 2:
-      if (util::printx(L"9999999999", wsSource).GetLength() >= 10)
-        wsFormat = L"(999) 999-9999";
-      else
-        wsFormat = L"999-9999";
-      break;
-    case 3:
-      wsFormat = L"999-99-9999";
-      break;
-  }
-
-  pEvent->Value() = util::printx(wsFormat, wsSource);
-  return true;
-}
-
-// function AFSpecial_KeystrokeEx(mask)
-bool CJS_PublicMethods::AFSpecial_KeystrokeEx(
-    CJS_Runtime* pRuntime,
-    const std::vector<CJS_Value>& params,
-    CJS_Value& vRet,
-    CFX_WideString& sError) {
-  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;
-
-  CFX_WideString& valEvent = pEvent->Value();
-  CFX_WideString wstrMask = params[0].ToCFXWideString(pRuntime);
-  if (wstrMask.IsEmpty())
-    return true;
-
-  if (pEvent->WillCommit()) {
-    if (valEvent.IsEmpty())
-      return true;
-
-    FX_STRSIZE iIndexMask = 0;
-    for (; iIndexMask < valEvent.GetLength(); ++iIndexMask) {
-      if (!maskSatisfied(valEvent[iIndexMask], wstrMask[iIndexMask]))
-        break;
-    }
-
-    if (iIndexMask != wstrMask.GetLength() ||
-        (iIndexMask != valEvent.GetLength() && wstrMask.GetLength() != 0)) {
-      AlertIfPossible(
-          pContext, JSGetStringFromID(IDS_STRING_JSAFNUMBER_KEYSTROKE).c_str());
-      pEvent->Rc() = false;
-    }
-    return true;
-  }
-
-  CFX_WideString& wideChange = pEvent->Change();
-  if (wideChange.IsEmpty())
-    return true;
-
-  CFX_WideString wChange = wideChange;
-  FX_STRSIZE iIndexMask = pEvent->SelStart();
-  FX_STRSIZE combined_len = valEvent.GetLength() + wChange.GetLength() +
-                            pEvent->SelStart() - pEvent->SelEnd();
-  if (combined_len > wstrMask.GetLength()) {
-    AlertIfPossible(pContext,
-                    JSGetStringFromID(IDS_STRING_JSPARAM_TOOLONG).c_str());
-    pEvent->Rc() = false;
-    return true;
-  }
-
-  if (iIndexMask >= wstrMask.GetLength() && !wChange.IsEmpty()) {
-    AlertIfPossible(pContext,
-                    JSGetStringFromID(IDS_STRING_JSPARAM_TOOLONG).c_str());
-    pEvent->Rc() = false;
-    return true;
-  }
-
-  for (FX_STRSIZE i = 0; i < wChange.GetLength(); ++i) {
-    if (iIndexMask >= wstrMask.GetLength()) {
-      AlertIfPossible(pContext,
-                      JSGetStringFromID(IDS_STRING_JSPARAM_TOOLONG).c_str());
-      pEvent->Rc() = false;
-      return true;
-    }
-    FX_WCHAR wMask = wstrMask[iIndexMask];
-    if (!isReservedMaskChar(wMask))
-      wChange.SetAt(i, wMask);
-
-    if (!maskSatisfied(wChange[i], wMask)) {
-      pEvent->Rc() = false;
-      return true;
-    }
-    iIndexMask++;
-  }
-  wideChange = wChange;
-  return true;
-}
-
-// function AFSpecial_Keystroke(psf)
-bool CJS_PublicMethods::AFSpecial_Keystroke(
-    CJS_Runtime* pRuntime,
-    const std::vector<CJS_Value>& params,
-    CJS_Value& vRet,
-    CFX_WideString& sError) {
-  if (params.size() != 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  CJS_EventHandler* pEvent =
-      pRuntime->GetCurrentEventContext()->GetEventHandler();
-  if (!pEvent->m_pValue)
-    return false;
-
-  const char* cFormat = "";
-  switch (params[0].ToInt(pRuntime)) {
-    case 0:
-      cFormat = "99999";
-      break;
-    case 1:
-      cFormat = "999999999";
-      break;
-    case 2:
-      if (pEvent->Value().GetLength() + pEvent->Change().GetLength() > 7)
-        cFormat = "9999999999";
-      else
-        cFormat = "9999999";
-      break;
-    case 3:
-      cFormat = "999999999";
-      break;
-  }
-
-  std::vector<CJS_Value> params2;
-  params2.push_back(CJS_Value(pRuntime, cFormat));
-  return AFSpecial_KeystrokeEx(pRuntime, params2, vRet, sError);
-}
-
-bool CJS_PublicMethods::AFMergeChange(CJS_Runtime* pRuntime,
-                                      const std::vector<CJS_Value>& params,
-                                      CJS_Value& vRet,
-                                      CFX_WideString& sError) {
-  if (params.size() != 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  CJS_EventHandler* pEventHandler =
-      pRuntime->GetCurrentEventContext()->GetEventHandler();
-
-  CFX_WideString swValue;
-  if (pEventHandler->m_pValue)
-    swValue = pEventHandler->Value();
-
-  if (pEventHandler->WillCommit()) {
-    vRet = CJS_Value(pRuntime, swValue.c_str());
-    return true;
-  }
-
-  CFX_WideString prefix, postfix;
-
-  if (pEventHandler->SelStart() >= 0)
-    prefix = swValue.Mid(0, pEventHandler->SelStart());
-  else
-    prefix = L"";
-
-  if (pEventHandler->SelEnd() >= 0 &&
-      pEventHandler->SelEnd() <= swValue.GetLength())
-    postfix = swValue.Mid(pEventHandler->SelEnd(),
-                          swValue.GetLength() - pEventHandler->SelEnd());
-  else
-    postfix = L"";
-
-  vRet =
-      CJS_Value(pRuntime, (prefix + pEventHandler->Change() + postfix).c_str());
-  return true;
-}
-
-bool CJS_PublicMethods::AFParseDateEx(CJS_Runtime* pRuntime,
-                                      const std::vector<CJS_Value>& params,
-                                      CJS_Value& vRet,
-                                      CFX_WideString& sError) {
-  if (params.size() != 2) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  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(pRuntime->GetCurrentEventContext(), swMsg.c_str());
-    return false;
-  }
-
-  vRet = CJS_Value(pRuntime, dDate);
-  return true;
-}
-
-bool CJS_PublicMethods::AFSimple(CJS_Runtime* pRuntime,
-                                 const std::vector<CJS_Value>& params,
-                                 CJS_Value& vRet,
-                                 CFX_WideString& sError) {
-  if (params.size() != 3) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  vRet = CJS_Value(pRuntime, static_cast<double>(AF_Simple(
-                                 params[0].ToCFXWideString(pRuntime).c_str(),
-                                 params[1].ToDouble(pRuntime),
-                                 params[2].ToDouble(pRuntime))));
-
-  return true;
-}
-
-bool CJS_PublicMethods::AFMakeNumber(CJS_Runtime* pRuntime,
-                                     const std::vector<CJS_Value>& params,
-                                     CJS_Value& vRet,
-                                     CFX_WideString& sError) {
-  if (params.size() != 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  CFX_WideString ws = params[0].ToCFXWideString(pRuntime);
-  ws.Replace(L",", L".");
-  vRet = CJS_Value(pRuntime, ws.c_str());
-  vRet.MaybeCoerceToNumber(pRuntime);
-  if (vRet.GetType() != CJS_Value::VT_number)
-    vRet = CJS_Value(pRuntime, 0);
-  return true;
-}
-
-bool CJS_PublicMethods::AFSimple_Calculate(CJS_Runtime* pRuntime,
-                                           const std::vector<CJS_Value>& params,
-                                           CJS_Value& vRet,
-                                           CFX_WideString& sError) {
-  if (params.size() != 2) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  CJS_Value params1 = params[1];
-  if (!params1.IsArrayObject() && params1.GetType() != CJS_Value::VT_string) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  CPDFSDK_InterForm* pReaderInterForm =
-      pRuntime->GetFormFillEnv()->GetInterForm();
-  CPDF_InterForm* pInterForm = pReaderInterForm->GetInterForm();
-
-  CFX_WideString sFunction = params[0].ToCFXWideString(pRuntime);
-  double dValue = wcscmp(sFunction.c_str(), L"PRD") == 0 ? 1.0 : 0.0;
-
-  CJS_Array FieldNameArray = AF_MakeArrayFromList(pRuntime, params1);
-  int nFieldsCount = 0;
-
-  for (int i = 0, isz = FieldNameArray.GetLength(pRuntime); i < isz; i++) {
-    CJS_Value jsValue(pRuntime);
-    FieldNameArray.GetElement(pRuntime, i, jsValue);
-    CFX_WideString wsFieldName = jsValue.ToCFXWideString(pRuntime);
-
-    for (int j = 0, jsz = pInterForm->CountFields(wsFieldName); j < jsz; j++) {
-      if (CPDF_FormField* pFormField = pInterForm->GetField(j, wsFieldName)) {
-        double dTemp = 0.0;
-        switch (pFormField->GetFieldType()) {
-          case FIELDTYPE_TEXTFIELD:
-          case FIELDTYPE_COMBOBOX: {
-            CFX_WideString trimmed = pFormField->GetValue();
-            trimmed.TrimRight();
-            trimmed.TrimLeft();
-            dTemp = FX_atof(trimmed.AsStringC());
-          } break;
-          case FIELDTYPE_PUSHBUTTON: {
-            dTemp = 0.0;
-          } break;
-          case FIELDTYPE_CHECKBOX:
-          case FIELDTYPE_RADIOBUTTON: {
-            dTemp = 0.0;
-            for (int c = 0, csz = pFormField->CountControls(); c < csz; c++) {
-              if (CPDF_FormControl* pFormCtrl = pFormField->GetControl(c)) {
-                if (pFormCtrl->IsChecked()) {
-                  CFX_WideString trimmed = pFormCtrl->GetExportValue();
-                  trimmed.TrimRight();
-                  trimmed.TrimLeft();
-                  dTemp = FX_atof(trimmed.AsStringC());
-                  break;
-                }
-              }
-            }
-          } break;
-          case FIELDTYPE_LISTBOX: {
-            if (pFormField->CountSelectedItems() <= 1) {
-              CFX_WideString trimmed = pFormField->GetValue();
-              trimmed.TrimRight();
-              trimmed.TrimLeft();
-              dTemp = FX_atof(trimmed.AsStringC());
-            }
-          } break;
-          default:
-            break;
-        }
-
-        if (i == 0 && j == 0 && (wcscmp(sFunction.c_str(), L"MIN") == 0 ||
-                                 wcscmp(sFunction.c_str(), L"MAX") == 0))
-          dValue = dTemp;
-
-        dValue = AF_Simple(sFunction.c_str(), dValue, dTemp);
-
-        nFieldsCount++;
-      }
-    }
-  }
-
-  if (wcscmp(sFunction.c_str(), L"AVG") == 0 && nFieldsCount > 0)
-    dValue /= nFieldsCount;
-
-  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);
-
-  return true;
-}
-
-/* This function validates the current event to ensure that its value is
-** within the specified range. */
-
-bool CJS_PublicMethods::AFRange_Validate(CJS_Runtime* pRuntime,
-                                         const std::vector<CJS_Value>& params,
-                                         CJS_Value& vRet,
-                                         CFX_WideString& sError) {
-  if (params.size() != 4) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-  CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
-  CJS_EventHandler* pEvent = pContext->GetEventHandler();
-  if (!pEvent->m_pValue)
-    return false;
-
-  if (pEvent->Value().IsEmpty())
-    return true;
-
-  double dEentValue =
-      atof(CFX_ByteString::FromUnicode(pEvent->Value()).c_str());
-  bool bGreaterThan = params[0].ToBool(pRuntime);
-  double dGreaterThan = params[1].ToDouble(pRuntime);
-  bool bLessThan = params[2].ToBool(pRuntime);
-  double dLessThan = params[3].ToDouble(pRuntime);
-  CFX_WideString swMsg;
-
-  if (bGreaterThan && bLessThan) {
-    if (dEentValue < dGreaterThan || dEentValue > dLessThan)
-      swMsg.Format(JSGetStringFromID(IDS_STRING_JSRANGE1).c_str(),
-                   params[1].ToCFXWideString(pRuntime).c_str(),
-                   params[3].ToCFXWideString(pRuntime).c_str());
-  } else if (bGreaterThan) {
-    if (dEentValue < dGreaterThan)
-      swMsg.Format(JSGetStringFromID(IDS_STRING_JSRANGE2).c_str(),
-                   params[1].ToCFXWideString(pRuntime).c_str());
-  } else if (bLessThan) {
-    if (dEentValue > dLessThan)
-      swMsg.Format(JSGetStringFromID(IDS_STRING_JSRANGE3).c_str(),
-                   params[3].ToCFXWideString(pRuntime).c_str());
-  }
-
-  if (!swMsg.IsEmpty()) {
-    AlertIfPossible(pContext, swMsg.c_str());
-    pEvent->Rc() = false;
-  }
-  return true;
-}
-
-bool CJS_PublicMethods::AFExtractNums(CJS_Runtime* pRuntime,
-                                      const std::vector<CJS_Value>& params,
-                                      CJS_Value& vRet,
-                                      CFX_WideString& sError) {
-  if (params.size() != 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  CFX_WideString str = params[0].ToCFXWideString(pRuntime);
-  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);
-    if (FXSYS_iswdigit(wc)) {
-      sPart += wc;
-    } else {
-      if (sPart.GetLength() > 0) {
-        nums.SetElement(pRuntime, nIndex, CJS_Value(pRuntime, sPart.c_str()));
-        sPart = L"";
-        nIndex++;
-      }
-    }
-  }
-
-  if (sPart.GetLength() > 0) {
-    nums.SetElement(pRuntime, nIndex, CJS_Value(pRuntime, sPart.c_str()));
-  }
-
-  if (nums.GetLength(pRuntime) > 0)
-    vRet = CJS_Value(pRuntime, nums);
-  else
-    vRet.SetNull(pRuntime);
-
-  return true;
-}
diff --git a/fpdfsdk/javascript/PublicMethods.h b/fpdfsdk/javascript/PublicMethods.h
deleted file mode 100644
index 060c743..0000000
--- a/fpdfsdk/javascript/PublicMethods.h
+++ /dev/null
@@ -1,162 +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 FPDFSDK_JAVASCRIPT_PUBLICMETHODS_H_
-#define FPDFSDK_JAVASCRIPT_PUBLICMETHODS_H_
-
-#include <string>
-#include <vector>
-
-#include "fpdfsdk/javascript/JS_Define.h"
-
-class CJS_PublicMethods : public CJS_Object {
- public:
-  explicit CJS_PublicMethods(v8::Local<v8::Object> pObject)
-      : CJS_Object(pObject) {}
-  ~CJS_PublicMethods() override {}
-
-  static bool AFNumber_Format(CJS_Runtime* pRuntime,
-                              const std::vector<CJS_Value>& params,
-                              CJS_Value& vRet,
-                              CFX_WideString& sError);
-  static bool AFNumber_Keystroke(CJS_Runtime* pRuntime,
-                                 const std::vector<CJS_Value>& params,
-                                 CJS_Value& vRet,
-                                 CFX_WideString& sError);
-  static bool AFPercent_Format(CJS_Runtime* pRuntime,
-                               const std::vector<CJS_Value>& params,
-                               CJS_Value& vRet,
-                               CFX_WideString& sError);
-  static bool AFPercent_Keystroke(CJS_Runtime* pRuntime,
-                                  const std::vector<CJS_Value>& params,
-                                  CJS_Value& vRet,
-                                  CFX_WideString& sError);
-  static bool AFDate_FormatEx(CJS_Runtime* pRuntime,
-                              const std::vector<CJS_Value>& params,
-                              CJS_Value& vRet,
-                              CFX_WideString& sError);
-  static bool AFDate_KeystrokeEx(CJS_Runtime* pRuntime,
-                                 const std::vector<CJS_Value>& params,
-                                 CJS_Value& vRet,
-                                 CFX_WideString& sError);
-  static bool AFDate_Format(CJS_Runtime* pRuntime,
-                            const std::vector<CJS_Value>& params,
-                            CJS_Value& vRet,
-                            CFX_WideString& sError);
-  static bool AFDate_Keystroke(CJS_Runtime* pRuntime,
-                               const std::vector<CJS_Value>& params,
-                               CJS_Value& vRet,
-                               CFX_WideString& sError);
-  static bool AFTime_FormatEx(CJS_Runtime* pRuntime,
-                              const std::vector<CJS_Value>& params,
-                              CJS_Value& vRet,
-                              CFX_WideString& sError);  //
-  static bool AFTime_KeystrokeEx(CJS_Runtime* pRuntime,
-                                 const std::vector<CJS_Value>& params,
-                                 CJS_Value& vRet,
-                                 CFX_WideString& sError);
-  static bool AFTime_Format(CJS_Runtime* pRuntime,
-                            const std::vector<CJS_Value>& params,
-                            CJS_Value& vRet,
-                            CFX_WideString& sError);
-  static bool AFTime_Keystroke(CJS_Runtime* pRuntime,
-                               const std::vector<CJS_Value>& params,
-                               CJS_Value& vRet,
-                               CFX_WideString& sError);
-  static bool AFSpecial_Format(CJS_Runtime* pRuntime,
-                               const std::vector<CJS_Value>& params,
-                               CJS_Value& vRet,
-                               CFX_WideString& sError);
-  static bool AFSpecial_Keystroke(CJS_Runtime* pRuntime,
-                                  const std::vector<CJS_Value>& params,
-                                  CJS_Value& vRet,
-                                  CFX_WideString& sError);
-  static bool AFSpecial_KeystrokeEx(CJS_Runtime* pRuntime,
-                                    const std::vector<CJS_Value>& params,
-                                    CJS_Value& vRet,
-                                    CFX_WideString& sError);  //
-  static bool AFSimple(CJS_Runtime* pRuntime,
-                       const std::vector<CJS_Value>& params,
-                       CJS_Value& vRet,
-                       CFX_WideString& sError);
-  static bool AFMakeNumber(CJS_Runtime* pRuntime,
-                           const std::vector<CJS_Value>& params,
-                           CJS_Value& vRet,
-                           CFX_WideString& sError);
-  static bool AFSimple_Calculate(CJS_Runtime* pRuntime,
-                                 const std::vector<CJS_Value>& params,
-                                 CJS_Value& vRet,
-                                 CFX_WideString& sError);
-  static bool AFRange_Validate(CJS_Runtime* pRuntime,
-                               const std::vector<CJS_Value>& params,
-                               CJS_Value& vRet,
-                               CFX_WideString& sError);
-  static bool AFMergeChange(CJS_Runtime* pRuntime,
-                            const std::vector<CJS_Value>& params,
-                            CJS_Value& vRet,
-                            CFX_WideString& sError);
-  static bool AFParseDateEx(CJS_Runtime* pRuntime,
-                            const std::vector<CJS_Value>& params,
-                            CJS_Value& vRet,
-                            CFX_WideString& sError);
-  static bool AFExtractNums(CJS_Runtime* pRuntime,
-                            const std::vector<CJS_Value>& params,
-                            CJS_Value& vRet,
-                            CFX_WideString& sError);
-
-  JS_STATIC_GLOBAL_FUN(AFNumber_Format);
-  JS_STATIC_GLOBAL_FUN(AFNumber_Keystroke);
-  JS_STATIC_GLOBAL_FUN(AFPercent_Format);
-  JS_STATIC_GLOBAL_FUN(AFPercent_Keystroke);
-  JS_STATIC_GLOBAL_FUN(AFDate_FormatEx);
-  JS_STATIC_GLOBAL_FUN(AFDate_KeystrokeEx);
-  JS_STATIC_GLOBAL_FUN(AFDate_Format);
-  JS_STATIC_GLOBAL_FUN(AFDate_Keystroke);
-  JS_STATIC_GLOBAL_FUN(AFTime_FormatEx);
-  JS_STATIC_GLOBAL_FUN(AFTime_KeystrokeEx);
-  JS_STATIC_GLOBAL_FUN(AFTime_Format);
-  JS_STATIC_GLOBAL_FUN(AFTime_Keystroke);
-  JS_STATIC_GLOBAL_FUN(AFSpecial_Format);
-  JS_STATIC_GLOBAL_FUN(AFSpecial_Keystroke);
-  JS_STATIC_GLOBAL_FUN(AFSpecial_KeystrokeEx);
-  JS_STATIC_GLOBAL_FUN(AFSimple);
-  JS_STATIC_GLOBAL_FUN(AFMakeNumber);
-  JS_STATIC_GLOBAL_FUN(AFSimple_Calculate);
-  JS_STATIC_GLOBAL_FUN(AFRange_Validate);
-  JS_STATIC_GLOBAL_FUN(AFMergeChange);
-  JS_STATIC_GLOBAL_FUN(AFParseDateEx);
-  JS_STATIC_GLOBAL_FUN(AFExtractNums);
-
-  JS_STATIC_DECLARE_GLOBAL_FUN();
-
-  static int ParseStringInteger(const CFX_WideString& string,
-                                int nStart,
-                                int& nSkip,
-                                int nMaxStep);
-  static CFX_WideString ParseStringString(const CFX_WideString& string,
-                                          int nStart,
-                                          int& nSkip);
-  static double MakeRegularDate(const CFX_WideString& value,
-                                const CFX_WideString& format,
-                                bool* bWrongFormat);
-  static CFX_WideString MakeFormatDate(double dDate,
-                                       const CFX_WideString& format);
-  static double ParseNormalDate(const CFX_WideString& value,
-                                bool* bWrongFormat);
-  static double MakeInterDate(const CFX_WideString& value);
-
-  static bool IsNumber(const CFX_WideString& str);
-
-  static bool maskSatisfied(wchar_t c_Change, wchar_t c_Mask);
-  static bool isReservedMaskChar(wchar_t ch);
-
-  static double AF_Simple(const FX_WCHAR* sFuction,
-                          double dValue1,
-                          double dValue2);
-  static CJS_Array AF_MakeArrayFromList(CJS_Runtime* pRuntime, CJS_Value val);
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_PUBLICMETHODS_H_
diff --git a/fpdfsdk/javascript/app.cpp b/fpdfsdk/javascript/app.cpp
deleted file mode 100644
index 3a8bf08..0000000
--- a/fpdfsdk/javascript/app.cpp
+++ /dev/null
@@ -1,790 +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/app.h"
-
-#include <map>
-#include <memory>
-#include <vector>
-
-#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
-#include "fpdfsdk/cpdfsdk_interform.h"
-#include "fpdfsdk/javascript/Document.h"
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_EventHandler.h"
-#include "fpdfsdk/javascript/JS_Object.h"
-#include "fpdfsdk/javascript/JS_Value.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"
-
-class GlobalTimer {
- public:
-  GlobalTimer(app* pObj,
-              CPDFSDK_FormFillEnvironment* pFormFillEnv,
-              CJS_Runtime* pRuntime,
-              int nType,
-              const CFX_WideString& script,
-              uint32_t dwElapse,
-              uint32_t dwTimeOut);
-  ~GlobalTimer();
-
-  static void Trigger(int nTimerID);
-  static void Cancel(int nTimerID);
-
-  bool IsOneShot() const { return m_nType == 1; }
-  uint32_t GetTimeOut() const { return m_dwTimeOut; }
-  int GetTimerID() const { return m_nTimerID; }
-  CJS_Runtime* GetRuntime() const { return m_pRuntime.Get(); }
-  CFX_WideString GetJScript() const { return m_swJScript; }
-
- private:
-  using TimerMap = std::map<uint32_t, GlobalTimer*>;
-  static TimerMap* GetGlobalTimerMap();
-
-  uint32_t m_nTimerID;
-  app* const m_pEmbedObj;
-  bool m_bProcessing;
-
-  // data
-  const int m_nType;  // 0:Interval; 1:TimeOut
-  const uint32_t m_dwTimeOut;
-  const CFX_WideString m_swJScript;
-  CJS_Runtime::ObservedPtr m_pRuntime;
-  CPDFSDK_FormFillEnvironment::ObservedPtr m_pFormFillEnv;
-};
-
-GlobalTimer::GlobalTimer(app* pObj,
-                         CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                         CJS_Runtime* pRuntime,
-                         int nType,
-                         const CFX_WideString& script,
-                         uint32_t dwElapse,
-                         uint32_t dwTimeOut)
-    : m_nTimerID(0),
-      m_pEmbedObj(pObj),
-      m_bProcessing(false),
-      m_nType(nType),
-      m_dwTimeOut(dwTimeOut),
-      m_swJScript(script),
-      m_pRuntime(pRuntime),
-      m_pFormFillEnv(pFormFillEnv) {
-  CFX_SystemHandler* pHandler = m_pFormFillEnv->GetSysHandler();
-  m_nTimerID = pHandler->SetTimer(dwElapse, Trigger);
-  if (m_nTimerID)
-    (*GetGlobalTimerMap())[m_nTimerID] = this;
-}
-
-GlobalTimer::~GlobalTimer() {
-  if (!m_nTimerID)
-    return;
-
-  if (GetRuntime())
-    m_pFormFillEnv->GetSysHandler()->KillTimer(m_nTimerID);
-
-  GetGlobalTimerMap()->erase(m_nTimerID);
-}
-
-// static
-void GlobalTimer::Trigger(int nTimerID) {
-  auto it = GetGlobalTimerMap()->find(nTimerID);
-  if (it == GetGlobalTimerMap()->end())
-    return;
-
-  GlobalTimer* pTimer = it->second;
-  if (pTimer->m_bProcessing)
-    return;
-
-  pTimer->m_bProcessing = true;
-  if (pTimer->m_pEmbedObj)
-    pTimer->m_pEmbedObj->TimerProc(pTimer);
-
-  // Timer proc may have destroyed timer, find it again.
-  it = GetGlobalTimerMap()->find(nTimerID);
-  if (it == GetGlobalTimerMap()->end())
-    return;
-
-  pTimer = it->second;
-  pTimer->m_bProcessing = false;
-  if (pTimer->IsOneShot())
-    pTimer->m_pEmbedObj->CancelProc(pTimer);
-}
-
-// static
-void GlobalTimer::Cancel(int nTimerID) {
-  auto it = GetGlobalTimerMap()->find(nTimerID);
-  if (it == GetGlobalTimerMap()->end())
-    return;
-
-  GlobalTimer* pTimer = it->second;
-  pTimer->m_pEmbedObj->CancelProc(pTimer);
-}
-
-// static
-GlobalTimer::TimerMap* GlobalTimer::GetGlobalTimerMap() {
-  // Leak the timer array at shutdown.
-  static auto* s_TimerMap = new TimerMap;
-  return s_TimerMap;
-}
-
-JSConstSpec CJS_TimerObj::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
-
-JSPropertySpec CJS_TimerObj::PropertySpecs[] = {{0, 0, 0}};
-
-JSMethodSpec CJS_TimerObj::MethodSpecs[] = {{0, 0}};
-
-IMPLEMENT_JS_CLASS(CJS_TimerObj, TimerObj)
-
-TimerObj::TimerObj(CJS_Object* pJSObject)
-    : CJS_EmbedObj(pJSObject), m_nTimerID(0) {}
-
-TimerObj::~TimerObj() {}
-
-void TimerObj::SetTimer(GlobalTimer* pTimer) {
-  m_nTimerID = pTimer->GetTimerID();
-}
-
-#define JS_STR_VIEWERTYPE L"pdfium"
-#define JS_STR_VIEWERVARIATION L"Full"
-#define JS_STR_PLATFORM L"WIN"
-#define JS_STR_LANGUAGE L"ENU"
-#define JS_NUM_VIEWERVERSION 8
-#ifdef PDF_ENABLE_XFA
-#define JS_NUM_VIEWERVERSION_XFA 11
-#endif  // PDF_ENABLE_XFA
-#define JS_NUM_FORMSVERSION 7
-
-JSConstSpec CJS_App::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
-
-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}};
-
-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)
-
-app::app(CJS_Object* pJSObject)
-    : CJS_EmbedObj(pJSObject), m_bCalculate(true), m_bRuntimeHighLight(false) {}
-
-app::~app() {
-}
-
-bool app::activeDocs(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  CJS_Document* pJSDocument = nullptr;
-  v8::Local<v8::Object> pObj = pRuntime->GetThisObj();
-  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
-    vp.GetJSValue()->SetNull(pRuntime);
-
-  return true;
-}
-
-bool app::calculate(CJS_Runtime* pRuntime,
-                    CJS_PropValue& vp,
-                    CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    bool bVP;
-    vp >> bVP;
-    m_bCalculate = (bool)bVP;
-    pRuntime->GetFormFillEnv()->GetInterForm()->EnableCalculate(
-        (bool)m_bCalculate);
-  } else {
-    vp << (bool)m_bCalculate;
-  }
-  return true;
-}
-
-bool app::formsVersion(CJS_Runtime* pRuntime,
-                       CJS_PropValue& vp,
-                       CFX_WideString& sError) {
-  if (vp.IsGetting()) {
-    vp << JS_NUM_FORMSVERSION;
-    return true;
-  }
-
-  return false;
-}
-
-bool app::viewerType(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  if (vp.IsGetting()) {
-    vp << JS_STR_VIEWERTYPE;
-    return true;
-  }
-
-  return false;
-}
-
-bool app::viewerVariation(CJS_Runtime* pRuntime,
-                          CJS_PropValue& vp,
-                          CFX_WideString& sError) {
-  if (vp.IsGetting()) {
-    vp << JS_STR_VIEWERVARIATION;
-    return true;
-  }
-
-  return false;
-}
-
-bool app::viewerVersion(CJS_Runtime* pRuntime,
-                        CJS_PropValue& vp,
-                        CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-#ifdef PDF_ENABLE_XFA
-  CPDFXFA_Context* pXFAContext = pRuntime->GetFormFillEnv()->GetXFAContext();
-  if (pXFAContext->GetDocType() == 1 || pXFAContext->GetDocType() == 2) {
-    vp << JS_NUM_VIEWERVERSION_XFA;
-    return true;
-  }
-#endif  // PDF_ENABLE_XFA
-  vp << JS_NUM_VIEWERVERSION;
-  return true;
-}
-
-bool app::platform(CJS_Runtime* pRuntime,
-                   CJS_PropValue& vp,
-                   CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-#ifdef PDF_ENABLE_XFA
-  CPDFSDK_FormFillEnvironment* pFormFillEnv = pRuntime->GetFormFillEnv();
-  if (!pFormFillEnv)
-    return false;
-  CFX_WideString platfrom = pFormFillEnv->GetPlatform();
-  if (!platfrom.IsEmpty()) {
-    vp << platfrom;
-    return true;
-  }
-#endif
-  vp << JS_STR_PLATFORM;
-  return true;
-}
-
-bool app::language(CJS_Runtime* pRuntime,
-                   CJS_PropValue& vp,
-                   CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-#ifdef PDF_ENABLE_XFA
-  CPDFSDK_FormFillEnvironment* pFormFillEnv = pRuntime->GetFormFillEnv();
-  if (!pFormFillEnv)
-    return false;
-  CFX_WideString language = pFormFillEnv->GetLanguage();
-  if (!language.IsEmpty()) {
-    vp << language;
-    return true;
-  }
-#endif
-  vp << JS_STR_LANGUAGE;
-  return true;
-}
-
-// creates a new fdf object that contains no data
-// comment: need reader support
-// note:
-// CFDF_Document * CPDFSDK_FormFillEnvironment::NewFDF();
-bool app::newFDF(CJS_Runtime* pRuntime,
-                 const std::vector<CJS_Value>& params,
-                 CJS_Value& vRet,
-                 CFX_WideString& sError) {
-  return true;
-}
-// opens a specified pdf document and returns its document object
-// comment:need reader support
-// note: as defined in js reference, the proto of this function's fourth
-// parmeters, how old an fdf document while do not show it.
-// CFDF_Document * CPDFSDK_FormFillEnvironment::OpenFDF(string strPath,bool
-// bUserConv);
-
-bool app::openFDF(CJS_Runtime* pRuntime,
-                  const std::vector<CJS_Value>& params,
-                  CJS_Value& vRet,
-                  CFX_WideString& sError) {
-  return true;
-}
-
-bool app::alert(CJS_Runtime* pRuntime,
-                const std::vector<CJS_Value>& params,
-                CJS_Value& vRet,
-                CFX_WideString& sError) {
-  std::vector<CJS_Value> newParams = JS_ExpandKeywordParams(
-      pRuntime, params, 4, L"cMsg", L"nIcon", L"nType", L"cTitle");
-
-  if (newParams[0].GetType() == CJS_Value::VT_unknown) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  CPDFSDK_FormFillEnvironment* pFormFillEnv = pRuntime->GetFormFillEnv();
-  if (!pFormFillEnv) {
-    vRet = CJS_Value(pRuntime, 0);
-    return true;
-  }
-
-  CFX_WideString swMsg;
-  if (newParams[0].GetType() == CJS_Value::VT_object) {
-    CJS_Array carray;
-    if (newParams[0].ConvertToArray(pRuntime, carray)) {
-      swMsg = L"[";
-      CJS_Value element(pRuntime);
-      for (int i = 0; i < carray.GetLength(pRuntime); ++i) {
-        if (i)
-          swMsg += L", ";
-        carray.GetElement(pRuntime, i, element);
-        swMsg += element.ToCFXWideString(pRuntime);
-      }
-      swMsg += L"]";
-    } else {
-      swMsg = newParams[0].ToCFXWideString(pRuntime);
-    }
-  } else {
-    swMsg = newParams[0].ToCFXWideString(pRuntime);
-  }
-
-  int iIcon = 0;
-  if (newParams[1].GetType() != CJS_Value::VT_unknown)
-    iIcon = newParams[1].ToInt(pRuntime);
-
-  int iType = 0;
-  if (newParams[2].GetType() != CJS_Value::VT_unknown)
-    iType = newParams[2].ToInt(pRuntime);
-
-  CFX_WideString swTitle;
-  if (newParams[3].GetType() != CJS_Value::VT_unknown)
-    swTitle = newParams[3].ToCFXWideString(pRuntime);
-  else
-    swTitle = JSGetStringFromID(IDS_STRING_JSALERT);
-
-  pRuntime->BeginBlock();
-  pFormFillEnv->KillFocusAnnot(0);
-
-  vRet = CJS_Value(pRuntime, pFormFillEnv->JS_appAlert(
-                                 swMsg.c_str(), swTitle.c_str(), iType, iIcon));
-  pRuntime->EndBlock();
-  return true;
-}
-
-bool app::beep(CJS_Runtime* pRuntime,
-               const std::vector<CJS_Value>& params,
-               CJS_Value& vRet,
-               CFX_WideString& sError) {
-  if (params.size() == 1) {
-    pRuntime->GetFormFillEnv()->JS_appBeep(params[0].ToInt(pRuntime));
-    return true;
-  }
-
-  sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-  return false;
-}
-
-bool app::findComponent(CJS_Runtime* pRuntime,
-                        const std::vector<CJS_Value>& params,
-                        CJS_Value& vRet,
-                        CFX_WideString& sError) {
-  return true;
-}
-
-bool app::popUpMenuEx(CJS_Runtime* pRuntime,
-                      const std::vector<CJS_Value>& params,
-                      CJS_Value& vRet,
-                      CFX_WideString& sError) {
-  return false;
-}
-
-bool app::fs(CJS_Runtime* pRuntime, CJS_PropValue& vp, CFX_WideString& sError) {
-  return false;
-}
-
-bool app::setInterval(CJS_Runtime* pRuntime,
-                      const std::vector<CJS_Value>& params,
-                      CJS_Value& vRet,
-                      CFX_WideString& sError) {
-  if (params.size() > 2 || params.size() == 0) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  CFX_WideString script =
-      params.size() > 0 ? params[0].ToCFXWideString(pRuntime) : L"";
-  if (script.IsEmpty()) {
-    sError = JSGetStringFromID(IDS_STRING_JSAFNUMBER_KEYSTROKE);
-    return true;
-  }
-
-  uint32_t dwInterval = params.size() > 1 ? params[1].ToInt(pRuntime) : 1000;
-
-  GlobalTimer* timerRef = new GlobalTimer(this, pRuntime->GetFormFillEnv(),
-                                          pRuntime, 0, script, dwInterval, 0);
-  m_Timers.insert(std::unique_ptr<GlobalTimer>(timerRef));
-
-  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::setTimeOut(CJS_Runtime* pRuntime,
-                     const std::vector<CJS_Value>& params,
-                     CJS_Value& vRet,
-                     CFX_WideString& sError) {
-  if (params.size() > 2 || params.size() == 0) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  CFX_WideString script = params[0].ToCFXWideString(pRuntime);
-  if (script.IsEmpty()) {
-    sError = JSGetStringFromID(IDS_STRING_JSAFNUMBER_KEYSTROKE);
-    return true;
-  }
-
-  uint32_t dwTimeOut = params.size() > 1 ? params[1].ToInt(pRuntime) : 1000;
-  GlobalTimer* timerRef =
-      new GlobalTimer(this, pRuntime->GetFormFillEnv(), pRuntime, 1, script,
-                      dwTimeOut, dwTimeOut);
-  m_Timers.insert(std::unique_ptr<GlobalTimer>(timerRef));
-
-  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(CJS_Runtime* pRuntime,
-                       const std::vector<CJS_Value>& params,
-                       CJS_Value& vRet,
-                       CFX_WideString& sError) {
-  if (params.size() != 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  app::ClearTimerCommon(pRuntime, params[0]);
-  return true;
-}
-
-bool app::clearInterval(CJS_Runtime* pRuntime,
-                        const std::vector<CJS_Value>& params,
-                        CJS_Value& vRet,
-                        CFX_WideString& sError) {
-  if (params.size() != 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  app::ClearTimerCommon(pRuntime, params[0]);
-  return true;
-}
-
-void app::ClearTimerCommon(CJS_Runtime* pRuntime, const CJS_Value& param) {
-  if (param.GetType() != CJS_Value::VT_object)
-    return;
-
-  v8::Local<v8::Object> pObj = param.ToV8Object(pRuntime);
-  if (CFXJS_Engine::GetObjDefnID(pObj) != CJS_TimerObj::g_nObjDefnID)
-    return;
-
-  CJS_Object* pJSObj = param.ToCJSObject(pRuntime);
-  if (!pJSObj)
-    return;
-
-  TimerObj* pTimerObj = static_cast<TimerObj*>(pJSObj->GetEmbedObject());
-  if (!pTimerObj)
-    return;
-
-  GlobalTimer::Cancel(pTimerObj->GetTimerID());
-}
-
-bool app::execMenuItem(CJS_Runtime* pRuntime,
-                       const std::vector<CJS_Value>& params,
-                       CJS_Value& vRet,
-                       CFX_WideString& sError) {
-  return false;
-}
-
-void app::TimerProc(GlobalTimer* pTimer) {
-  CJS_Runtime* pRuntime = pTimer->GetRuntime();
-  if (pRuntime && (!pTimer->IsOneShot() || pTimer->GetTimeOut() > 0))
-    RunJsScript(pRuntime, pTimer->GetJScript());
-}
-
-void app::CancelProc(GlobalTimer* pTimer) {
-  m_Timers.erase(pdfium::FakeUniquePtr<GlobalTimer>(pTimer));
-}
-
-void app::RunJsScript(CJS_Runtime* pRuntime, const CFX_WideString& wsScript) {
-  if (!pRuntime->IsBlocking()) {
-    IJS_EventContext* pContext = pRuntime->NewEventContext();
-    pContext->OnExternal_Exec();
-    CFX_WideString wtInfo;
-    pContext->RunScript(wsScript, &wtInfo);
-    pRuntime->ReleaseEventContext(pContext);
-  }
-}
-
-bool app::goBack(CJS_Runtime* pRuntime,
-                 const std::vector<CJS_Value>& params,
-                 CJS_Value& vRet,
-                 CFX_WideString& sError) {
-  // Not supported.
-  return true;
-}
-
-bool app::goForward(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError) {
-  // Not supported.
-  return true;
-}
-
-bool app::mailMsg(CJS_Runtime* pRuntime,
-                  const std::vector<CJS_Value>& params,
-                  CJS_Value& vRet,
-                  CFX_WideString& sError) {
-  std::vector<CJS_Value> newParams =
-      JS_ExpandKeywordParams(pRuntime, params, 6, L"bUI", L"cTo", L"cCc",
-                             L"cBcc", L"cSubject", L"cMsg");
-
-  if (newParams[0].GetType() == CJS_Value::VT_unknown) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-  bool bUI = newParams[0].ToBool(pRuntime);
-
-  CFX_WideString cTo;
-  if (newParams[1].GetType() != CJS_Value::VT_unknown) {
-    cTo = newParams[1].ToCFXWideString(pRuntime);
-  } else {
-    if (!bUI) {
-      // cTo parameter required when UI not invoked.
-      sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-      return false;
-    }
-  }
-
-  CFX_WideString cCc;
-  if (newParams[2].GetType() != CJS_Value::VT_unknown)
-    cCc = newParams[2].ToCFXWideString(pRuntime);
-
-  CFX_WideString cBcc;
-  if (newParams[3].GetType() != CJS_Value::VT_unknown)
-    cBcc = newParams[3].ToCFXWideString(pRuntime);
-
-  CFX_WideString cSubject;
-  if (newParams[4].GetType() != CJS_Value::VT_unknown)
-    cSubject = newParams[4].ToCFXWideString(pRuntime);
-
-  CFX_WideString cMsg;
-  if (newParams[5].GetType() != CJS_Value::VT_unknown)
-    cMsg = newParams[5].ToCFXWideString(pRuntime);
-
-  pRuntime->BeginBlock();
-  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(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError) {
-  // Unsafe, not supported.
-  return true;
-}
-
-bool app::runtimeHighlight(CJS_Runtime* pRuntime,
-                           CJS_PropValue& vp,
-                           CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    vp >> m_bRuntimeHighLight;
-  } else {
-    vp << m_bRuntimeHighLight;
-  }
-  return true;
-}
-
-bool app::fullscreen(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  return false;
-}
-
-bool app::popUpMenu(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError) {
-  return false;
-}
-
-bool app::browseForDoc(CJS_Runtime* pRuntime,
-                       const std::vector<CJS_Value>& params,
-                       CJS_Value& vRet,
-                       CFX_WideString& sError) {
-  // Unsafe, not supported.
-  return true;
-}
-
-CFX_WideString app::SysPathToPDFPath(const CFX_WideString& sOldPath) {
-  CFX_WideString sRet = L"/";
-
-  for (int i = 0, sz = sOldPath.GetLength(); i < sz; i++) {
-    wchar_t c = sOldPath.GetAt(i);
-    if (c == L':') {
-    } else {
-      if (c == L'\\') {
-        sRet += L"/";
-      } else {
-        sRet += c;
-      }
-    }
-  }
-
-  return sRet;
-}
-
-bool app::newDoc(CJS_Runtime* pRuntime,
-                 const std::vector<CJS_Value>& params,
-                 CJS_Value& vRet,
-                 CFX_WideString& sError) {
-  return false;
-}
-
-bool app::openDoc(CJS_Runtime* pRuntime,
-                  const std::vector<CJS_Value>& params,
-                  CJS_Value& vRet,
-                  CFX_WideString& sError) {
-  return false;
-}
-
-bool app::response(CJS_Runtime* pRuntime,
-                   const std::vector<CJS_Value>& params,
-                   CJS_Value& vRet,
-                   CFX_WideString& sError) {
-  std::vector<CJS_Value> newParams =
-      JS_ExpandKeywordParams(pRuntime, params, 5, L"cQuestion", L"cTitle",
-                             L"cDefault", L"bPassword", L"cLabel");
-
-  if (newParams[0].GetType() == CJS_Value::VT_unknown) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-  CFX_WideString swQuestion = newParams[0].ToCFXWideString(pRuntime);
-
-  CFX_WideString swTitle = L"PDF";
-  if (newParams[1].GetType() != CJS_Value::VT_unknown)
-    swTitle = newParams[1].ToCFXWideString(pRuntime);
-
-  CFX_WideString swDefault;
-  if (newParams[2].GetType() != CJS_Value::VT_unknown)
-    swDefault = newParams[2].ToCFXWideString(pRuntime);
-
-  bool bPassword = false;
-  if (newParams[3].GetType() != CJS_Value::VT_unknown)
-    bPassword = newParams[3].ToBool(pRuntime);
-
-  CFX_WideString swLabel;
-  if (newParams[4].GetType() != CJS_Value::VT_unknown)
-    swLabel = newParams[4].ToCFXWideString(pRuntime);
-
-  const int MAX_INPUT_BYTES = 2048;
-  std::unique_ptr<char[]> pBuff(new char[MAX_INPUT_BYTES + 2]);
-  memset(pBuff.get(), 0, MAX_INPUT_BYTES + 2);
-
-  int nLengthBytes = pRuntime->GetFormFillEnv()->JS_appResponse(
-      swQuestion.c_str(), swTitle.c_str(), swDefault.c_str(), swLabel.c_str(),
-      bPassword, pBuff.get(), MAX_INPUT_BYTES);
-
-  if (nLengthBytes < 0 || nLengthBytes > MAX_INPUT_BYTES) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAM_TOOLONG);
-    return false;
-  }
-
-  vRet = CJS_Value(pRuntime, CFX_WideString::FromUTF16LE(
-                                 reinterpret_cast<uint16_t*>(pBuff.get()),
-                                 nLengthBytes / sizeof(uint16_t))
-                                 .c_str());
-
-  return true;
-}
-
-bool app::media(CJS_Runtime* pRuntime,
-                CJS_PropValue& vp,
-                CFX_WideString& sError) {
-  return false;
-}
-
-bool app::execDialog(CJS_Runtime* pRuntime,
-                     const std::vector<CJS_Value>& params,
-                     CJS_Value& vRet,
-                     CFX_WideString& sError) {
-  return true;
-}
diff --git a/fpdfsdk/javascript/app.h b/fpdfsdk/javascript/app.h
deleted file mode 100644
index 9e11b82..0000000
--- a/fpdfsdk/javascript/app.h
+++ /dev/null
@@ -1,221 +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 FPDFSDK_JAVASCRIPT_APP_H_
-#define FPDFSDK_JAVASCRIPT_APP_H_
-
-#include <memory>
-#include <unordered_set>
-#include <vector>
-
-#include "fpdfsdk/javascript/JS_Define.h"
-
-class CJS_Runtime;
-class GlobalTimer;
-
-class TimerObj : public CJS_EmbedObj {
- public:
-  explicit TimerObj(CJS_Object* pJSObject);
-  ~TimerObj() override;
-
-  void SetTimer(GlobalTimer* pTimer);
-  int GetTimerID() const { return m_nTimerID; }
-
- private:
-  int m_nTimerID;  // Weak reference to GlobalTimer through global map.
-};
-
-class CJS_TimerObj : public CJS_Object {
- public:
-  explicit CJS_TimerObj(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_TimerObj() override {}
-
-  DECLARE_JS_CLASS();
-};
-
-class app : public CJS_EmbedObj {
- public:
-  explicit app(CJS_Object* pJSObject);
-  ~app() override;
-
-  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(CJS_Runtime* pRuntime,
-                  CJS_PropValue& vp,
-                  CFX_WideString& sError);
-  bool viewerVariation(CJS_Runtime* pRuntime,
-                       CJS_PropValue& vp,
-                       CFX_WideString& sError);
-  bool viewerVersion(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError);
-
-  bool alert(CJS_Runtime* pRuntime,
-             const std::vector<CJS_Value>& params,
-             CJS_Value& vRet,
-             CFX_WideString& sError);
-  bool beep(CJS_Runtime* pRuntime,
-            const std::vector<CJS_Value>& params,
-            CJS_Value& vRet,
-            CFX_WideString& sError);
-  bool browseForDoc(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError);
-  bool clearInterval(CJS_Runtime* pRuntime,
-                     const std::vector<CJS_Value>& params,
-                     CJS_Value& vRet,
-                     CFX_WideString& sError);
-  bool clearTimeOut(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError);
-  bool execDialog(CJS_Runtime* pRuntime,
-                  const std::vector<CJS_Value>& params,
-                  CJS_Value& vRet,
-                  CFX_WideString& sError);
-  bool execMenuItem(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError);
-  bool findComponent(CJS_Runtime* pRuntime,
-                     const std::vector<CJS_Value>& params,
-                     CJS_Value& vRet,
-                     CFX_WideString& sError);
-  bool goBack(CJS_Runtime* pRuntime,
-              const std::vector<CJS_Value>& params,
-              CJS_Value& vRet,
-              CFX_WideString& sError);
-  bool goForward(CJS_Runtime* pRuntime,
-                 const std::vector<CJS_Value>& params,
-                 CJS_Value& vRet,
-                 CFX_WideString& sError);
-  bool launchURL(CJS_Runtime* pRuntime,
-                 const std::vector<CJS_Value>& params,
-                 CJS_Value& vRet,
-                 CFX_WideString& sError);
-  bool mailMsg(CJS_Runtime* pRuntime,
-               const std::vector<CJS_Value>& params,
-               CJS_Value& vRet,
-               CFX_WideString& sError);
-  bool newFDF(CJS_Runtime* pRuntime,
-              const std::vector<CJS_Value>& params,
-              CJS_Value& vRet,
-              CFX_WideString& sError);
-  bool newDoc(CJS_Runtime* pRuntime,
-              const std::vector<CJS_Value>& params,
-              CJS_Value& vRet,
-              CFX_WideString& sError);
-  bool openDoc(CJS_Runtime* pRuntime,
-               const std::vector<CJS_Value>& params,
-               CJS_Value& vRet,
-               CFX_WideString& sError);
-  bool openFDF(CJS_Runtime* pRuntime,
-               const std::vector<CJS_Value>& params,
-               CJS_Value& vRet,
-               CFX_WideString& sError);
-  bool popUpMenuEx(CJS_Runtime* pRuntime,
-                   const std::vector<CJS_Value>& params,
-                   CJS_Value& vRet,
-                   CFX_WideString& sError);
-  bool popUpMenu(CJS_Runtime* pRuntime,
-                 const std::vector<CJS_Value>& params,
-                 CJS_Value& vRet,
-                 CFX_WideString& sError);
-  bool response(CJS_Runtime* pRuntime,
-                const std::vector<CJS_Value>& params,
-                CJS_Value& vRet,
-                CFX_WideString& sError);
-  bool setInterval(CJS_Runtime* pRuntime,
-                   const std::vector<CJS_Value>& params,
-                   CJS_Value& vRet,
-                   CFX_WideString& sError);
-  bool setTimeOut(CJS_Runtime* pRuntime,
-                  const std::vector<CJS_Value>& params,
-                  CJS_Value& vRet,
-                  CFX_WideString& sError);
-
-  void TimerProc(GlobalTimer* pTimer);
-  void CancelProc(GlobalTimer* pTimer);
-
-  static CFX_WideString SysPathToPDFPath(const CFX_WideString& sOldPath);
-
- private:
-  // CJS_EmbedObj
-  void RunJsScript(CJS_Runtime* pRuntime, const CFX_WideString& wsScript);
-
-  void ClearTimerCommon(CJS_Runtime* pRuntime, const CJS_Value& param);
-
-  bool m_bCalculate;
-  bool m_bRuntimeHighLight;
-  std::unordered_set<std::unique_ptr<GlobalTimer>> m_Timers;
-};
-
-class CJS_App : public CJS_Object {
- public:
-  explicit CJS_App(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_App() override {}
-
-  DECLARE_JS_CLASS();
-
-  JS_STATIC_PROP(activeDocs, app);
-  JS_STATIC_PROP(calculate, app);
-  JS_STATIC_PROP(formsVersion, app);
-  JS_STATIC_PROP(fs, app);
-  JS_STATIC_PROP(fullscreen, app);
-  JS_STATIC_PROP(language, app);
-  JS_STATIC_PROP(media, app);
-  JS_STATIC_PROP(platform, app);
-  JS_STATIC_PROP(runtimeHighlight, app);
-  JS_STATIC_PROP(viewerType, app);
-  JS_STATIC_PROP(viewerVariation, app);
-  JS_STATIC_PROP(viewerVersion, app);
-
-  JS_STATIC_METHOD(alert, app);
-  JS_STATIC_METHOD(beep, app);
-  JS_STATIC_METHOD(browseForDoc, app);
-  JS_STATIC_METHOD(clearInterval, app);
-  JS_STATIC_METHOD(clearTimeOut, app);
-  JS_STATIC_METHOD(execDialog, app);
-  JS_STATIC_METHOD(execMenuItem, app);
-  JS_STATIC_METHOD(findComponent, app);
-  JS_STATIC_METHOD(goBack, app);
-  JS_STATIC_METHOD(goForward, app);
-  JS_STATIC_METHOD(launchURL, app);
-  JS_STATIC_METHOD(mailMsg, app);
-  JS_STATIC_METHOD(newFDF, app);
-  JS_STATIC_METHOD(newDoc, app);
-  JS_STATIC_METHOD(openDoc, app);
-  JS_STATIC_METHOD(openFDF, app);
-  JS_STATIC_METHOD(popUpMenuEx, app);
-  JS_STATIC_METHOD(popUpMenu, app);
-  JS_STATIC_METHOD(response, app);
-  JS_STATIC_METHOD(setInterval, app);
-  JS_STATIC_METHOD(setTimeOut, app);
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_APP_H_
diff --git a/fpdfsdk/javascript/cjs_event_context.cpp b/fpdfsdk/javascript/cjs_event_context.cpp
deleted file mode 100644
index abfb6da..0000000
--- a/fpdfsdk/javascript/cjs_event_context.cpp
+++ /dev/null
@@ -1,280 +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 "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_event_context.h b/fpdfsdk/javascript/cjs_event_context.h
deleted file mode 100644
index 7bfe528..0000000
--- a/fpdfsdk/javascript/cjs_event_context.h
+++ /dev/null
@@ -1,135 +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 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_event_context.h"
-
-class CJS_EventHandler;
-class CJS_Runtime;
-class CPDFSDK_FormFillEnvironment;
-
-class CJS_EventContext : public IJS_EventContext {
- public:
-  explicit CJS_EventContext(CJS_Runtime* pRuntime);
-  ~CJS_EventContext() override;
-
-  // IJS_EventContext
-  bool RunScript(const CFX_WideString& script, CFX_WideString* info) override;
-  void OnApp_Init() override;
-  void OnDoc_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                  const CFX_WideString& strTargetName) override;
-  void OnDoc_WillPrint(CPDFSDK_FormFillEnvironment* pFormFillEnv) override;
-  void OnDoc_DidPrint(CPDFSDK_FormFillEnvironment* pFormFillEnv) override;
-  void OnDoc_WillSave(CPDFSDK_FormFillEnvironment* pFormFillEnv) override;
-  void OnDoc_DidSave(CPDFSDK_FormFillEnvironment* pFormFillEnv) override;
-  void OnDoc_WillClose(CPDFSDK_FormFillEnvironment* pFormFillEnv) override;
-  void OnPage_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv) override;
-  void OnPage_Close(CPDFSDK_FormFillEnvironment* pFormFillEnv) override;
-  void OnPage_InView(CPDFSDK_FormFillEnvironment* pFormFillEnv) override;
-  void OnPage_OutView(CPDFSDK_FormFillEnvironment* pFormFillEnv) override;
-  void OnField_MouseDown(bool bModifier,
-                         bool bShift,
-                         CPDF_FormField* pTarget) override;
-  void OnField_MouseEnter(bool bModifier,
-                          bool bShift,
-                          CPDF_FormField* pTarget) override;
-  void OnField_MouseExit(bool bModifier,
-                         bool bShift,
-                         CPDF_FormField* pTarget) override;
-  void OnField_MouseUp(bool bModifier,
-                       bool bShift,
-                       CPDF_FormField* pTarget) override;
-  void OnField_Focus(bool bModifier,
-                     bool bShift,
-                     CPDF_FormField* pTarget,
-                     const CFX_WideString& Value) override;
-  void OnField_Blur(bool bModifier,
-                    bool bShift,
-                    CPDF_FormField* pTarget,
-                    const CFX_WideString& Value) override;
-  void OnField_Calculate(CPDF_FormField* pSource,
-                         CPDF_FormField* pTarget,
-                         CFX_WideString& Value,
-                         bool& bRc) override;
-  void OnField_Format(CPDF_FormField* pTarget,
-                      CFX_WideString& Value,
-                      bool bWillCommit) override;
-  void 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) override;
-  void OnField_Validate(CFX_WideString& strChange,
-                        const CFX_WideString& strChangeEx,
-                        bool bKeyDown,
-                        bool bModifier,
-                        bool bShift,
-                        CPDF_FormField* pTarget,
-                        CFX_WideString& Value,
-                        bool& bRc) override;
-  void OnScreen_Focus(bool bModifier,
-                      bool bShift,
-                      CPDFSDK_Annot* pScreen) override;
-  void OnScreen_Blur(bool bModifier,
-                     bool bShift,
-                     CPDFSDK_Annot* pScreen) override;
-  void OnScreen_Open(bool bModifier,
-                     bool bShift,
-                     CPDFSDK_Annot* pScreen) override;
-  void OnScreen_Close(bool bModifier,
-                      bool bShift,
-                      CPDFSDK_Annot* pScreen) override;
-  void OnScreen_MouseDown(bool bModifier,
-                          bool bShift,
-                          CPDFSDK_Annot* pScreen) override;
-  void OnScreen_MouseUp(bool bModifier,
-                        bool bShift,
-                        CPDFSDK_Annot* pScreen) override;
-  void OnScreen_MouseEnter(bool bModifier,
-                           bool bShift,
-                           CPDFSDK_Annot* pScreen) override;
-  void OnScreen_MouseExit(bool bModifier,
-                          bool bShift,
-                          CPDFSDK_Annot* pScreen) override;
-  void OnScreen_InView(bool bModifier,
-                       bool bShift,
-                       CPDFSDK_Annot* pScreen) override;
-  void OnScreen_OutView(bool bModifier,
-                        bool bShift,
-                        CPDFSDK_Annot* pScreen) override;
-  void OnBookmark_MouseUp(CPDF_Bookmark* pBookMark) override;
-  void OnLink_MouseUp(CPDFSDK_FormFillEnvironment* pFormFillEnv) override;
-  void OnMenu_Exec(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                   const CFX_WideString& strTargetName) override;
-  void OnBatchExec(CPDFSDK_FormFillEnvironment* pFormFillEnv) override;
-  void OnConsole_Exec() override;
-  void OnExternal_Exec() override;
-
-  CJS_Runtime* GetJSRuntime() const { return m_pRuntime; }
-  CJS_EventHandler* GetEventHandler() const { return m_pEventHandler.get(); }
-
-  CPDFSDK_FormFillEnvironment* GetFormFillEnv();
-
- private:
-  CJS_Runtime* const m_pRuntime;
-  std::unique_ptr<CJS_EventHandler> m_pEventHandler;
-  bool m_bBusy;
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_CJS_EVENT_CONTEXT_H_
diff --git a/fpdfsdk/javascript/cjs_runtime.cpp b/fpdfsdk/javascript/cjs_runtime.cpp
deleted file mode 100644
index 1ece0b6..0000000
--- a/fpdfsdk/javascript/cjs_runtime.cpp
+++ /dev/null
@@ -1,263 +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_runtime.h"
-
-#include <algorithm>
-
-#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
-#include "fpdfsdk/javascript/Annot.h"
-#include "fpdfsdk/javascript/Consts.h"
-#include "fpdfsdk/javascript/Document.h"
-#include "fpdfsdk/javascript/Field.h"
-#include "fpdfsdk/javascript/Icon.h"
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_EventHandler.h"
-#include "fpdfsdk/javascript/JS_GlobalData.h"
-#include "fpdfsdk/javascript/JS_Object.h"
-#include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/PublicMethods.h"
-#include "fpdfsdk/javascript/app.h"
-#include "fpdfsdk/javascript/cjs_event_context.h"
-#include "fpdfsdk/javascript/color.h"
-#include "fpdfsdk/javascript/console.h"
-#include "fpdfsdk/javascript/event.h"
-#include "fpdfsdk/javascript/global.h"
-#include "fpdfsdk/javascript/report.h"
-#include "fpdfsdk/javascript/util.h"
-#include "public/fpdf_formfill.h"
-#include "third_party/base/stl_util.h"
-
-#ifdef PDF_ENABLE_XFA
-#include "fxjs/cfxjse_value.h"
-#endif  // PDF_ENABLE_XFA
-
-// static
-void IJS_Runtime::Initialize(unsigned int slot, void* isolate) {
-  FXJS_Initialize(slot, reinterpret_cast<v8::Isolate*>(isolate));
-}
-
-// static
-void IJS_Runtime::Destroy() {
-  FXJS_Release();
-}
-
-// static
-IJS_Runtime* IJS_Runtime::Create(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  return new CJS_Runtime(pFormFillEnv);
-}
-
-// static
-CJS_Runtime* CJS_Runtime::CurrentRuntimeFromIsolate(v8::Isolate* pIsolate) {
-  return static_cast<CJS_Runtime*>(
-      CFXJS_Engine::CurrentEngineFromIsolate(pIsolate));
-}
-
-CJS_Runtime::CJS_Runtime(CPDFSDK_FormFillEnvironment* pFormFillEnv)
-    : m_pFormFillEnv(pFormFillEnv),
-      m_bBlocking(false),
-      m_isolateManaged(false) {
-  v8::Isolate* pIsolate = nullptr;
-
-  IPDF_JSPLATFORM* pPlatform = m_pFormFillEnv->GetFormFillInfo()->m_pJsPlatform;
-  if (pPlatform->version <= 2) {
-    unsigned int embedderDataSlot = 0;
-    v8::Isolate* pExternalIsolate = nullptr;
-    if (pPlatform->version == 2) {
-      pExternalIsolate = reinterpret_cast<v8::Isolate*>(pPlatform->m_isolate);
-      embedderDataSlot = pPlatform->m_v8EmbedderSlot;
-    }
-    FXJS_Initialize(embedderDataSlot, pExternalIsolate);
-  }
-  m_isolateManaged = FXJS_GetIsolate(&pIsolate);
-  SetIsolate(pIsolate);
-
-#ifdef PDF_ENABLE_XFA
-  v8::Isolate::Scope isolate_scope(pIsolate);
-  v8::HandleScope handle_scope(pIsolate);
-#endif
-
-  if (m_isolateManaged || FXJS_GlobalIsolateRefCount() == 0)
-    DefineJSObjects();
-
-  IJS_EventContext* pContext = NewEventContext();
-  InitializeEngine();
-  ReleaseEventContext(pContext);
-  SetFormFillEnvToDocument();
-}
-
-CJS_Runtime::~CJS_Runtime() {
-  NotifyObservedPtrs();
-  ReleaseEngine();
-  if (m_isolateManaged) {
-    GetIsolate()->Dispose();
-    SetIsolate(nullptr);
-  }
-}
-
-void CJS_Runtime::DefineJSObjects() {
-  v8::Isolate::Scope isolate_scope(GetIsolate());
-  v8::HandleScope handle_scope(GetIsolate());
-  v8::Local<v8::Context> context = v8::Context::New(GetIsolate());
-  v8::Context::Scope context_scope(context);
-
-  // The call order determines the "ObjDefID" assigned to each class.
-  // ObjDefIDs 0 - 2
-  CJS_Border::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
-  CJS_Display::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
-  CJS_Font::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
-
-  // ObjDefIDs 3 - 5
-  CJS_Highlight::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
-  CJS_Position::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
-  CJS_ScaleHow::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
-
-  // ObjDefIDs 6 - 8
-  CJS_ScaleWhen::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
-  CJS_Style::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
-  CJS_Zoomtype::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
-
-  // ObjDefIDs 9 - 11
-  CJS_App::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
-  CJS_Color::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
-  CJS_Console::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
-
-  // ObjDefIDs 12 - 14
-  CJS_Document::DefineJSObjects(this, FXJSOBJTYPE_GLOBAL);
-  CJS_Event::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
-  CJS_Field::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
-
-  // ObjDefIDs 15 - 17
-  CJS_Global::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
-  CJS_Icon::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
-  CJS_Util::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
-
-  // ObjDefIDs 18 - 20 (these can't fail, return void).
-  CJS_PublicMethods::DefineJSObjects(this);
-  CJS_GlobalConsts::DefineJSObjects(this);
-  CJS_GlobalArrays::DefineJSObjects(this);
-
-  // ObjDefIDs 21 - 23.
-  CJS_TimerObj::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
-  CJS_PrintParamsObj::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
-  CJS_Annot::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
-}
-
-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::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);
-}
-
-CJS_EventContext* CJS_Runtime::GetCurrentEventContext() const {
-  return m_EventContextArray.empty() ? nullptr
-                                     : m_EventContextArray.back().get();
-}
-
-void CJS_Runtime::SetFormFillEnvToDocument() {
-  v8::Isolate::Scope isolate_scope(GetIsolate());
-  v8::HandleScope handle_scope(GetIsolate());
-  v8::Local<v8::Context> context = NewLocalContext();
-  v8::Context::Scope context_scope(context);
-
-  v8::Local<v8::Object> pThis = GetThisObj();
-  if (pThis.IsEmpty())
-    return;
-
-  if (CFXJS_Engine::GetObjDefnID(pThis) != CJS_Document::g_nObjDefnID)
-    return;
-
-  CJS_Document* pJSDocument =
-      static_cast<CJS_Document*>(GetObjectPrivate(pThis));
-  if (!pJSDocument)
-    return;
-
-  Document* pDocument = static_cast<Document*>(pJSDocument->GetEmbedObject());
-  if (!pDocument)
-    return;
-
-  pDocument->SetFormFillEnv(m_pFormFillEnv.Get());
-}
-
-CPDFSDK_FormFillEnvironment* CJS_Runtime::GetFormFillEnv() const {
-  return m_pFormFillEnv.Get();
-}
-
-int CJS_Runtime::ExecuteScript(const CFX_WideString& script,
-                               CFX_WideString* info) {
-  FXJSErr error = {};
-  int nRet = Execute(script, &error);
-  if (nRet < 0) {
-    info->Format(L"[ Line: %05d { %s } ] : %s", error.linnum - 1, error.srcline,
-                 error.message);
-  }
-  return nRet;
-}
-
-bool CJS_Runtime::AddEventToSet(const FieldEvent& event) {
-  return m_FieldEventSet.insert(event).second;
-}
-
-void CJS_Runtime::RemoveEventFromSet(const FieldEvent& event) {
-  m_FieldEventSet.erase(event);
-}
-
-#ifdef PDF_ENABLE_XFA
-CFX_WideString ChangeObjName(const CFX_WideString& str) {
-  CFX_WideString sRet = str;
-  sRet.Replace(L"_", L".");
-  return sRet;
-}
-bool CJS_Runtime::GetValueByName(const CFX_ByteStringC& utf8Name,
-                                 CFXJSE_Value* pValue) {
-  const FX_CHAR* name = utf8Name.c_str();
-
-  v8::Isolate::Scope isolate_scope(GetIsolate());
-  v8::HandleScope handle_scope(GetIsolate());
-  v8::Local<v8::Context> context = NewLocalContext();
-  v8::Context::Scope context_scope(context);
-
-  v8::Local<v8::Value> propvalue =
-      context->Global()->Get(v8::String::NewFromUtf8(
-          GetIsolate(), name, v8::String::kNormalString, utf8Name.GetLength()));
-
-  if (propvalue.IsEmpty()) {
-    pValue->SetUndefined();
-    return false;
-  }
-  pValue->ForceSetValue(propvalue);
-  return true;
-}
-bool CJS_Runtime::SetValueByName(const CFX_ByteStringC& utf8Name,
-                                 CFXJSE_Value* pValue) {
-  if (utf8Name.IsEmpty() || !pValue)
-    return false;
-  const FX_CHAR* name = utf8Name.c_str();
-  v8::Isolate* pIsolate = GetIsolate();
-  v8::Isolate::Scope isolate_scope(pIsolate);
-  v8::HandleScope handle_scope(pIsolate);
-  v8::Local<v8::Context> context = NewLocalContext();
-  v8::Context::Scope context_scope(context);
-
-  // v8::Local<v8::Context> tmpCotext =
-  // v8::Local<v8::Context>::New(GetIsolate(), m_context);
-  v8::Local<v8::Value> propvalue =
-      v8::Local<v8::Value>::New(GetIsolate(), pValue->DirectGetValue());
-  context->Global()->Set(
-      v8::String::NewFromUtf8(pIsolate, name, v8::String::kNormalString,
-                              utf8Name.GetLength()),
-      propvalue);
-  return true;
-}
-#endif
diff --git a/fpdfsdk/javascript/cjs_runtime.h b/fpdfsdk/javascript/cjs_runtime.h
deleted file mode 100644
index 0bde51f..0000000
--- a/fpdfsdk/javascript/cjs_runtime.h
+++ /dev/null
@@ -1,71 +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 FPDFSDK_JAVASCRIPT_CJS_RUNTIME_H_
-#define FPDFSDK_JAVASCRIPT_CJS_RUNTIME_H_
-
-#include <map>
-#include <memory>
-#include <set>
-#include <utility>
-#include <vector>
-
-#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_EventContext;
-
-class CJS_Runtime : public IJS_Runtime,
-                    public CFXJS_Engine,
-                    public CFX_Observable<CJS_Runtime> {
- public:
-  using FieldEvent = std::pair<CFX_WideString, JS_EVENT_T>;
-
-  static CJS_Runtime* CurrentRuntimeFromIsolate(v8::Isolate* pIsolate);
-
-  explicit CJS_Runtime(CPDFSDK_FormFillEnvironment* pFormFillEnv);
-  ~CJS_Runtime() override;
-
-  // IJS_Runtime
-  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);
-
-  void BeginBlock() { m_bBlocking = true; }
-  void EndBlock() { m_bBlocking = false; }
-  bool IsBlocking() const { return m_bBlocking; }
-
-#ifdef PDF_ENABLE_XFA
-  bool GetValueByName(const CFX_ByteStringC& utf8Name,
-                      CFXJSE_Value* pValue) override;
-  bool SetValueByName(const CFX_ByteStringC& utf8Name,
-                      CFXJSE_Value* pValue) override;
-#endif  // PDF_ENABLE_XFA
-
- private:
-  void DefineJSObjects();
-  void SetFormFillEnvToDocument();
-
-  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;
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_CJS_RUNTIME_H_
diff --git a/fpdfsdk/javascript/color.cpp b/fpdfsdk/javascript/color.cpp
deleted file mode 100644
index b5ccbad..0000000
--- a/fpdfsdk/javascript/color.cpp
+++ /dev/null
@@ -1,279 +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/color.h"
-
-#include <vector>
-
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_EventHandler.h"
-#include "fpdfsdk/javascript/JS_Object.h"
-#include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/cjs_event_context.h"
-#include "fpdfsdk/javascript/cjs_runtime.h"
-
-JSConstSpec CJS_Color::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
-
-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}};
-
-JSMethodSpec CJS_Color::MethodSpecs[] = {{"convert", convert_static},
-                                         {"equal", equal_static},
-                                         {0, 0}};
-
-IMPLEMENT_JS_CLASS(CJS_Color, color)
-
-color::color(CJS_Object* pJSObject) : CJS_EmbedObj(pJSObject) {
-  m_crTransparent = CPWL_Color(COLORTYPE_TRANSPARENT);
-  m_crBlack = CPWL_Color(COLORTYPE_GRAY, 0);
-  m_crWhite = CPWL_Color(COLORTYPE_GRAY, 1);
-  m_crRed = CPWL_Color(COLORTYPE_RGB, 1, 0, 0);
-  m_crGreen = CPWL_Color(COLORTYPE_RGB, 0, 1, 0);
-  m_crBlue = CPWL_Color(COLORTYPE_RGB, 0, 0, 1);
-  m_crCyan = CPWL_Color(COLORTYPE_CMYK, 1, 0, 0, 0);
-  m_crMagenta = CPWL_Color(COLORTYPE_CMYK, 0, 1, 0, 0);
-  m_crYellow = CPWL_Color(COLORTYPE_CMYK, 0, 0, 1, 0);
-  m_crDKGray = CPWL_Color(COLORTYPE_GRAY, 0.25);
-  m_crGray = CPWL_Color(COLORTYPE_GRAY, 0.5);
-  m_crLTGray = CPWL_Color(COLORTYPE_GRAY, 0.75);
-}
-
-color::~color() {}
-
-void color::ConvertPWLColorToArray(CJS_Runtime* pRuntime,
-                                   const CPWL_Color& color,
-                                   CJS_Array* array) {
-  switch (color.nColorType) {
-    case COLORTYPE_TRANSPARENT:
-      array->SetElement(pRuntime, 0, CJS_Value(pRuntime, "T"));
-      break;
-    case COLORTYPE_GRAY:
-      array->SetElement(pRuntime, 0, CJS_Value(pRuntime, "G"));
-      array->SetElement(pRuntime, 1, CJS_Value(pRuntime, color.fColor1));
-      break;
-    case COLORTYPE_RGB:
-      array->SetElement(pRuntime, 0, CJS_Value(pRuntime, "RGB"));
-      array->SetElement(pRuntime, 1, CJS_Value(pRuntime, color.fColor1));
-      array->SetElement(pRuntime, 2, CJS_Value(pRuntime, color.fColor2));
-      array->SetElement(pRuntime, 3, CJS_Value(pRuntime, color.fColor3));
-      break;
-    case COLORTYPE_CMYK:
-      array->SetElement(pRuntime, 0, CJS_Value(pRuntime, "CMYK"));
-      array->SetElement(pRuntime, 1, CJS_Value(pRuntime, color.fColor1));
-      array->SetElement(pRuntime, 2, CJS_Value(pRuntime, color.fColor2));
-      array->SetElement(pRuntime, 3, CJS_Value(pRuntime, color.fColor3));
-      array->SetElement(pRuntime, 4, CJS_Value(pRuntime, color.fColor4));
-      break;
-  }
-}
-
-void color::ConvertArrayToPWLColor(CJS_Runtime* pRuntime,
-                                   const CJS_Array& array,
-                                   CPWL_Color* color) {
-  int nArrayLen = array.GetLength(pRuntime);
-  if (nArrayLen < 1)
-    return;
-
-  CJS_Value value(pRuntime);
-  array.GetElement(pRuntime, 0, value);
-  CFX_ByteString sSpace = value.ToCFXByteString(pRuntime);
-
-  double d1 = 0;
-  double d2 = 0;
-  double d3 = 0;
-  double d4 = 0;
-
-  if (nArrayLen > 1) {
-    array.GetElement(pRuntime, 1, value);
-    d1 = value.ToDouble(pRuntime);
-  }
-
-  if (nArrayLen > 2) {
-    array.GetElement(pRuntime, 2, value);
-    d2 = value.ToDouble(pRuntime);
-  }
-
-  if (nArrayLen > 3) {
-    array.GetElement(pRuntime, 3, value);
-    d3 = value.ToDouble(pRuntime);
-  }
-
-  if (nArrayLen > 4) {
-    array.GetElement(pRuntime, 4, value);
-    d4 = value.ToDouble(pRuntime);
-  }
-
-  if (sSpace == "T") {
-    *color = CPWL_Color(COLORTYPE_TRANSPARENT);
-  } else if (sSpace == "G") {
-    *color = CPWL_Color(COLORTYPE_GRAY, (FX_FLOAT)d1);
-  } else if (sSpace == "RGB") {
-    *color =
-        CPWL_Color(COLORTYPE_RGB, (FX_FLOAT)d1, (FX_FLOAT)d2, (FX_FLOAT)d3);
-  } else if (sSpace == "CMYK") {
-    *color = CPWL_Color(COLORTYPE_CMYK, (FX_FLOAT)d1, (FX_FLOAT)d2,
-                        (FX_FLOAT)d3, (FX_FLOAT)d4);
-  }
-}
-
-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;
-
-  ConvertArrayToPWLColor(pRuntime, array, var);
-  return true;
-}
-
-bool color::convert(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError) {
-  int iSize = params.size();
-  if (iSize < 2)
-    return false;
-
-  CJS_Array aSource;
-  if (!params[0].ConvertToArray(pRuntime, aSource))
-    return false;
-
-  CPWL_Color crSource;
-  ConvertArrayToPWLColor(pRuntime, aSource, &crSource);
-
-  CFX_ByteString sDestSpace = params[1].ToCFXByteString(pRuntime);
-  int nColorType = COLORTYPE_TRANSPARENT;
-
-  if (sDestSpace == "T") {
-    nColorType = COLORTYPE_TRANSPARENT;
-  } else if (sDestSpace == "G") {
-    nColorType = COLORTYPE_GRAY;
-  } else if (sDestSpace == "RGB") {
-    nColorType = COLORTYPE_RGB;
-  } else if (sDestSpace == "CMYK") {
-    nColorType = COLORTYPE_CMYK;
-  }
-
-  CJS_Array aDest;
-  CPWL_Color crDest = crSource.ConvertColorType(nColorType);
-  ConvertPWLColorToArray(pRuntime, crDest, &aDest);
-  vRet = CJS_Value(pRuntime, aDest);
-
-  return true;
-}
-
-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_Array array1;
-  CJS_Array array2;
-  if (!params[0].ConvertToArray(pRuntime, array1))
-    return false;
-  if (!params[1].ConvertToArray(pRuntime, array2))
-    return false;
-
-  CPWL_Color color1;
-  CPWL_Color color2;
-  ConvertArrayToPWLColor(pRuntime, array1, &color1);
-  ConvertArrayToPWLColor(pRuntime, array2, &color2);
-  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
deleted file mode 100644
index 8d6187a..0000000
--- a/fpdfsdk/javascript/color.h
+++ /dev/null
@@ -1,96 +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 FPDFSDK_JAVASCRIPT_COLOR_H_
-#define FPDFSDK_JAVASCRIPT_COLOR_H_
-
-#include <vector>
-
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-
-class color : public CJS_EmbedObj {
- public:
-  explicit color(CJS_Object* pJSObject);
-  ~color() override;
-
-  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(CJS_Runtime* pRuntime,
-               const std::vector<CJS_Value>& params,
-               CJS_Value& vRet,
-               CFX_WideString& sError);
-  bool equal(CJS_Runtime* pRuntime,
-             const std::vector<CJS_Value>& params,
-             CJS_Value& vRet,
-             CFX_WideString& sError);
-
-  static void ConvertPWLColorToArray(CJS_Runtime* pRuntime,
-                                     const CPWL_Color& color,
-                                     CJS_Array* array);
-  static void ConvertArrayToPWLColor(CJS_Runtime* pRuntime,
-                                     const CJS_Array& array,
-                                     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;
-  CPWL_Color m_crRed;
-  CPWL_Color m_crGreen;
-  CPWL_Color m_crBlue;
-  CPWL_Color m_crCyan;
-  CPWL_Color m_crMagenta;
-  CPWL_Color m_crYellow;
-  CPWL_Color m_crDKGray;
-  CPWL_Color m_crGray;
-  CPWL_Color m_crLTGray;
-};
-
-class CJS_Color : public CJS_Object {
- public:
-  explicit CJS_Color(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Color() override {}
-
-  DECLARE_JS_CLASS();
-
-  JS_STATIC_PROP(black, color);
-  JS_STATIC_PROP(blue, color);
-  JS_STATIC_PROP(cyan, color);
-  JS_STATIC_PROP(dkGray, color);
-  JS_STATIC_PROP(gray, color);
-  JS_STATIC_PROP(green, color);
-  JS_STATIC_PROP(ltGray, color);
-  JS_STATIC_PROP(magenta, color);
-  JS_STATIC_PROP(red, color);
-  JS_STATIC_PROP(transparent, color);
-  JS_STATIC_PROP(white, color);
-  JS_STATIC_PROP(yellow, color);
-
-  JS_STATIC_METHOD(convert, color);
-  JS_STATIC_METHOD(equal, color);
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_COLOR_H_
diff --git a/fpdfsdk/javascript/console.cpp b/fpdfsdk/javascript/console.cpp
deleted file mode 100644
index e9d1308..0000000
--- a/fpdfsdk/javascript/console.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2014 PDFium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
-
-#include "fpdfsdk/javascript/console.h"
-
-#include <vector>
-
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_EventHandler.h"
-#include "fpdfsdk/javascript/JS_Object.h"
-#include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/cjs_event_context.h"
-
-JSConstSpec CJS_Console::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
-
-JSPropertySpec CJS_Console::PropertySpecs[] = {{0, 0, 0}};
-
-JSMethodSpec CJS_Console::MethodSpecs[] = {{"clear", clear_static},
-                                           {"hide", hide_static},
-                                           {"println", println_static},
-                                           {"show", show_static},
-                                           {0, 0}};
-
-IMPLEMENT_JS_CLASS(CJS_Console, console)
-
-console::console(CJS_Object* pJSObject) : CJS_EmbedObj(pJSObject) {}
-
-console::~console() {}
-
-bool console::clear(CJS_Runtime* pRuntime,
-                    const std::vector<CJS_Value>& params,
-                    CJS_Value& vRet,
-                    CFX_WideString& sError) {
-  return true;
-}
-
-bool console::hide(CJS_Runtime* pRuntime,
-                   const std::vector<CJS_Value>& params,
-                   CJS_Value& vRet,
-                   CFX_WideString& sError) {
-  return true;
-}
-
-bool console::println(CJS_Runtime* pRuntime,
-                      const std::vector<CJS_Value>& params,
-                      CJS_Value& vRet,
-                      CFX_WideString& sError) {
-  if (params.size() < 1) {
-    return false;
-  }
-  return true;
-}
-
-bool console::show(CJS_Runtime* pRuntime,
-                   const std::vector<CJS_Value>& params,
-                   CJS_Value& vRet,
-                   CFX_WideString& sError) {
-  return true;
-}
diff --git a/fpdfsdk/javascript/console.h b/fpdfsdk/javascript/console.h
deleted file mode 100644
index a7e4d8e..0000000
--- a/fpdfsdk/javascript/console.h
+++ /dev/null
@@ -1,51 +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 FPDFSDK_JAVASCRIPT_CONSOLE_H_
-#define FPDFSDK_JAVASCRIPT_CONSOLE_H_
-
-#include <vector>
-
-#include "fpdfsdk/javascript/JS_Define.h"
-
-class console : public CJS_EmbedObj {
- public:
-  explicit console(CJS_Object* pJSObject);
-  ~console() override;
-
- public:
-  bool clear(CJS_Runtime* pRuntime,
-             const std::vector<CJS_Value>& params,
-             CJS_Value& vRet,
-             CFX_WideString& sError);
-  bool hide(CJS_Runtime* pRuntime,
-            const std::vector<CJS_Value>& params,
-            CJS_Value& vRet,
-            CFX_WideString& sError);
-  bool println(CJS_Runtime* pRuntime,
-               const std::vector<CJS_Value>& params,
-               CJS_Value& vRet,
-               CFX_WideString& sError);
-  bool show(CJS_Runtime* pRuntime,
-            const std::vector<CJS_Value>& params,
-            CJS_Value& vRet,
-            CFX_WideString& sError);
-};
-
-class CJS_Console : public CJS_Object {
- public:
-  explicit CJS_Console(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Console() override {}
-
-  DECLARE_JS_CLASS();
-
-  JS_STATIC_METHOD(clear, console);
-  JS_STATIC_METHOD(hide, console);
-  JS_STATIC_METHOD(println, console);
-  JS_STATIC_METHOD(show, console);
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_CONSOLE_H_
diff --git a/fpdfsdk/javascript/event.cpp b/fpdfsdk/javascript/event.cpp
deleted file mode 100644
index 2b00cbc..0000000
--- a/fpdfsdk/javascript/event.cpp
+++ /dev/null
@@ -1,309 +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/event.h"
-
-#include "fpdfsdk/javascript/Field.h"
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_EventHandler.h"
-#include "fpdfsdk/javascript/JS_Object.h"
-#include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/cjs_event_context.h"
-
-JSConstSpec CJS_Event::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
-
-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}};
-
-JSMethodSpec CJS_Event::MethodSpecs[] = {{0, 0}};
-
-IMPLEMENT_JS_CLASS(CJS_Event, event)
-
-event::event(CJS_Object* pJsObject) : CJS_EmbedObj(pJsObject) {}
-
-event::~event() {}
-
-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;
-    return true;
-  }
-  vp << wChange;
-  return true;
-}
-
-bool event::changeEx(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  CJS_EventHandler* pEvent =
-      pRuntime->GetCurrentEventContext()->GetEventHandler();
-
-  vp << pEvent->ChangeEx();
-  return true;
-}
-
-bool event::commitKey(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  CJS_EventHandler* pEvent =
-      pRuntime->GetCurrentEventContext()->GetEventHandler();
-
-  vp << pEvent->CommitKey();
-  return true;
-}
-
-bool event::fieldFull(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError) {
-  CJS_EventHandler* pEvent =
-      pRuntime->GetCurrentEventContext()->GetEventHandler();
-
-  if (!vp.IsGetting() &&
-      wcscmp((const wchar_t*)pEvent->Name(), L"Keystroke") != 0)
-    return false;
-
-  vp << pEvent->FieldFull();
-  return true;
-}
-
-bool event::keyDown(CJS_Runtime* pRuntime,
-                    CJS_PropValue& vp,
-                    CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  CJS_EventHandler* pEvent =
-      pRuntime->GetCurrentEventContext()->GetEventHandler();
-
-  vp << pEvent->KeyDown();
-  return true;
-}
-
-bool event::modifier(CJS_Runtime* pRuntime,
-                     CJS_PropValue& vp,
-                     CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  CJS_EventHandler* pEvent =
-      pRuntime->GetCurrentEventContext()->GetEventHandler();
-
-  vp << pEvent->Modifier();
-  return true;
-}
-
-bool event::name(CJS_Runtime* pRuntime,
-                 CJS_PropValue& vp,
-                 CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  CJS_EventHandler* pEvent =
-      pRuntime->GetCurrentEventContext()->GetEventHandler();
-
-  vp << pEvent->Name();
-  return true;
-}
-
-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())
-    vp >> bRc;
-  else
-    vp << bRc;
-
-  return true;
-}
-
-bool event::richChange(CJS_Runtime* pRuntime,
-                       CJS_PropValue& vp,
-                       CFX_WideString& sError) {
-  return true;
-}
-
-bool event::richChangeEx(CJS_Runtime* pRuntime,
-                         CJS_PropValue& vp,
-                         CFX_WideString& sError) {
-  return true;
-}
-
-bool event::richValue(CJS_Runtime* pRuntime,
-                      CJS_PropValue& vp,
-                      CFX_WideString& sError) {
-  return true;
-}
-
-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)
-    return true;
-
-  int& iSelEnd = pEvent->SelEnd();
-  if (vp.IsSetting())
-    vp >> iSelEnd;
-  else
-    vp << iSelEnd;
-
-  return true;
-}
-
-bool event::selStart(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)
-    return true;
-
-  int& iSelStart = pEvent->SelStart();
-  if (vp.IsSetting())
-    vp >> iSelStart;
-  else
-    vp << iSelStart;
-
-  return true;
-}
-
-bool event::shift(CJS_Runtime* pRuntime,
-                  CJS_PropValue& vp,
-                  CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  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(CJS_Runtime* pRuntime,
-                   CJS_PropValue& vp,
-                   CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  CJS_EventHandler* pEvent =
-      pRuntime->GetCurrentEventContext()->GetEventHandler();
-
-  vp << pEvent->Target_Field()->GetJSObject();
-  return true;
-}
-
-bool event::targetName(CJS_Runtime* pRuntime,
-                       CJS_PropValue& vp,
-                       CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  CJS_EventHandler* pEvent =
-      pRuntime->GetCurrentEventContext()->GetEventHandler();
-
-  vp << pEvent->TargetName();
-  return true;
-}
-
-bool event::type(CJS_Runtime* pRuntime,
-                 CJS_PropValue& vp,
-                 CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  CJS_EventHandler* pEvent =
-      pRuntime->GetCurrentEventContext()->GetEventHandler();
-
-  vp << pEvent->Type();
-  return true;
-}
-
-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())
-    vp >> val;
-  else
-    vp << val;
-
-  return true;
-}
-
-bool event::willCommit(CJS_Runtime* pRuntime,
-                       CJS_PropValue& vp,
-                       CFX_WideString& sError) {
-  if (!vp.IsGetting())
-    return false;
-
-  CJS_EventHandler* pEvent =
-      pRuntime->GetCurrentEventContext()->GetEventHandler();
-
-  vp << pEvent->WillCommit();
-  return true;
-}
diff --git a/fpdfsdk/javascript/event.h b/fpdfsdk/javascript/event.h
deleted file mode 100644
index 2be8a0a..0000000
--- a/fpdfsdk/javascript/event.h
+++ /dev/null
@@ -1,90 +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 FPDFSDK_JAVASCRIPT_EVENT_H_
-#define FPDFSDK_JAVASCRIPT_EVENT_H_
-
-#include "fpdfsdk/javascript/JS_Define.h"
-
-class event : public CJS_EmbedObj {
- public:
-  explicit event(CJS_Object* pJSObject);
-  ~event() override;
-
- public:
-  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 {
- public:
-  explicit CJS_Event(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Event() override {}
-
-  DECLARE_JS_CLASS();
-  JS_STATIC_PROP(change, event);
-  JS_STATIC_PROP(changeEx, event);
-  JS_STATIC_PROP(commitKey, event);
-  JS_STATIC_PROP(fieldFull, event);
-  JS_STATIC_PROP(keyDown, event);
-  JS_STATIC_PROP(modifier, event);
-  JS_STATIC_PROP(name, event);
-  JS_STATIC_PROP(rc, event);
-  JS_STATIC_PROP(richChange, event);
-  JS_STATIC_PROP(richChangeEx, event);
-  JS_STATIC_PROP(richValue, event);
-  JS_STATIC_PROP(selEnd, event);
-  JS_STATIC_PROP(selStart, event);
-  JS_STATIC_PROP(shift, event);
-  JS_STATIC_PROP(source, event);
-  JS_STATIC_PROP(target, event);
-  JS_STATIC_PROP(targetName, event);
-  JS_STATIC_PROP(type, event);
-  JS_STATIC_PROP(value, event);
-  JS_STATIC_PROP(willCommit, event);
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_EVENT_H_
diff --git a/fpdfsdk/javascript/global.cpp b/fpdfsdk/javascript/global.cpp
deleted file mode 100644
index a450606..0000000
--- a/fpdfsdk/javascript/global.cpp
+++ /dev/null
@@ -1,440 +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/global.h"
-
-#include <vector>
-
-#include "core/fxcrt/fx_ext.h"
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_EventHandler.h"
-#include "fpdfsdk/javascript/JS_GlobalData.h"
-#include "fpdfsdk/javascript/JS_Object.h"
-#include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/cjs_event_context.h"
-#include "fpdfsdk/javascript/resource.h"
-
-JSConstSpec CJS_Global::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
-
-JSPropertySpec CJS_Global::PropertySpecs[] = {{0, 0, 0}};
-
-JSMethodSpec CJS_Global::MethodSpecs[] = {
-    {"setPersistent", setPersistent_static},
-    {0, 0}};
-
-IMPLEMENT_SPECIAL_JS_CLASS(CJS_Global, JSGlobalAlternate, global);
-
-void CJS_Global::InitInstance(IJS_Runtime* pIRuntime) {
-  CJS_Runtime* pRuntime = static_cast<CJS_Runtime*>(pIRuntime);
-  JSGlobalAlternate* pGlobal =
-      static_cast<JSGlobalAlternate*>(GetEmbedObject());
-  pGlobal->Initial(pRuntime->GetFormFillEnv());
-}
-
-JSGlobalData::JSGlobalData()
-    : nType(JS_GlobalDataType::NUMBER),
-      dData(0),
-      bData(false),
-      sData(""),
-      bPersistent(false),
-      bDeleted(false) {}
-
-JSGlobalData::~JSGlobalData() {
-  pData.Reset();
-}
-
-JSGlobalAlternate::JSGlobalAlternate(CJS_Object* pJSObject)
-    : CJS_EmbedObj(pJSObject), m_pFormFillEnv(nullptr) {}
-
-JSGlobalAlternate::~JSGlobalAlternate() {
-  DestroyGlobalPersisitentVariables();
-  m_pGlobalData->Release();
-}
-
-void JSGlobalAlternate::Initial(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
-  m_pFormFillEnv.Reset(pFormFillEnv);
-  m_pGlobalData = CJS_GlobalData::GetRetainedInstance(pFormFillEnv);
-  UpdateGlobalPersistentVariables();
-}
-
-bool JSGlobalAlternate::QueryProperty(const FX_WCHAR* propname) {
-  return CFX_WideString(propname) != L"setPersistent";
-}
-
-bool JSGlobalAlternate::DelProperty(CJS_Runtime* pRuntime,
-                                    const FX_WCHAR* propname,
-                                    CFX_WideString& sError) {
-  auto it = m_mapGlobal.find(CFX_ByteString::FromUnicode(propname));
-  if (it == m_mapGlobal.end())
-    return false;
-
-  it->second->bDeleted = true;
-  return true;
-}
-
-bool JSGlobalAlternate::DoProperty(CJS_Runtime* pRuntime,
-                                   const FX_WCHAR* propname,
-                                   CJS_PropValue& vp,
-                                   CFX_WideString& sError) {
-  if (vp.IsSetting()) {
-    CFX_ByteString sPropName = CFX_ByteString::FromUnicode(propname);
-    switch (vp.GetJSValue()->GetType()) {
-      case CJS_Value::VT_number: {
-        double dData;
-        vp >> dData;
-        return SetGlobalVariables(sPropName, JS_GlobalDataType::NUMBER, dData,
-                                  false, "", v8::Local<v8::Object>(), false);
-      }
-      case CJS_Value::VT_boolean: {
-        bool bData;
-        vp >> bData;
-        return SetGlobalVariables(sPropName, JS_GlobalDataType::BOOLEAN, 0,
-                                  bData, "", v8::Local<v8::Object>(), false);
-      }
-      case CJS_Value::VT_string: {
-        CFX_ByteString sData;
-        vp >> sData;
-        return SetGlobalVariables(sPropName, JS_GlobalDataType::STRING, 0,
-                                  false, sData, v8::Local<v8::Object>(), false);
-      }
-      case CJS_Value::VT_object: {
-        v8::Local<v8::Object> pData;
-        vp >> pData;
-        return SetGlobalVariables(sPropName, JS_GlobalDataType::OBJECT, 0,
-                                  false, "", pData, false);
-      }
-      case CJS_Value::VT_null: {
-        return SetGlobalVariables(sPropName, JS_GlobalDataType::NULLOBJ, 0,
-                                  false, "", v8::Local<v8::Object>(), false);
-      }
-      case CJS_Value::VT_undefined: {
-        DelProperty(pRuntime, propname, sError);
-        return true;
-      }
-      default:
-        break;
-    }
-  } else {
-    auto it = m_mapGlobal.find(CFX_ByteString::FromUnicode(propname));
-    if (it == m_mapGlobal.end()) {
-      vp.GetJSValue()->SetNull(pRuntime);
-      return true;
-    }
-    JSGlobalData* pData = it->second;
-    if (pData->bDeleted) {
-      vp.GetJSValue()->SetNull(pRuntime);
-      return true;
-    }
-    switch (pData->nType) {
-      case JS_GlobalDataType::NUMBER:
-        vp << pData->dData;
-        return true;
-      case JS_GlobalDataType::BOOLEAN:
-        vp << pData->bData;
-        return true;
-      case JS_GlobalDataType::STRING:
-        vp << pData->sData;
-        return true;
-      case JS_GlobalDataType::OBJECT: {
-        v8::Local<v8::Object> obj = v8::Local<v8::Object>::New(
-            vp.GetJSRuntime()->GetIsolate(), pData->pData);
-        vp << obj;
-        return true;
-      }
-      case JS_GlobalDataType::NULLOBJ:
-        vp.GetJSValue()->SetNull(pRuntime);
-        return true;
-      default:
-        break;
-    }
-  }
-  return false;
-}
-
-bool JSGlobalAlternate::setPersistent(CJS_Runtime* pRuntime,
-                                      const std::vector<CJS_Value>& params,
-                                      CJS_Value& vRet,
-                                      CFX_WideString& sError) {
-  if (params.size() != 2) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  auto it = m_mapGlobal.find(params[0].ToCFXByteString(pRuntime));
-  if (it != m_mapGlobal.end()) {
-    JSGlobalData* pData = it->second;
-    if (!pData->bDeleted) {
-      pData->bPersistent = params[1].ToBool(pRuntime);
-      return true;
-    }
-  }
-
-  sError = JSGetStringFromID(IDS_STRING_JSNOGLOBAL);
-  return false;
-}
-
-void JSGlobalAlternate::UpdateGlobalPersistentVariables() {
-  CJS_Runtime* pRuntime =
-      static_cast<CJS_Runtime*>(CFXJS_Engine::CurrentEngineFromIsolate(
-          m_pJSObject->ToV8Object()->GetIsolate()));
-
-  for (int i = 0, sz = m_pGlobalData->GetSize(); i < sz; i++) {
-    CJS_GlobalData_Element* pData = m_pGlobalData->GetAt(i);
-    switch (pData->data.nType) {
-      case JS_GlobalDataType::NUMBER:
-        SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::NUMBER,
-                           pData->data.dData, false, "",
-                           v8::Local<v8::Object>(), pData->bPersistent == 1);
-        pRuntime->PutObjectProperty(m_pJSObject->ToV8Object(),
-                                    pData->data.sKey.UTF8Decode(),
-                                    pRuntime->NewNumber(pData->data.dData));
-        break;
-      case JS_GlobalDataType::BOOLEAN:
-        SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::BOOLEAN, 0,
-                           pData->data.bData == 1, "", v8::Local<v8::Object>(),
-                           pData->bPersistent == 1);
-        pRuntime->PutObjectProperty(
-            m_pJSObject->ToV8Object(), pData->data.sKey.UTF8Decode(),
-            pRuntime->NewBoolean(pData->data.bData == 1));
-        break;
-      case JS_GlobalDataType::STRING:
-        SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::STRING, 0,
-                           false, pData->data.sData, v8::Local<v8::Object>(),
-                           pData->bPersistent == 1);
-        pRuntime->PutObjectProperty(
-            m_pJSObject->ToV8Object(), pData->data.sKey.UTF8Decode(),
-            pRuntime->NewString(pData->data.sData.UTF8Decode().AsStringC()));
-        break;
-      case JS_GlobalDataType::OBJECT: {
-        v8::Local<v8::Object> pObj = pRuntime->NewFxDynamicObj(-1);
-        PutObjectProperty(pObj, &pData->data);
-        SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::OBJECT, 0,
-                           false, "", pObj, pData->bPersistent == 1);
-        pRuntime->PutObjectProperty(m_pJSObject->ToV8Object(),
-                                    pData->data.sKey.UTF8Decode(), pObj);
-      } break;
-      case JS_GlobalDataType::NULLOBJ:
-        SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::NULLOBJ, 0,
-                           false, "", v8::Local<v8::Object>(),
-                           pData->bPersistent == 1);
-        pRuntime->PutObjectProperty(m_pJSObject->ToV8Object(),
-                                    pData->data.sKey.UTF8Decode(),
-                                    pRuntime->NewNull());
-        break;
-    }
-  }
-}
-
-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;
-    if (pData->bDeleted) {
-      m_pGlobalData->DeleteGlobalVariable(name);
-    } else {
-      switch (pData->nType) {
-        case JS_GlobalDataType::NUMBER:
-          m_pGlobalData->SetGlobalVariableNumber(name, pData->dData);
-          m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
-          break;
-        case JS_GlobalDataType::BOOLEAN:
-          m_pGlobalData->SetGlobalVariableBoolean(name, pData->bData);
-          m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
-          break;
-        case JS_GlobalDataType::STRING:
-          m_pGlobalData->SetGlobalVariableString(name, pData->sData);
-          m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
-          break;
-        case JS_GlobalDataType::OBJECT: {
-          CJS_GlobalVariableArray array;
-          v8::Local<v8::Object> obj = v8::Local<v8::Object>::New(
-              GetJSObject()->GetIsolate(), pData->pData);
-          ObjectToArray(pRuntime, obj, array);
-          m_pGlobalData->SetGlobalVariableObject(name, array);
-          m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
-        } break;
-        case JS_GlobalDataType::NULLOBJ:
-          m_pGlobalData->SetGlobalVariableNull(name);
-          m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
-          break;
-      }
-    }
-  }
-}
-
-void JSGlobalAlternate::ObjectToArray(CJS_Runtime* pRuntime,
-                                      v8::Local<v8::Object> pObj,
-                                      CJS_GlobalVariableArray& array) {
-  std::vector<CFX_WideString> pKeyList = pRuntime->GetObjectPropertyNames(pObj);
-  for (const auto& ws : pKeyList) {
-    CFX_ByteString sKey = ws.UTF8Encode();
-    v8::Local<v8::Value> v = pRuntime->GetObjectProperty(pObj, ws);
-    switch (CJS_Value::GetValueType(v)) {
-      case CJS_Value::VT_number: {
-        CJS_KeyValue* pObjElement = new CJS_KeyValue;
-        pObjElement->nType = JS_GlobalDataType::NUMBER;
-        pObjElement->sKey = sKey;
-        pObjElement->dData = pRuntime->ToDouble(v);
-        array.Add(pObjElement);
-      } break;
-      case CJS_Value::VT_boolean: {
-        CJS_KeyValue* pObjElement = new CJS_KeyValue;
-        pObjElement->nType = JS_GlobalDataType::BOOLEAN;
-        pObjElement->sKey = sKey;
-        pObjElement->dData = pRuntime->ToBoolean(v);
-        array.Add(pObjElement);
-      } break;
-      case CJS_Value::VT_string: {
-        CFX_ByteString sValue =
-            CJS_Value(pRuntime, v).ToCFXByteString(pRuntime);
-        CJS_KeyValue* pObjElement = new CJS_KeyValue;
-        pObjElement->nType = JS_GlobalDataType::STRING;
-        pObjElement->sKey = sKey;
-        pObjElement->sData = sValue;
-        array.Add(pObjElement);
-      } break;
-      case CJS_Value::VT_object: {
-        CJS_KeyValue* pObjElement = new CJS_KeyValue;
-        pObjElement->nType = JS_GlobalDataType::OBJECT;
-        pObjElement->sKey = sKey;
-        ObjectToArray(pRuntime, pRuntime->ToObject(v), pObjElement->objData);
-        array.Add(pObjElement);
-      } break;
-      case CJS_Value::VT_null: {
-        CJS_KeyValue* pObjElement = new CJS_KeyValue;
-        pObjElement->nType = JS_GlobalDataType::NULLOBJ;
-        pObjElement->sKey = sKey;
-        array.Add(pObjElement);
-      } break;
-      default:
-        break;
-    }
-  }
-}
-
-void JSGlobalAlternate::PutObjectProperty(v8::Local<v8::Object> pObj,
-                                          CJS_KeyValue* pData) {
-  CJS_Runtime* pRuntime = CJS_Runtime::CurrentRuntimeFromIsolate(
-      m_pJSObject->ToV8Object()->GetIsolate());
-
-  for (int i = 0, sz = pData->objData.Count(); i < sz; i++) {
-    CJS_KeyValue* pObjData = pData->objData.GetAt(i);
-    switch (pObjData->nType) {
-      case JS_GlobalDataType::NUMBER:
-        pRuntime->PutObjectProperty(pObj, pObjData->sKey.UTF8Decode(),
-                                    pRuntime->NewNumber(pObjData->dData));
-        break;
-      case JS_GlobalDataType::BOOLEAN:
-        pRuntime->PutObjectProperty(pObj, pObjData->sKey.UTF8Decode(),
-                                    pRuntime->NewBoolean(pObjData->bData == 1));
-        break;
-      case JS_GlobalDataType::STRING:
-        pRuntime->PutObjectProperty(
-            pObj, pObjData->sKey.UTF8Decode(),
-            pRuntime->NewString(pObjData->sData.UTF8Decode().AsStringC()));
-        break;
-      case JS_GlobalDataType::OBJECT: {
-        v8::Local<v8::Object> pNewObj = pRuntime->NewFxDynamicObj(-1);
-        PutObjectProperty(pNewObj, pObjData);
-        pRuntime->PutObjectProperty(pObj, pObjData->sKey.UTF8Decode(), pNewObj);
-      } break;
-      case JS_GlobalDataType::NULLOBJ:
-        pRuntime->PutObjectProperty(pObj, pObjData->sKey.UTF8Decode(),
-                                    pRuntime->NewNull());
-        break;
-    }
-  }
-}
-
-void JSGlobalAlternate::DestroyGlobalPersisitentVariables() {
-  for (const auto& pair : m_mapGlobal) {
-    delete pair.second;
-  }
-  m_mapGlobal.clear();
-}
-
-bool JSGlobalAlternate::SetGlobalVariables(const CFX_ByteString& propname,
-                                           JS_GlobalDataType nType,
-                                           double dData,
-                                           bool bData,
-                                           const CFX_ByteString& sData,
-                                           v8::Local<v8::Object> pData,
-                                           bool bDefaultPersistent) {
-  if (propname.IsEmpty())
-    return false;
-
-  auto it = m_mapGlobal.find(propname);
-  if (it != m_mapGlobal.end()) {
-    JSGlobalData* pTemp = it->second;
-    if (pTemp->bDeleted || pTemp->nType != nType) {
-      pTemp->dData = 0;
-      pTemp->bData = 0;
-      pTemp->sData = "";
-      pTemp->nType = nType;
-    }
-
-    pTemp->bDeleted = false;
-    switch (nType) {
-      case JS_GlobalDataType::NUMBER: {
-        pTemp->dData = dData;
-      } break;
-      case JS_GlobalDataType::BOOLEAN: {
-        pTemp->bData = bData;
-      } break;
-      case JS_GlobalDataType::STRING: {
-        pTemp->sData = sData;
-      } break;
-      case JS_GlobalDataType::OBJECT: {
-        pTemp->pData.Reset(pData->GetIsolate(), pData);
-      } break;
-      case JS_GlobalDataType::NULLOBJ:
-        break;
-      default:
-        return false;
-    }
-    return true;
-  }
-
-  JSGlobalData* pNewData = nullptr;
-
-  switch (nType) {
-    case JS_GlobalDataType::NUMBER: {
-      pNewData = new JSGlobalData;
-      pNewData->nType = JS_GlobalDataType::NUMBER;
-      pNewData->dData = dData;
-      pNewData->bPersistent = bDefaultPersistent;
-    } break;
-    case JS_GlobalDataType::BOOLEAN: {
-      pNewData = new JSGlobalData;
-      pNewData->nType = JS_GlobalDataType::BOOLEAN;
-      pNewData->bData = bData;
-      pNewData->bPersistent = bDefaultPersistent;
-    } break;
-    case JS_GlobalDataType::STRING: {
-      pNewData = new JSGlobalData;
-      pNewData->nType = JS_GlobalDataType::STRING;
-      pNewData->sData = sData;
-      pNewData->bPersistent = bDefaultPersistent;
-    } break;
-    case JS_GlobalDataType::OBJECT: {
-      pNewData = new JSGlobalData;
-      pNewData->nType = JS_GlobalDataType::OBJECT;
-      pNewData->pData.Reset(pData->GetIsolate(), pData);
-      pNewData->bPersistent = bDefaultPersistent;
-    } break;
-    case JS_GlobalDataType::NULLOBJ: {
-      pNewData = new JSGlobalData;
-      pNewData->nType = JS_GlobalDataType::NULLOBJ;
-      pNewData->bPersistent = bDefaultPersistent;
-    } break;
-    default:
-      return false;
-  }
-
-  m_mapGlobal[propname] = pNewData;
-  return true;
-}
diff --git a/fpdfsdk/javascript/global.h b/fpdfsdk/javascript/global.h
deleted file mode 100644
index e313929..0000000
--- a/fpdfsdk/javascript/global.h
+++ /dev/null
@@ -1,86 +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 FPDFSDK_JAVASCRIPT_GLOBAL_H_
-#define FPDFSDK_JAVASCRIPT_GLOBAL_H_
-
-#include <map>
-#include <vector>
-
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_KeyValue.h"
-
-class CJS_GlobalData;
-class CJS_GlobalVariableArray;
-class CJS_KeyValue;
-
-struct JSGlobalData {
-  JSGlobalData();
-  ~JSGlobalData();
-
-  JS_GlobalDataType nType;
-  double dData;
-  bool bData;
-  CFX_ByteString sData;
-  v8::Global<v8::Object> pData;
-  bool bPersistent;
-  bool bDeleted;
-};
-
-class JSGlobalAlternate : public CJS_EmbedObj {
- public:
-  explicit JSGlobalAlternate(CJS_Object* pJSObject);
-  ~JSGlobalAlternate() override;
-
-  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(CJS_Runtime* pRuntime,
-                  const FX_WCHAR* propname,
-                  CJS_PropValue& vp,
-                  CFX_WideString& sError);
-  bool DelProperty(CJS_Runtime* pRuntime,
-                   const FX_WCHAR* propname,
-                   CFX_WideString& sError);
-  void Initial(CPDFSDK_FormFillEnvironment* pFormFillEnv);
-
- private:
-  void UpdateGlobalPersistentVariables();
-  void CommitGlobalPersisitentVariables(CJS_Runtime* pRuntime);
-  void DestroyGlobalPersisitentVariables();
-  bool SetGlobalVariables(const CFX_ByteString& propname,
-                          JS_GlobalDataType nType,
-                          double dData,
-                          bool bData,
-                          const CFX_ByteString& sData,
-                          v8::Local<v8::Object> pData,
-                          bool bDefaultPersistent);
-  void ObjectToArray(CJS_Runtime* pRuntime,
-                     v8::Local<v8::Object> pObj,
-                     CJS_GlobalVariableArray& array);
-  void PutObjectProperty(v8::Local<v8::Object> obj, CJS_KeyValue* pData);
-
-  std::map<CFX_ByteString, JSGlobalData*> m_mapGlobal;
-  CFX_WideString m_sFilePath;
-  CJS_GlobalData* m_pGlobalData;
-  CPDFSDK_FormFillEnvironment::ObservedPtr m_pFormFillEnv;
-};
-
-class CJS_Global : public CJS_Object {
- public:
-  explicit CJS_Global(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Global() override {}
-
-  // CJS_Object
-  void InitInstance(IJS_Runtime* pIRuntime) override;
-
-  DECLARE_SPECIAL_JS_CLASS();
-  JS_SPECIAL_STATIC_METHOD(setPersistent, JSGlobalAlternate, global);
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_GLOBAL_H_
diff --git a/fpdfsdk/javascript/ijs_event_context.h b/fpdfsdk/javascript/ijs_event_context.h
deleted file mode 100644
index 8428072..0000000
--- a/fpdfsdk/javascript/ijs_event_context.h
+++ /dev/null
@@ -1,134 +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 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"
-
-class CPDF_Bookmark;
-class CPDF_FormField;
-class CPDFSDK_Annot;
-class CPDFSDK_FormFillEnvironment;
-
-// 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;
-
-  virtual void OnApp_Init() = 0;
-
-  virtual void OnDoc_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                          const CFX_WideString& strTargetName) = 0;
-  virtual void OnDoc_WillPrint(CPDFSDK_FormFillEnvironment* pFormFillEnv) = 0;
-  virtual void OnDoc_DidPrint(CPDFSDK_FormFillEnvironment* pFormFillEnv) = 0;
-  virtual void OnDoc_WillSave(CPDFSDK_FormFillEnvironment* pFormFillEnv) = 0;
-  virtual void OnDoc_DidSave(CPDFSDK_FormFillEnvironment* pFormFillEnv) = 0;
-  virtual void OnDoc_WillClose(CPDFSDK_FormFillEnvironment* pFormFillEnv) = 0;
-
-  virtual void OnPage_Open(CPDFSDK_FormFillEnvironment* pFormFillEnv) = 0;
-  virtual void OnPage_Close(CPDFSDK_FormFillEnvironment* pFormFillEnv) = 0;
-  virtual void OnPage_InView(CPDFSDK_FormFillEnvironment* pFormFillEnv) = 0;
-  virtual void OnPage_OutView(CPDFSDK_FormFillEnvironment* pFormFillEnv) = 0;
-
-  virtual void OnField_MouseDown(bool bModifier,
-                                 bool bShift,
-                                 CPDF_FormField* pTarget) = 0;
-  virtual void OnField_MouseEnter(bool bModifier,
-                                  bool bShift,
-                                  CPDF_FormField* pTarget) = 0;
-  virtual void OnField_MouseExit(bool bModifier,
-                                 bool bShift,
-                                 CPDF_FormField* pTarget) = 0;
-  virtual void OnField_MouseUp(bool bModifier,
-                               bool bShift,
-                               CPDF_FormField* pTarget) = 0;
-  virtual void OnField_Focus(bool bModifier,
-                             bool bShift,
-                             CPDF_FormField* pTarget,
-                             const CFX_WideString& Value) = 0;
-  virtual void OnField_Blur(bool bModifier,
-                            bool bShift,
-                            CPDF_FormField* pTarget,
-                            const CFX_WideString& Value) = 0;
-
-  virtual void OnField_Calculate(CPDF_FormField* pSource,
-                                 CPDF_FormField* pTarget,
-                                 CFX_WideString& Value,
-                                 bool& bRc) = 0;
-  virtual void OnField_Format(CPDF_FormField* pTarget,
-                              CFX_WideString& Value,
-                              bool bWillCommit) = 0;
-  virtual void OnField_Keystroke(CFX_WideString& strChange,
-                                 const CFX_WideString& strChangeEx,
-                                 bool KeyDown,
-                                 bool bModifier,
-                                 int& nSelEnd,
-                                 int& nSelStart,
-                                 bool bShift,
-                                 CPDF_FormField* pTarget,
-                                 CFX_WideString& Value,
-                                 bool bWillCommit,
-                                 bool bFieldFull,
-                                 bool& bRc) = 0;
-  virtual void OnField_Validate(CFX_WideString& strChange,
-                                const CFX_WideString& strChangeEx,
-                                bool bKeyDown,
-                                bool bModifier,
-                                bool bShift,
-                                CPDF_FormField* pTarget,
-                                CFX_WideString& Value,
-                                bool& bRc) = 0;
-
-  virtual void OnScreen_Focus(bool bModifier,
-                              bool bShift,
-                              CPDFSDK_Annot* pScreen) = 0;
-  virtual void OnScreen_Blur(bool bModifier,
-                             bool bShift,
-                             CPDFSDK_Annot* pScreen) = 0;
-  virtual void OnScreen_Open(bool bModifier,
-                             bool bShift,
-                             CPDFSDK_Annot* pScreen) = 0;
-  virtual void OnScreen_Close(bool bModifier,
-                              bool bShift,
-                              CPDFSDK_Annot* pScreen) = 0;
-  virtual void OnScreen_MouseDown(bool bModifier,
-                                  bool bShift,
-                                  CPDFSDK_Annot* pScreen) = 0;
-  virtual void OnScreen_MouseUp(bool bModifier,
-                                bool bShift,
-                                CPDFSDK_Annot* pScreen) = 0;
-  virtual void OnScreen_MouseEnter(bool bModifier,
-                                   bool bShift,
-                                   CPDFSDK_Annot* pScreen) = 0;
-  virtual void OnScreen_MouseExit(bool bModifier,
-                                  bool bShift,
-                                  CPDFSDK_Annot* pScreen) = 0;
-  virtual void OnScreen_InView(bool bModifier,
-                               bool bShift,
-                               CPDFSDK_Annot* pScreen) = 0;
-  virtual void OnScreen_OutView(bool bModifier,
-                                bool bShift,
-                                CPDFSDK_Annot* pScreen) = 0;
-
-  virtual void OnBookmark_MouseUp(CPDF_Bookmark* pBookMark) = 0;
-  virtual void OnLink_MouseUp(CPDFSDK_FormFillEnvironment* pFormFillEnv) = 0;
-
-  virtual void OnMenu_Exec(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                           const CFX_WideString&) = 0;
-  virtual void OnBatchExec(CPDFSDK_FormFillEnvironment* pFormFillEnv) = 0;
-  virtual void OnConsole_Exec() = 0;
-  virtual void OnExternal_Exec() = 0;
-
- protected:
-  virtual ~IJS_EventContext() {}
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_IJS_EVENT_CONTEXT_H_
diff --git a/fpdfsdk/javascript/ijs_runtime.h b/fpdfsdk/javascript/ijs_runtime.h
deleted file mode 100644
index babc418..0000000
--- a/fpdfsdk/javascript/ijs_runtime.h
+++ /dev/null
@@ -1,45 +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 FPDFSDK_JAVASCRIPT_IJS_RUNTIME_H_
-#define FPDFSDK_JAVASCRIPT_IJS_RUNTIME_H_
-
-#include "core/fxcrt/fx_string.h"
-#include "core/fxcrt/fx_system.h"
-
-#ifdef PDF_ENABLE_XFA
-#include "fxjs/fxjse.h"
-#endif  // PDF_ENABLE_XFA
-
-class CPDFSDK_FormFillEnvironment;
-class IJS_EventContext;
-
-// Owns the FJXS objects needed to actually execute JS.
-class IJS_Runtime {
- public:
-  static void Initialize(unsigned int slot, void* isolate);
-  static void Destroy();
-  static IJS_Runtime* Create(CPDFSDK_FormFillEnvironment* pFormFillEnv);
-  virtual ~IJS_Runtime() {}
-
-  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;
-
-#ifdef PDF_ENABLE_XFA
-  virtual bool GetValueByName(const CFX_ByteStringC& utf8Name,
-                              CFXJSE_Value* pValue) = 0;
-  virtual bool SetValueByName(const CFX_ByteStringC& utf8Name,
-                              CFXJSE_Value* pValue) = 0;
-#endif  // PDF_ENABLE_XFA
-
- protected:
-  IJS_Runtime() {}
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_IJS_RUNTIME_H_
diff --git a/fpdfsdk/javascript/public_methods_embeddertest.cpp b/fpdfsdk/javascript/public_methods_embeddertest.cpp
deleted file mode 100644
index 2479366..0000000
--- a/fpdfsdk/javascript/public_methods_embeddertest.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2015 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 <cmath>
-
-#include "core/fxcrt/fx_string.h"
-#include "fpdfsdk/javascript/PublicMethods.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/js_embedder_test.h"
-
-namespace {
-
-double RoundDownDate(double date) {
-  return date - fmod(date, 86400000);
-}
-
-}  // namespace
-
-class PublicMethodsEmbedderTest : public JSEmbedderTest {};
-
-TEST_F(PublicMethodsEmbedderTest, MakeRegularDate) {
-  v8::Isolate::Scope isolate_scope(isolate());
-  v8::HandleScope handle_scope(isolate());
-  v8::Context::Scope context_scope(GetV8Context());
-  bool bWrongFormat;
-  double date;
-
-  // 1968
-  bWrongFormat = false;
-  date = CJS_PublicMethods::MakeRegularDate(L"06/25/1968", L"mm/dd/yyyy",
-                                            &bWrongFormat);
-  date = RoundDownDate(date);
-  EXPECT_DOUBLE_EQ(-47865600000, date);
-  EXPECT_FALSE(bWrongFormat);
-
-  // 1968
-  bWrongFormat = false;
-  date = CJS_PublicMethods::MakeRegularDate(L"25061968", L"ddmmyyyy",
-                                            &bWrongFormat);
-  date = RoundDownDate(date);
-  EXPECT_DOUBLE_EQ(-47865600000, date);
-  EXPECT_FALSE(bWrongFormat);
-
-  // 1968
-  bWrongFormat = false;
-  date = CJS_PublicMethods::MakeRegularDate(L"19680625", L"yyyymmdd",
-                                            &bWrongFormat);
-  date = RoundDownDate(date);
-  EXPECT_DOUBLE_EQ(-47865600000, date);
-  EXPECT_FALSE(bWrongFormat);
-
-  // 1985
-  bWrongFormat = false;
-  date = CJS_PublicMethods::MakeRegularDate(L"31121985", L"ddmmyyyy",
-                                            &bWrongFormat);
-  date = RoundDownDate(date);
-  EXPECT_DOUBLE_EQ(504835200000.0, date);
-  EXPECT_FALSE(bWrongFormat);
-
-  // 2085, the other '85.
-  bWrongFormat = false;
-  date =
-      CJS_PublicMethods::MakeRegularDate(L"311285", L"ddmmyy", &bWrongFormat);
-  date = RoundDownDate(date);
-  EXPECT_DOUBLE_EQ(3660595200000.0, date);
-  EXPECT_FALSE(bWrongFormat);
-
-  // 1995
-  bWrongFormat = false;
-  date = CJS_PublicMethods::MakeRegularDate(L"01021995", L"ddmmyyyy",
-                                            &bWrongFormat);
-  date = RoundDownDate(date);
-  EXPECT_DOUBLE_EQ(791596800000.0, date);
-  EXPECT_FALSE(bWrongFormat);
-
-  // 2095, the other '95.
-  bWrongFormat = false;
-  date =
-      CJS_PublicMethods::MakeRegularDate(L"010295", L"ddmmyy", &bWrongFormat);
-  date = RoundDownDate(date);
-  EXPECT_DOUBLE_EQ(3947356800000.0, date);
-  EXPECT_FALSE(bWrongFormat);
-
-  // 2005
-  bWrongFormat = false;
-  date = CJS_PublicMethods::MakeRegularDate(L"01022005", L"ddmmyyyy",
-                                            &bWrongFormat);
-  date = RoundDownDate(date);
-  EXPECT_DOUBLE_EQ(1107216000000.0, date);
-  EXPECT_FALSE(bWrongFormat);
-
-  // 2005
-  bWrongFormat = false;
-  date =
-      CJS_PublicMethods::MakeRegularDate(L"010205", L"ddmmyy", &bWrongFormat);
-  date = RoundDownDate(date);
-  EXPECT_DOUBLE_EQ(1107216000000.0, date);
-  EXPECT_FALSE(bWrongFormat);
-}
-
-TEST_F(PublicMethodsEmbedderTest, MakeFormatDate) {
-  v8::Isolate::Scope isolate_scope(isolate());
-  v8::HandleScope handle_scope(isolate());
-  v8::Context::Scope context_scope(GetV8Context());
-  CFX_WideString formatted_date;
-
-  // 1968-06-25
-  formatted_date = CJS_PublicMethods::MakeFormatDate(-47952000000, L"ddmmyy");
-  EXPECT_STREQ(L"250668", formatted_date.c_str());
-  formatted_date = CJS_PublicMethods::MakeFormatDate(-47952000000, L"yy/mm/dd");
-  EXPECT_STREQ(L"68/06/25", formatted_date.c_str());
-
-  // 1969-12-31
-  formatted_date = CJS_PublicMethods::MakeFormatDate(-0.0001, L"ddmmyy");
-  EXPECT_STREQ(L"311269", formatted_date.c_str());
-  formatted_date = CJS_PublicMethods::MakeFormatDate(-0.0001, L"yy!mmdd");
-  EXPECT_STREQ(L"69!1231", formatted_date.c_str());
-
-  // 1970-01-01
-  formatted_date = CJS_PublicMethods::MakeFormatDate(0, L"ddmmyy");
-  EXPECT_STREQ(L"010170", formatted_date.c_str());
-  formatted_date = CJS_PublicMethods::MakeFormatDate(0, L"mm-yyyy-dd");
-  EXPECT_STREQ(L"01-1970-01", formatted_date.c_str());
-
-  // 1985-12-31
-  formatted_date = CJS_PublicMethods::MakeFormatDate(504835200000.0, L"ddmmyy");
-  EXPECT_STREQ(L"311285", formatted_date.c_str());
-  formatted_date = CJS_PublicMethods::MakeFormatDate(504835200000.0, L"yymmdd");
-  EXPECT_STREQ(L"851231", formatted_date.c_str());
-
-  // 1995-02-01
-  formatted_date = CJS_PublicMethods::MakeFormatDate(791596800000.0, L"ddmmyy");
-  EXPECT_STREQ(L"010295", formatted_date.c_str());
-  formatted_date =
-      CJS_PublicMethods::MakeFormatDate(791596800000.0, L"yyyymmdd");
-  EXPECT_STREQ(L"19950201", formatted_date.c_str());
-
-  // 2005-02-01
-  formatted_date =
-      CJS_PublicMethods::MakeFormatDate(1107216000000.0, L"ddmmyy");
-  EXPECT_STREQ(L"010205", formatted_date.c_str());
-  formatted_date =
-      CJS_PublicMethods::MakeFormatDate(1107216000000.0, L"yyyyddmm");
-  EXPECT_STREQ(L"20050102", formatted_date.c_str());
-
-  // 2085-12-31
-  formatted_date =
-      CJS_PublicMethods::MakeFormatDate(3660595200000.0, L"ddmmyy");
-  EXPECT_STREQ(L"311285", formatted_date.c_str());
-  formatted_date =
-      CJS_PublicMethods::MakeFormatDate(3660595200000.0, L"yyyydd");
-  EXPECT_STREQ(L"208531", formatted_date.c_str());
-
-  // 2095-02-01
-  formatted_date =
-      CJS_PublicMethods::MakeFormatDate(3947356800000.0, L"ddmmyy");
-  EXPECT_STREQ(L"010295", formatted_date.c_str());
-  formatted_date =
-      CJS_PublicMethods::MakeFormatDate(3947356800000.0, L"mmddyyyy");
-  EXPECT_STREQ(L"02012095", formatted_date.c_str());
-}
diff --git a/fpdfsdk/javascript/public_methods_unittest.cpp b/fpdfsdk/javascript/public_methods_unittest.cpp
deleted file mode 100644
index ace0920..0000000
--- a/fpdfsdk/javascript/public_methods_unittest.cpp
+++ /dev/null
@@ -1,51 +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.
-
-#include "fpdfsdk/javascript/PublicMethods.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/test_support.h"
-
-TEST(CJS_PublicMethods, IsNumber) {
-  // TODO(weili): Check whether results from case 0, 1, 10, 15 are intended.
-  struct {
-    const wchar_t* input;
-    bool expected;
-  } test_data[] = {
-      // Empty string.
-      {L"", true},
-      // Only whitespaces.
-      {L"  ", true},
-      // Content with invalid characters.
-      {L"xyz00", false},
-      {L"1%", false},
-      // Hex string.
-      {L"0x234", false},
-      // Signed numbers.
-      {L"+123", true},
-      {L"-98765", true},
-      // Numbers with whitespaces.
-      {L"  345 ", true},
-      // Float numbers.
-      {L"-1e5", false},
-      {L"-2e", false},
-      {L"e-5", true},
-      {L"0.023", true},
-      {L".356089", true},
-      {L"1e-9", true},
-      {L"-1.23e+23", true},
-      // Numbers with commas.
-      {L"1,000,000", false},
-      {L"560,024", true},
-      // Regular numbers.
-      {L"0", true},
-      {L"0123", true},
-      {L"9876123", true},
-  };
-  for (size_t i = 0; i < FX_ArraySize(test_data); ++i) {
-    EXPECT_EQ(test_data[i].expected,
-              CJS_PublicMethods::IsNumber(test_data[i].input))
-        << "for case " << i;
-  }
-}
diff --git a/fpdfsdk/javascript/report.cpp b/fpdfsdk/javascript/report.cpp
deleted file mode 100644
index c9c986d..0000000
--- a/fpdfsdk/javascript/report.cpp
+++ /dev/null
@@ -1,43 +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/report.h"
-
-#include <vector>
-
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_Object.h"
-#include "fpdfsdk/javascript/JS_Value.h"
-
-JSConstSpec CJS_Report::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
-
-JSPropertySpec CJS_Report::PropertySpecs[] = {{0, 0, 0}};
-
-JSMethodSpec CJS_Report::MethodSpecs[] = {{"save", save_static},
-                                          {"writeText", writeText_static},
-                                          {0, 0}};
-
-IMPLEMENT_JS_CLASS(CJS_Report, Report)
-
-Report::Report(CJS_Object* pJSObject) : CJS_EmbedObj(pJSObject) {}
-
-Report::~Report() {}
-
-bool Report::writeText(CJS_Runtime* pRuntime,
-                       const std::vector<CJS_Value>& params,
-                       CJS_Value& vRet,
-                       CFX_WideString& sError) {
-  // Unsafe, not supported.
-  return true;
-}
-
-bool Report::save(CJS_Runtime* pRuntime,
-                  const std::vector<CJS_Value>& params,
-                  CJS_Value& vRet,
-                  CFX_WideString& sError) {
-  // Unsafe, not supported.
-  return true;
-}
diff --git a/fpdfsdk/javascript/report.h b/fpdfsdk/javascript/report.h
deleted file mode 100644
index c66db80..0000000
--- a/fpdfsdk/javascript/report.h
+++ /dev/null
@@ -1,41 +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 FPDFSDK_JAVASCRIPT_REPORT_H_
-#define FPDFSDK_JAVASCRIPT_REPORT_H_
-
-#include <vector>
-
-#include "fpdfsdk/javascript/JS_Define.h"
-
-class Report : public CJS_EmbedObj {
- public:
-  explicit Report(CJS_Object* pJSObject);
-  ~Report() override;
-
- public:
-  bool save(CJS_Runtime* pRuntime,
-            const std::vector<CJS_Value>& params,
-            CJS_Value& vRet,
-            CFX_WideString& sError);
-  bool writeText(CJS_Runtime* pRuntime,
-                 const std::vector<CJS_Value>& params,
-                 CJS_Value& vRet,
-                 CFX_WideString& sError);
-};
-
-class CJS_Report : public CJS_Object {
- public:
-  explicit CJS_Report(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Report() override {}
-
-  DECLARE_JS_CLASS();
-
-  JS_STATIC_METHOD(save, Report)
-  JS_STATIC_METHOD(writeText, Report);
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_REPORT_H_
diff --git a/fpdfsdk/javascript/resource.cpp b/fpdfsdk/javascript/resource.cpp
deleted file mode 100644
index 6113c54..0000000
--- a/fpdfsdk/javascript/resource.cpp
+++ /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
-
-#include "fpdfsdk/javascript/resource.h"
-
-CFX_WideString JSGetStringFromID(uint32_t id) {
-  switch (id) {
-    case IDS_STRING_JSALERT:
-      return L"Alert";
-    case IDS_STRING_JSPARAMERROR:
-      return L"Incorrect number of parameters passed to function.";
-    case IDS_STRING_JSAFNUMBER_KEYSTROKE:
-      return L"The input value is invalid.";
-    case IDS_STRING_JSPARAM_TOOLONG:
-      return L"The input value is too long.";
-    case IDS_STRING_JSPARSEDATE:
-      return L"The input value can't be parsed as a valid date/time (%s).";
-    case IDS_STRING_JSRANGE1:
-      return L"The input value must be greater than or equal to %s"
-             L" and less than or equal to %s.";
-    case IDS_STRING_JSRANGE2:
-      return L"The input value must be greater than or equal to %s.";
-    case IDS_STRING_JSRANGE3:
-      return L"The input value must be less than or equal to %s.";
-    case IDS_STRING_JSNOTSUPPORT:
-      return L"Operation not supported.";
-    case IDS_STRING_JSBUSY:
-      return L"System is busy.";
-    case IDS_STRING_JSEVENT:
-      return L"Duplicate formfield event found.";
-    case IDS_STRING_RUN:
-      return L"Script ran successfully.";
-    case IDS_STRING_JSPRINT1:
-      return L"The second parameter can't be converted to a Date.";
-    case IDS_STRING_JSPRINT2:
-      return L"The second parameter is an invalid Date!";
-    case IDS_STRING_JSNOGLOBAL:
-      return L"Global value not found.";
-    case IDS_STRING_JSREADONLY:
-      return L"Cannot assign to readonly property.";
-    case IDS_STRING_JSTYPEERROR:
-      return L"Incorrect parameter type.";
-    case IDS_STRING_JSVALUEERROR:
-      return L"Incorrect parameter value.";
-    case IDS_STRING_JSNOPERMISSION:
-      return L"Permission denied.";
-    case IDS_STRING_JSBADOBJECT:
-      return L"Object no longer exists.";
-    default:
-      return L"";
-  }
-}
-
-CFX_WideString JSFormatErrorString(const char* class_name,
-                                   const char* property_name,
-                                   const CFX_WideString& details) {
-  CFX_WideString result = CFX_WideString::FromLocal(class_name);
-  if (property_name) {
-    result += L".";
-    result += CFX_WideString::FromLocal(property_name);
-  }
-  result += L": ";
-  result += details;
-  return result;
-}
diff --git a/fpdfsdk/javascript/resource.h b/fpdfsdk/javascript/resource.h
deleted file mode 100644
index af7788f..0000000
--- a/fpdfsdk/javascript/resource.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014 PDFium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
-
-#ifndef FPDFSDK_JAVASCRIPT_RESOURCE_H_
-#define FPDFSDK_JAVASCRIPT_RESOURCE_H_
-
-#include "core/fxcrt/fx_string.h"
-
-class CJS_EventContext;
-
-#define IDS_STRING_JSALERT 25613
-#define IDS_STRING_JSPARAMERROR 25614
-#define IDS_STRING_JSAFNUMBER_KEYSTROKE 25615
-#define IDS_STRING_JSPARAM_TOOLONG 25617
-#define IDS_STRING_JSPARSEDATE 25618
-#define IDS_STRING_JSRANGE1 25619
-#define IDS_STRING_JSRANGE2 25620
-#define IDS_STRING_JSRANGE3 25621
-#define IDS_STRING_JSNOTSUPPORT 25627
-#define IDS_STRING_JSBUSY 25628
-#define IDS_STRING_JSEVENT 25629
-#define IDS_STRING_RUN 25630
-#define IDS_STRING_JSPRINT1 25632
-#define IDS_STRING_JSPRINT2 25633
-#define IDS_STRING_JSNOGLOBAL 25635
-#define IDS_STRING_JSREADONLY 25636
-#define IDS_STRING_JSTYPEERROR 25637
-#define IDS_STRING_JSVALUEERROR 25638
-#define IDS_STRING_JSNOPERMISSION 25639
-#define IDS_STRING_JSBADOBJECT 25640
-
-CFX_WideString JSGetStringFromID(uint32_t id);
-CFX_WideString JSFormatErrorString(const char* class_name,
-                                   const char* property_name,
-                                   const CFX_WideString& details);
-
-#endif  // FPDFSDK_JAVASCRIPT_RESOURCE_H_
diff --git a/fpdfsdk/javascript/util.cpp b/fpdfsdk/javascript/util.cpp
deleted file mode 100644
index 3221cfb..0000000
--- a/fpdfsdk/javascript/util.cpp
+++ /dev/null
@@ -1,462 +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/util.h"
-
-#include <time.h>
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-#include "core/fxcrt/fx_ext.h"
-#include "fpdfsdk/javascript/JS_Define.h"
-#include "fpdfsdk/javascript/JS_EventHandler.h"
-#include "fpdfsdk/javascript/JS_Object.h"
-#include "fpdfsdk/javascript/JS_Value.h"
-#include "fpdfsdk/javascript/PublicMethods.h"
-#include "fpdfsdk/javascript/cjs_event_context.h"
-#include "fpdfsdk/javascript/cjs_runtime.h"
-#include "fpdfsdk/javascript/resource.h"
-
-#if _FX_OS_ == _FX_ANDROID_
-#include <ctype.h>
-#endif
-
-JSConstSpec CJS_Util::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
-
-JSPropertySpec CJS_Util::PropertySpecs[] = {{0, 0, 0}};
-
-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)
-
-#define UTIL_INT 0
-#define UTIL_DOUBLE 1
-#define UTIL_STRING 2
-
-namespace {
-
-// Map PDF-style directives to equivalent wcsftime directives. Not
-// all have direct equivalents, though.
-struct TbConvert {
-  const FX_WCHAR* lpszJSMark;
-  const FX_WCHAR* lpszCppMark;
-};
-
-// Map PDF-style directives lacking direct wcsftime directives to
-// the value with which they will be replaced.
-struct TbConvertAdditional {
-  const FX_WCHAR* lpszJSMark;
-  int iValue;
-};
-
-const TbConvert TbConvertTable[] = {
-    {L"mmmm", L"%B"}, {L"mmm", L"%b"}, {L"mm", L"%m"},   {L"dddd", L"%A"},
-    {L"ddd", L"%a"},  {L"dd", L"%d"},  {L"yyyy", L"%Y"}, {L"yy", L"%y"},
-    {L"HH", L"%H"},   {L"hh", L"%I"},  {L"MM", L"%M"},   {L"ss", L"%S"},
-    {L"TT", L"%p"},
-#if defined(_WIN32)
-    {L"tt", L"%p"},   {L"h", L"%#I"},
-#else
-    {L"tt", L"%P"},   {L"h", L"%l"},
-#endif
-};
-
-int ParseDataType(std::wstring* sFormat) {
-  bool bPercent = false;
-  for (size_t i = 0; i < sFormat->length(); ++i) {
-    wchar_t c = (*sFormat)[i];
-    if (c == L'%') {
-      bPercent = true;
-      continue;
-    }
-
-    if (bPercent) {
-      if (c == L'c' || c == L'C' || c == L'd' || c == L'i' || c == L'o' ||
-          c == L'u' || c == L'x' || c == L'X') {
-        return UTIL_INT;
-      }
-      if (c == L'e' || c == L'E' || c == L'f' || c == L'g' || c == L'G') {
-        return UTIL_DOUBLE;
-      }
-      if (c == L's' || c == L'S') {
-        // Map s to S since we always deal internally
-        // with wchar_t strings.
-        (*sFormat)[i] = L'S';
-        return UTIL_STRING;
-      }
-      if (c == L'.' || c == L'+' || c == L'-' || c == L'#' || c == L' ' ||
-          FXSYS_iswdigit(c)) {
-        continue;
-      }
-      break;
-    }
-  }
-
-  return -1;
-}
-
-}  // namespace
-
-util::util(CJS_Object* pJSObject) : CJS_EmbedObj(pJSObject) {}
-
-util::~util() {}
-
-bool util::printf(CJS_Runtime* pRuntime,
-                  const std::vector<CJS_Value>& params,
-                  CJS_Value& vRet,
-                  CFX_WideString& sError) {
-  int iSize = params.size();
-  if (iSize < 1)
-    return false;
-  std::wstring c_ConvChar(params[0].ToCFXWideString(pRuntime).c_str());
-  std::vector<std::wstring> c_strConvers;
-  int iOffset = 0;
-  int iOffend = 0;
-  c_ConvChar.insert(c_ConvChar.begin(), L'S');
-  while (iOffset != -1) {
-    iOffend = c_ConvChar.find(L"%", iOffset + 1);
-    std::wstring strSub;
-    if (iOffend == -1)
-      strSub = c_ConvChar.substr(iOffset);
-    else
-      strSub = c_ConvChar.substr(iOffset, iOffend - iOffset);
-    c_strConvers.push_back(strSub);
-    iOffset = iOffend;
-  }
-
-  std::wstring c_strResult;
-  std::wstring c_strFormat;
-  for (int iIndex = 0; iIndex < (int)c_strConvers.size(); iIndex++) {
-    c_strFormat = c_strConvers[iIndex];
-    if (iIndex == 0) {
-      c_strResult = c_strFormat;
-      continue;
-    }
-
-    CFX_WideString strSegment;
-    if (iIndex >= iSize) {
-      c_strResult += c_strFormat;
-      continue;
-    }
-
-    switch (ParseDataType(&c_strFormat)) {
-      case UTIL_INT:
-        strSegment.Format(c_strFormat.c_str(), params[iIndex].ToInt(pRuntime));
-        break;
-      case UTIL_DOUBLE:
-        strSegment.Format(c_strFormat.c_str(),
-                          params[iIndex].ToDouble(pRuntime));
-        break;
-      case UTIL_STRING:
-        strSegment.Format(c_strFormat.c_str(),
-                          params[iIndex].ToCFXWideString(pRuntime).c_str());
-        break;
-      default:
-        strSegment.Format(L"%S", c_strFormat.c_str());
-        break;
-    }
-    c_strResult += strSegment.GetBuffer(strSegment.GetLength() + 1);
-  }
-
-  c_strResult.erase(c_strResult.begin());
-  vRet = CJS_Value(pRuntime, c_strResult.c_str());
-  return true;
-}
-
-bool util::printd(CJS_Runtime* pRuntime,
-                  const std::vector<CJS_Value>& params,
-                  CJS_Value& vRet,
-                  CFX_WideString& sError) {
-  int iSize = params.size();
-  if (iSize < 2)
-    return false;
-
-  CJS_Value p1 = params[0];
-  CJS_Value p2 = params[1];
-  CJS_Date jsDate;
-  if (!p2.ConvertToDate(pRuntime, jsDate)) {
-    sError = JSGetStringFromID(IDS_STRING_JSPRINT1);
-    return false;
-  }
-
-  if (!jsDate.IsValidDate(pRuntime)) {
-    sError = JSGetStringFromID(IDS_STRING_JSPRINT2);
-    return false;
-  }
-
-  if (p1.GetType() == CJS_Value::VT_number) {
-    CFX_WideString swResult;
-    switch (p1.ToInt(pRuntime)) {
-      case 0:
-        swResult.Format(L"D:%04d%02d%02d%02d%02d%02d", jsDate.GetYear(pRuntime),
-                        jsDate.GetMonth(pRuntime) + 1, jsDate.GetDay(pRuntime),
-                        jsDate.GetHours(pRuntime), jsDate.GetMinutes(pRuntime),
-                        jsDate.GetSeconds(pRuntime));
-        break;
-      case 1:
-        swResult.Format(L"%04d.%02d.%02d %02d:%02d:%02d",
-                        jsDate.GetYear(pRuntime), jsDate.GetMonth(pRuntime) + 1,
-                        jsDate.GetDay(pRuntime), jsDate.GetHours(pRuntime),
-                        jsDate.GetMinutes(pRuntime),
-                        jsDate.GetSeconds(pRuntime));
-        break;
-      case 2:
-        swResult.Format(L"%04d/%02d/%02d %02d:%02d:%02d",
-                        jsDate.GetYear(pRuntime), jsDate.GetMonth(pRuntime) + 1,
-                        jsDate.GetDay(pRuntime), jsDate.GetHours(pRuntime),
-                        jsDate.GetMinutes(pRuntime),
-                        jsDate.GetSeconds(pRuntime));
-        break;
-      default:
-        sError = JSGetStringFromID(IDS_STRING_JSVALUEERROR);
-        return false;
-    }
-
-    vRet = CJS_Value(pRuntime, swResult.c_str());
-    return true;
-  }
-
-  if (p1.GetType() == CJS_Value::VT_string) {
-    if (iSize > 2 && params[2].ToBool(pRuntime)) {
-      sError = JSGetStringFromID(IDS_STRING_JSNOTSUPPORT);
-      return false;  // currently, it doesn't support XFAPicture.
-    }
-
-    // Convert PDF-style format specifiers to wcsftime specifiers. Remove any
-    // pre-existing %-directives before inserting our own.
-    std::basic_string<wchar_t> cFormat = p1.ToCFXWideString(pRuntime).c_str();
-    cFormat.erase(std::remove(cFormat.begin(), cFormat.end(), '%'),
-                  cFormat.end());
-
-    for (size_t i = 0; i < FX_ArraySize(TbConvertTable); ++i) {
-      int iStart = 0;
-      int iEnd;
-      while ((iEnd = cFormat.find(TbConvertTable[i].lpszJSMark, iStart)) !=
-             -1) {
-        cFormat.replace(iEnd, FXSYS_wcslen(TbConvertTable[i].lpszJSMark),
-                        TbConvertTable[i].lpszCppMark);
-        iStart = iEnd;
-      }
-    }
-
-    int iYear = jsDate.GetYear(pRuntime);
-    int iMonth = jsDate.GetMonth(pRuntime);
-    int iDay = jsDate.GetDay(pRuntime);
-    int iHour = jsDate.GetHours(pRuntime);
-    int iMin = jsDate.GetMinutes(pRuntime);
-    int iSec = jsDate.GetSeconds(pRuntime);
-
-    TbConvertAdditional cTableAd[] = {
-        {L"m", iMonth + 1}, {L"d", iDay},
-        {L"H", iHour},      {L"h", iHour > 12 ? iHour - 12 : iHour},
-        {L"M", iMin},       {L"s", iSec},
-    };
-
-    for (size_t i = 0; i < FX_ArraySize(cTableAd); ++i) {
-      wchar_t tszValue[16];
-      CFX_WideString sValue;
-      sValue.Format(L"%d", cTableAd[i].iValue);
-      memcpy(tszValue, (wchar_t*)sValue.GetBuffer(sValue.GetLength() + 1),
-             (sValue.GetLength() + 1) * sizeof(wchar_t));
-
-      int iStart = 0;
-      int iEnd;
-      while ((iEnd = cFormat.find(cTableAd[i].lpszJSMark, iStart)) != -1) {
-        if (iEnd > 0) {
-          if (cFormat[iEnd - 1] == L'%') {
-            iStart = iEnd + 1;
-            continue;
-          }
-        }
-        cFormat.replace(iEnd, FXSYS_wcslen(cTableAd[i].lpszJSMark), tszValue);
-        iStart = iEnd;
-      }
-    }
-
-    struct tm time = {};
-    time.tm_year = iYear - 1900;
-    time.tm_mon = iMonth;
-    time.tm_mday = iDay;
-    time.tm_hour = iHour;
-    time.tm_min = iMin;
-    time.tm_sec = iSec;
-
-    wchar_t buf[64] = {};
-    wcsftime(buf, 64, cFormat.c_str(), &time);
-    cFormat = buf;
-    vRet = CJS_Value(pRuntime, cFormat.c_str());
-    return true;
-  }
-
-  sError = JSGetStringFromID(IDS_STRING_JSTYPEERROR);
-  return false;
-}
-
-bool util::printx(CJS_Runtime* pRuntime,
-                  const std::vector<CJS_Value>& params,
-                  CJS_Value& vRet,
-                  CFX_WideString& sError) {
-  if (params.size() < 2) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  vRet = CJS_Value(pRuntime, printx(params[0].ToCFXWideString(pRuntime),
-                                    params[1].ToCFXWideString(pRuntime))
-                                 .c_str());
-
-  return true;
-}
-
-enum CaseMode { kPreserveCase, kUpperCase, kLowerCase };
-
-static FX_WCHAR TranslateCase(FX_WCHAR input, CaseMode eMode) {
-  if (eMode == kLowerCase && input >= 'A' && input <= 'Z')
-    return input | 0x20;
-  if (eMode == kUpperCase && input >= 'a' && input <= 'z')
-    return input & ~0x20;
-  return input;
-}
-
-CFX_WideString util::printx(const CFX_WideString& wsFormat,
-                            const CFX_WideString& wsSource) {
-  CFX_WideString wsResult;
-  FX_STRSIZE iSourceIdx = 0;
-  FX_STRSIZE iFormatIdx = 0;
-  CaseMode eCaseMode = kPreserveCase;
-  bool bEscaped = false;
-  while (iFormatIdx < wsFormat.GetLength()) {
-    if (bEscaped) {
-      bEscaped = false;
-      wsResult += wsFormat[iFormatIdx];
-      ++iFormatIdx;
-      continue;
-    }
-    switch (wsFormat[iFormatIdx]) {
-      case '\\': {
-        bEscaped = true;
-        ++iFormatIdx;
-      } break;
-      case '<': {
-        eCaseMode = kLowerCase;
-        ++iFormatIdx;
-      } break;
-      case '>': {
-        eCaseMode = kUpperCase;
-        ++iFormatIdx;
-      } break;
-      case '=': {
-        eCaseMode = kPreserveCase;
-        ++iFormatIdx;
-      } break;
-      case '?': {
-        if (iSourceIdx < wsSource.GetLength()) {
-          wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode);
-          ++iSourceIdx;
-        }
-        ++iFormatIdx;
-      } break;
-      case 'X': {
-        if (iSourceIdx < wsSource.GetLength()) {
-          if ((wsSource[iSourceIdx] >= '0' && wsSource[iSourceIdx] <= '9') ||
-              (wsSource[iSourceIdx] >= 'a' && wsSource[iSourceIdx] <= 'z') ||
-              (wsSource[iSourceIdx] >= 'A' && wsSource[iSourceIdx] <= 'Z')) {
-            wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode);
-            ++iFormatIdx;
-          }
-          ++iSourceIdx;
-        } else {
-          ++iFormatIdx;
-        }
-      } break;
-      case 'A': {
-        if (iSourceIdx < wsSource.GetLength()) {
-          if ((wsSource[iSourceIdx] >= 'a' && wsSource[iSourceIdx] <= 'z') ||
-              (wsSource[iSourceIdx] >= 'A' && wsSource[iSourceIdx] <= 'Z')) {
-            wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode);
-            ++iFormatIdx;
-          }
-          ++iSourceIdx;
-        } else {
-          ++iFormatIdx;
-        }
-      } break;
-      case '9': {
-        if (iSourceIdx < wsSource.GetLength()) {
-          if (wsSource[iSourceIdx] >= '0' && wsSource[iSourceIdx] <= '9') {
-            wsResult += wsSource[iSourceIdx];
-            ++iFormatIdx;
-          }
-          ++iSourceIdx;
-        } else {
-          ++iFormatIdx;
-        }
-      } break;
-      case '*': {
-        if (iSourceIdx < wsSource.GetLength()) {
-          wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode);
-          ++iSourceIdx;
-        } else {
-          ++iFormatIdx;
-        }
-      } break;
-      default: {
-        wsResult += wsFormat[iFormatIdx];
-        ++iFormatIdx;
-      } break;
-    }
-  }
-  return wsResult;
-}
-
-bool util::scand(CJS_Runtime* pRuntime,
-                 const std::vector<CJS_Value>& params,
-                 CJS_Value& vRet,
-                 CFX_WideString& sError) {
-  int iSize = params.size();
-  if (iSize < 2)
-    return false;
-
-  CFX_WideString sFormat = params[0].ToCFXWideString(pRuntime);
-  CFX_WideString sDate = params[1].ToCFXWideString(pRuntime);
-  double dDate = JS_GetDateTime();
-  if (sDate.GetLength() > 0) {
-    dDate = CJS_PublicMethods::MakeRegularDate(sDate, sFormat, nullptr);
-  }
-
-  if (!JS_PortIsNan(dDate)) {
-    vRet = CJS_Value(pRuntime, CJS_Date(pRuntime, dDate));
-  } else {
-    vRet.SetNull(pRuntime);
-  }
-
-  return true;
-}
-
-bool util::byteToChar(CJS_Runtime* pRuntime,
-                      const std::vector<CJS_Value>& params,
-                      CJS_Value& vRet,
-                      CFX_WideString& sError) {
-  if (params.size() < 1) {
-    sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
-    return false;
-  }
-
-  int arg = params[0].ToInt(pRuntime);
-  if (arg < 0 || arg > 255) {
-    sError = JSGetStringFromID(IDS_STRING_JSVALUEERROR);
-    return false;
-  }
-
-  CFX_WideString wStr(static_cast<FX_WCHAR>(arg));
-  vRet = CJS_Value(pRuntime, wStr.c_str());
-  return true;
-}
diff --git a/fpdfsdk/javascript/util.h b/fpdfsdk/javascript/util.h
deleted file mode 100644
index 98761b6..0000000
--- a/fpdfsdk/javascript/util.h
+++ /dev/null
@@ -1,59 +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 FPDFSDK_JAVASCRIPT_UTIL_H_
-#define FPDFSDK_JAVASCRIPT_UTIL_H_
-
-#include <string>
-#include <vector>
-
-#include "fpdfsdk/javascript/JS_Define.h"
-
-class util : public CJS_EmbedObj {
- public:
-  explicit util(CJS_Object* pJSObject);
-  ~util() override;
-
-  bool printd(CJS_Runtime* pRuntime,
-              const std::vector<CJS_Value>& params,
-              CJS_Value& vRet,
-              CFX_WideString& sError);
-  bool printf(CJS_Runtime* pRuntime,
-              const std::vector<CJS_Value>& params,
-              CJS_Value& vRet,
-              CFX_WideString& sError);
-  bool printx(CJS_Runtime* pRuntime,
-              const std::vector<CJS_Value>& params,
-              CJS_Value& vRet,
-              CFX_WideString& sError);
-  bool scand(CJS_Runtime* pRuntime,
-             const std::vector<CJS_Value>& params,
-             CJS_Value& vRet,
-             CFX_WideString& sError);
-  bool byteToChar(CJS_Runtime* pRuntime,
-                  const std::vector<CJS_Value>& params,
-                  CJS_Value& vRet,
-                  CFX_WideString& sError);
-
-  static CFX_WideString printx(const CFX_WideString& cFormat,
-                               const CFX_WideString& cSource);
-};
-
-class CJS_Util : public CJS_Object {
- public:
-  explicit CJS_Util(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Util() override {}
-
-  DECLARE_JS_CLASS();
-
-  JS_STATIC_METHOD(printd, util);
-  JS_STATIC_METHOD(printf, util);
-  JS_STATIC_METHOD(printx, util);
-  JS_STATIC_METHOD(scand, util);
-  JS_STATIC_METHOD(byteToChar, util);
-};
-
-#endif  // FPDFSDK_JAVASCRIPT_UTIL_H_
diff --git a/fpdfsdk/pdfsdk_fieldaction.h b/fpdfsdk/pdfsdk_fieldaction.h
index 4ee56ac..aec5dca 100644
--- a/fpdfsdk/pdfsdk_fieldaction.h
+++ b/fpdfsdk/pdfsdk_fieldaction.h
@@ -25,12 +25,12 @@
   bool bModifier;
   bool bShift;
   int nCommitKey;
-  CFX_WideString sChange;
-  CFX_WideString sChangeEx;
+  WideString sChange;
+  WideString sChangeEx;
   bool bKeyDown;
   int nSelEnd;
   int nSelStart;
-  CFX_WideString sValue;
+  WideString sValue;
   bool bWillCommit;
   bool bFieldFull;
   bool bRC;
diff --git a/fpdfsdk/pdfwindow/PWL_Caret.cpp b/fpdfsdk/pdfwindow/PWL_Caret.cpp
deleted file mode 100644
index 3360bbf..0000000
--- a/fpdfsdk/pdfwindow/PWL_Caret.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2014 PDFium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
-
-#include "fpdfsdk/pdfwindow/PWL_Caret.h"
-
-#include "core/fxge/cfx_graphstatedata.h"
-#include "core/fxge/cfx_pathdata.h"
-#include "core/fxge/cfx_renderdevice.h"
-#include "fpdfsdk/pdfwindow/PWL_Utils.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-
-#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() {}
-
-CFX_ByteString CPWL_Caret::GetClassName() const {
-  return "CPWL_Caret";
-}
-
-void CPWL_Caret::GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) {
-  GetCaretApp(sAppStream, CFX_PointF());
-}
-
-void CPWL_Caret::DrawThisAppearance(CFX_RenderDevice* pDevice,
-                                    CFX_Matrix* pUser2Device) {
-  if (IsVisible() && m_bFlash) {
-    CFX_FloatRect rcRect = GetCaretRect();
-    CFX_FloatRect rcClip = GetClipRect();
-    CFX_PathData path;
-
-    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())
-        return;
-
-      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),
-                      FXFILL_ALTERNATE);
-  }
-}
-
-void CPWL_Caret::GetCaretApp(CFX_ByteTextBuf& sAppStream,
-                             const CFX_PointF& ptOffset) {
-  if (IsVisible() && m_bFlash) {
-    CFX_ByteTextBuf sCaret;
-
-    CFX_FloatRect rcRect = GetCaretRect();
-    CFX_FloatRect rcClip = GetClipRect();
-
-    rcRect = CPWL_Utils::OffsetRect(rcRect, ptOffset.x, ptOffset.y);
-    rcClip = CPWL_Utils::OffsetRect(rcClip, ptOffset.x, ptOffset.y);
-
-    sCaret << "q\n";
-    if (!rcClip.IsEmpty()) {
-      sCaret << rcClip.left << " " << rcClip.bottom + 2.5f << " "
-             << rcClip.right - rcClip.left << " "
-             << rcClip.top - rcClip.bottom - 4.5f << " re W n\n";
-    }
-    sCaret << m_fWidth << " w\n0 G\n";
-    sCaret << rcRect.left + m_fWidth / 2 << " " << rcRect.bottom << " m\n";
-    sCaret << rcRect.left + m_fWidth / 2 << " " << rcRect.top << " l S\nQ\n";
-
-    sAppStream << sCaret;
-  }
-}
-
-CFX_ByteString CPWL_Caret::GetCaretAppearanceStream(
-    const CFX_PointF& ptOffset) {
-  CFX_ByteTextBuf sCaret;
-  GetCaretApp(sCaret, ptOffset);
-  return sCaret.MakeString();
-}
-
-void CPWL_Caret::TimerProc() {
-  if (m_nDelay > 0) {
-    m_nDelay--;
-  } else {
-    m_bFlash = !m_bFlash;
-    InvalidateRect();
-  }
-}
-
-CFX_FloatRect CPWL_Caret::GetCaretRect() const {
-  return CFX_FloatRect(m_ptFoot.x, m_ptFoot.y, m_ptHead.x + m_fWidth,
-                       m_ptHead.y);
-}
-
-void CPWL_Caret::SetCaret(bool bVisible,
-                          const CFX_PointF& ptHead,
-                          const CFX_PointF& ptFoot) {
-  if (bVisible) {
-    if (IsVisible()) {
-      if (m_ptHead != ptHead || m_ptFoot != ptFoot) {
-        m_ptHead = ptHead;
-        m_ptFoot = ptFoot;
-        m_bFlash = true;
-        Move(m_rcInvalid, false, true);
-      }
-    } else {
-      m_ptHead = ptHead;
-      m_ptFoot = ptFoot;
-      EndTimer();
-      BeginTimer(PWL_CARET_FLASHINTERVAL);
-      CPWL_Wnd::SetVisible(true);
-      m_bFlash = true;
-      Move(m_rcInvalid, false, true);
-    }
-  } else {
-    m_ptHead = CFX_PointF();
-    m_ptFoot = CFX_PointF();
-    m_bFlash = false;
-    if (IsVisible()) {
-      EndTimer();
-      CPWL_Wnd::SetVisible(false);
-    }
-  }
-}
-
-void CPWL_Caret::InvalidateRect(CFX_FloatRect* pRect) {
-  if (pRect) {
-    CFX_FloatRect rcRefresh = CPWL_Utils::InflateRect(*pRect, 0.5f);
-    rcRefresh.top += 1;
-    rcRefresh.bottom -= 1;
-    CPWL_Wnd::InvalidateRect(&rcRefresh);
-  } else {
-    CPWL_Wnd::InvalidateRect(pRect);
-  }
-}
diff --git a/fpdfsdk/pdfwindow/PWL_Caret.h b/fpdfsdk/pdfwindow/PWL_Caret.h
deleted file mode 100644
index 60ebbdc..0000000
--- a/fpdfsdk/pdfwindow/PWL_Caret.h
+++ /dev/null
@@ -1,53 +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 FPDFSDK_PDFWINDOW_PWL_CARET_H_
-#define FPDFSDK_PDFWINDOW_PWL_CARET_H_
-
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-
-struct PWL_CARET_INFO {
- public:
-  PWL_CARET_INFO();
-
-  bool bVisible;
-  CFX_PointF ptHead;
-  CFX_PointF ptFoot;
-};
-
-class CPWL_Caret : public CPWL_Wnd {
- public:
-  CPWL_Caret();
-  ~CPWL_Caret() override;
-
-  // CPWL_Wnd
-  CFX_ByteString GetClassName() const override;
-  void GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) override;
-  void DrawThisAppearance(CFX_RenderDevice* pDevice,
-                          CFX_Matrix* pUser2Device) override;
-  void InvalidateRect(CFX_FloatRect* pRect = nullptr) override;
-  void SetVisible(bool bVisible) override {}
-  void TimerProc() override;
-
-  void SetCaret(bool bVisible,
-                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_PointF& ptOffset);
-  CFX_FloatRect GetCaretRect() const;
-
-  bool m_bFlash;
-  CFX_PointF m_ptHead;
-  CFX_PointF m_ptFoot;
-  FX_FLOAT m_fWidth;
-  int32_t m_nDelay;
-  CFX_FloatRect m_rcInvalid;
-};
-
-#endif  // FPDFSDK_PDFWINDOW_PWL_CARET_H_
diff --git a/fpdfsdk/pdfwindow/PWL_ComboBox.cpp b/fpdfsdk/pdfwindow/PWL_ComboBox.cpp
deleted file mode 100644
index bc6909a..0000000
--- a/fpdfsdk/pdfwindow/PWL_ComboBox.cpp
+++ /dev/null
@@ -1,626 +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/pdfwindow/PWL_ComboBox.h"
-
-#include "core/fxge/cfx_pathdata.h"
-#include "core/fxge/cfx_renderdevice.h"
-#include "fpdfsdk/fxedit/fxet_list.h"
-#include "fpdfsdk/pdfwindow/PWL_Edit.h"
-#include "fpdfsdk/pdfwindow/PWL_EditCtrl.h"
-#include "fpdfsdk/pdfwindow/PWL_ListBox.h"
-#include "fpdfsdk/pdfwindow/PWL_Utils.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-#include "public/fpdf_fwlevent.h"
-
-#define PWLCB_DEFAULTFONTSIZE 12.0f
-
-bool CPWL_CBListBox::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
-  CPWL_Wnd::OnLButtonUp(point, nFlag);
-
-  if (!m_bMouseDown)
-    return true;
-
-  ReleaseCapture();
-  m_bMouseDown = false;
-
-  if (!ClientHitTest(point))
-    return true;
-  if (CPWL_Wnd* pParent = GetParentWindow())
-    pParent->OnNotify(this, PNM_LBUTTONUP, 0, PWL_MAKEDWORD(point.x, point.y));
-
-  bool bExit = false;
-  OnNotifySelChanged(false, bExit, nFlag);
-
-  return !bExit;
-}
-
-bool CPWL_CBListBox::OnKeyDownWithExit(uint16_t nChar,
-                                       bool& bExit,
-                                       uint32_t nFlag) {
-  switch (nChar) {
-    case FWL_VKEY_Up:
-    case FWL_VKEY_Down:
-    case FWL_VKEY_Home:
-    case FWL_VKEY_Left:
-    case FWL_VKEY_End:
-    case FWL_VKEY_Right:
-      break;
-    default:
-      return false;
-  }
-
-  switch (nChar) {
-    case FWL_VKEY_Up:
-      m_pList->OnVK_UP(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-      break;
-    case FWL_VKEY_Down:
-      m_pList->OnVK_DOWN(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-      break;
-    case FWL_VKEY_Home:
-      m_pList->OnVK_HOME(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-      break;
-    case FWL_VKEY_Left:
-      m_pList->OnVK_LEFT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-      break;
-    case FWL_VKEY_End:
-      m_pList->OnVK_END(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-      break;
-    case FWL_VKEY_Right:
-      m_pList->OnVK_RIGHT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-      break;
-    case FWL_VKEY_Delete:
-      break;
-  }
-
-  OnNotifySelChanged(true, bExit, nFlag);
-
-  return true;
-}
-
-bool CPWL_CBListBox::OnCharWithExit(uint16_t nChar,
-                                    bool& bExit,
-                                    uint32_t nFlag) {
-  if (!m_pList->OnChar(nChar, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)))
-    return false;
-  if (CPWL_ComboBox* pComboBox = (CPWL_ComboBox*)GetParentWindow())
-    pComboBox->SetSelectText();
-
-  OnNotifySelChanged(true, bExit, nFlag);
-
-  return true;
-}
-
-void CPWL_CBButton::GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) {
-  CPWL_Wnd::GetThisAppearanceStream(sAppStream);
-
-  CFX_FloatRect rectWnd = CPWL_Wnd::GetWindowRect();
-
-  if (IsVisible() && !rectWnd.IsEmpty()) {
-    CFX_ByteTextBuf sButton;
-
-    CFX_PointF ptCenter = GetCenterPoint();
-
-    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)) {
-      sButton << "0 g\n";
-      sButton << pt1.x << " " << pt1.y << " m\n";
-      sButton << pt2.x << " " << pt2.y << " l\n";
-      sButton << pt3.x << " " << pt3.y << " l\n";
-      sButton << pt1.x << " " << pt1.y << " l f\n";
-
-      sAppStream << "q\n" << sButton << "Q\n";
-    }
-  }
-}
-
-void CPWL_CBButton::DrawThisAppearance(CFX_RenderDevice* pDevice,
-                                       CFX_Matrix* pUser2Device) {
-  CPWL_Wnd::DrawThisAppearance(pDevice, pUser2Device);
-
-  CFX_FloatRect rectWnd = CPWL_Wnd::GetWindowRect();
-
-  if (IsVisible() && !rectWnd.IsEmpty()) {
-    CFX_PointF ptCenter = GetCenterPoint();
-
-    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.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,
-                        PWL_DEFAULT_BLACKCOLOR.ToFXColor(GetTransparency()), 0,
-                        FXFILL_ALTERNATE);
-    }
-  }
-}
-
-bool CPWL_CBButton::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
-  CPWL_Wnd::OnLButtonDown(point, nFlag);
-
-  SetCapture();
-
-  if (CPWL_Wnd* pParent = GetParentWindow()) {
-    pParent->OnNotify(this, PNM_LBUTTONDOWN, 0,
-                      PWL_MAKEDWORD(point.x, point.y));
-  }
-
-  return true;
-}
-
-bool CPWL_CBButton::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
-  CPWL_Wnd::OnLButtonUp(point, nFlag);
-
-  ReleaseCapture();
-
-  return true;
-}
-
-CPWL_ComboBox::CPWL_ComboBox()
-    : m_pEdit(nullptr),
-      m_pButton(nullptr),
-      m_pList(nullptr),
-      m_bPopup(false),
-      m_nPopupWhere(0),
-      m_nSelectItem(-1),
-      m_pFillerNotify(nullptr) {}
-
-CFX_ByteString CPWL_ComboBox::GetClassName() const {
-  return "CPWL_ComboBox";
-}
-
-void CPWL_ComboBox::OnCreate(PWL_CREATEPARAM& cp) {
-  cp.dwFlags &= ~PWS_HSCROLL;
-  cp.dwFlags &= ~PWS_VSCROLL;
-}
-
-void CPWL_ComboBox::SetFocus() {
-  if (m_pEdit)
-    m_pEdit->SetFocus();
-}
-
-void CPWL_ComboBox::KillFocus() {
-  SetPopup(false);
-  CPWL_Wnd::KillFocus();
-}
-
-CFX_WideString CPWL_ComboBox::GetText() const {
-  if (m_pEdit) {
-    return m_pEdit->GetText();
-  }
-  return CFX_WideString();
-}
-
-void CPWL_ComboBox::SetText(const CFX_WideString& text) {
-  if (m_pEdit)
-    m_pEdit->SetText(text);
-}
-
-void CPWL_ComboBox::AddString(const CFX_WideString& str) {
-  if (m_pList)
-    m_pList->AddString(str);
-}
-
-int32_t CPWL_ComboBox::GetSelect() const {
-  return m_nSelectItem;
-}
-
-void CPWL_ComboBox::SetSelect(int32_t nItemIndex) {
-  if (m_pList)
-    m_pList->Select(nItemIndex);
-
-  m_pEdit->SetText(m_pList->GetText());
-  m_nSelectItem = nItemIndex;
-}
-
-void CPWL_ComboBox::SetEditSel(int32_t nStartChar, int32_t nEndChar) {
-  if (m_pEdit)
-    m_pEdit->SetSel(nStartChar, nEndChar);
-}
-
-void CPWL_ComboBox::GetEditSel(int32_t& nStartChar, int32_t& nEndChar) const {
-  nStartChar = -1;
-  nEndChar = -1;
-
-  if (m_pEdit)
-    m_pEdit->GetSel(nStartChar, nEndChar);
-}
-
-void CPWL_ComboBox::Clear() {
-  if (m_pEdit)
-    m_pEdit->Clear();
-}
-
-void CPWL_ComboBox::CreateChildWnd(const PWL_CREATEPARAM& cp) {
-  CreateEdit(cp);
-  CreateButton(cp);
-  CreateListBox(cp);
-}
-
-void CPWL_ComboBox::CreateEdit(const PWL_CREATEPARAM& cp) {
-  if (!m_pEdit) {
-    m_pEdit = new CPWL_CBEdit;
-    m_pEdit->AttachFFLData(m_pFormFiller);
-
-    PWL_CREATEPARAM ecp = cp;
-    ecp.pParentWnd = this;
-    ecp.dwFlags = PWS_VISIBLE | PWS_CHILD | PWS_BORDER | PES_CENTER |
-                  PES_AUTOSCROLL | PES_UNDO;
-
-    if (HasFlag(PWS_AUTOFONTSIZE))
-      ecp.dwFlags |= PWS_AUTOFONTSIZE;
-
-    if (!HasFlag(PCBS_ALLOWCUSTOMTEXT))
-      ecp.dwFlags |= PWS_READONLY;
-
-    ecp.rcRectWnd = CFX_FloatRect(0, 0, 0, 0);
-    ecp.dwBorderWidth = 0;
-    ecp.nBorderStyle = BorderStyle::SOLID;
-
-    m_pEdit->Create(ecp);
-  }
-}
-
-void CPWL_ComboBox::CreateButton(const PWL_CREATEPARAM& cp) {
-  if (!m_pButton) {
-    m_pButton = new CPWL_CBButton;
-
-    PWL_CREATEPARAM bcp = cp;
-    bcp.pParentWnd = this;
-    bcp.dwFlags = PWS_VISIBLE | PWS_CHILD | PWS_BORDER | PWS_BACKGROUND;
-    bcp.sBackgroundColor = PWL_SCROLLBAR_BKCOLOR;
-    bcp.sBorderColor = PWL_DEFAULT_BLACKCOLOR;
-    bcp.dwBorderWidth = 2;
-    bcp.nBorderStyle = BorderStyle::BEVELED;
-    bcp.eCursorType = FXCT_ARROW;
-
-    m_pButton->Create(bcp);
-  }
-}
-
-void CPWL_ComboBox::CreateListBox(const PWL_CREATEPARAM& cp) {
-  if (!m_pList) {
-    m_pList = new CPWL_CBListBox;
-    m_pList->AttachFFLData(m_pFormFiller);
-    PWL_CREATEPARAM lcp = cp;
-    lcp.pParentWnd = this;
-    lcp.dwFlags =
-        PWS_CHILD | PWS_BORDER | PWS_BACKGROUND | PLBS_HOVERSEL | PWS_VSCROLL;
-    lcp.nBorderStyle = BorderStyle::SOLID;
-    lcp.dwBorderWidth = 1;
-    lcp.eCursorType = FXCT_ARROW;
-    lcp.rcRectWnd = CFX_FloatRect(0, 0, 0, 0);
-
-    if (cp.dwFlags & PWS_AUTOFONTSIZE)
-      lcp.fFontSize = PWLCB_DEFAULTFONTSIZE;
-    else
-      lcp.fFontSize = cp.fFontSize;
-
-    if (cp.sBorderColor.nColorType == COLORTYPE_TRANSPARENT)
-      lcp.sBorderColor = PWL_DEFAULT_BLACKCOLOR;
-
-    if (cp.sBackgroundColor.nColorType == COLORTYPE_TRANSPARENT)
-      lcp.sBackgroundColor = PWL_DEFAULT_WHITECOLOR;
-
-    m_pList->Create(lcp);
-  }
-}
-
-void CPWL_ComboBox::RePosChildWnd() {
-  CFX_FloatRect rcClient = GetClientRect();
-
-  if (m_bPopup) {
-    CFX_FloatRect rclient = GetClientRect();
-    CFX_FloatRect rcButton = rclient;
-    CFX_FloatRect rcEdit = rcClient;
-    CFX_FloatRect rcList = CPWL_Wnd::GetWindowRect();
-
-    FX_FLOAT fOldWindowHeight = m_rcOldWindow.Height();
-    FX_FLOAT fOldClientHeight = fOldWindowHeight - GetBorderWidth() * 2;
-
-    switch (m_nPopupWhere) {
-      case 0:
-        rcButton.left = rcButton.right - PWL_COMBOBOX_BUTTON_WIDTH;
-
-        if (rcButton.left < rclient.left)
-          rcButton.left = rclient.left;
-
-        rcButton.bottom = rcButton.top - fOldClientHeight;
-
-        rcEdit.right = rcButton.left - 1.0f;
-
-        if (rcEdit.left < rclient.left)
-          rcEdit.left = rclient.left;
-
-        if (rcEdit.right < rcEdit.left)
-          rcEdit.right = rcEdit.left;
-
-        rcEdit.bottom = rcEdit.top - fOldClientHeight;
-
-        rcList.top -= fOldWindowHeight;
-
-        break;
-      case 1:
-        rcButton.left = rcButton.right - PWL_COMBOBOX_BUTTON_WIDTH;
-
-        if (rcButton.left < rclient.left)
-          rcButton.left = rclient.left;
-
-        rcButton.top = rcButton.bottom + fOldClientHeight;
-
-        rcEdit.right = rcButton.left - 1.0f;
-
-        if (rcEdit.left < rclient.left)
-          rcEdit.left = rclient.left;
-
-        if (rcEdit.right < rcEdit.left)
-          rcEdit.right = rcEdit.left;
-
-        rcEdit.top = rcEdit.bottom + fOldClientHeight;
-
-        rcList.bottom += fOldWindowHeight;
-
-        break;
-    }
-
-    if (m_pButton)
-      m_pButton->Move(rcButton, true, false);
-
-    if (m_pEdit)
-      m_pEdit->Move(rcEdit, true, false);
-
-    if (m_pList) {
-      m_pList->SetVisible(true);
-      m_pList->Move(rcList, true, false);
-      m_pList->ScrollToListItem(m_nSelectItem);
-    }
-  } else {
-    CFX_FloatRect rcButton = rcClient;
-
-    rcButton.left = rcButton.right - PWL_COMBOBOX_BUTTON_WIDTH;
-
-    if (rcButton.left < rcClient.left)
-      rcButton.left = rcClient.left;
-
-    if (m_pButton)
-      m_pButton->Move(rcButton, true, false);
-
-    CFX_FloatRect rcEdit = rcClient;
-    rcEdit.right = rcButton.left - 1.0f;
-
-    if (rcEdit.left < rcClient.left)
-      rcEdit.left = rcClient.left;
-
-    if (rcEdit.right < rcEdit.left)
-      rcEdit.right = rcEdit.left;
-
-    if (m_pEdit)
-      m_pEdit->Move(rcEdit, true, false);
-
-    if (m_pList)
-      m_pList->SetVisible(false);
-  }
-}
-
-void CPWL_ComboBox::SelectAll() {
-  if (m_pEdit && HasFlag(PCBS_ALLOWCUSTOMTEXT))
-    m_pEdit->SelectAll();
-}
-
-CFX_FloatRect CPWL_ComboBox::GetFocusRect() const {
-  return CFX_FloatRect();
-}
-
-void CPWL_ComboBox::SetPopup(bool bPopup) {
-  if (!m_pList)
-    return;
-  if (bPopup == m_bPopup)
-    return;
-  FX_FLOAT fListHeight = m_pList->GetContentRect().Height();
-  if (!IsFloatBigger(fListHeight, 0.0f))
-    return;
-
-  if (bPopup) {
-    if (m_pFillerNotify) {
-#ifdef PDF_ENABLE_XFA
-      bool bExit = false;
-      m_pFillerNotify->OnPopupPreOpen(GetAttachedData(), bExit, 0);
-      if (bExit)
-        return;
-#endif  // PDF_ENABLE_XFA
-      int32_t nWhere = 0;
-      FX_FLOAT fPopupRet = 0.0f;
-      FX_FLOAT fPopupMin = 0.0f;
-      if (m_pList->GetCount() > 3)
-        fPopupMin =
-            m_pList->GetFirstHeight() * 3 + m_pList->GetBorderWidth() * 2;
-      FX_FLOAT fPopupMax = fListHeight + m_pList->GetBorderWidth() * 2;
-      m_pFillerNotify->QueryWherePopup(GetAttachedData(), fPopupMin, fPopupMax,
-                                       nWhere, fPopupRet);
-
-      if (IsFloatBigger(fPopupRet, 0.0f)) {
-        m_bPopup = bPopup;
-
-        CFX_FloatRect rcWindow = CPWL_Wnd::GetWindowRect();
-        m_rcOldWindow = rcWindow;
-        switch (nWhere) {
-          default:
-          case 0:
-            rcWindow.bottom -= fPopupRet;
-            break;
-          case 1:
-            rcWindow.top += fPopupRet;
-            break;
-        }
-
-        m_nPopupWhere = nWhere;
-        Move(rcWindow, true, true);
-#ifdef PDF_ENABLE_XFA
-        bExit = false;
-        m_pFillerNotify->OnPopupPostOpen(GetAttachedData(), bExit, 0);
-        if (bExit)
-          return;
-#endif  // PDF_ENABLE_XFA
-      }
-    }
-  } else {
-    m_bPopup = bPopup;
-    Move(m_rcOldWindow, true, true);
-  }
-}
-
-bool CPWL_ComboBox::OnKeyDown(uint16_t nChar, uint32_t nFlag) {
-  if (!m_pList)
-    return false;
-  if (!m_pEdit)
-    return false;
-
-  m_nSelectItem = -1;
-
-  switch (nChar) {
-    case FWL_VKEY_Up:
-      if (m_pList->GetCurSel() > 0) {
-        bool bExit = false;
-#ifdef PDF_ENABLE_XFA
-        if (m_pFillerNotify) {
-          m_pFillerNotify->OnPopupPreOpen(GetAttachedData(), bExit, nFlag);
-          if (bExit)
-            return false;
-          bExit = false;
-          m_pFillerNotify->OnPopupPostOpen(GetAttachedData(), bExit, nFlag);
-          if (bExit)
-            return false;
-        }
-#endif  // PDF_ENABLE_XFA
-        if (m_pList->OnKeyDownWithExit(nChar, bExit, nFlag)) {
-          if (bExit)
-            return false;
-          SetSelectText();
-        }
-      }
-      return true;
-    case FWL_VKEY_Down:
-      if (m_pList->GetCurSel() < m_pList->GetCount() - 1) {
-        bool bExit = false;
-#ifdef PDF_ENABLE_XFA
-        if (m_pFillerNotify) {
-          m_pFillerNotify->OnPopupPreOpen(GetAttachedData(), bExit, nFlag);
-          if (bExit)
-            return false;
-          bExit = false;
-          m_pFillerNotify->OnPopupPostOpen(GetAttachedData(), bExit, nFlag);
-          if (bExit)
-            return false;
-        }
-#endif  // PDF_ENABLE_XFA
-        if (m_pList->OnKeyDownWithExit(nChar, bExit, nFlag)) {
-          if (bExit)
-            return false;
-          SetSelectText();
-        }
-      }
-      return true;
-  }
-
-  if (HasFlag(PCBS_ALLOWCUSTOMTEXT))
-    return m_pEdit->OnKeyDown(nChar, nFlag);
-
-  return false;
-}
-
-bool CPWL_ComboBox::OnChar(uint16_t nChar, uint32_t nFlag) {
-  if (!m_pList)
-    return false;
-
-  if (!m_pEdit)
-    return false;
-
-  m_nSelectItem = -1;
-  if (HasFlag(PCBS_ALLOWCUSTOMTEXT))
-    return m_pEdit->OnChar(nChar, nFlag);
-
-  bool bExit = false;
-#ifdef PDF_ENABLE_XFA
-  if (m_pFillerNotify) {
-    m_pFillerNotify->OnPopupPreOpen(GetAttachedData(), bExit, nFlag);
-    if (bExit)
-      return false;
-
-    m_pFillerNotify->OnPopupPostOpen(GetAttachedData(), bExit, nFlag);
-    if (bExit)
-      return false;
-  }
-#endif  // PDF_ENABLE_XFA
-  return m_pList->OnCharWithExit(nChar, bExit, nFlag) ? bExit : false;
-}
-
-void CPWL_ComboBox::OnNotify(CPWL_Wnd* pWnd,
-                             uint32_t msg,
-                             intptr_t wParam,
-                             intptr_t lParam) {
-  switch (msg) {
-    case PNM_LBUTTONDOWN:
-      if (pWnd == m_pButton) {
-        SetPopup(!m_bPopup);
-        return;
-      }
-      break;
-    case PNM_LBUTTONUP:
-      if (m_pEdit && m_pList) {
-        if (pWnd == m_pList) {
-          SetSelectText();
-          SelectAll();
-          m_pEdit->SetFocus();
-          SetPopup(false);
-          return;
-        }
-      }
-  }
-
-  CPWL_Wnd::OnNotify(pWnd, msg, wParam, lParam);
-}
-
-bool CPWL_ComboBox::IsPopup() const {
-  return m_bPopup;
-}
-
-void CPWL_ComboBox::SetSelectText() {
-  m_pEdit->SelectAll();
-  m_pEdit->ReplaceSel(m_pList->GetText());
-  m_pEdit->SelectAll();
-  m_nSelectItem = m_pList->GetCurSel();
-}
-
-void CPWL_ComboBox::SetFillerNotify(IPWL_Filler_Notify* pNotify) {
-  m_pFillerNotify = pNotify;
-
-  if (m_pEdit)
-    m_pEdit->SetFillerNotify(pNotify);
-
-  if (m_pList)
-    m_pList->SetFillerNotify(pNotify);
-}
diff --git a/fpdfsdk/pdfwindow/PWL_ComboBox.h b/fpdfsdk/pdfwindow/PWL_ComboBox.h
deleted file mode 100644
index e1a8df7..0000000
--- a/fpdfsdk/pdfwindow/PWL_ComboBox.h
+++ /dev/null
@@ -1,104 +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 FPDFSDK_PDFWINDOW_PWL_COMBOBOX_H_
-#define FPDFSDK_PDFWINDOW_PWL_COMBOBOX_H_
-
-#include "fpdfsdk/pdfwindow/PWL_Edit.h"
-#include "fpdfsdk/pdfwindow/PWL_ListBox.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-
-class CPWL_CBEdit : public CPWL_Edit {
- public:
-  CPWL_CBEdit() {}
-  ~CPWL_CBEdit() override {}
-};
-
-class CPWL_CBListBox : public CPWL_ListBox {
- public:
-  CPWL_CBListBox() {}
-  ~CPWL_CBListBox() override {}
-
-  // CPWL_ListBox
-  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);
-};
-
-#define PWL_COMBOBOX_BUTTON_WIDTH 13
-
-class CPWL_CBButton : public CPWL_Wnd {
- public:
-  CPWL_CBButton() {}
-  ~CPWL_CBButton() override {}
-
-  // CPWL_Wnd
-  void GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) override;
-  void DrawThisAppearance(CFX_RenderDevice* pDevice,
-                          CFX_Matrix* pUser2Device) 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 {
- public:
-  CPWL_ComboBox();
-  ~CPWL_ComboBox() override {}
-
-  CPWL_Edit* GetEdit() const { return m_pEdit; }
-
-  // CPWL_Wnd:
-  CFX_ByteString GetClassName() const override;
-  void OnCreate(PWL_CREATEPARAM& cp) override;
-  bool OnKeyDown(uint16_t nChar, uint32_t nFlag) override;
-  bool OnChar(uint16_t nChar, uint32_t nFlag) override;
-  void OnNotify(CPWL_Wnd* pWnd,
-                uint32_t msg,
-                intptr_t wParam = 0,
-                intptr_t lParam = 0) override;
-  void CreateChildWnd(const PWL_CREATEPARAM& cp) override;
-  void RePosChildWnd() override;
-  CFX_FloatRect GetFocusRect() const override;
-  void SetFocus() override;
-  void KillFocus() override;
-
-  void SetFillerNotify(IPWL_Filler_Notify* pNotify);
-
-  CFX_WideString GetText() const;
-  void SetText(const CFX_WideString& text);
-  void AddString(const CFX_WideString& str);
-  int32_t GetSelect() const;
-  void SetSelect(int32_t nItemIndex);
-
-  void SetEditSel(int32_t nStartChar, int32_t nEndChar);
-  void GetEditSel(int32_t& nStartChar, int32_t& nEndChar) const;
-  void Clear();
-  void SelectAll();
-  bool IsPopup() const;
-
-  void SetSelectText();
-
-  void AttachFFLData(CFFL_FormFiller* pData) { m_pFormFiller = pData; }
-
- private:
-  void CreateEdit(const PWL_CREATEPARAM& cp);
-  void CreateButton(const PWL_CREATEPARAM& cp);
-  void CreateListBox(const PWL_CREATEPARAM& cp);
-  void SetPopup(bool bPopup);
-
-  CPWL_CBEdit* m_pEdit;
-  CPWL_CBButton* m_pButton;
-  CPWL_CBListBox* m_pList;
-  bool m_bPopup;
-  CFX_FloatRect m_rcOldWindow;
-  int32_t m_nPopupWhere;
-  int32_t m_nSelectItem;
-  IPWL_Filler_Notify* m_pFillerNotify;
-  CFFL_FormFiller* m_pFormFiller;  // Not owned.
-};
-
-#endif  // FPDFSDK_PDFWINDOW_PWL_COMBOBOX_H_
diff --git a/fpdfsdk/pdfwindow/PWL_Edit.cpp b/fpdfsdk/pdfwindow/PWL_Edit.cpp
deleted file mode 100644
index b77aad9..0000000
--- a/fpdfsdk/pdfwindow/PWL_Edit.cpp
+++ /dev/null
@@ -1,878 +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/pdfwindow/PWL_Edit.h"
-
-#include <memory>
-#include <vector>
-
-#include "core/fpdfapi/font/cpdf_font.h"
-#include "core/fpdfdoc/cpvt_word.h"
-#include "core/fxcrt/fx_safe_types.h"
-#include "core/fxcrt/fx_xml.h"
-#include "core/fxge/cfx_graphstatedata.h"
-#include "core/fxge/cfx_pathdata.h"
-#include "core/fxge/cfx_renderdevice.h"
-#include "core/fxge/fx_font.h"
-#include "fpdfsdk/fxedit/fxet_edit.h"
-#include "fpdfsdk/pdfwindow/PWL_Caret.h"
-#include "fpdfsdk/pdfwindow/PWL_EditCtrl.h"
-#include "fpdfsdk/pdfwindow/PWL_FontMap.h"
-#include "fpdfsdk/pdfwindow/PWL_ScrollBar.h"
-#include "fpdfsdk/pdfwindow/PWL_Utils.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-#include "public/fpdf_fwlevent.h"
-#include "third_party/base/stl_util.h"
-
-CPWL_Edit::CPWL_Edit()
-    : m_pFillerNotify(nullptr), m_bFocus(false), m_pFormFiller(nullptr) {}
-
-CPWL_Edit::~CPWL_Edit() {
-  ASSERT(m_bFocus == false);
-}
-
-CFX_ByteString CPWL_Edit::GetClassName() const {
-  return PWL_CLASSNAME_EDIT;
-}
-
-void CPWL_Edit::OnDestroy() {}
-
-void CPWL_Edit::SetText(const CFX_WideString& csText) {
-  CFX_WideString swText = csText;
-  if (!HasFlag(PES_RICH)) {
-    m_pEdit->SetText(swText);
-    return;
-  }
-
-  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;
-  }
-
-  int32_t nCount = pXML->CountChildren();
-  bool bFirst = true;
-
-  swText.clear();
-
-  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;
-    }
-  }
-
-  m_pEdit->SetText(swText);
-}
-
-void CPWL_Edit::RePosChildWnd() {
-  if (CPWL_ScrollBar* pVSB = GetVScrollBar()) {
-    CFX_FloatRect rcWindow = m_rcOldWindow;
-    CFX_FloatRect rcVScroll =
-        CFX_FloatRect(rcWindow.right, rcWindow.bottom,
-                      rcWindow.right + PWL_SCROLLBAR_WIDTH, rcWindow.top);
-    pVSB->Move(rcVScroll, true, false);
-  }
-
-  if (m_pEditCaret && !HasFlag(PES_TEXTOVERFLOW))
-    m_pEditCaret->SetClipRect(CPWL_Utils::InflateRect(
-        GetClientRect(), 1.0f));  // +1 for caret beside border
-
-  CPWL_EditCtrl::RePosChildWnd();
-}
-
-CFX_FloatRect CPWL_Edit::GetClientRect() const {
-  CFX_FloatRect rcClient = CPWL_Utils::DeflateRect(
-      GetWindowRect(), (FX_FLOAT)(GetBorderWidth() + GetInnerBorderWidth()));
-
-  if (CPWL_ScrollBar* pVSB = GetVScrollBar()) {
-    if (pVSB->IsVisible()) {
-      rcClient.right -= PWL_SCROLLBAR_WIDTH;
-    }
-  }
-
-  return rcClient;
-}
-
-void CPWL_Edit::SetAlignFormatV(PWL_EDIT_ALIGNFORMAT_V nFormat, bool bPaint) {
-  m_pEdit->SetAlignmentV((int32_t)nFormat, bPaint);
-}
-
-bool CPWL_Edit::CanSelectAll() const {
-  return GetSelectWordRange() != m_pEdit->GetWholeWordRange();
-}
-
-bool CPWL_Edit::CanClear() const {
-  return !IsReadOnly() && m_pEdit->IsSelected();
-}
-
-bool CPWL_Edit::CanCopy() const {
-  return !HasFlag(PES_PASSWORD) && !HasFlag(PES_NOREAD) &&
-         m_pEdit->IsSelected();
-}
-
-bool CPWL_Edit::CanCut() const {
-  return CanCopy() && !IsReadOnly();
-}
-void CPWL_Edit::CutText() {
-  if (!CanCut())
-    return;
-  m_pEdit->Clear();
-}
-
-void CPWL_Edit::OnCreated() {
-  CPWL_EditCtrl::OnCreated();
-
-  if (CPWL_ScrollBar* pScroll = GetVScrollBar()) {
-    pScroll->RemoveFlag(PWS_AUTOTRANSPARENT);
-    pScroll->SetTransparency(255);
-  }
-
-  SetParamByFlag();
-
-  m_rcOldWindow = GetWindowRect();
-
-  m_pEdit->SetOprNotify(this);
-  m_pEdit->EnableOprNotify(true);
-}
-
-void CPWL_Edit::SetParamByFlag() {
-  if (HasFlag(PES_RIGHT)) {
-    m_pEdit->SetAlignmentH(2, false);
-  } else if (HasFlag(PES_MIDDLE)) {
-    m_pEdit->SetAlignmentH(1, false);
-  } else {
-    m_pEdit->SetAlignmentH(0, false);
-  }
-
-  if (HasFlag(PES_BOTTOM)) {
-    m_pEdit->SetAlignmentV(2, false);
-  } else if (HasFlag(PES_CENTER)) {
-    m_pEdit->SetAlignmentV(1, false);
-  } else {
-    m_pEdit->SetAlignmentV(0, false);
-  }
-
-  if (HasFlag(PES_PASSWORD)) {
-    m_pEdit->SetPasswordChar('*', false);
-  }
-
-  m_pEdit->SetMultiLine(HasFlag(PES_MULTILINE), false);
-  m_pEdit->SetAutoReturn(HasFlag(PES_AUTORETURN), false);
-  m_pEdit->SetAutoFontSize(HasFlag(PWS_AUTOFONTSIZE), false);
-  m_pEdit->SetAutoScroll(HasFlag(PES_AUTOSCROLL), false);
-  m_pEdit->EnableUndo(HasFlag(PES_UNDO));
-
-  if (HasFlag(PES_TEXTOVERFLOW)) {
-    SetClipRect(CFX_FloatRect(0.0f, 0.0f, 0.0f, 0.0f));
-    m_pEdit->SetTextOverflow(true, false);
-  } else {
-    if (m_pEditCaret) {
-      m_pEditCaret->SetClipRect(CPWL_Utils::InflateRect(
-          GetClientRect(), 1.0f));  // +1 for caret beside border
-    }
-  }
-}
-
-void CPWL_Edit::GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) {
-  CPWL_Wnd::GetThisAppearanceStream(sAppStream);
-
-  CFX_FloatRect rcClient = GetClientRect();
-  CFX_ByteTextBuf sLine;
-
-  int32_t nCharArray = m_pEdit->GetCharArray();
-
-  if (nCharArray > 0) {
-    switch (GetBorderStyle()) {
-      case BorderStyle::SOLID: {
-        sLine << "q\n"
-              << GetBorderWidth() << " w\n"
-              << CPWL_Utils::GetColorAppStream(GetBorderColor(), false)
-                     .AsStringC()
-              << " 2 J 0 j\n";
-
-        for (int32_t i = 1; i < nCharArray; i++) {
-          sLine << rcClient.left +
-                       ((rcClient.right - rcClient.left) / nCharArray) * i
-                << " " << rcClient.bottom << " m\n"
-                << rcClient.left +
-                       ((rcClient.right - rcClient.left) / nCharArray) * i
-                << " " << rcClient.top << " l S\n";
-        }
-
-        sLine << "Q\n";
-        break;
-      }
-      case BorderStyle::DASH: {
-        sLine << "q\n"
-              << GetBorderWidth() << " w\n"
-              << CPWL_Utils::GetColorAppStream(GetBorderColor(), false)
-                     .AsStringC()
-              << " 2 J 0 j\n"
-              << "[" << GetBorderDash().nDash << " " << GetBorderDash().nGap
-              << "] " << GetBorderDash().nPhase << " d\n";
-
-        for (int32_t i = 1; i < nCharArray; i++) {
-          sLine << rcClient.left +
-                       ((rcClient.right - rcClient.left) / nCharArray) * i
-                << " " << rcClient.bottom << " m\n"
-                << rcClient.left +
-                       ((rcClient.right - rcClient.left) / nCharArray) * i
-                << " " << rcClient.top << " l S\n";
-        }
-
-        sLine << "Q\n";
-        break;
-      }
-      default:
-        break;
-    }
-  }
-
-  sAppStream << sLine;
-
-  CFX_ByteTextBuf sText;
-  CFX_PointF ptOffset;
-  CPVT_WordRange wrWhole = m_pEdit->GetWholeWordRange();
-  CPVT_WordRange wrSelect = GetSelectWordRange();
-  CPVT_WordRange wrVisible =
-      HasFlag(PES_TEXTOVERFLOW) ? wrWhole : m_pEdit->GetVisibleWordRange();
-
-  CPVT_WordRange wrSelBefore(wrWhole.BeginPos, wrSelect.BeginPos);
-  CPVT_WordRange wrSelAfter(wrSelect.EndPos, wrWhole.EndPos);
-  CPVT_WordRange wrTemp =
-      CPWL_Utils::OverlapWordRange(GetSelectWordRange(), wrVisible);
-  CFX_ByteString sEditSel =
-      CPWL_Utils::GetEditSelAppStream(m_pEdit.get(), ptOffset, &wrTemp);
-
-  if (sEditSel.GetLength() > 0)
-    sText << CPWL_Utils::GetColorAppStream(PWL_DEFAULT_SELBACKCOLOR).AsStringC()
-          << sEditSel.AsStringC();
-
-  wrTemp = CPWL_Utils::OverlapWordRange(wrVisible, wrSelBefore);
-  CFX_ByteString sEditBefore = CPWL_Utils::GetEditAppStream(
-      m_pEdit.get(), ptOffset, &wrTemp, !HasFlag(PES_CHARARRAY),
-      m_pEdit->GetPasswordChar());
-
-  if (sEditBefore.GetLength() > 0)
-    sText << "BT\n"
-          << CPWL_Utils::GetColorAppStream(GetTextColor()).AsStringC()
-          << sEditBefore.AsStringC() << "ET\n";
-
-  wrTemp = CPWL_Utils::OverlapWordRange(wrVisible, wrSelect);
-  CFX_ByteString sEditMid = CPWL_Utils::GetEditAppStream(
-      m_pEdit.get(), ptOffset, &wrTemp, !HasFlag(PES_CHARARRAY),
-      m_pEdit->GetPasswordChar());
-
-  if (sEditMid.GetLength() > 0)
-    sText << "BT\n"
-          << CPWL_Utils::GetColorAppStream(CPWL_Color(COLORTYPE_GRAY, 1))
-                 .AsStringC()
-          << sEditMid.AsStringC() << "ET\n";
-
-  wrTemp = CPWL_Utils::OverlapWordRange(wrVisible, wrSelAfter);
-  CFX_ByteString sEditAfter = CPWL_Utils::GetEditAppStream(
-      m_pEdit.get(), ptOffset, &wrTemp, !HasFlag(PES_CHARARRAY),
-      m_pEdit->GetPasswordChar());
-
-  if (sEditAfter.GetLength() > 0)
-    sText << "BT\n"
-          << CPWL_Utils::GetColorAppStream(GetTextColor()).AsStringC()
-          << sEditAfter.AsStringC() << "ET\n";
-
-  if (sText.GetLength() > 0) {
-    CFX_FloatRect rect = GetClientRect();
-    sAppStream << "q\n/Tx BMC\n";
-
-    if (!HasFlag(PES_TEXTOVERFLOW))
-      sAppStream << rect.left << " " << rect.bottom << " "
-                 << rect.right - rect.left << " " << rect.top - rect.bottom
-                 << " re W n\n";
-
-    sAppStream << sText;
-
-    sAppStream << "EMC\nQ\n";
-  }
-}
-
-void CPWL_Edit::DrawThisAppearance(CFX_RenderDevice* pDevice,
-                                   CFX_Matrix* pUser2Device) {
-  CPWL_Wnd::DrawThisAppearance(pDevice, pUser2Device);
-
-  CFX_FloatRect rcClient = GetClientRect();
-  CFX_ByteTextBuf sLine;
-
-  int32_t nCharArray = m_pEdit->GetCharArray();
-  FX_SAFE_INT32 nCharArraySafe = nCharArray;
-  nCharArraySafe -= 1;
-  nCharArraySafe *= 2;
-
-  if (nCharArray > 0 && nCharArraySafe.IsValid()) {
-    switch (GetBorderStyle()) {
-      case BorderStyle::SOLID: {
-        CFX_GraphStateData gsd;
-        gsd.m_LineWidth = (FX_FLOAT)GetBorderWidth();
-
-        CFX_PathData path;
-
-        for (int32_t i = 0; i < nCharArray - 1; i++) {
-          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.GetPoints().empty()) {
-          pDevice->DrawPath(&path, pUser2Device, &gsd, 0,
-                            GetBorderColor().ToFXColor(255), FXFILL_ALTERNATE);
-        }
-        break;
-      }
-      case BorderStyle::DASH: {
-        CFX_GraphStateData gsd;
-        gsd.m_LineWidth = (FX_FLOAT)GetBorderWidth();
-
-        gsd.SetDashCount(2);
-        gsd.m_DashArray[0] = (FX_FLOAT)GetBorderDash().nDash;
-        gsd.m_DashArray[1] = (FX_FLOAT)GetBorderDash().nGap;
-        gsd.m_DashPhase = (FX_FLOAT)GetBorderDash().nPhase;
-
-        CFX_PathData path;
-        for (int32_t i = 0; i < nCharArray - 1; i++) {
-          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.GetPoints().empty()) {
-          pDevice->DrawPath(&path, pUser2Device, &gsd, 0,
-                            GetBorderColor().ToFXColor(255), FXFILL_ALTERNATE);
-        }
-        break;
-      }
-      default:
-        break;
-    }
-  }
-
-  CFX_FloatRect rcClip;
-  CPVT_WordRange wrRange = m_pEdit->GetVisibleWordRange();
-  CPVT_WordRange* pRange = nullptr;
-  if (!HasFlag(PES_TEXTOVERFLOW)) {
-    rcClip = GetClientRect();
-    pRange = &wrRange;
-  }
-
-  CFX_SystemHandler* pSysHandler = GetSystemHandler();
-  CFX_Edit::DrawEdit(pDevice, pUser2Device, m_pEdit.get(),
-                     GetTextColor().ToFXColor(GetTransparency()), rcClip,
-                     CFX_PointF(), pRange, pSysHandler, m_pFormFiller);
-}
-
-bool CPWL_Edit::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
-  CPWL_Wnd::OnLButtonDown(point, nFlag);
-
-  if (HasFlag(PES_TEXTOVERFLOW) || ClientHitTest(point)) {
-    if (m_bMouseDown)
-      InvalidateRect();
-
-    m_bMouseDown = true;
-    SetCapture();
-
-    m_pEdit->OnMouseDown(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-  }
-
-  return true;
-}
-
-bool CPWL_Edit::OnLButtonDblClk(const CFX_PointF& point, uint32_t nFlag) {
-  CPWL_Wnd::OnLButtonDblClk(point, nFlag);
-
-  if (HasFlag(PES_TEXTOVERFLOW) || ClientHitTest(point)) {
-    m_pEdit->SelectAll();
-  }
-
-  return true;
-}
-
-bool CPWL_Edit::OnRButtonUp(const CFX_PointF& point, uint32_t nFlag) {
-  if (m_bMouseDown)
-    return false;
-
-  CPWL_Wnd::OnRButtonUp(point, nFlag);
-
-  if (!HasFlag(PES_TEXTOVERFLOW) && !ClientHitTest(point))
-    return true;
-
-  CFX_SystemHandler* pSH = GetSystemHandler();
-  if (!pSH)
-    return false;
-
-  SetFocus();
-
-  return false;
-}
-
-void CPWL_Edit::OnSetFocus() {
-  SetEditCaret(true);
-  if (!IsReadOnly()) {
-    if (IPWL_FocusHandler* pFocusHandler = GetFocusHandler())
-      pFocusHandler->OnSetFocus(this);
-  }
-  m_bFocus = true;
-}
-
-void CPWL_Edit::OnKillFocus() {
-  ShowVScrollBar(false);
-  m_pEdit->SelectNone();
-  SetCaret(false, CFX_PointF(), CFX_PointF());
-  SetCharSet(FXFONT_ANSI_CHARSET);
-  m_bFocus = false;
-}
-
-void CPWL_Edit::SetCharSpace(FX_FLOAT fCharSpace) {
-  m_pEdit->SetCharSpace(fCharSpace);
-}
-
-CFX_ByteString CPWL_Edit::GetSelectAppearanceStream(
-    const CFX_PointF& ptOffset) const {
-  CPVT_WordRange wr = GetSelectWordRange();
-  return CPWL_Utils::GetEditSelAppStream(m_pEdit.get(), ptOffset, &wr);
-}
-
-CPVT_WordRange CPWL_Edit::GetSelectWordRange() const {
-  if (m_pEdit->IsSelected()) {
-    int32_t nStart = -1;
-    int32_t nEnd = -1;
-
-    m_pEdit->GetSel(nStart, nEnd);
-
-    CPVT_WordPlace wpStart = m_pEdit->WordIndexToWordPlace(nStart);
-    CPVT_WordPlace wpEnd = m_pEdit->WordIndexToWordPlace(nEnd);
-
-    return CPVT_WordRange(wpStart, wpEnd);
-  }
-
-  return CPVT_WordRange();
-}
-
-CFX_ByteString CPWL_Edit::GetTextAppearanceStream(
-    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()
-         << sEdit.AsStringC() << "ET\n";
-  }
-  return sRet.MakeString();
-}
-
-CFX_ByteString CPWL_Edit::GetCaretAppearanceStream(
-    const CFX_PointF& ptOffset) const {
-  if (m_pEditCaret)
-    return m_pEditCaret->GetCaretAppearanceStream(ptOffset);
-
-  return CFX_ByteString();
-}
-
-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_PointF pt;
-  CPVT_Word word;
-  if (pIterator->GetWord(word)) {
-    pt = CFX_PointF(word.ptWord.x + word.fWidth, word.ptWord.y + word.fDescent);
-  }
-  pIterator->SetAt(wpOld);
-  return pt;
-}
-
-bool CPWL_Edit::IsTextFull() const {
-  return m_pEdit->IsTextFull();
-}
-
-FX_FLOAT CPWL_Edit::GetCharArrayAutoFontSize(CPDF_Font* pFont,
-                                             const CFX_FloatRect& rcPlate,
-                                             int32_t nCharArray) {
-  if (pFont && !pFont->IsStandardFont()) {
-    FX_RECT rcBBox;
-    pFont->GetFontBBox(rcBBox);
-
-    CFX_FloatRect rcCell = rcPlate;
-    FX_FLOAT xdiv = rcCell.Width() / nCharArray * 1000.0f / rcBBox.Width();
-    FX_FLOAT ydiv = -rcCell.Height() * 1000.0f / rcBBox.Height();
-
-    return xdiv < ydiv ? xdiv : ydiv;
-  }
-
-  return 0.0f;
-}
-
-void CPWL_Edit::SetCharArray(int32_t nCharArray) {
-  if (HasFlag(PES_CHARARRAY) && nCharArray > 0) {
-    m_pEdit->SetCharArray(nCharArray);
-    m_pEdit->SetTextOverflow(true, true);
-
-    if (HasFlag(PWS_AUTOFONTSIZE)) {
-      if (IPVT_FontMap* pFontMap = GetFontMap()) {
-        FX_FLOAT fFontSize = GetCharArrayAutoFontSize(
-            pFontMap->GetPDFFont(0), GetClientRect(), nCharArray);
-        if (fFontSize > 0.0f) {
-          m_pEdit->SetAutoFontSize(false, true);
-          m_pEdit->SetFontSize(fFontSize);
-        }
-      }
-    }
-  }
-}
-
-void CPWL_Edit::SetLimitChar(int32_t nLimitChar) {
-  m_pEdit->SetLimitChar(nLimitChar);
-}
-
-void CPWL_Edit::ReplaceSel(const CFX_WideString& wsText) {
-  m_pEdit->Clear();
-  m_pEdit->InsertText(wsText, FXFONT_DEFAULT_CHARSET);
-}
-
-CFX_FloatRect CPWL_Edit::GetFocusRect() const {
-  return CFX_FloatRect();
-}
-
-void CPWL_Edit::ShowVScrollBar(bool bShow) {
-  if (CPWL_ScrollBar* pScroll = GetVScrollBar()) {
-    if (bShow) {
-      if (!pScroll->IsVisible()) {
-        pScroll->SetVisible(true);
-        CFX_FloatRect rcWindow = GetWindowRect();
-        m_rcOldWindow = rcWindow;
-        rcWindow.right += PWL_SCROLLBAR_WIDTH;
-        Move(rcWindow, true, true);
-      }
-    } else {
-      if (pScroll->IsVisible()) {
-        pScroll->SetVisible(false);
-        Move(m_rcOldWindow, true, true);
-      }
-    }
-  }
-}
-
-bool CPWL_Edit::IsVScrollBarVisible() const {
-  if (CPWL_ScrollBar* pScroll = GetVScrollBar()) {
-    return pScroll->IsVisible();
-  }
-
-  return false;
-}
-
-bool CPWL_Edit::OnKeyDown(uint16_t nChar, uint32_t nFlag) {
-  if (m_bMouseDown)
-    return true;
-
-  if (nChar == FWL_VKEY_Delete) {
-    if (m_pFillerNotify) {
-      bool bRC = true;
-      bool bExit = false;
-      CFX_WideString strChange;
-      CFX_WideString strChangeEx;
-
-      int nSelStart = 0;
-      int nSelEnd = 0;
-      GetSel(nSelStart, nSelEnd);
-
-      if (nSelStart == nSelEnd)
-        nSelEnd = nSelStart + 1;
-      m_pFillerNotify->OnBeforeKeyStroke(GetAttachedData(), strChange,
-                                         strChangeEx, nSelStart, nSelEnd, true,
-                                         bRC, bExit, nFlag);
-      if (!bRC)
-        return false;
-      if (bExit)
-        return false;
-    }
-  }
-
-  bool bRet = CPWL_EditCtrl::OnKeyDown(nChar, nFlag);
-
-  // In case of implementation swallow the OnKeyDown event.
-  if (IsProceedtoOnChar(nChar, nFlag))
-    return true;
-
-  return bRet;
-}
-
-/**
-*In case of implementation swallow the OnKeyDown event.
-*If the event is swallowed, implementation may do other unexpected things, which
-*is not the control means to do.
-*/
-bool CPWL_Edit::IsProceedtoOnChar(uint16_t nKeyCode, uint32_t nFlag) {
-  bool bCtrl = IsCTRLpressed(nFlag);
-  bool bAlt = IsALTpressed(nFlag);
-  if (bCtrl && !bAlt) {
-    // hot keys for edit control.
-    switch (nKeyCode) {
-      case 'C':
-      case 'V':
-      case 'X':
-      case 'A':
-      case 'Z':
-        return true;
-      default:
-        break;
-    }
-  }
-  // control characters.
-  switch (nKeyCode) {
-    case FWL_VKEY_Escape:
-    case FWL_VKEY_Back:
-    case FWL_VKEY_Return:
-    case FWL_VKEY_Space:
-      return true;
-    default:
-      return false;
-  }
-}
-
-bool CPWL_Edit::OnChar(uint16_t nChar, uint32_t nFlag) {
-  if (m_bMouseDown)
-    return true;
-
-  bool bRC = true;
-  bool bExit = false;
-
-  if (!IsCTRLpressed(nFlag)) {
-    if (m_pFillerNotify) {
-      CFX_WideString swChange;
-
-      int nSelStart = 0;
-      int nSelEnd = 0;
-      GetSel(nSelStart, nSelEnd);
-
-      switch (nChar) {
-        case FWL_VKEY_Back:
-          if (nSelStart == nSelEnd)
-            nSelStart = nSelEnd - 1;
-          break;
-        case FWL_VKEY_Return:
-          break;
-        default:
-          swChange += nChar;
-          break;
-      }
-
-      CFX_WideString strChangeEx;
-      m_pFillerNotify->OnBeforeKeyStroke(GetAttachedData(), swChange,
-                                         strChangeEx, nSelStart, nSelEnd, true,
-                                         bRC, bExit, nFlag);
-    }
-  }
-
-  if (!bRC)
-    return true;
-  if (bExit)
-    return false;
-
-  if (IPVT_FontMap* pFontMap = GetFontMap()) {
-    int32_t nOldCharSet = GetCharSet();
-    int32_t nNewCharSet =
-        pFontMap->CharSetFromUnicode(nChar, FXFONT_DEFAULT_CHARSET);
-    if (nOldCharSet != nNewCharSet) {
-      SetCharSet(nNewCharSet);
-    }
-  }
-
-  return CPWL_EditCtrl::OnChar(nChar, nFlag);
-}
-
-bool CPWL_Edit::OnMouseWheel(short zDelta,
-                             const CFX_PointF& point,
-                             uint32_t nFlag) {
-  if (HasFlag(PES_MULTILINE)) {
-    CFX_PointF ptScroll = GetScrollPos();
-
-    if (zDelta > 0) {
-      ptScroll.y += GetFontSize();
-    } else {
-      ptScroll.y -= GetFontSize();
-    }
-    SetScrollPos(ptScroll);
-
-    return true;
-  }
-
-  return false;
-}
-
-void CPWL_Edit::OnInsertReturn(const CPVT_WordPlace& place,
-                               const CPVT_WordPlace& oldplace) {
-  if (HasFlag(PES_SPELLCHECK)) {
-    m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
-                                               GetLatinWordsRange(place)));
-  }
-}
-
-void CPWL_Edit::OnBackSpace(const CPVT_WordPlace& place,
-                            const CPVT_WordPlace& oldplace) {
-  if (HasFlag(PES_SPELLCHECK)) {
-    m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
-                                               GetLatinWordsRange(place)));
-  }
-}
-
-void CPWL_Edit::OnDelete(const CPVT_WordPlace& place,
-                         const CPVT_WordPlace& oldplace) {
-  if (HasFlag(PES_SPELLCHECK)) {
-    m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
-                                               GetLatinWordsRange(place)));
-  }
-}
-
-void CPWL_Edit::OnClear(const CPVT_WordPlace& place,
-                        const CPVT_WordPlace& oldplace) {
-  if (HasFlag(PES_SPELLCHECK)) {
-    m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
-                                               GetLatinWordsRange(place)));
-  }
-}
-
-void CPWL_Edit::OnInsertWord(const CPVT_WordPlace& place,
-                             const CPVT_WordPlace& oldplace) {
-  if (HasFlag(PES_SPELLCHECK)) {
-    m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
-                                               GetLatinWordsRange(place)));
-  }
-}
-
-void CPWL_Edit::OnInsertText(const CPVT_WordPlace& place,
-                             const CPVT_WordPlace& oldplace) {
-  if (HasFlag(PES_SPELLCHECK)) {
-    m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
-                                               GetLatinWordsRange(place)));
-  }
-}
-
-CPVT_WordRange CPWL_Edit::CombineWordRange(const CPVT_WordRange& wr1,
-                                           const CPVT_WordRange& wr2) {
-  CPVT_WordRange wrRet;
-
-  if (wr1.BeginPos.WordCmp(wr2.BeginPos) < 0) {
-    wrRet.BeginPos = wr1.BeginPos;
-  } else {
-    wrRet.BeginPos = wr2.BeginPos;
-  }
-
-  if (wr1.EndPos.WordCmp(wr2.EndPos) < 0) {
-    wrRet.EndPos = wr2.EndPos;
-  } else {
-    wrRet.EndPos = wr1.EndPos;
-  }
-
-  return wrRet;
-}
-
-CPVT_WordRange CPWL_Edit::GetLatinWordsRange(const CFX_PointF& point) const {
-  return GetSameWordsRange(m_pEdit->SearchWordPlace(point), true, false);
-}
-
-CPVT_WordRange CPWL_Edit::GetLatinWordsRange(
-    const CPVT_WordPlace& place) const {
-  return GetSameWordsRange(place, true, false);
-}
-
-CPVT_WordRange CPWL_Edit::GetArabicWordsRange(
-    const CPVT_WordPlace& place) const {
-  return GetSameWordsRange(place, false, true);
-}
-
-#define PWL_ISARABICWORD(word) \
-  ((word >= 0x0600 && word <= 0x06FF) || (word >= 0xFB50 && word <= 0xFEFC))
-
-CPVT_WordRange CPWL_Edit::GetSameWordsRange(const CPVT_WordPlace& place,
-                                            bool bLatin,
-                                            bool bArabic) const {
-  CPVT_WordRange range;
-
-  CFX_Edit_Iterator* pIterator = m_pEdit->GetIterator();
-  CPVT_Word wordinfo;
-  CPVT_WordPlace wpStart(place), wpEnd(place);
-  pIterator->SetAt(place);
-
-  if (bLatin) {
-    while (pIterator->NextWord()) {
-      if (!pIterator->GetWord(wordinfo) ||
-          !FX_EDIT_ISLATINWORD(wordinfo.Word)) {
-        break;
-      }
-
-      wpEnd = pIterator->GetAt();
-    }
-  } else if (bArabic) {
-    while (pIterator->NextWord()) {
-      if (!pIterator->GetWord(wordinfo) || !PWL_ISARABICWORD(wordinfo.Word))
-        break;
-
-      wpEnd = pIterator->GetAt();
-    }
-  }
-
-  pIterator->SetAt(place);
-
-  if (bLatin) {
-    do {
-      if (!pIterator->GetWord(wordinfo) ||
-          !FX_EDIT_ISLATINWORD(wordinfo.Word)) {
-        break;
-      }
-
-      wpStart = pIterator->GetAt();
-    } while (pIterator->PrevWord());
-  } else if (bArabic) {
-    do {
-      if (!pIterator->GetWord(wordinfo) || !PWL_ISARABICWORD(wordinfo.Word))
-        break;
-
-      wpStart = pIterator->GetAt();
-    } while (pIterator->PrevWord());
-  }
-
-  range.Set(wpStart, wpEnd);
-  return range;
-}
diff --git a/fpdfsdk/pdfwindow/PWL_Edit.h b/fpdfsdk/pdfwindow/PWL_Edit.h
deleted file mode 100644
index b6d0130..0000000
--- a/fpdfsdk/pdfwindow/PWL_Edit.h
+++ /dev/null
@@ -1,143 +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 FPDFSDK_PDFWINDOW_PWL_EDIT_H_
-#define FPDFSDK_PDFWINDOW_PWL_EDIT_H_
-
-#include <vector>
-
-#include "core/fxcrt/fx_basic.h"
-#include "fpdfsdk/fxedit/fx_edit.h"
-#include "fpdfsdk/pdfwindow/PWL_EditCtrl.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-
-class CPDF_PageObjectHolder;
-class CPDF_TextObject;
-class IFX_Edit_UndoItem;
-
-class IPWL_Filler_Notify {
- public:
-  virtual ~IPWL_Filler_Notify() {}
-  virtual void QueryWherePopup(
-      void* pPrivateData,
-      FX_FLOAT fPopupMin,
-      FX_FLOAT fPopupMax,
-      int32_t& nRet,
-      FX_FLOAT& fPopupRet) = 0;  // nRet: (0:bottom 1:top)
-  virtual void OnBeforeKeyStroke(void* pPrivateData,
-                                 CFX_WideString& strChange,
-                                 const CFX_WideString& strChangeEx,
-                                 int nSelStart,
-                                 int nSelEnd,
-                                 bool bKeyDown,
-                                 bool& bRC,
-                                 bool& bExit,
-                                 uint32_t nFlag) = 0;
-#ifdef PDF_ENABLE_XFA
-  virtual void OnPopupPreOpen(void* pPrivateData,
-                              bool& bExit,
-                              uint32_t nFlag) = 0;
-  virtual void OnPopupPostOpen(void* pPrivateData,
-                               bool& bExit,
-                               uint32_t nFlag) = 0;
-#endif  // PDF_ENABLE_XFA
-};
-
-class CPWL_Edit : public CPWL_EditCtrl {
- public:
-  CPWL_Edit();
-  ~CPWL_Edit() override;
-
-  // CPWL_EditCtrl
-  CFX_ByteString GetClassName() const override;
-  void OnDestroy() override;
-  void OnCreated() override;
-  void RePosChildWnd() override;
-  CFX_FloatRect GetClientRect() const override;
-  void GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) override;
-  void DrawThisAppearance(CFX_RenderDevice* pDevice,
-                          CFX_Matrix* pUser2Device) 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_PointF& point,
-                    uint32_t nFlag) override;
-  bool OnKeyDown(uint16_t nChar, uint32_t nFlag) override;
-  bool OnChar(uint16_t nChar, uint32_t nFlag) override;
-  CFX_FloatRect GetFocusRect() const override;
-  void OnSetFocus() override;
-  void OnKillFocus() override;
-
-  void SetAlignFormatV(PWL_EDIT_ALIGNFORMAT_V nFormat = PEAV_TOP,
-                       bool bPaint = true);  // 0:top 1:bottom 2:center
-
-  void SetCharArray(int32_t nCharArray);
-  void SetLimitChar(int32_t nLimitChar);
-
-  void SetCharSpace(FX_FLOAT fCharSpace);
-
-  bool CanSelectAll() const;
-  bool CanClear() const;
-  bool CanCopy() const;
-  bool CanCut() const;
-
-  void CutText();
-
-  void SetText(const CFX_WideString& csText);
-  void ReplaceSel(const CFX_WideString& csText);
-
-  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;
-
-  static FX_FLOAT GetCharArrayAutoFontSize(CPDF_Font* pFont,
-                                           const CFX_FloatRect& rcPlate,
-                                           int32_t nCharArray);
-
-  void SetFillerNotify(IPWL_Filler_Notify* pNotify) {
-    m_pFillerNotify = pNotify;
-  }
-
-  bool IsProceedtoOnChar(uint16_t nKeyCode, uint32_t nFlag);
-  void AttachFFLData(CFFL_FormFiller* pData) { m_pFormFiller = pData; }
-
-  void OnInsertWord(const CPVT_WordPlace& place,
-                    const CPVT_WordPlace& oldplace);
-  void OnInsertReturn(const CPVT_WordPlace& place,
-                      const CPVT_WordPlace& oldplace);
-  void OnBackSpace(const CPVT_WordPlace& place, const CPVT_WordPlace& oldplace);
-  void OnDelete(const CPVT_WordPlace& place, const CPVT_WordPlace& oldplace);
-  void OnClear(const CPVT_WordPlace& place, const CPVT_WordPlace& oldplace);
-  void OnInsertText(const CPVT_WordPlace& place,
-                    const CPVT_WordPlace& oldplace);
-
- private:
-  CPVT_WordRange GetSelectWordRange() const;
-  virtual void ShowVScrollBar(bool bShow);
-  bool IsVScrollBarVisible() const;
-  void SetParamByFlag();
-
-  FX_FLOAT GetCharArrayAutoFontSize(int32_t nCharArray);
-  CFX_PointF GetWordRightBottomPoint(const CPVT_WordPlace& wpWord);
-
-  CPVT_WordRange CombineWordRange(const CPVT_WordRange& wr1,
-                                  const CPVT_WordRange& wr2);
-  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,
-                                   bool bLatin,
-                                   bool bArabic) const;
-  IPWL_Filler_Notify* m_pFillerNotify;
-  bool m_bFocus;
-  CFX_FloatRect m_rcOldWindow;
-  CFFL_FormFiller* m_pFormFiller;  // Not owned.
-};
-
-#endif  // FPDFSDK_PDFWINDOW_PWL_EDIT_H_
diff --git a/fpdfsdk/pdfwindow/PWL_EditCtrl.cpp b/fpdfsdk/pdfwindow/PWL_EditCtrl.cpp
deleted file mode 100644
index 4921ab7..0000000
--- a/fpdfsdk/pdfwindow/PWL_EditCtrl.cpp
+++ /dev/null
@@ -1,577 +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/pdfwindow/PWL_EditCtrl.h"
-
-#include "core/fpdfdoc/cpvt_section.h"
-#include "core/fpdfdoc/cpvt_word.h"
-#include "core/fxge/fx_font.h"
-#include "fpdfsdk/fxedit/fxet_edit.h"
-#include "fpdfsdk/pdfwindow/PWL_Caret.h"
-#include "fpdfsdk/pdfwindow/PWL_FontMap.h"
-#include "fpdfsdk/pdfwindow/PWL_ScrollBar.h"
-#include "fpdfsdk/pdfwindow/PWL_Utils.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-#include "public/fpdf_fwlevent.h"
-
-CPWL_EditCtrl::CPWL_EditCtrl()
-    : m_pEdit(new CFX_Edit),
-      m_pEditCaret(nullptr),
-      m_bMouseDown(false),
-      m_nCharSet(FXFONT_DEFAULT_CHARSET),
-      m_nCodePage(0) {}
-
-CPWL_EditCtrl::~CPWL_EditCtrl() {}
-
-void CPWL_EditCtrl::OnCreate(PWL_CREATEPARAM& cp) {
-  cp.eCursorType = FXCT_VBEAM;
-}
-
-void CPWL_EditCtrl::OnCreated() {
-  SetFontSize(GetCreationParam().fFontSize);
-
-  m_pEdit->SetFontMap(GetFontMap());
-  m_pEdit->SetNotify(this);
-  m_pEdit->Initialize();
-}
-
-bool CPWL_EditCtrl::IsWndHorV() {
-  CFX_Matrix mt = GetWindowMatrix();
-  return mt.Transform(CFX_PointF(1, 1)).y == mt.Transform(CFX_PointF(0, 1)).y;
-}
-
-void CPWL_EditCtrl::SetCursor() {
-  if (IsValid()) {
-    if (CFX_SystemHandler* pSH = GetSystemHandler()) {
-      if (IsWndHorV())
-        pSH->SetCursor(FXCT_VBEAM);
-      else
-        pSH->SetCursor(FXCT_HBEAM);
-    }
-  }
-}
-
-void CPWL_EditCtrl::RePosChildWnd() {
-  m_pEdit->SetPlateRect(GetClientRect());
-}
-
-void CPWL_EditCtrl::OnNotify(CPWL_Wnd* pWnd,
-                             uint32_t msg,
-                             intptr_t wParam,
-                             intptr_t lParam) {
-  CPWL_Wnd::OnNotify(pWnd, msg, wParam, lParam);
-
-  switch (msg) {
-    case PNM_SETSCROLLINFO:
-      switch (wParam) {
-        case SBT_VSCROLL:
-          if (CPWL_Wnd* pChild = GetVScrollBar()) {
-            pChild->OnNotify(pWnd, PNM_SETSCROLLINFO, wParam, lParam);
-          }
-          break;
-      }
-      break;
-    case PNM_SETSCROLLPOS:
-      switch (wParam) {
-        case SBT_VSCROLL:
-          if (CPWL_Wnd* pChild = GetVScrollBar()) {
-            pChild->OnNotify(pWnd, PNM_SETSCROLLPOS, wParam, lParam);
-          }
-          break;
-      }
-      break;
-    case PNM_SCROLLWINDOW: {
-      FX_FLOAT fPos = *(FX_FLOAT*)lParam;
-      switch (wParam) {
-        case SBT_VSCROLL:
-          m_pEdit->SetScrollPos(CFX_PointF(m_pEdit->GetScrollPos().x, fPos));
-          break;
-      }
-    } break;
-    case PNM_SETCARETINFO: {
-      if (PWL_CARET_INFO* pCaretInfo = (PWL_CARET_INFO*)wParam) {
-        SetCaret(pCaretInfo->bVisible, pCaretInfo->ptHead, pCaretInfo->ptFoot);
-      }
-    } break;
-  }
-}
-
-void CPWL_EditCtrl::CreateChildWnd(const PWL_CREATEPARAM& cp) {
-  if (!IsReadOnly())
-    CreateEditCaret(cp);
-}
-
-void CPWL_EditCtrl::CreateEditCaret(const PWL_CREATEPARAM& cp) {
-  if (m_pEditCaret)
-    return;
-
-  m_pEditCaret = new CPWL_Caret;
-  m_pEditCaret->SetInvalidRect(GetClientRect());
-
-  PWL_CREATEPARAM ecp = cp;
-  ecp.pParentWnd = this;
-  ecp.dwFlags = PWS_CHILD | PWS_NOREFRESHCLIP;
-  ecp.dwBorderWidth = 0;
-  ecp.nBorderStyle = BorderStyle::SOLID;
-  ecp.rcRectWnd = CFX_FloatRect(0, 0, 0, 0);
-
-  m_pEditCaret->Create(ecp);
-}
-
-void CPWL_EditCtrl::SetFontSize(FX_FLOAT fFontSize) {
-  m_pEdit->SetFontSize(fFontSize);
-}
-
-FX_FLOAT CPWL_EditCtrl::GetFontSize() const {
-  return m_pEdit->GetFontSize();
-}
-
-bool CPWL_EditCtrl::OnKeyDown(uint16_t nChar, uint32_t nFlag) {
-  if (m_bMouseDown)
-    return true;
-
-  bool bRet = CPWL_Wnd::OnKeyDown(nChar, nFlag);
-
-  // FILTER
-  switch (nChar) {
-    default:
-      return false;
-    case FWL_VKEY_Delete:
-    case FWL_VKEY_Up:
-    case FWL_VKEY_Down:
-    case FWL_VKEY_Left:
-    case FWL_VKEY_Right:
-    case FWL_VKEY_Home:
-    case FWL_VKEY_End:
-    case FWL_VKEY_Insert:
-    case 'C':
-    case 'V':
-    case 'X':
-    case 'A':
-    case 'Z':
-    case 'c':
-    case 'v':
-    case 'x':
-    case 'a':
-    case 'z':
-      break;
-  }
-
-  if (nChar == FWL_VKEY_Delete && m_pEdit->IsSelected())
-    nChar = FWL_VKEY_Unknown;
-
-  switch (nChar) {
-    case FWL_VKEY_Delete:
-      Delete();
-      return true;
-    case FWL_VKEY_Insert:
-      if (IsSHIFTpressed(nFlag))
-        PasteText();
-      return true;
-    case FWL_VKEY_Up:
-      m_pEdit->OnVK_UP(IsSHIFTpressed(nFlag), false);
-      return true;
-    case FWL_VKEY_Down:
-      m_pEdit->OnVK_DOWN(IsSHIFTpressed(nFlag), false);
-      return true;
-    case FWL_VKEY_Left:
-      m_pEdit->OnVK_LEFT(IsSHIFTpressed(nFlag), false);
-      return true;
-    case FWL_VKEY_Right:
-      m_pEdit->OnVK_RIGHT(IsSHIFTpressed(nFlag), false);
-      return true;
-    case FWL_VKEY_Home:
-      m_pEdit->OnVK_HOME(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-      return true;
-    case FWL_VKEY_End:
-      m_pEdit->OnVK_END(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-      return true;
-    case FWL_VKEY_Unknown:
-      if (!IsSHIFTpressed(nFlag))
-        Clear();
-      else
-        CutText();
-      return true;
-    default:
-      break;
-  }
-
-  return bRet;
-}
-
-bool CPWL_EditCtrl::OnChar(uint16_t nChar, uint32_t nFlag) {
-  if (m_bMouseDown)
-    return true;
-
-  CPWL_Wnd::OnChar(nChar, nFlag);
-
-  // FILTER
-  switch (nChar) {
-    case 0x0A:
-    case 0x1B:
-      return false;
-    default:
-      break;
-  }
-
-  bool bCtrl = IsCTRLpressed(nFlag);
-  bool bAlt = IsALTpressed(nFlag);
-  bool bShift = IsSHIFTpressed(nFlag);
-
-  uint16_t word = nChar;
-
-  if (bCtrl && !bAlt) {
-    switch (nChar) {
-      case 'C' - 'A' + 1:
-        CopyText();
-        return true;
-      case 'V' - 'A' + 1:
-        PasteText();
-        return true;
-      case 'X' - 'A' + 1:
-        CutText();
-        return true;
-      case 'A' - 'A' + 1:
-        SelectAll();
-        return true;
-      case 'Z' - 'A' + 1:
-        if (bShift)
-          Redo();
-        else
-          Undo();
-        return true;
-      default:
-        if (nChar < 32)
-          return false;
-    }
-  }
-
-  if (IsReadOnly())
-    return true;
-
-  if (m_pEdit->IsSelected() && word == FWL_VKEY_Back)
-    word = FWL_VKEY_Unknown;
-
-  Clear();
-
-  switch (word) {
-    case FWL_VKEY_Back:
-      Backspace();
-      break;
-    case FWL_VKEY_Return:
-      InsertReturn();
-      break;
-    case FWL_VKEY_Unknown:
-      break;
-    default:
-      InsertWord(word, GetCharSet());
-      break;
-  }
-
-  return true;
-}
-
-bool CPWL_EditCtrl::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
-  CPWL_Wnd::OnLButtonDown(point, nFlag);
-
-  if (ClientHitTest(point)) {
-    if (m_bMouseDown)
-      InvalidateRect();
-
-    m_bMouseDown = true;
-    SetCapture();
-
-    m_pEdit->OnMouseDown(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-  }
-
-  return true;
-}
-
-bool CPWL_EditCtrl::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
-  CPWL_Wnd::OnLButtonUp(point, nFlag);
-
-  if (m_bMouseDown) {
-    // can receive keybord message
-    if (ClientHitTest(point) && !IsFocused())
-      SetFocus();
-
-    ReleaseCapture();
-    m_bMouseDown = false;
-  }
-
-  return true;
-}
-
-bool CPWL_EditCtrl::OnMouseMove(const CFX_PointF& point, uint32_t nFlag) {
-  CPWL_Wnd::OnMouseMove(point, nFlag);
-
-  if (m_bMouseDown)
-    m_pEdit->OnMouseMove(point, false, false);
-
-  return true;
-}
-
-CFX_FloatRect CPWL_EditCtrl::GetContentRect() const {
-  return m_pEdit->GetContentRect();
-}
-
-void CPWL_EditCtrl::SetEditCaret(bool bVisible) {
-  CFX_PointF ptHead;
-  CFX_PointF ptFoot;
-  if (bVisible)
-    GetCaretInfo(&ptHead, &ptFoot);
-
-  CPVT_WordPlace wpTemp = m_pEdit->GetCaretWordPlace();
-  IOnSetCaret(bVisible, ptHead, ptFoot, wpTemp);
-}
-
-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;
-  } 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;
-  }
-}
-
-void CPWL_EditCtrl::SetCaret(bool bVisible,
-                             const CFX_PointF& ptHead,
-                             const CFX_PointF& ptFoot) {
-  if (m_pEditCaret) {
-    if (!IsFocused() || m_pEdit->IsSelected())
-      bVisible = false;
-
-    m_pEditCaret->SetCaret(bVisible, ptHead, ptFoot);
-  }
-}
-
-CFX_WideString CPWL_EditCtrl::GetText() const {
-  return m_pEdit->GetText();
-}
-
-void CPWL_EditCtrl::SetSel(int32_t nStartChar, int32_t nEndChar) {
-  m_pEdit->SetSel(nStartChar, nEndChar);
-}
-
-void CPWL_EditCtrl::GetSel(int32_t& nStartChar, int32_t& nEndChar) const {
-  m_pEdit->GetSel(nStartChar, nEndChar);
-}
-
-void CPWL_EditCtrl::Clear() {
-  if (!IsReadOnly())
-    m_pEdit->Clear();
-}
-
-void CPWL_EditCtrl::SelectAll() {
-  m_pEdit->SelectAll();
-}
-
-void CPWL_EditCtrl::Paint() {
-  m_pEdit->Paint();
-}
-
-void CPWL_EditCtrl::EnableRefresh(bool bRefresh) {
-  m_pEdit->EnableRefresh(bRefresh);
-}
-
-int32_t CPWL_EditCtrl::GetCaret() const {
-  return m_pEdit->GetCaret();
-}
-
-void CPWL_EditCtrl::SetCaret(int32_t nPos) {
-  m_pEdit->SetCaret(nPos);
-}
-
-int32_t CPWL_EditCtrl::GetTotalWords() const {
-  return m_pEdit->GetTotalWords();
-}
-
-void CPWL_EditCtrl::SetScrollPos(const CFX_PointF& point) {
-  m_pEdit->SetScrollPos(point);
-}
-
-CFX_PointF CPWL_EditCtrl::GetScrollPos() const {
-  return m_pEdit->GetScrollPos();
-}
-
-CPDF_Font* CPWL_EditCtrl::GetCaretFont() const {
-  int32_t nFontIndex = 0;
-
-  CFX_Edit_Iterator* pIterator = m_pEdit->GetIterator();
-  pIterator->SetAt(m_pEdit->GetCaret());
-  CPVT_Word word;
-  CPVT_Section section;
-  if (pIterator->GetWord(word)) {
-    nFontIndex = word.nFontIndex;
-  } else if (HasFlag(PES_RICH)) {
-    if (pIterator->GetSection(section)) {
-      nFontIndex = section.WordProps.nFontIndex;
-    }
-  }
-
-  if (IPVT_FontMap* pFontMap = GetFontMap())
-    return pFontMap->GetPDFFont(nFontIndex);
-
-  return nullptr;
-}
-
-FX_FLOAT CPWL_EditCtrl::GetCaretFontSize() const {
-  FX_FLOAT fFontSize = GetFontSize();
-
-  CFX_Edit_Iterator* pIterator = m_pEdit->GetIterator();
-  pIterator->SetAt(m_pEdit->GetCaret());
-  CPVT_Word word;
-  CPVT_Section section;
-  if (pIterator->GetWord(word)) {
-    fFontSize = word.fFontSize;
-  } else if (HasFlag(PES_RICH)) {
-    if (pIterator->GetSection(section)) {
-      fFontSize = section.WordProps.fFontSize;
-    }
-  }
-
-  return fFontSize;
-}
-
-void CPWL_EditCtrl::SetText(const CFX_WideString& wsText) {
-  m_pEdit->SetText(wsText);
-}
-
-void CPWL_EditCtrl::CopyText() {}
-
-void CPWL_EditCtrl::PasteText() {}
-
-void CPWL_EditCtrl::CutText() {}
-
-void CPWL_EditCtrl::ShowVScrollBar(bool bShow) {}
-
-void CPWL_EditCtrl::InsertText(const CFX_WideString& wsText) {
-  if (!IsReadOnly())
-    m_pEdit->InsertText(wsText, FXFONT_DEFAULT_CHARSET);
-}
-
-void CPWL_EditCtrl::InsertWord(uint16_t word, int32_t nCharset) {
-  if (!IsReadOnly())
-    m_pEdit->InsertWord(word, nCharset);
-}
-
-void CPWL_EditCtrl::InsertReturn() {
-  if (!IsReadOnly())
-    m_pEdit->InsertReturn();
-}
-
-void CPWL_EditCtrl::Delete() {
-  if (!IsReadOnly())
-    m_pEdit->Delete();
-}
-
-void CPWL_EditCtrl::Backspace() {
-  if (!IsReadOnly())
-    m_pEdit->Backspace();
-}
-
-bool CPWL_EditCtrl::CanUndo() const {
-  return !IsReadOnly() && m_pEdit->CanUndo();
-}
-
-bool CPWL_EditCtrl::CanRedo() const {
-  return !IsReadOnly() && m_pEdit->CanRedo();
-}
-
-void CPWL_EditCtrl::Redo() {
-  if (CanRedo())
-    m_pEdit->Redo();
-}
-
-void CPWL_EditCtrl::Undo() {
-  if (CanUndo())
-    m_pEdit->Undo();
-}
-
-void CPWL_EditCtrl::IOnSetScrollInfoY(FX_FLOAT fPlateMin,
-                                      FX_FLOAT fPlateMax,
-                                      FX_FLOAT fContentMin,
-                                      FX_FLOAT fContentMax,
-                                      FX_FLOAT fSmallStep,
-                                      FX_FLOAT fBigStep) {
-  PWL_SCROLL_INFO Info;
-
-  Info.fPlateWidth = fPlateMax - fPlateMin;
-  Info.fContentMin = fContentMin;
-  Info.fContentMax = fContentMax;
-  Info.fSmallStep = fSmallStep;
-  Info.fBigStep = fBigStep;
-
-  OnNotify(this, PNM_SETSCROLLINFO, SBT_VSCROLL, (intptr_t)&Info);
-
-  if (IsFloatBigger(Info.fPlateWidth, Info.fContentMax - Info.fContentMin) ||
-      IsFloatEqual(Info.fPlateWidth, Info.fContentMax - Info.fContentMin)) {
-    ShowVScrollBar(false);
-  } else {
-    ShowVScrollBar(true);
-  }
-}
-
-void CPWL_EditCtrl::IOnSetScrollPosY(FX_FLOAT fy) {
-  OnNotify(this, PNM_SETSCROLLPOS, SBT_VSCROLL, (intptr_t)&fy);
-}
-
-void CPWL_EditCtrl::IOnSetCaret(bool bVisible,
-                                const CFX_PointF& ptHead,
-                                const CFX_PointF& ptFoot,
-                                const CPVT_WordPlace& place) {
-  PWL_CARET_INFO cInfo;
-  cInfo.bVisible = bVisible;
-  cInfo.ptHead = ptHead;
-  cInfo.ptFoot = ptFoot;
-
-  OnNotify(this, PNM_SETCARETINFO, (intptr_t)&cInfo, (intptr_t) nullptr);
-}
-
-void CPWL_EditCtrl::IOnCaretChange(const CPVT_SecProps& secProps,
-                                   const CPVT_WordProps& wordProps) {}
-
-void CPWL_EditCtrl::IOnContentChange(const CFX_FloatRect& rcContent) {}
-
-void CPWL_EditCtrl::IOnInvalidateRect(CFX_FloatRect* pRect) {
-  InvalidateRect(pRect);
-}
-
-int32_t CPWL_EditCtrl::GetCharSet() const {
-  return m_nCharSet < 0 ? FXFONT_DEFAULT_CHARSET : m_nCharSet;
-}
-
-void CPWL_EditCtrl::GetTextRange(const CFX_FloatRect& rect,
-                                 int32_t& nStartChar,
-                                 int32_t& nEndChar) const {
-  nStartChar = m_pEdit->WordPlaceToWordIndex(
-      m_pEdit->SearchWordPlace(CFX_PointF(rect.left, rect.top)));
-  nEndChar = m_pEdit->WordPlaceToWordIndex(
-      m_pEdit->SearchWordPlace(CFX_PointF(rect.right, rect.bottom)));
-}
-
-CFX_WideString CPWL_EditCtrl::GetText(int32_t& nStartChar,
-                                      int32_t& nEndChar) const {
-  CPVT_WordPlace wpStart = m_pEdit->WordIndexToWordPlace(nStartChar);
-  CPVT_WordPlace wpEnd = m_pEdit->WordIndexToWordPlace(nEndChar);
-  return m_pEdit->GetRangeText(CPVT_WordRange(wpStart, wpEnd));
-}
-
-void CPWL_EditCtrl::SetReadyToInput() {
-  if (m_bMouseDown) {
-    ReleaseCapture();
-    m_bMouseDown = false;
-  }
-}
diff --git a/fpdfsdk/pdfwindow/PWL_EditCtrl.h b/fpdfsdk/pdfwindow/PWL_EditCtrl.h
deleted file mode 100644
index 498570b..0000000
--- a/fpdfsdk/pdfwindow/PWL_EditCtrl.h
+++ /dev/null
@@ -1,141 +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 FPDFSDK_PDFWINDOW_PWL_EDITCTRL_H_
-#define FPDFSDK_PDFWINDOW_PWL_EDITCTRL_H_
-
-#include <memory>
-
-#include "core/fxcrt/fx_string.h"
-#include "fpdfsdk/fxedit/fx_edit.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-
-class CFX_Edit;
-class CPWL_Caret;
-class CPWL_Edit;
-class CPWL_EditCtrl;
-struct CPVT_SecProps;
-struct CPVT_WordPlace;
-struct CPVT_WordProps;
-struct CPVT_WordRange;
-
-enum PWL_EDIT_ALIGNFORMAT_H { PEAH_LEFT = 0, PEAH_MIDDLE, PEAH_RIGHT };
-
-enum PWL_EDIT_ALIGNFORMAT_V { PEAV_TOP = 0, PEAV_CENTER, PEAV_BOTTOM };
-
-class CPWL_EditCtrl : public CPWL_Wnd {
-  friend class CPWL_Edit_Notify;
-
- public:
-  CPWL_EditCtrl();
-  ~CPWL_EditCtrl() override;
-
-  CFX_FloatRect GetContentRect() const;
-
-  CFX_WideString GetText() const;
-  void SetSel(int32_t nStartChar, int32_t nEndChar);
-  void GetSel(int32_t& nStartChar, int32_t& nEndChar) const;
-  void GetTextRange(const CFX_FloatRect& rect,
-                    int32_t& nStartChar,
-                    int32_t& nEndChar) const;
-  CFX_WideString GetText(int32_t& nStartChar, int32_t& nEndChar) const;
-  void Clear();
-  void SelectAll();
-
-  int32_t GetCaret() const;
-  void SetCaret(int32_t nPos);
-  int32_t GetTotalWords() const;
-
-  void Paint();
-
-  void EnableRefresh(bool bRefresh);
-  CFX_PointF GetScrollPos() const;
-  void SetScrollPos(const CFX_PointF& point);
-
-  void SetCharSet(uint8_t nCharSet) { m_nCharSet = nCharSet; }
-  int32_t GetCharSet() const;
-
-  void SetCodePage(int32_t nCodePage) { m_nCodePage = nCodePage; }
-  int32_t GetCodePage() const { return m_nCodePage; }
-
-  CPDF_Font* GetCaretFont() const;
-  FX_FLOAT GetCaretFontSize() const;
-
-  bool CanUndo() const;
-  bool CanRedo() const;
-  void Redo();
-  void Undo();
-
-  void SetReadyToInput();
-
-  // CPWL_Wnd
-  void OnCreate(PWL_CREATEPARAM& cp) override;
-  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_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,
-                intptr_t lParam = 0) override;
-  void CreateChildWnd(const PWL_CREATEPARAM& cp) override;
-  void RePosChildWnd() override;
-  void SetFontSize(FX_FLOAT fFontSize) override;
-  FX_FLOAT GetFontSize() const override;
-  void SetCursor() override;
-
-  void IOnSetScrollInfoY(FX_FLOAT fPlateMin,
-                         FX_FLOAT fPlateMax,
-                         FX_FLOAT fContentMin,
-                         FX_FLOAT fContentMax,
-                         FX_FLOAT fSmallStep,
-                         FX_FLOAT fBigStep);
-  void IOnSetScrollPosY(FX_FLOAT fy);
-  void IOnSetCaret(bool bVisible,
-                   const CFX_PointF& ptHead,
-                   const CFX_PointF& ptFoot,
-                   const CPVT_WordPlace& place);
-  void IOnCaretChange(const CPVT_SecProps& secProps,
-                      const CPVT_WordProps& wordProps);
-  void IOnContentChange(const CFX_FloatRect& rcContent);
-  void IOnInvalidateRect(CFX_FloatRect* pRect);
-
- protected:
-  void InsertText(const CFX_WideString& wsText);
-  void SetText(const CFX_WideString& wsText);
-  void CopyText();
-  void PasteText();
-  void CutText();
-  void ShowVScrollBar(bool bShow);
-  void InsertWord(uint16_t word, int32_t nCharset);
-  void InsertReturn();
-
-  bool IsWndHorV();
-
-  void Delete();
-  void Backspace();
-
-  void GetCaretInfo(CFX_PointF* ptHead, CFX_PointF* ptFoot) const;
-  void SetCaret(bool bVisible,
-                const CFX_PointF& ptHead,
-                const CFX_PointF& ptFoot);
-
-  void SetEditCaret(bool bVisible);
-
-  std::unique_ptr<CFX_Edit> m_pEdit;
-  CPWL_Caret* m_pEditCaret;
-  bool m_bMouseDown;
-
- private:
-  void CreateEditCaret(const PWL_CREATEPARAM& cp);
-
-  int32_t m_nCharSet;
-  int32_t m_nCodePage;
-};
-
-#endif  // FPDFSDK_PDFWINDOW_PWL_EDITCTRL_H_
diff --git a/fpdfsdk/pdfwindow/PWL_FontMap.cpp b/fpdfsdk/pdfwindow/PWL_FontMap.cpp
deleted file mode 100644
index 9a2962c..0000000
--- a/fpdfsdk/pdfwindow/PWL_FontMap.cpp
+++ /dev/null
@@ -1,426 +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/pdfwindow/PWL_FontMap.h"
-
-#include <utility>
-
-#include "core/fpdfapi/cpdf_modulemgr.h"
-#include "core/fpdfapi/font/cpdf_font.h"
-#include "core/fpdfapi/font/cpdf_fontencoding.h"
-#include "core/fpdfapi/parser/cpdf_document.h"
-#include "core/fpdfapi/parser/cpdf_parser.h"
-#include "core/fpdfdoc/ipvt_fontmap.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-#include "third_party/base/ptr_util.h"
-#include "third_party/base/stl_util.h"
-
-namespace {
-
-const char kDefaultFontName[] = "Helvetica";
-
-const char* const g_sDEStandardFontName[] = {"Courier",
-                                             "Courier-Bold",
-                                             "Courier-BoldOblique",
-                                             "Courier-Oblique",
-                                             "Helvetica",
-                                             "Helvetica-Bold",
-                                             "Helvetica-BoldOblique",
-                                             "Helvetica-Oblique",
-                                             "Times-Roman",
-                                             "Times-Bold",
-                                             "Times-Italic",
-                                             "Times-BoldItalic",
-                                             "Symbol",
-                                             "ZapfDingbats"};
-
-}  // namespace
-
-CPWL_FontMap::CPWL_FontMap(CFX_SystemHandler* pSystemHandler)
-    : m_pSystemHandler(pSystemHandler) {
-  ASSERT(m_pSystemHandler);
-}
-
-CPWL_FontMap::~CPWL_FontMap() {
-  Empty();
-}
-
-CPDF_Document* CPWL_FontMap::GetDocument() {
-  if (!m_pPDFDoc) {
-    if (CPDF_ModuleMgr::Get()) {
-      m_pPDFDoc = pdfium::MakeUnique<CPDF_Document>(nullptr);
-      m_pPDFDoc->CreateNewDoc();
-    }
-  }
-
-  return m_pPDFDoc.get();
-}
-
-CPDF_Font* CPWL_FontMap::GetPDFFont(int32_t nFontIndex) {
-  if (nFontIndex >= 0 && nFontIndex < pdfium::CollectionSize<int32_t>(m_Data)) {
-    if (m_Data[nFontIndex])
-      return m_Data[nFontIndex]->pFont;
-  }
-  return nullptr;
-}
-
-CFX_ByteString CPWL_FontMap::GetPDFFontAlias(int32_t nFontIndex) {
-  if (nFontIndex >= 0 && nFontIndex < pdfium::CollectionSize<int32_t>(m_Data)) {
-    if (m_Data[nFontIndex])
-      return m_Data[nFontIndex]->sFontName;
-  }
-  return CFX_ByteString();
-}
-
-bool CPWL_FontMap::KnowWord(int32_t nFontIndex, uint16_t word) {
-  if (nFontIndex >= 0 && nFontIndex < pdfium::CollectionSize<int32_t>(m_Data)) {
-    if (m_Data[nFontIndex])
-      return CharCodeFromUnicode(nFontIndex, word) >= 0;
-  }
-  return false;
-}
-
-int32_t CPWL_FontMap::GetWordFontIndex(uint16_t word,
-                                       int32_t nCharset,
-                                       int32_t nFontIndex) {
-  if (nFontIndex > 0) {
-    if (KnowWord(nFontIndex, word))
-      return nFontIndex;
-  } else {
-    if (const CPWL_FontMap_Data* pData = GetFontMapData(0)) {
-      if (nCharset == FXFONT_DEFAULT_CHARSET ||
-          pData->nCharset == FXFONT_SYMBOL_CHARSET ||
-          nCharset == pData->nCharset) {
-        if (KnowWord(0, word))
-          return 0;
-      }
-    }
-  }
-
-  int32_t nNewFontIndex =
-      GetFontIndex(GetNativeFontName(nCharset), nCharset, true);
-  if (nNewFontIndex >= 0) {
-    if (KnowWord(nNewFontIndex, word))
-      return nNewFontIndex;
-  }
-  nNewFontIndex =
-      GetFontIndex("Arial Unicode MS", FXFONT_DEFAULT_CHARSET, false);
-  if (nNewFontIndex >= 0) {
-    if (KnowWord(nNewFontIndex, word))
-      return nNewFontIndex;
-  }
-  return -1;
-}
-
-int32_t CPWL_FontMap::CharCodeFromUnicode(int32_t nFontIndex, uint16_t word) {
-  if (nFontIndex < 0 || nFontIndex >= pdfium::CollectionSize<int32_t>(m_Data))
-    return -1;
-
-  CPWL_FontMap_Data* pData = m_Data[nFontIndex].get();
-  if (!pData || !pData->pFont)
-    return -1;
-
-  if (pData->pFont->IsUnicodeCompatible())
-    return pData->pFont->CharCodeFromUnicode(word);
-
-  return word < 0xFF ? word : -1;
-}
-
-CFX_ByteString CPWL_FontMap::GetNativeFontName(int32_t nCharset) {
-  for (const auto& pData : m_NativeFont) {
-    if (pData && pData->nCharset == nCharset)
-      return pData->sFontName;
-  }
-
-  CFX_ByteString sNew = GetNativeFont(nCharset);
-  if (sNew.IsEmpty())
-    return CFX_ByteString();
-
-  auto pNewData = pdfium::MakeUnique<CPWL_FontMap_Native>();
-  pNewData->nCharset = nCharset;
-  pNewData->sFontName = sNew;
-  m_NativeFont.push_back(std::move(pNewData));
-  return sNew;
-}
-
-void CPWL_FontMap::Empty() {
-  m_Data.clear();
-  m_NativeFont.clear();
-}
-
-void CPWL_FontMap::Initialize() {
-  GetFontIndex(kDefaultFontName, FXFONT_ANSI_CHARSET, false);
-}
-
-bool CPWL_FontMap::IsStandardFont(const CFX_ByteString& sFontName) {
-  for (size_t i = 0; i < FX_ArraySize(g_sDEStandardFontName); ++i) {
-    if (sFontName == g_sDEStandardFontName[i])
-      return true;
-  }
-
-  return false;
-}
-
-int32_t CPWL_FontMap::FindFont(const CFX_ByteString& sFontName,
-                               int32_t nCharset) {
-  int32_t i = 0;
-  for (const auto& pData : m_Data) {
-    if (pData &&
-        (nCharset == FXFONT_DEFAULT_CHARSET || nCharset == pData->nCharset) &&
-        (sFontName.IsEmpty() || pData->sFontName == sFontName)) {
-      return i;
-    }
-    ++i;
-  }
-  return -1;
-}
-
-int32_t CPWL_FontMap::GetFontIndex(const CFX_ByteString& sFontName,
-                                   int32_t nCharset,
-                                   bool bFind) {
-  int32_t nFontIndex = FindFont(EncodeFontAlias(sFontName, nCharset), nCharset);
-  if (nFontIndex >= 0)
-    return nFontIndex;
-
-  CFX_ByteString sAlias;
-  CPDF_Font* pFont = nullptr;
-  if (bFind)
-    pFont = FindFontSameCharset(sAlias, nCharset);
-
-  if (!pFont) {
-    CFX_ByteString sTemp = sFontName;
-    pFont = AddFontToDocument(GetDocument(), sTemp, nCharset);
-    sAlias = EncodeFontAlias(sTemp, nCharset);
-  }
-  AddedFont(pFont, sAlias);
-  return AddFontData(pFont, sAlias, nCharset);
-}
-
-CPDF_Font* CPWL_FontMap::FindFontSameCharset(CFX_ByteString& sFontAlias,
-                                             int32_t nCharset) {
-  return nullptr;
-}
-
-int32_t CPWL_FontMap::AddFontData(CPDF_Font* pFont,
-                                  const CFX_ByteString& sFontAlias,
-                                  int32_t nCharset) {
-  auto pNewData = pdfium::MakeUnique<CPWL_FontMap_Data>();
-  pNewData->pFont = pFont;
-  pNewData->sFontName = sFontAlias;
-  pNewData->nCharset = nCharset;
-  m_Data.push_back(std::move(pNewData));
-  return pdfium::CollectionSize<int32_t>(m_Data) - 1;
-}
-
-void CPWL_FontMap::AddedFont(CPDF_Font* pFont,
-                             const CFX_ByteString& sFontAlias) {}
-
-CFX_ByteString CPWL_FontMap::GetNativeFont(int32_t nCharset) {
-  if (nCharset == FXFONT_DEFAULT_CHARSET)
-    nCharset = GetNativeCharset();
-
-  CFX_ByteString sFontName = GetDefaultFontByCharset(nCharset);
-  if (!m_pSystemHandler->FindNativeTrueTypeFont(sFontName))
-    return CFX_ByteString();
-
-  return sFontName;
-}
-
-CPDF_Font* CPWL_FontMap::AddFontToDocument(CPDF_Document* pDoc,
-                                           CFX_ByteString& sFontName,
-                                           uint8_t nCharset) {
-  if (IsStandardFont(sFontName))
-    return AddStandardFont(pDoc, sFontName);
-
-  return AddSystemFont(pDoc, sFontName, nCharset);
-}
-
-CPDF_Font* CPWL_FontMap::AddStandardFont(CPDF_Document* pDoc,
-                                         CFX_ByteString& sFontName) {
-  if (!pDoc)
-    return nullptr;
-
-  CPDF_Font* pFont = nullptr;
-
-  if (sFontName == "ZapfDingbats") {
-    pFont = pDoc->AddStandardFont(sFontName.c_str(), nullptr);
-  } else {
-    CPDF_FontEncoding fe(PDFFONT_ENCODING_WINANSI);
-    pFont = pDoc->AddStandardFont(sFontName.c_str(), &fe);
-  }
-
-  return pFont;
-}
-
-CPDF_Font* CPWL_FontMap::AddSystemFont(CPDF_Document* pDoc,
-                                       CFX_ByteString& sFontName,
-                                       uint8_t nCharset) {
-  if (!pDoc)
-    return nullptr;
-
-  if (sFontName.IsEmpty())
-    sFontName = GetNativeFont(nCharset);
-  if (nCharset == FXFONT_DEFAULT_CHARSET)
-    nCharset = GetNativeCharset();
-
-  return m_pSystemHandler->AddNativeTrueTypeFontToPDF(pDoc, sFontName,
-                                                      nCharset);
-}
-
-CFX_ByteString CPWL_FontMap::EncodeFontAlias(const CFX_ByteString& sFontName,
-                                             int32_t nCharset) {
-  CFX_ByteString sPostfix;
-  sPostfix.Format("_%02X", nCharset);
-  return EncodeFontAlias(sFontName) + sPostfix;
-}
-
-CFX_ByteString CPWL_FontMap::EncodeFontAlias(const CFX_ByteString& sFontName) {
-  CFX_ByteString sRet = sFontName;
-  sRet.Remove(' ');
-  return sRet;
-}
-
-const CPWL_FontMap_Data* CPWL_FontMap::GetFontMapData(int32_t nIndex) const {
-  if (nIndex < 0 || nIndex >= pdfium::CollectionSize<int32_t>(m_Data))
-    return nullptr;
-
-  return m_Data[nIndex].get();
-}
-
-int32_t CPWL_FontMap::GetNativeCharset() {
-  uint8_t nCharset = FXFONT_ANSI_CHARSET;
-  int32_t iCodePage = FXSYS_GetACP();
-  switch (iCodePage) {
-    case 932:  // Japan
-      nCharset = FXFONT_SHIFTJIS_CHARSET;
-      break;
-    case 936:  // Chinese (PRC, Singapore)
-      nCharset = FXFONT_GB2312_CHARSET;
-      break;
-    case 950:  // Chinese (Taiwan; Hong Kong SAR, PRC)
-      nCharset = FXFONT_GB2312_CHARSET;
-      break;
-    case 1252:  // Windows 3.1 Latin 1 (US, Western Europe)
-      nCharset = FXFONT_ANSI_CHARSET;
-      break;
-    case 874:  // Thai
-      nCharset = FXFONT_THAI_CHARSET;
-      break;
-    case 949:  // Korean
-      nCharset = FXFONT_HANGUL_CHARSET;
-      break;
-    case 1200:  // Unicode (BMP of ISO 10646)
-      nCharset = FXFONT_ANSI_CHARSET;
-      break;
-    case 1250:  // Windows 3.1 Eastern European
-      nCharset = FXFONT_EASTEUROPE_CHARSET;
-      break;
-    case 1251:  // Windows 3.1 Cyrillic
-      nCharset = FXFONT_RUSSIAN_CHARSET;
-      break;
-    case 1253:  // Windows 3.1 Greek
-      nCharset = FXFONT_GREEK_CHARSET;
-      break;
-    case 1254:  // Windows 3.1 Turkish
-      nCharset = FXFONT_TURKISH_CHARSET;
-      break;
-    case 1255:  // Hebrew
-      nCharset = FXFONT_HEBREW_CHARSET;
-      break;
-    case 1256:  // Arabic
-      nCharset = FXFONT_ARABIC_CHARSET;
-      break;
-    case 1257:  // Baltic
-      nCharset = FXFONT_BALTIC_CHARSET;
-      break;
-    case 1258:  // Vietnamese
-      nCharset = FXFONT_VIETNAMESE_CHARSET;
-      break;
-    case 1361:  // Korean(Johab)
-      nCharset = FXFONT_JOHAB_CHARSET;
-      break;
-  }
-  return nCharset;
-}
-
-const FPDF_CharsetFontMap CPWL_FontMap::defaultTTFMap[] = {
-    {FXFONT_ANSI_CHARSET, "Helvetica"},
-    {FXFONT_GB2312_CHARSET, "SimSun"},
-    {FXFONT_CHINESEBIG5_CHARSET, "MingLiU"},
-    {FXFONT_SHIFTJIS_CHARSET, "MS Gothic"},
-    {FXFONT_HANGUL_CHARSET, "Batang"},
-    {FXFONT_RUSSIAN_CHARSET, "Arial"},
-#if _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_ || \
-    _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
-    {FXFONT_EASTEUROPE_CHARSET, "Arial"},
-#else
-    {FXFONT_EASTEUROPE_CHARSET, "Tahoma"},
-#endif
-    {FXFONT_ARABIC_CHARSET, "Arial"},
-    {-1, nullptr}};
-
-CFX_ByteString CPWL_FontMap::GetDefaultFontByCharset(int32_t nCharset) {
-  int i = 0;
-  while (defaultTTFMap[i].charset != -1) {
-    if (nCharset == defaultTTFMap[i].charset)
-      return defaultTTFMap[i].fontname;
-    ++i;
-  }
-  return "";
-}
-
-int32_t CPWL_FontMap::CharSetFromUnicode(uint16_t word, int32_t nOldCharset) {
-  // to avoid CJK Font to show ASCII
-  if (word < 0x7F)
-    return FXFONT_ANSI_CHARSET;
-  // follow the old charset
-  if (nOldCharset != FXFONT_DEFAULT_CHARSET)
-    return nOldCharset;
-
-  // find new charset
-  if ((word >= 0x4E00 && word <= 0x9FA5) ||
-      (word >= 0xE7C7 && word <= 0xE7F3) ||
-      (word >= 0x3000 && word <= 0x303F) ||
-      (word >= 0x2000 && word <= 0x206F)) {
-    return FXFONT_GB2312_CHARSET;
-  }
-
-  if (((word >= 0x3040) && (word <= 0x309F)) ||
-      ((word >= 0x30A0) && (word <= 0x30FF)) ||
-      ((word >= 0x31F0) && (word <= 0x31FF)) ||
-      ((word >= 0xFF00) && (word <= 0xFFEF))) {
-    return FXFONT_SHIFTJIS_CHARSET;
-  }
-
-  if (((word >= 0xAC00) && (word <= 0xD7AF)) ||
-      ((word >= 0x1100) && (word <= 0x11FF)) ||
-      ((word >= 0x3130) && (word <= 0x318F))) {
-    return FXFONT_HANGUL_CHARSET;
-  }
-
-  if (word >= 0x0E00 && word <= 0x0E7F)
-    return FXFONT_THAI_CHARSET;
-
-  if ((word >= 0x0370 && word <= 0x03FF) || (word >= 0x1F00 && word <= 0x1FFF))
-    return FXFONT_GREEK_CHARSET;
-
-  if ((word >= 0x0600 && word <= 0x06FF) || (word >= 0xFB50 && word <= 0xFEFC))
-    return FXFONT_ARABIC_CHARSET;
-
-  if (word >= 0x0590 && word <= 0x05FF)
-    return FXFONT_HEBREW_CHARSET;
-
-  if (word >= 0x0400 && word <= 0x04FF)
-    return FXFONT_RUSSIAN_CHARSET;
-
-  if (word >= 0x0100 && word <= 0x024F)
-    return FXFONT_EASTEUROPE_CHARSET;
-
-  if (word >= 0x1E00 && word <= 0x1EFF)
-    return FXFONT_VIETNAMESE_CHARSET;
-
-  return FXFONT_ANSI_CHARSET;
-}
diff --git a/fpdfsdk/pdfwindow/PWL_FontMap.h b/fpdfsdk/pdfwindow/PWL_FontMap.h
deleted file mode 100644
index c14fcd7..0000000
--- a/fpdfsdk/pdfwindow/PWL_FontMap.h
+++ /dev/null
@@ -1,95 +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 FPDFSDK_PDFWINDOW_PWL_FONTMAP_H_
-#define FPDFSDK_PDFWINDOW_PWL_FONTMAP_H_
-
-#include <memory>
-#include <vector>
-
-#include "core/fpdfdoc/ipvt_fontmap.h"
-#include "core/fxge/fx_font.h"
-#include "fpdfsdk/fxedit/fx_edit.h"
-#include "public/fpdf_sysfontinfo.h"
-
-class CPDF_Document;
-class CFX_SystemHandler;
-
-struct CPWL_FontMap_Data {
-  CPDF_Font* pFont;
-  int32_t nCharset;
-  CFX_ByteString sFontName;
-};
-
-struct CPWL_FontMap_Native {
-  int32_t nCharset;
-  CFX_ByteString sFontName;
-};
-
-class CPWL_FontMap : public IPVT_FontMap {
- public:
-  explicit CPWL_FontMap(CFX_SystemHandler* pSystemHandler);
-  ~CPWL_FontMap() override;
-
-  // IPVT_FontMap
-  CPDF_Font* GetPDFFont(int32_t nFontIndex) override;
-  CFX_ByteString GetPDFFontAlias(int32_t nFontIndex) override;
-  int32_t GetWordFontIndex(uint16_t word,
-                           int32_t nCharset,
-                           int32_t nFontIndex) override;
-  int32_t CharCodeFromUnicode(int32_t nFontIndex, uint16_t word) override;
-  int32_t CharSetFromUnicode(uint16_t word, int32_t nOldCharset) override;
-
-  const CPWL_FontMap_Data* GetFontMapData(int32_t nIndex) const;
-  static int32_t GetNativeCharset();
-  CFX_ByteString GetNativeFontName(int32_t nCharset);
-
-  static CFX_ByteString GetDefaultFontByCharset(int32_t nCharset);
-  static const FPDF_CharsetFontMap defaultTTFMap[];
-
- protected:
-  virtual void Initialize();
-  virtual CPDF_Document* GetDocument();
-  virtual CPDF_Font* FindFontSameCharset(CFX_ByteString& sFontAlias,
-                                         int32_t nCharset);
-  virtual void AddedFont(CPDF_Font* pFont, const CFX_ByteString& sFontAlias);
-
-  bool KnowWord(int32_t nFontIndex, uint16_t word);
-
-  void Empty();
-  int32_t GetFontIndex(const CFX_ByteString& sFontName,
-                       int32_t nCharset,
-                       bool bFind);
-  int32_t AddFontData(CPDF_Font* pFont,
-                      const CFX_ByteString& sFontAlias,
-                      int32_t nCharset = FXFONT_DEFAULT_CHARSET);
-
-  CFX_ByteString EncodeFontAlias(const CFX_ByteString& sFontName,
-                                 int32_t nCharset);
-  CFX_ByteString EncodeFontAlias(const CFX_ByteString& sFontName);
-
-  std::vector<std::unique_ptr<CPWL_FontMap_Data>> m_Data;
-  std::vector<std::unique_ptr<CPWL_FontMap_Native>> m_NativeFont;
-
- private:
-  int32_t FindFont(const CFX_ByteString& sFontName,
-                   int32_t nCharset = FXFONT_DEFAULT_CHARSET);
-
-  CFX_ByteString GetNativeFont(int32_t nCharset);
-  CPDF_Font* AddFontToDocument(CPDF_Document* pDoc,
-                               CFX_ByteString& sFontName,
-                               uint8_t nCharset);
-  bool IsStandardFont(const CFX_ByteString& sFontName);
-  CPDF_Font* AddStandardFont(CPDF_Document* pDoc, CFX_ByteString& sFontName);
-  CPDF_Font* AddSystemFont(CPDF_Document* pDoc,
-                           CFX_ByteString& sFontName,
-                           uint8_t nCharset);
-
-  std::unique_ptr<CPDF_Document> m_pPDFDoc;
-  CFX_SystemHandler* const m_pSystemHandler;
-};
-
-#endif  // FPDFSDK_PDFWINDOW_PWL_FONTMAP_H_
diff --git a/fpdfsdk/pdfwindow/PWL_Icon.cpp b/fpdfsdk/pdfwindow/PWL_Icon.cpp
deleted file mode 100644
index b0d0c76..0000000
--- a/fpdfsdk/pdfwindow/PWL_Icon.cpp
+++ /dev/null
@@ -1,225 +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/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"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-
-CPWL_Image::CPWL_Image() : m_pPDFStream(nullptr) {}
-
-CPWL_Image::~CPWL_Image() {}
-
-CFX_ByteString CPWL_Image::GetImageAppStream() {
-  CFX_ByteTextBuf sAppStream;
-
-  CFX_ByteString sAlias = GetImageAlias();
-  CFX_FloatRect rcPlate = GetClientRect();
-  CFX_Matrix mt;
-  mt.SetReverse(GetImageMatrix());
-
-  FX_FLOAT fHScale = 1.0f;
-  FX_FLOAT fVScale = 1.0f;
-  GetScale(fHScale, fVScale);
-
-  FX_FLOAT fx = 0.0f;
-  FX_FLOAT fy = 0.0f;
-  GetImageOffset(fx, fy);
-
-  if (m_pPDFStream && sAlias.GetLength() > 0) {
-    sAppStream << "q\n";
-    sAppStream << rcPlate.left << " " << rcPlate.bottom << " "
-               << rcPlate.right - rcPlate.left << " "
-               << rcPlate.top - rcPlate.bottom << " re W n\n";
-
-    sAppStream << fHScale << " 0 0 " << fVScale << " " << rcPlate.left + fx
-               << " " << rcPlate.bottom + fy << " 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";
-  }
-
-  return sAppStream.MakeString();
-}
-
-void CPWL_Image::SetPDFStream(CPDF_Stream* pStream) {
-  m_pPDFStream = pStream;
-}
-
-CPDF_Stream* CPWL_Image::GetPDFStream() {
-  return m_pPDFStream;
-}
-
-void CPWL_Image::GetImageSize(FX_FLOAT& fWidth, FX_FLOAT& fHeight) {
-  fWidth = 0.0f;
-  fHeight = 0.0f;
-
-  if (m_pPDFStream) {
-    if (CPDF_Dictionary* pDict = m_pPDFStream->GetDict()) {
-      CFX_FloatRect rect = pDict->GetRectFor("BBox");
-
-      fWidth = rect.right - rect.left;
-      fHeight = rect.top - rect.bottom;
-    }
-  }
-}
-
-CFX_Matrix CPWL_Image::GetImageMatrix() {
-  if (m_pPDFStream) {
-    if (CPDF_Dictionary* pDict = m_pPDFStream->GetDict()) {
-      return pDict->GetMatrixFor("Matrix");
-    }
-  }
-
-  return CFX_Matrix();
-}
-
-CFX_ByteString CPWL_Image::GetImageAlias() {
-  if (!m_sImageAlias.IsEmpty())
-    return m_sImageAlias;
-
-  if (m_pPDFStream) {
-    if (CPDF_Dictionary* pDict = m_pPDFStream->GetDict()) {
-      return pDict->GetStringFor("Name");
-    }
-  }
-
-  return CFX_ByteString();
-}
-
-void CPWL_Image::SetImageAlias(const FX_CHAR* sImageAlias) {
-  m_sImageAlias = sImageAlias;
-}
-
-void CPWL_Image::GetScale(FX_FLOAT& fHScale, FX_FLOAT& fVScale) {
-  fHScale = 1.0f;
-  fVScale = 1.0f;
-}
-
-void CPWL_Image::GetImageOffset(FX_FLOAT& x, FX_FLOAT& y) {
-  x = 0.0f;
-  y = 0.0f;
-}
-
-CPWL_Icon::CPWL_Icon() : m_pIconFit(nullptr) {}
-
-CPWL_Icon::~CPWL_Icon() {}
-
-CPDF_IconFit* CPWL_Icon::GetIconFit() {
-  return m_pIconFit;
-}
-
-int32_t CPWL_Icon::GetScaleMethod() {
-  if (m_pIconFit)
-    return m_pIconFit->GetScaleMethod();
-
-  return 0;
-}
-
-bool CPWL_Icon::IsProportionalScale() {
-  if (m_pIconFit)
-    return m_pIconFit->IsProportionalScale();
-
-  return false;
-}
-
-void CPWL_Icon::GetIconPosition(FX_FLOAT& fLeft, FX_FLOAT& fBottom) {
-  if (m_pIconFit) {
-    fLeft = 0.0f;
-    fBottom = 0.0f;
-    CPDF_Array* pA = m_pIconFit->GetDict()
-                         ? m_pIconFit->GetDict()->GetArrayFor("A")
-                         : nullptr;
-    if (pA) {
-      size_t dwCount = pA->GetCount();
-      if (dwCount > 0)
-        fLeft = pA->GetNumberAt(0);
-      if (dwCount > 1)
-        fBottom = pA->GetNumberAt(1);
-    }
-  } else {
-    fLeft = 0.0f;
-    fBottom = 0.0f;
-  }
-}
-
-void CPWL_Icon::GetScale(FX_FLOAT& fHScale, FX_FLOAT& fVScale) {
-  fHScale = 1.0f;
-  fVScale = 1.0f;
-
-  if (m_pPDFStream) {
-    FX_FLOAT fImageWidth, fImageHeight;
-    FX_FLOAT fPlateWidth, fPlateHeight;
-
-    CFX_FloatRect rcPlate = GetClientRect();
-    fPlateWidth = rcPlate.right - rcPlate.left;
-    fPlateHeight = rcPlate.top - rcPlate.bottom;
-
-    GetImageSize(fImageWidth, fImageHeight);
-
-    int32_t nScaleMethod = GetScaleMethod();
-
-    switch (nScaleMethod) {
-      default:
-      case 0:
-        fHScale = fPlateWidth / std::max(fImageWidth, 1.0f);
-        fVScale = fPlateHeight / std::max(fImageHeight, 1.0f);
-        break;
-      case 1:
-        if (fPlateWidth < fImageWidth)
-          fHScale = fPlateWidth / std::max(fImageWidth, 1.0f);
-        if (fPlateHeight < fImageHeight)
-          fVScale = fPlateHeight / std::max(fImageHeight, 1.0f);
-        break;
-      case 2:
-        if (fPlateWidth > fImageWidth)
-          fHScale = fPlateWidth / std::max(fImageWidth, 1.0f);
-        if (fPlateHeight > fImageHeight)
-          fVScale = fPlateHeight / std::max(fImageHeight, 1.0f);
-        break;
-      case 3:
-        break;
-    }
-
-    FX_FLOAT fMinScale;
-    if (IsProportionalScale()) {
-      fMinScale = std::min(fHScale, fVScale);
-      fHScale = fMinScale;
-      fVScale = fMinScale;
-    }
-  }
-}
-
-void CPWL_Icon::GetImageOffset(FX_FLOAT& x, FX_FLOAT& y) {
-  FX_FLOAT fLeft, fBottom;
-
-  GetIconPosition(fLeft, fBottom);
-  x = 0.0f;
-  y = 0.0f;
-
-  FX_FLOAT fImageWidth, fImageHeight;
-  GetImageSize(fImageWidth, fImageHeight);
-
-  FX_FLOAT fHScale, fVScale;
-  GetScale(fHScale, fVScale);
-
-  FX_FLOAT fImageFactWidth = fImageWidth * fHScale;
-  FX_FLOAT fImageFactHeight = fImageHeight * fVScale;
-
-  FX_FLOAT fPlateWidth, fPlateHeight;
-  CFX_FloatRect rcPlate = GetClientRect();
-  fPlateWidth = rcPlate.right - rcPlate.left;
-  fPlateHeight = rcPlate.top - rcPlate.bottom;
-
-  x = (fPlateWidth - fImageFactWidth) * fLeft;
-  y = (fPlateHeight - fImageFactHeight) * fBottom;
-}
diff --git a/fpdfsdk/pdfwindow/PWL_Icon.h b/fpdfsdk/pdfwindow/PWL_Icon.h
deleted file mode 100644
index 4b62db4..0000000
--- a/fpdfsdk/pdfwindow/PWL_Icon.h
+++ /dev/null
@@ -1,57 +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 FPDFSDK_PDFWINDOW_PWL_ICON_H_
-#define FPDFSDK_PDFWINDOW_PWL_ICON_H_
-
-#include "core/fxcrt/fx_string.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-
-class CPWL_Image : public CPWL_Wnd {
- public:
-  CPWL_Image();
-  ~CPWL_Image() override;
-
-  virtual CFX_ByteString GetImageAppStream();
-
-  virtual void GetScale(FX_FLOAT& fHScale, FX_FLOAT& fVScale);
-  virtual void GetImageOffset(FX_FLOAT& x, FX_FLOAT& y);
-  virtual CPDF_Stream* GetPDFStream();
-
- public:
-  void SetPDFStream(CPDF_Stream* pStream);
-  void GetImageSize(FX_FLOAT& fWidth, FX_FLOAT& fHeight);
-  CFX_Matrix GetImageMatrix();
-  CFX_ByteString GetImageAlias();
-  void SetImageAlias(const FX_CHAR* sImageAlias);
-
- protected:
-  CPDF_Stream* m_pPDFStream;
-  CFX_ByteString m_sImageAlias;
-};
-
-class CPWL_Icon : public CPWL_Image {
- public:
-  CPWL_Icon();
-  ~CPWL_Icon() override;
-
-  virtual CPDF_IconFit* GetIconFit();
-
-  // CPWL_Image
-  void GetScale(FX_FLOAT& fHScale, FX_FLOAT& fVScale) override;
-  void GetImageOffset(FX_FLOAT& x, FX_FLOAT& y) override;
-
-  int32_t GetScaleMethod();
-  bool IsProportionalScale();
-  void GetIconPosition(FX_FLOAT& fLeft, FX_FLOAT& fBottom);
-
-  void SetIconFit(CPDF_IconFit* pIconFit) { m_pIconFit = pIconFit; }
-
- private:
-  CPDF_IconFit* m_pIconFit;
-};
-
-#endif  // FPDFSDK_PDFWINDOW_PWL_ICON_H_
diff --git a/fpdfsdk/pdfwindow/PWL_ListBox.cpp b/fpdfsdk/pdfwindow/PWL_ListBox.cpp
deleted file mode 100644
index ed96e20..0000000
--- a/fpdfsdk/pdfwindow/PWL_ListBox.cpp
+++ /dev/null
@@ -1,459 +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/pdfwindow/PWL_ListBox.h"
-
-#include "fpdfsdk/fxedit/fxet_edit.h"
-#include "fpdfsdk/fxedit/fxet_list.h"
-#include "fpdfsdk/pdfwindow/PWL_Edit.h"
-#include "fpdfsdk/pdfwindow/PWL_EditCtrl.h"
-#include "fpdfsdk/pdfwindow/PWL_ScrollBar.h"
-#include "fpdfsdk/pdfwindow/PWL_Utils.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-#include "public/fpdf_fwlevent.h"
-#include "third_party/base/ptr_util.h"
-
-CPWL_List_Notify::CPWL_List_Notify(CPWL_ListBox* pList) : m_pList(pList) {
-  ASSERT(m_pList);
-}
-
-CPWL_List_Notify::~CPWL_List_Notify() {}
-
-void CPWL_List_Notify::IOnSetScrollInfoY(FX_FLOAT fPlateMin,
-                                         FX_FLOAT fPlateMax,
-                                         FX_FLOAT fContentMin,
-                                         FX_FLOAT fContentMax,
-                                         FX_FLOAT fSmallStep,
-                                         FX_FLOAT fBigStep) {
-  PWL_SCROLL_INFO Info;
-
-  Info.fPlateWidth = fPlateMax - fPlateMin;
-  Info.fContentMin = fContentMin;
-  Info.fContentMax = fContentMax;
-  Info.fSmallStep = fSmallStep;
-  Info.fBigStep = fBigStep;
-
-  m_pList->OnNotify(m_pList, PNM_SETSCROLLINFO, SBT_VSCROLL, (intptr_t)&Info);
-
-  if (CPWL_ScrollBar* pScroll = m_pList->GetVScrollBar()) {
-    if (IsFloatBigger(Info.fPlateWidth, Info.fContentMax - Info.fContentMin) ||
-        IsFloatEqual(Info.fPlateWidth, Info.fContentMax - Info.fContentMin)) {
-      if (pScroll->IsVisible()) {
-        pScroll->SetVisible(false);
-        m_pList->RePosChildWnd();
-      }
-    } else {
-      if (!pScroll->IsVisible()) {
-        pScroll->SetVisible(true);
-        m_pList->RePosChildWnd();
-      }
-    }
-  }
-}
-
-void CPWL_List_Notify::IOnSetScrollPosY(FX_FLOAT fy) {
-  m_pList->OnNotify(m_pList, PNM_SETSCROLLPOS, SBT_VSCROLL, (intptr_t)&fy);
-}
-
-void CPWL_List_Notify::IOnInvalidateRect(CFX_FloatRect* pRect) {
-  m_pList->InvalidateRect(pRect);
-}
-
-CPWL_ListBox::CPWL_ListBox()
-    : m_pList(new CFX_ListCtrl),
-      m_bMouseDown(false),
-      m_bHoverSel(false),
-      m_pFillerNotify(nullptr) {}
-
-CPWL_ListBox::~CPWL_ListBox() {
-}
-
-CFX_ByteString CPWL_ListBox::GetClassName() const {
-  return "CPWL_ListBox";
-}
-
-void CPWL_ListBox::OnCreated() {
-  m_pList->SetFontMap(GetFontMap());
-  m_pListNotify = pdfium::MakeUnique<CPWL_List_Notify>(this);
-  m_pList->SetNotify(m_pListNotify.get());
-
-  SetHoverSel(HasFlag(PLBS_HOVERSEL));
-  m_pList->SetMultipleSel(HasFlag(PLBS_MULTIPLESEL));
-  m_pList->SetFontSize(GetCreationParam().fFontSize);
-
-  m_bHoverSel = HasFlag(PLBS_HOVERSEL);
-}
-
-void CPWL_ListBox::OnDestroy() {
-  // Make sure the notifier is removed from the list as we are about to
-  // destroy the notifier and don't want to leave a dangling pointer.
-  m_pList->SetNotify(nullptr);
-  m_pListNotify.reset();
-}
-
-void CPWL_ListBox::GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) {
-  CPWL_Wnd::GetThisAppearanceStream(sAppStream);
-
-  CFX_ByteTextBuf sListItems;
-
-  CFX_FloatRect rcPlate = m_pList->GetPlateRect();
-  for (int32_t i = 0, sz = m_pList->GetCount(); i < sz; i++) {
-    CFX_FloatRect rcItem = m_pList->GetItemRect(i);
-
-    if (rcItem.bottom > rcPlate.top || rcItem.top < rcPlate.bottom)
-      continue;
-
-    CFX_PointF ptOffset(rcItem.left, (rcItem.top + rcItem.bottom) * 0.5f);
-    if (m_pList->IsItemSelected(i)) {
-      sListItems << CPWL_Utils::GetRectFillAppStream(rcItem,
-                                                     PWL_DEFAULT_SELBACKCOLOR)
-                        .AsStringC();
-      CFX_ByteString sItem =
-          CPWL_Utils::GetEditAppStream(m_pList->GetItemEdit(i), ptOffset);
-      if (sItem.GetLength() > 0) {
-        sListItems << "BT\n"
-                   << CPWL_Utils::GetColorAppStream(PWL_DEFAULT_SELTEXTCOLOR)
-                          .AsStringC()
-                   << sItem.AsStringC() << "ET\n";
-      }
-    } else {
-      CFX_ByteString sItem =
-          CPWL_Utils::GetEditAppStream(m_pList->GetItemEdit(i), ptOffset);
-      if (sItem.GetLength() > 0) {
-        sListItems << "BT\n"
-                   << CPWL_Utils::GetColorAppStream(GetTextColor()).AsStringC()
-                   << sItem.AsStringC() << "ET\n";
-      }
-    }
-  }
-
-  if (sListItems.GetLength() > 0) {
-    CFX_ByteTextBuf sClip;
-    CFX_FloatRect rcClient = GetClientRect();
-
-    sClip << "q\n";
-    sClip << rcClient.left << " " << rcClient.bottom << " "
-          << rcClient.right - rcClient.left << " "
-          << rcClient.top - rcClient.bottom << " re W n\n";
-
-    sClip << sListItems << "Q\n";
-
-    sAppStream << "/Tx BMC\n" << sClip << "EMC\n";
-  }
-}
-
-void CPWL_ListBox::DrawThisAppearance(CFX_RenderDevice* pDevice,
-                                      CFX_Matrix* pUser2Device) {
-  CPWL_Wnd::DrawThisAppearance(pDevice, pUser2Device);
-
-  CFX_FloatRect rcPlate = m_pList->GetPlateRect();
-  CFX_FloatRect rcList = GetListRect();
-  CFX_FloatRect rcClient = GetClientRect();
-
-  for (int32_t i = 0, sz = m_pList->GetCount(); i < sz; i++) {
-    CFX_FloatRect rcItem = m_pList->GetItemRect(i);
-    if (rcItem.bottom > rcPlate.top || rcItem.top < rcPlate.bottom)
-      continue;
-
-    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())
-        rcItem.Intersect(rcList);
-      else
-        rcItem.Intersect(rcClient);
-    }
-
-    if (m_pList->IsItemSelected(i)) {
-      CFX_SystemHandler* pSysHandler = GetSystemHandler();
-      if (pSysHandler && pSysHandler->IsSelectionImplemented()) {
-        CFX_Edit::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i),
-                           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), rcList, ptOffset,
-                           nullptr, pSysHandler, m_pFormFiller);
-      }
-    } else {
-      CFX_SystemHandler* pSysHandler = GetSystemHandler();
-      CFX_Edit::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i),
-                         GetTextColor().ToFXColor(255), rcList, ptOffset,
-                         nullptr, pSysHandler, nullptr);
-    }
-  }
-}
-
-bool CPWL_ListBox::OnKeyDown(uint16_t nChar, uint32_t nFlag) {
-  CPWL_Wnd::OnKeyDown(nChar, nFlag);
-
-  switch (nChar) {
-    default:
-      return false;
-    case FWL_VKEY_Up:
-    case FWL_VKEY_Down:
-    case FWL_VKEY_Home:
-    case FWL_VKEY_Left:
-    case FWL_VKEY_End:
-    case FWL_VKEY_Right:
-      break;
-  }
-
-  switch (nChar) {
-    case FWL_VKEY_Up:
-      m_pList->OnVK_UP(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-      break;
-    case FWL_VKEY_Down:
-      m_pList->OnVK_DOWN(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-      break;
-    case FWL_VKEY_Home:
-      m_pList->OnVK_HOME(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-      break;
-    case FWL_VKEY_Left:
-      m_pList->OnVK_LEFT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-      break;
-    case FWL_VKEY_End:
-      m_pList->OnVK_END(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-      break;
-    case FWL_VKEY_Right:
-      m_pList->OnVK_RIGHT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-      break;
-    case FWL_VKEY_Delete:
-      break;
-  }
-
-  bool bExit = false;
-  OnNotifySelChanged(true, bExit, nFlag);
-
-  return true;
-}
-
-bool CPWL_ListBox::OnChar(uint16_t nChar, uint32_t nFlag) {
-  CPWL_Wnd::OnChar(nChar, nFlag);
-
-  if (!m_pList->OnChar(nChar, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)))
-    return false;
-
-  bool bExit = false;
-  OnNotifySelChanged(true, bExit, nFlag);
-
-  return true;
-}
-
-bool CPWL_ListBox::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
-  CPWL_Wnd::OnLButtonDown(point, nFlag);
-
-  if (ClientHitTest(point)) {
-    m_bMouseDown = true;
-    SetFocus();
-    SetCapture();
-
-    m_pList->OnMouseDown(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-  }
-
-  return true;
-}
-
-bool CPWL_ListBox::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
-  CPWL_Wnd::OnLButtonUp(point, nFlag);
-
-  if (m_bMouseDown) {
-    ReleaseCapture();
-    m_bMouseDown = false;
-  }
-
-  bool bExit = false;
-  OnNotifySelChanged(false, bExit, nFlag);
-
-  return true;
-}
-
-void CPWL_ListBox::SetHoverSel(bool bHoverSel) {
-  m_bHoverSel = bHoverSel;
-}
-
-bool CPWL_ListBox::OnMouseMove(const CFX_PointF& point, uint32_t nFlag) {
-  CPWL_Wnd::OnMouseMove(point, nFlag);
-
-  if (m_bHoverSel && !IsCaptureMouse() && ClientHitTest(point))
-    m_pList->Select(m_pList->GetItemIndex(point));
-  if (m_bMouseDown)
-    m_pList->OnMouseMove(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-
-  return true;
-}
-
-void CPWL_ListBox::OnNotify(CPWL_Wnd* pWnd,
-                            uint32_t msg,
-                            intptr_t wParam,
-                            intptr_t lParam) {
-  CPWL_Wnd::OnNotify(pWnd, msg, wParam, lParam);
-
-  FX_FLOAT fPos;
-
-  switch (msg) {
-    case PNM_SETSCROLLINFO:
-      switch (wParam) {
-        case SBT_VSCROLL:
-          if (CPWL_Wnd* pChild = GetVScrollBar()) {
-            pChild->OnNotify(pWnd, PNM_SETSCROLLINFO, wParam, lParam);
-          }
-          break;
-      }
-      break;
-    case PNM_SETSCROLLPOS:
-      switch (wParam) {
-        case SBT_VSCROLL:
-          if (CPWL_Wnd* pChild = GetVScrollBar()) {
-            pChild->OnNotify(pWnd, PNM_SETSCROLLPOS, wParam, lParam);
-          }
-          break;
-      }
-      break;
-    case PNM_SCROLLWINDOW:
-      fPos = *(FX_FLOAT*)lParam;
-      switch (wParam) {
-        case SBT_VSCROLL:
-          m_pList->SetScrollPos(CFX_PointF(0, fPos));
-          break;
-      }
-      break;
-  }
-}
-
-void CPWL_ListBox::KillFocus() {
-  CPWL_Wnd::KillFocus();
-}
-
-void CPWL_ListBox::RePosChildWnd() {
-  CPWL_Wnd::RePosChildWnd();
-
-  m_pList->SetPlateRect(GetListRect());
-}
-
-void CPWL_ListBox::OnNotifySelChanged(bool bKeyDown,
-                                      bool& bExit,
-                                      uint32_t nFlag) {
-  if (!m_pFillerNotify)
-    return;
-
-  bool bRC = true;
-  CFX_WideString swChange = GetText();
-  CFX_WideString strChangeEx;
-  int nSelStart = 0;
-  int nSelEnd = swChange.GetLength();
-  m_pFillerNotify->OnBeforeKeyStroke(GetAttachedData(), swChange, strChangeEx,
-                                     nSelStart, nSelEnd, bKeyDown, bRC, bExit,
-                                     nFlag);
-}
-
-CFX_FloatRect CPWL_ListBox::GetFocusRect() const {
-  if (m_pList->IsMultipleSel()) {
-    CFX_FloatRect rcCaret = m_pList->GetItemRect(m_pList->GetCaret());
-    rcCaret.Intersect(GetClientRect());
-    return rcCaret;
-  }
-
-  return CPWL_Wnd::GetFocusRect();
-}
-
-void CPWL_ListBox::AddString(const CFX_WideString& str) {
-  m_pList->AddString(str);
-}
-
-CFX_WideString CPWL_ListBox::GetText() const {
-  return m_pList->GetText();
-}
-
-void CPWL_ListBox::SetFontSize(FX_FLOAT fFontSize) {
-  m_pList->SetFontSize(fFontSize);
-}
-
-FX_FLOAT CPWL_ListBox::GetFontSize() const {
-  return m_pList->GetFontSize();
-}
-
-void CPWL_ListBox::Select(int32_t nItemIndex) {
-  m_pList->Select(nItemIndex);
-}
-
-void CPWL_ListBox::SetCaret(int32_t nItemIndex) {
-  m_pList->SetCaret(nItemIndex);
-}
-
-void CPWL_ListBox::SetTopVisibleIndex(int32_t nItemIndex) {
-  m_pList->SetTopItem(nItemIndex);
-}
-
-void CPWL_ListBox::ScrollToListItem(int32_t nItemIndex) {
-  m_pList->ScrollToListItem(nItemIndex);
-}
-
-void CPWL_ListBox::ResetContent() {
-  m_pList->Empty();
-}
-
-void CPWL_ListBox::Reset() {
-  m_pList->Cancel();
-}
-
-bool CPWL_ListBox::IsMultipleSel() const {
-  return m_pList->IsMultipleSel();
-}
-
-int32_t CPWL_ListBox::GetCaretIndex() const {
-  return m_pList->GetCaret();
-}
-
-int32_t CPWL_ListBox::GetCurSel() const {
-  return m_pList->GetSelect();
-}
-
-bool CPWL_ListBox::IsItemSelected(int32_t nItemIndex) const {
-  return m_pList->IsItemSelected(nItemIndex);
-}
-
-int32_t CPWL_ListBox::GetTopVisibleIndex() const {
-  m_pList->ScrollToListItem(m_pList->GetFirstSelected());
-  return m_pList->GetTopItem();
-}
-
-int32_t CPWL_ListBox::GetCount() const {
-  return m_pList->GetCount();
-}
-
-int32_t CPWL_ListBox::FindNext(int32_t nIndex, FX_WCHAR nChar) const {
-  return m_pList->FindNext(nIndex, nChar);
-}
-
-CFX_FloatRect CPWL_ListBox::GetContentRect() const {
-  return m_pList->GetContentRect();
-}
-
-FX_FLOAT CPWL_ListBox::GetFirstHeight() const {
-  return m_pList->GetFirstHeight();
-}
-
-CFX_FloatRect CPWL_ListBox::GetListRect() const {
-  return CPWL_Utils::DeflateRect(
-      GetWindowRect(), (FX_FLOAT)(GetBorderWidth() + GetInnerBorderWidth()));
-}
-
-bool CPWL_ListBox::OnMouseWheel(short zDelta,
-                                const CFX_PointF& point,
-                                uint32_t nFlag) {
-  if (zDelta < 0)
-    m_pList->OnVK_DOWN(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-  else
-    m_pList->OnVK_UP(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
-
-  bool bExit = false;
-  OnNotifySelChanged(false, bExit, nFlag);
-  return true;
-}
diff --git a/fpdfsdk/pdfwindow/PWL_ListBox.h b/fpdfsdk/pdfwindow/PWL_ListBox.h
deleted file mode 100644
index f9108a1..0000000
--- a/fpdfsdk/pdfwindow/PWL_ListBox.h
+++ /dev/null
@@ -1,117 +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 FPDFSDK_PDFWINDOW_PWL_LISTBOX_H_
-#define FPDFSDK_PDFWINDOW_PWL_LISTBOX_H_
-
-#include <memory>
-
-#include "fpdfsdk/fxedit/fx_edit.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-
-class CFX_ListCtrl;
-class CPWL_List_Notify;
-class CPWL_ListBox;
-class IPWL_Filler_Notify;
-struct CPVT_SecProps;
-struct CPVT_WordPlace;
-struct CPVT_WordProps;
-
-class CPWL_List_Notify {
- public:
-  explicit CPWL_List_Notify(CPWL_ListBox* pList);
-  ~CPWL_List_Notify();
-
-  void IOnSetScrollInfoY(FX_FLOAT fPlateMin,
-                         FX_FLOAT fPlateMax,
-                         FX_FLOAT fContentMin,
-                         FX_FLOAT fContentMax,
-                         FX_FLOAT fSmallStep,
-                         FX_FLOAT fBigStep);
-  void IOnSetScrollPosY(FX_FLOAT fy);
-  void IOnInvalidateRect(CFX_FloatRect* pRect);
-
-  void IOnSetCaret(bool bVisible,
-                   const CFX_PointF& ptHead,
-                   const CFX_PointF& ptFoot,
-                   const CPVT_WordPlace& place);
-
- private:
-  CPWL_ListBox* m_pList;
-};
-
-class CPWL_ListBox : public CPWL_Wnd {
- public:
-  CPWL_ListBox();
-  ~CPWL_ListBox() override;
-
-  // CPWL_Wnd
-  CFX_ByteString GetClassName() const override;
-  void OnCreated() override;
-  void OnDestroy() override;
-  void GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) override;
-  void DrawThisAppearance(CFX_RenderDevice* pDevice,
-                          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_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_PointF& point,
-                    uint32_t nFlag) override;
-  void KillFocus() override;
-  void OnNotify(CPWL_Wnd* pWnd,
-                uint32_t msg,
-                intptr_t wParam = 0,
-                intptr_t lParam = 0) override;
-  void RePosChildWnd() override;
-  CFX_FloatRect GetFocusRect() const override;
-  void SetFontSize(FX_FLOAT fFontSize) override;
-  FX_FLOAT GetFontSize() const override;
-
-  virtual CFX_WideString GetText() const;
-
-  void OnNotifySelChanged(bool bKeyDown, bool& bExit, uint32_t nFlag);
-
-  void AddString(const CFX_WideString& str);
-  void SetTopVisibleIndex(int32_t nItemIndex);
-  void ScrollToListItem(int32_t nItemIndex);
-  void ResetContent();
-  void Reset();
-  void Select(int32_t nItemIndex);
-  void SetCaret(int32_t nItemIndex);
-  void SetHoverSel(bool bHoverSel);
-
-  int32_t GetCount() const;
-  bool IsMultipleSel() const;
-  int32_t GetCaretIndex() const;
-  int32_t GetCurSel() const;
-  bool IsItemSelected(int32_t nItemIndex) const;
-  int32_t GetTopVisibleIndex() const;
-  int32_t FindNext(int32_t nIndex, FX_WCHAR nChar) const;
-  CFX_FloatRect GetContentRect() const;
-  FX_FLOAT GetFirstHeight() const;
-  CFX_FloatRect GetListRect() const;
-
-  void SetFillerNotify(IPWL_Filler_Notify* pNotify) {
-    m_pFillerNotify = pNotify;
-  }
-
-  void AttachFFLData(CFFL_FormFiller* pData) { m_pFormFiller = pData; }
-
- protected:
-  std::unique_ptr<CFX_ListCtrl> m_pList;
-  std::unique_ptr<CPWL_List_Notify> m_pListNotify;
-  bool m_bMouseDown;
-  bool m_bHoverSel;
-  IPWL_Filler_Notify* m_pFillerNotify;
-
- private:
-  CFFL_FormFiller* m_pFormFiller;  // Not owned.
-};
-
-#endif  // FPDFSDK_PDFWINDOW_PWL_LISTBOX_H_
diff --git a/fpdfsdk/pdfwindow/PWL_ScrollBar.cpp b/fpdfsdk/pdfwindow/PWL_ScrollBar.cpp
deleted file mode 100644
index e379936..0000000
--- a/fpdfsdk/pdfwindow/PWL_ScrollBar.cpp
+++ /dev/null
@@ -1,1175 +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/pdfwindow/PWL_ScrollBar.h"
-
-#include "core/fxge/cfx_pathdata.h"
-#include "core/fxge/cfx_renderdevice.h"
-#include "fpdfsdk/pdfwindow/PWL_Utils.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-
-PWL_FLOATRANGE::PWL_FLOATRANGE() {
-  Default();
-}
-
-PWL_FLOATRANGE::PWL_FLOATRANGE(FX_FLOAT min, FX_FLOAT max) {
-  Set(min, max);
-}
-
-void PWL_FLOATRANGE::Default() {
-  fMin = 0;
-  fMax = 0;
-}
-
-void PWL_FLOATRANGE::Set(FX_FLOAT min, FX_FLOAT max) {
-  if (min > max) {
-    fMin = max;
-    fMax = min;
-  } else {
-    fMin = min;
-    fMax = max;
-  }
-}
-
-bool PWL_FLOATRANGE::In(FX_FLOAT x) const {
-  return (IsFloatBigger(x, fMin) || IsFloatEqual(x, fMin)) &&
-         (IsFloatSmaller(x, fMax) || IsFloatEqual(x, fMax));
-}
-
-FX_FLOAT PWL_FLOATRANGE::GetWidth() const {
-  return fMax - fMin;
-}
-
-PWL_SCROLL_PRIVATEDATA::PWL_SCROLL_PRIVATEDATA() {
-  Default();
-}
-
-void PWL_SCROLL_PRIVATEDATA::Default() {
-  ScrollRange.Default();
-  fScrollPos = ScrollRange.fMin;
-  fClientWidth = 0;
-  fBigStep = 10;
-  fSmallStep = 1;
-}
-
-void PWL_SCROLL_PRIVATEDATA::SetScrollRange(FX_FLOAT min, FX_FLOAT max) {
-  ScrollRange.Set(min, max);
-
-  if (IsFloatSmaller(fScrollPos, ScrollRange.fMin))
-    fScrollPos = ScrollRange.fMin;
-  if (IsFloatBigger(fScrollPos, ScrollRange.fMax))
-    fScrollPos = ScrollRange.fMax;
-}
-
-void PWL_SCROLL_PRIVATEDATA::SetClientWidth(FX_FLOAT width) {
-  fClientWidth = width;
-}
-
-void PWL_SCROLL_PRIVATEDATA::SetSmallStep(FX_FLOAT step) {
-  fSmallStep = step;
-}
-
-void PWL_SCROLL_PRIVATEDATA::SetBigStep(FX_FLOAT step) {
-  fBigStep = step;
-}
-
-bool PWL_SCROLL_PRIVATEDATA::SetPos(FX_FLOAT pos) {
-  if (ScrollRange.In(pos)) {
-    fScrollPos = pos;
-    return true;
-  }
-  return false;
-}
-
-void PWL_SCROLL_PRIVATEDATA::AddSmall() {
-  if (!SetPos(fScrollPos + fSmallStep))
-    SetPos(ScrollRange.fMax);
-}
-
-void PWL_SCROLL_PRIVATEDATA::SubSmall() {
-  if (!SetPos(fScrollPos - fSmallStep))
-    SetPos(ScrollRange.fMin);
-}
-
-void PWL_SCROLL_PRIVATEDATA::AddBig() {
-  if (!SetPos(fScrollPos + fBigStep))
-    SetPos(ScrollRange.fMax);
-}
-
-void PWL_SCROLL_PRIVATEDATA::SubBig() {
-  if (!SetPos(fScrollPos - fBigStep))
-    SetPos(ScrollRange.fMin);
-}
-
-CPWL_SBButton::CPWL_SBButton(PWL_SCROLLBAR_TYPE eScrollBarType,
-                             PWL_SBBUTTON_TYPE eButtonType) {
-  m_eScrollBarType = eScrollBarType;
-  m_eSBButtonType = eButtonType;
-
-  m_bMouseDown = false;
-}
-
-CPWL_SBButton::~CPWL_SBButton() {}
-
-CFX_ByteString CPWL_SBButton::GetClassName() const {
-  return "CPWL_SBButton";
-}
-
-void CPWL_SBButton::OnCreate(PWL_CREATEPARAM& cp) {
-  cp.eCursorType = FXCT_ARROW;
-}
-
-void CPWL_SBButton::GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) {
-  CPWL_Wnd::GetThisAppearanceStream(sAppStream);
-
-  if (!IsVisible())
-    return;
-
-  CFX_ByteTextBuf sButton;
-
-  CFX_FloatRect rectWnd = GetWindowRect();
-
-  if (rectWnd.IsEmpty())
-    return;
-
-  sAppStream << "q\n";
-
-  CFX_PointF ptCenter = GetCenterPoint();
-
-  switch (m_eScrollBarType) {
-    case SBT_HSCROLL:
-      switch (m_eSBButtonType) {
-        case PSBT_MIN: {
-          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) {
-            sButton << "0 g\n";
-            sButton << pt1.x << " " << pt1.y << " m\n";
-            sButton << pt2.x << " " << pt2.y << " l\n";
-            sButton << pt3.x << " " << pt3.y << " l\n";
-            sButton << pt1.x << " " << pt1.y << " l f\n";
-
-            sAppStream << sButton;
-          }
-        } break;
-        case PSBT_MAX: {
-          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) {
-            sButton << "0 g\n";
-            sButton << pt1.x << " " << pt1.y << " m\n";
-            sButton << pt2.x << " " << pt2.y << " l\n";
-            sButton << pt3.x << " " << pt3.y << " l\n";
-            sButton << pt1.x << " " << pt1.y << " l f\n";
-
-            sAppStream << sButton;
-          }
-        } break;
-        default:
-          break;
-      }
-      break;
-    case SBT_VSCROLL:
-      switch (m_eSBButtonType) {
-        case PSBT_MIN: {
-          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) {
-            sButton << "0 g\n";
-            sButton << pt1.x << " " << pt1.y << " m\n";
-            sButton << pt2.x << " " << pt2.y << " l\n";
-            sButton << pt3.x << " " << pt3.y << " l\n";
-            sButton << pt1.x << " " << pt1.y << " l f\n";
-
-            sAppStream << sButton;
-          }
-        } break;
-        case PSBT_MAX: {
-          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) {
-            sButton << "0 g\n";
-            sButton << pt1.x << " " << pt1.y << " m\n";
-            sButton << pt2.x << " " << pt2.y << " l\n";
-            sButton << pt3.x << " " << pt3.y << " l\n";
-            sButton << pt1.x << " " << pt1.y << " l f\n";
-
-            sAppStream << sButton;
-          }
-        } break;
-        default:
-          break;
-      }
-      break;
-    default:
-      break;
-  }
-
-  sAppStream << "Q\n";
-}
-
-void CPWL_SBButton::DrawThisAppearance(CFX_RenderDevice* pDevice,
-                                       CFX_Matrix* pUser2Device) {
-  if (!IsVisible())
-    return;
-
-  CFX_FloatRect rectWnd = GetWindowRect();
-  if (rectWnd.IsEmpty())
-    return;
-
-  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_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.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,
-                              PWL_DEFAULT_BLACKCOLOR.ToFXColor(nTransparency),
-                              0, FXFILL_ALTERNATE);
-          }
-        } break;
-        case PSBT_MAX: {
-          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.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,
-                              PWL_DEFAULT_BLACKCOLOR.ToFXColor(nTransparency),
-                              0, FXFILL_ALTERNATE);
-          }
-        } break;
-        default:
-          break;
-      }
-      break;
-    case SBT_VSCROLL:
-      switch (m_eSBButtonType) {
-        case PSBT_MIN: {
-          // draw border
-          CFX_FloatRect rcDraw = rectWnd;
-          CPWL_Utils::DrawStrokeRect(pDevice, pUser2Device, rcDraw,
-                                     ArgbEncode(nTransparency, 100, 100, 100),
-                                     0.0f);
-
-          // draw inner border
-          rcDraw = CPWL_Utils::DeflateRect(rectWnd, 0.5f);
-          CPWL_Utils::DrawStrokeRect(pDevice, pUser2Device, rcDraw,
-                                     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,
-                                   nTransparency, 80, 220);
-          else
-            CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcDraw,
-                                     ArgbEncode(255, 255, 255, 255));
-
-          // draw arrow
-
-          if (rectWnd.top - rectWnd.bottom > 6.0f) {
-            FX_FLOAT fX = rectWnd.left + 1.5f;
-            FX_FLOAT fY = rectWnd.bottom;
-            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(nTransparency, 255, 255, 255));
-            else
-              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(nTransparency, 100, 100, 100),
-                                     0.0f);
-
-          // draw inner border
-          rcDraw = CPWL_Utils::DeflateRect(rectWnd, 0.5f);
-          CPWL_Utils::DrawStrokeRect(pDevice, pUser2Device, rcDraw,
-                                     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,
-                                   nTransparency, 80, 220);
-          else
-            CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcDraw,
-                                     ArgbEncode(255, 255, 255, 255));
-
-          // draw arrow
-
-          if (rectWnd.top - rectWnd.bottom > 6.0f) {
-            FX_FLOAT fX = rectWnd.left + 1.5f;
-            FX_FLOAT fY = rectWnd.bottom;
-
-            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(nTransparency, 255, 255, 255));
-            else
-              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(nTransparency, 100, 100, 100),
-                                     0.0f);
-
-          // draw inner border
-          rcDraw = CPWL_Utils::DeflateRect(rectWnd, 0.5f);
-          CPWL_Utils::DrawStrokeRect(pDevice, pUser2Device, rcDraw,
-                                     ArgbEncode(nTransparency, 255, 255, 255),
-                                     1.0f);
-
-          if (IsEnabled()) {
-            // draw shadow effect
-
-            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(nTransparency, 210, 210, 210),
-                                       1.0f);
-
-            ptTop.x += 1.0f;
-            ptBottom.x += 1.0f;
-
-            CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparency, 220, 220, 220),
-                                       1.0f);
-
-            ptTop.x += 1.0f;
-            ptBottom.x += 1.0f;
-
-            CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparency, 240, 240, 240),
-                                       1.0f);
-
-            ptTop.x += 1.0f;
-            ptBottom.x += 1.0f;
-
-            CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparency, 240, 240, 240),
-                                       1.0f);
-
-            ptTop.x += 1.0f;
-            ptBottom.x += 1.0f;
-
-            CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparency, 210, 210, 210),
-                                       1.0f);
-
-            ptTop.x += 1.0f;
-            ptBottom.x += 1.0f;
-
-            CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparency, 180, 180, 180),
-                                       1.0f);
-
-            ptTop.x += 1.0f;
-            ptBottom.x += 1.0f;
-
-            CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparency, 150, 150, 150),
-                                       1.0f);
-
-            ptTop.x += 1.0f;
-            ptBottom.x += 1.0f;
-
-            CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparency, 150, 150, 150),
-                                       1.0f);
-
-            ptTop.x += 1.0f;
-            ptBottom.x += 1.0f;
-
-            CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparency, 180, 180, 180),
-                                       1.0f);
-
-            ptTop.x += 1.0f;
-            ptBottom.x += 1.0f;
-
-            CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom,
-                                       ArgbEncode(nTransparency, 210, 210, 210),
-                                       1.0f);
-          } else {
-            CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcDraw,
-                                     ArgbEncode(255, 255, 255, 255));
-          }
-
-          // draw friction
-
-          if (rectWnd.Height() > 8.0f) {
-            FX_COLORREF crStroke = ArgbEncode(nTransparency, 120, 120, 120);
-            if (!IsEnabled())
-              crStroke = PWL_DEFAULT_HEAVYGRAYCOLOR.ToFXColor(255);
-
-            FX_FLOAT nFrictionWidth = 5.0f;
-            FX_FLOAT nFrictionHeight = 5.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);
-
-            ptLeft.y += 2.0f;
-            ptRight.y += 2.0f;
-
-            CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptLeft, ptRight,
-                                       crStroke, 1.0f);
-
-            ptLeft.y += 2.0f;
-            ptRight.y += 2.0f;
-
-            CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptLeft, ptRight,
-                                       crStroke, 1.0f);
-          }
-        } break;
-        default:
-          break;
-      }
-      break;
-    default:
-      break;
-  }
-}
-
-bool CPWL_SBButton::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
-  CPWL_Wnd::OnLButtonDown(point, nFlag);
-
-  if (CPWL_Wnd* pParent = GetParentWindow())
-    pParent->OnNotify(this, PNM_LBUTTONDOWN, 0, (intptr_t)&point);
-
-  m_bMouseDown = true;
-  SetCapture();
-
-  return true;
-}
-
-bool CPWL_SBButton::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
-  CPWL_Wnd::OnLButtonUp(point, nFlag);
-
-  if (CPWL_Wnd* pParent = GetParentWindow())
-    pParent->OnNotify(this, PNM_LBUTTONUP, 0, (intptr_t)&point);
-
-  m_bMouseDown = false;
-  ReleaseCapture();
-
-  return true;
-}
-
-bool CPWL_SBButton::OnMouseMove(const CFX_PointF& point, uint32_t nFlag) {
-  CPWL_Wnd::OnMouseMove(point, nFlag);
-
-  if (CPWL_Wnd* pParent = GetParentWindow()) {
-    pParent->OnNotify(this, PNM_MOUSEMOVE, 0, (intptr_t)&point);
-  }
-
-  return true;
-}
-
-CPWL_ScrollBar::CPWL_ScrollBar(PWL_SCROLLBAR_TYPE sbType)
-    : m_sbType(sbType),
-      m_pMinButton(nullptr),
-      m_pMaxButton(nullptr),
-      m_pPosButton(nullptr),
-      m_bMouseDown(false),
-      m_bMinOrMax(false),
-      m_bNotifyForever(true) {}
-
-CPWL_ScrollBar::~CPWL_ScrollBar() {}
-
-CFX_ByteString CPWL_ScrollBar::GetClassName() const {
-  return "CPWL_ScrollBar";
-}
-
-void CPWL_ScrollBar::OnCreate(PWL_CREATEPARAM& cp) {
-  cp.eCursorType = FXCT_ARROW;
-}
-
-void CPWL_ScrollBar::RePosChildWnd() {
-  CFX_FloatRect rcClient = GetClientRect();
-  CFX_FloatRect rcMinButton, rcMaxButton;
-  FX_FLOAT fBWidth = 0;
-
-  switch (m_sbType) {
-    case SBT_HSCROLL:
-      if (rcClient.right - rcClient.left >
-          PWL_SCROLLBAR_BUTTON_WIDTH * 2 + PWL_SCROLLBAR_POSBUTTON_MINWIDTH +
-              2) {
-        rcMinButton = CFX_FloatRect(rcClient.left, rcClient.bottom,
-                                    rcClient.left + PWL_SCROLLBAR_BUTTON_WIDTH,
-                                    rcClient.top);
-        rcMaxButton =
-            CFX_FloatRect(rcClient.right - PWL_SCROLLBAR_BUTTON_WIDTH,
-                          rcClient.bottom, rcClient.right, rcClient.top);
-      } else {
-        fBWidth = (rcClient.right - rcClient.left -
-                   PWL_SCROLLBAR_POSBUTTON_MINWIDTH - 2) /
-                  2;
-
-        if (fBWidth > 0) {
-          rcMinButton = CFX_FloatRect(rcClient.left, rcClient.bottom,
-                                      rcClient.left + fBWidth, rcClient.top);
-          rcMaxButton = CFX_FloatRect(rcClient.right - fBWidth, rcClient.bottom,
-                                      rcClient.right, rcClient.top);
-        } else {
-          SetVisible(false);
-        }
-      }
-      break;
-    case SBT_VSCROLL:
-      if (IsFloatBigger(rcClient.top - rcClient.bottom,
-                        PWL_SCROLLBAR_BUTTON_WIDTH * 2 +
-                            PWL_SCROLLBAR_POSBUTTON_MINWIDTH + 2)) {
-        rcMinButton = CFX_FloatRect(rcClient.left,
-                                    rcClient.top - PWL_SCROLLBAR_BUTTON_WIDTH,
-                                    rcClient.right, rcClient.top);
-        rcMaxButton =
-            CFX_FloatRect(rcClient.left, rcClient.bottom, rcClient.right,
-                          rcClient.bottom + PWL_SCROLLBAR_BUTTON_WIDTH);
-      } else {
-        fBWidth = (rcClient.top - rcClient.bottom -
-                   PWL_SCROLLBAR_POSBUTTON_MINWIDTH - 2) /
-                  2;
-
-        if (IsFloatBigger(fBWidth, 0)) {
-          rcMinButton = CFX_FloatRect(rcClient.left, rcClient.top - fBWidth,
-                                      rcClient.right, rcClient.top);
-          rcMaxButton =
-              CFX_FloatRect(rcClient.left, rcClient.bottom, rcClient.right,
-                            rcClient.bottom + fBWidth);
-        } else {
-          SetVisible(false);
-        }
-      }
-      break;
-  }
-
-  if (m_pMinButton)
-    m_pMinButton->Move(rcMinButton, true, false);
-  if (m_pMaxButton)
-    m_pMaxButton->Move(rcMaxButton, true, false);
-  MovePosButton(false);
-}
-
-void CPWL_ScrollBar::GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) {
-  CFX_FloatRect rectWnd = GetWindowRect();
-
-  if (IsVisible() && !rectWnd.IsEmpty()) {
-    CFX_ByteTextBuf sButton;
-
-    sButton << "q\n";
-    sButton << "0 w\n"
-            << CPWL_Utils::GetColorAppStream(GetBackgroundColor(), true)
-                   .AsStringC();
-    sButton << rectWnd.left << " " << rectWnd.bottom << " "
-            << rectWnd.right - rectWnd.left << " "
-            << rectWnd.top - rectWnd.bottom << " re b Q\n";
-
-    sAppStream << sButton;
-  }
-}
-
-void CPWL_ScrollBar::DrawThisAppearance(CFX_RenderDevice* pDevice,
-                                        CFX_Matrix* pUser2Device) {
-  CFX_FloatRect rectWnd = GetWindowRect();
-
-  if (IsVisible() && !rectWnd.IsEmpty()) {
-    CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rectWnd,
-                             GetBackgroundColor(), GetTransparency());
-
-    CPWL_Utils::DrawStrokeLine(
-        pDevice, pUser2Device,
-        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_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_PointF& point, uint32_t nFlag) {
-  CPWL_Wnd::OnLButtonDown(point, nFlag);
-
-  if (HasFlag(PWS_AUTOTRANSPARENT)) {
-    if (GetTransparency() != 255) {
-      SetTransparency(255);
-      InvalidateRect();
-    }
-  }
-
-  CFX_FloatRect rcMinArea, rcMaxArea;
-
-  if (m_pPosButton && m_pPosButton->IsVisible()) {
-    CFX_FloatRect rcClient = GetClientRect();
-    CFX_FloatRect rcPosButton = m_pPosButton->GetWindowRect();
-
-    switch (m_sbType) {
-      case SBT_HSCROLL:
-        rcMinArea =
-            CFX_FloatRect(rcClient.left + PWL_SCROLLBAR_BUTTON_WIDTH,
-                          rcClient.bottom, rcPosButton.left, rcClient.top);
-        rcMaxArea = CFX_FloatRect(rcPosButton.right, rcClient.bottom,
-                                  rcClient.right - PWL_SCROLLBAR_BUTTON_WIDTH,
-                                  rcClient.top);
-
-        break;
-      case SBT_VSCROLL:
-        rcMinArea =
-            CFX_FloatRect(rcClient.left, rcPosButton.top, rcClient.right,
-                          rcClient.top - PWL_SCROLLBAR_BUTTON_WIDTH);
-        rcMaxArea = CFX_FloatRect(rcClient.left,
-                                  rcClient.bottom + PWL_SCROLLBAR_BUTTON_WIDTH,
-                                  rcClient.right, rcPosButton.bottom);
-        break;
-    }
-
-    rcMinArea.Normalize();
-    rcMaxArea.Normalize();
-
-    if (rcMinArea.Contains(point)) {
-      m_sData.SubBig();
-      MovePosButton(true);
-      NotifyScrollWindow();
-    }
-
-    if (rcMaxArea.Contains(point)) {
-      m_sData.AddBig();
-      MovePosButton(true);
-      NotifyScrollWindow();
-    }
-  }
-
-  return true;
-}
-
-bool CPWL_ScrollBar::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
-  CPWL_Wnd::OnLButtonUp(point, nFlag);
-
-  if (HasFlag(PWS_AUTOTRANSPARENT)) {
-    if (GetTransparency() != PWL_SCROLLBAR_TRANSPARENCY) {
-      SetTransparency(PWL_SCROLLBAR_TRANSPARENCY);
-      InvalidateRect();
-    }
-  }
-
-  EndTimer();
-  m_bMouseDown = false;
-
-  return true;
-}
-
-void CPWL_ScrollBar::OnNotify(CPWL_Wnd* pWnd,
-                              uint32_t msg,
-                              intptr_t wParam,
-                              intptr_t lParam) {
-  CPWL_Wnd::OnNotify(pWnd, msg, wParam, lParam);
-
-  switch (msg) {
-    case PNM_LBUTTONDOWN:
-      if (pWnd == m_pMinButton) {
-        OnMinButtonLBDown(*(CFX_PointF*)lParam);
-      }
-
-      if (pWnd == m_pMaxButton) {
-        OnMaxButtonLBDown(*(CFX_PointF*)lParam);
-      }
-
-      if (pWnd == m_pPosButton) {
-        OnPosButtonLBDown(*(CFX_PointF*)lParam);
-      }
-      break;
-    case PNM_LBUTTONUP:
-      if (pWnd == m_pMinButton) {
-        OnMinButtonLBUp(*(CFX_PointF*)lParam);
-      }
-
-      if (pWnd == m_pMaxButton) {
-        OnMaxButtonLBUp(*(CFX_PointF*)lParam);
-      }
-
-      if (pWnd == m_pPosButton) {
-        OnPosButtonLBUp(*(CFX_PointF*)lParam);
-      }
-      break;
-    case PNM_MOUSEMOVE:
-      if (pWnd == m_pMinButton) {
-        OnMinButtonMouseMove(*(CFX_PointF*)lParam);
-      }
-
-      if (pWnd == m_pMaxButton) {
-        OnMaxButtonMouseMove(*(CFX_PointF*)lParam);
-      }
-
-      if (pWnd == m_pPosButton) {
-        OnPosButtonMouseMove(*(CFX_PointF*)lParam);
-      }
-      break;
-    case PNM_SETSCROLLINFO: {
-      PWL_SCROLL_INFO* pInfo = reinterpret_cast<PWL_SCROLL_INFO*>(lParam);
-      if (pInfo && *pInfo != m_OriginInfo) {
-        m_OriginInfo = *pInfo;
-        FX_FLOAT fMax =
-            pInfo->fContentMax - pInfo->fContentMin - pInfo->fPlateWidth;
-        fMax = fMax > 0.0f ? fMax : 0.0f;
-        SetScrollRange(0, fMax, pInfo->fPlateWidth);
-        SetScrollStep(pInfo->fBigStep, pInfo->fSmallStep);
-      }
-    } break;
-    case PNM_SETSCROLLPOS: {
-      FX_FLOAT fPos = *(FX_FLOAT*)lParam;
-      switch (m_sbType) {
-        case SBT_HSCROLL:
-          fPos = fPos - m_OriginInfo.fContentMin;
-          break;
-        case SBT_VSCROLL:
-          fPos = m_OriginInfo.fContentMax - fPos;
-          break;
-      }
-      SetScrollPos(fPos);
-    } break;
-  }
-}
-
-void CPWL_ScrollBar::CreateButtons(const PWL_CREATEPARAM& cp) {
-  PWL_CREATEPARAM scp = cp;
-  scp.pParentWnd = this;
-  scp.dwBorderWidth = 2;
-  scp.nBorderStyle = BorderStyle::BEVELED;
-
-  scp.dwFlags =
-      PWS_VISIBLE | PWS_CHILD | PWS_BORDER | PWS_BACKGROUND | PWS_NOREFRESHCLIP;
-
-  if (!m_pMinButton) {
-    m_pMinButton = new CPWL_SBButton(m_sbType, PSBT_MIN);
-    m_pMinButton->Create(scp);
-  }
-
-  if (!m_pMaxButton) {
-    m_pMaxButton = new CPWL_SBButton(m_sbType, PSBT_MAX);
-    m_pMaxButton->Create(scp);
-  }
-
-  if (!m_pPosButton) {
-    m_pPosButton = new CPWL_SBButton(m_sbType, PSBT_POS);
-    m_pPosButton->SetVisible(false);
-    m_pPosButton->Create(scp);
-  }
-}
-
-FX_FLOAT CPWL_ScrollBar::GetScrollBarWidth() const {
-  if (!IsVisible())
-    return 0;
-
-  return PWL_SCROLLBAR_WIDTH;
-}
-
-void CPWL_ScrollBar::SetScrollRange(FX_FLOAT fMin,
-                                    FX_FLOAT fMax,
-                                    FX_FLOAT fClientWidth) {
-  if (m_pPosButton) {
-    m_sData.SetScrollRange(fMin, fMax);
-    m_sData.SetClientWidth(fClientWidth);
-
-    if (IsFloatSmaller(m_sData.ScrollRange.GetWidth(), 0.0f)) {
-      m_pPosButton->SetVisible(false);
-    } else {
-      m_pPosButton->SetVisible(true);
-      MovePosButton(true);
-    }
-  }
-}
-
-void CPWL_ScrollBar::SetScrollPos(FX_FLOAT fPos) {
-  FX_FLOAT fOldPos = m_sData.fScrollPos;
-
-  m_sData.SetPos(fPos);
-
-  if (!IsFloatEqual(m_sData.fScrollPos, fOldPos))
-    MovePosButton(true);
-}
-
-void CPWL_ScrollBar::SetScrollStep(FX_FLOAT fBigStep, FX_FLOAT fSmallStep) {
-  m_sData.SetBigStep(fBigStep);
-  m_sData.SetSmallStep(fSmallStep);
-}
-
-void CPWL_ScrollBar::MovePosButton(bool bRefresh) {
-  ASSERT(m_pMinButton);
-  ASSERT(m_pMaxButton);
-
-  if (m_pPosButton->IsVisible()) {
-    CFX_FloatRect rcClient;
-    CFX_FloatRect rcPosArea, rcPosButton;
-
-    rcClient = GetClientRect();
-    rcPosArea = GetScrollArea();
-
-    FX_FLOAT fLeft, fRight, fTop, fBottom;
-
-    switch (m_sbType) {
-      case SBT_HSCROLL:
-        fLeft = TrueToFace(m_sData.fScrollPos);
-        fRight = TrueToFace(m_sData.fScrollPos + m_sData.fClientWidth);
-
-        if (fRight - fLeft < PWL_SCROLLBAR_POSBUTTON_MINWIDTH)
-          fRight = fLeft + PWL_SCROLLBAR_POSBUTTON_MINWIDTH;
-
-        if (fRight > rcPosArea.right) {
-          fRight = rcPosArea.right;
-          fLeft = fRight - PWL_SCROLLBAR_POSBUTTON_MINWIDTH;
-        }
-
-        rcPosButton =
-            CFX_FloatRect(fLeft, rcPosArea.bottom, fRight, rcPosArea.top);
-
-        break;
-      case SBT_VSCROLL:
-        fBottom = TrueToFace(m_sData.fScrollPos + m_sData.fClientWidth);
-        fTop = TrueToFace(m_sData.fScrollPos);
-
-        if (IsFloatSmaller(fTop - fBottom, PWL_SCROLLBAR_POSBUTTON_MINWIDTH))
-          fBottom = fTop - PWL_SCROLLBAR_POSBUTTON_MINWIDTH;
-
-        if (IsFloatSmaller(fBottom, rcPosArea.bottom)) {
-          fBottom = rcPosArea.bottom;
-          fTop = fBottom + PWL_SCROLLBAR_POSBUTTON_MINWIDTH;
-        }
-
-        rcPosButton =
-            CFX_FloatRect(rcPosArea.left, fBottom, rcPosArea.right, fTop);
-
-        break;
-    }
-
-    m_pPosButton->Move(rcPosButton, true, bRefresh);
-  }
-}
-
-void CPWL_ScrollBar::OnMinButtonLBDown(const CFX_PointF& point) {
-  m_sData.SubSmall();
-  MovePosButton(true);
-  NotifyScrollWindow();
-
-  m_bMinOrMax = true;
-
-  EndTimer();
-  BeginTimer(100);
-}
-
-void CPWL_ScrollBar::OnMinButtonLBUp(const CFX_PointF& point) {}
-
-void CPWL_ScrollBar::OnMinButtonMouseMove(const CFX_PointF& point) {}
-
-void CPWL_ScrollBar::OnMaxButtonLBDown(const CFX_PointF& point) {
-  m_sData.AddSmall();
-  MovePosButton(true);
-  NotifyScrollWindow();
-
-  m_bMinOrMax = false;
-
-  EndTimer();
-  BeginTimer(100);
-}
-
-void CPWL_ScrollBar::OnMaxButtonLBUp(const CFX_PointF& point) {}
-
-void CPWL_ScrollBar::OnMaxButtonMouseMove(const CFX_PointF& point) {}
-
-void CPWL_ScrollBar::OnPosButtonLBDown(const CFX_PointF& point) {
-  m_bMouseDown = true;
-
-  if (m_pPosButton) {
-    CFX_FloatRect rcPosButton = m_pPosButton->GetWindowRect();
-
-    switch (m_sbType) {
-      case SBT_HSCROLL:
-        m_nOldPos = point.x;
-        m_fOldPosButton = rcPosButton.left;
-        break;
-      case SBT_VSCROLL:
-        m_nOldPos = point.y;
-        m_fOldPosButton = rcPosButton.top;
-        break;
-    }
-  }
-}
-
-void CPWL_ScrollBar::OnPosButtonLBUp(const CFX_PointF& point) {
-  if (m_bMouseDown) {
-    if (!m_bNotifyForever)
-      NotifyScrollWindow();
-  }
-  m_bMouseDown = false;
-}
-
-void CPWL_ScrollBar::OnPosButtonMouseMove(const CFX_PointF& point) {
-  FX_FLOAT fOldScrollPos = m_sData.fScrollPos;
-
-  FX_FLOAT fNewPos = 0;
-
-  switch (m_sbType) {
-    case SBT_HSCROLL:
-      if (FXSYS_fabs(point.x - m_nOldPos) < 1)
-        return;
-      fNewPos = FaceToTrue(m_fOldPosButton + point.x - m_nOldPos);
-      break;
-    case SBT_VSCROLL:
-      if (FXSYS_fabs(point.y - m_nOldPos) < 1)
-        return;
-      fNewPos = FaceToTrue(m_fOldPosButton + point.y - m_nOldPos);
-      break;
-  }
-
-  if (m_bMouseDown) {
-    switch (m_sbType) {
-      case SBT_HSCROLL:
-
-        if (IsFloatSmaller(fNewPos, m_sData.ScrollRange.fMin)) {
-          fNewPos = m_sData.ScrollRange.fMin;
-        }
-
-        if (IsFloatBigger(fNewPos, m_sData.ScrollRange.fMax)) {
-          fNewPos = m_sData.ScrollRange.fMax;
-        }
-
-        m_sData.SetPos(fNewPos);
-
-        break;
-      case SBT_VSCROLL:
-
-        if (IsFloatSmaller(fNewPos, m_sData.ScrollRange.fMin)) {
-          fNewPos = m_sData.ScrollRange.fMin;
-        }
-
-        if (IsFloatBigger(fNewPos, m_sData.ScrollRange.fMax)) {
-          fNewPos = m_sData.ScrollRange.fMax;
-        }
-
-        m_sData.SetPos(fNewPos);
-
-        break;
-    }
-
-    if (!IsFloatEqual(fOldScrollPos, m_sData.fScrollPos)) {
-      MovePosButton(true);
-
-      if (m_bNotifyForever)
-        NotifyScrollWindow();
-    }
-  }
-}
-
-void CPWL_ScrollBar::NotifyScrollWindow() {
-  if (CPWL_Wnd* pParent = GetParentWindow()) {
-    FX_FLOAT fPos;
-    switch (m_sbType) {
-      case SBT_HSCROLL:
-        fPos = m_OriginInfo.fContentMin + m_sData.fScrollPos;
-        break;
-      case SBT_VSCROLL:
-        fPos = m_OriginInfo.fContentMax - m_sData.fScrollPos;
-        break;
-    }
-    pParent->OnNotify(this, PNM_SCROLLWINDOW, (intptr_t)m_sbType,
-                      (intptr_t)&fPos);
-  }
-}
-
-CFX_FloatRect CPWL_ScrollBar::GetScrollArea() const {
-  CFX_FloatRect rcClient = GetClientRect();
-  CFX_FloatRect rcArea;
-
-  if (!m_pMinButton || !m_pMaxButton)
-    return rcClient;
-
-  CFX_FloatRect rcMin = m_pMinButton->GetWindowRect();
-  CFX_FloatRect rcMax = m_pMaxButton->GetWindowRect();
-
-  FX_FLOAT fMinWidth = rcMin.right - rcMin.left;
-  FX_FLOAT fMinHeight = rcMin.top - rcMin.bottom;
-  FX_FLOAT fMaxWidth = rcMax.right - rcMax.left;
-  FX_FLOAT fMaxHeight = rcMax.top - rcMax.bottom;
-
-  switch (m_sbType) {
-    case SBT_HSCROLL:
-      if (rcClient.right - rcClient.left > fMinWidth + fMaxWidth + 2) {
-        rcArea = CFX_FloatRect(rcClient.left + fMinWidth + 1, rcClient.bottom,
-                               rcClient.right - fMaxWidth - 1, rcClient.top);
-      } else {
-        rcArea = CFX_FloatRect(rcClient.left + fMinWidth + 1, rcClient.bottom,
-                               rcClient.left + fMinWidth + 1, rcClient.top);
-      }
-      break;
-    case SBT_VSCROLL:
-      if (rcClient.top - rcClient.bottom > fMinHeight + fMaxHeight + 2) {
-        rcArea = CFX_FloatRect(rcClient.left, rcClient.bottom + fMinHeight + 1,
-                               rcClient.right, rcClient.top - fMaxHeight - 1);
-      } else {
-        rcArea =
-            CFX_FloatRect(rcClient.left, rcClient.bottom + fMinHeight + 1,
-                          rcClient.right, rcClient.bottom + fMinHeight + 1);
-      }
-      break;
-  }
-
-  rcArea.Normalize();
-
-  return rcArea;
-}
-
-FX_FLOAT CPWL_ScrollBar::TrueToFace(FX_FLOAT fTrue) {
-  CFX_FloatRect rcPosArea;
-  rcPosArea = GetScrollArea();
-
-  FX_FLOAT fFactWidth = m_sData.ScrollRange.GetWidth() + m_sData.fClientWidth;
-  fFactWidth = fFactWidth == 0 ? 1 : fFactWidth;
-
-  FX_FLOAT fFace = 0;
-
-  switch (m_sbType) {
-    case SBT_HSCROLL:
-      fFace = rcPosArea.left +
-              fTrue * (rcPosArea.right - rcPosArea.left) / fFactWidth;
-      break;
-    case SBT_VSCROLL:
-      fFace = rcPosArea.top -
-              fTrue * (rcPosArea.top - rcPosArea.bottom) / fFactWidth;
-      break;
-  }
-
-  return fFace;
-}
-
-FX_FLOAT CPWL_ScrollBar::FaceToTrue(FX_FLOAT fFace) {
-  CFX_FloatRect rcPosArea;
-  rcPosArea = GetScrollArea();
-
-  FX_FLOAT fFactWidth = m_sData.ScrollRange.GetWidth() + m_sData.fClientWidth;
-  fFactWidth = fFactWidth == 0 ? 1 : fFactWidth;
-
-  FX_FLOAT fTrue = 0;
-
-  switch (m_sbType) {
-    case SBT_HSCROLL:
-      fTrue = (fFace - rcPosArea.left) * fFactWidth /
-              (rcPosArea.right - rcPosArea.left);
-      break;
-    case SBT_VSCROLL:
-      fTrue = (rcPosArea.top - fFace) * fFactWidth /
-              (rcPosArea.top - rcPosArea.bottom);
-      break;
-  }
-
-  return fTrue;
-}
-
-void CPWL_ScrollBar::CreateChildWnd(const PWL_CREATEPARAM& cp) {
-  CreateButtons(cp);
-}
-
-void CPWL_ScrollBar::TimerProc() {
-  PWL_SCROLL_PRIVATEDATA sTemp = m_sData;
-  if (m_bMinOrMax)
-    m_sData.SubSmall();
-  else
-    m_sData.AddSmall();
-
-  if (sTemp != m_sData) {
-    MovePosButton(true);
-    NotifyScrollWindow();
-  }
-}
diff --git a/fpdfsdk/pdfwindow/PWL_Utils.cpp b/fpdfsdk/pdfwindow/PWL_Utils.cpp
deleted file mode 100644
index 45668b6..0000000
--- a/fpdfsdk/pdfwindow/PWL_Utils.cpp
+++ /dev/null
@@ -1,1172 +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/pdfwindow/PWL_Utils.h"
-
-#include <algorithm>
-#include <memory>
-
-#include "core/fpdfdoc/cpvt_word.h"
-#include "core/fxge/cfx_graphstatedata.h"
-#include "core/fxge/cfx_pathdata.h"
-#include "core/fxge/cfx_renderdevice.h"
-#include "fpdfsdk/fxedit/fxet_edit.h"
-#include "fpdfsdk/pdfwindow/PWL_Icon.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-
-CFX_FloatRect CPWL_Utils::OffsetRect(const CFX_FloatRect& rect,
-                                     FX_FLOAT x,
-                                     FX_FLOAT y) {
-  return CFX_FloatRect(rect.left + x, rect.bottom + y, rect.right + x,
-                       rect.top + y);
-}
-
-CPVT_WordRange CPWL_Utils::OverlapWordRange(const CPVT_WordRange& wr1,
-                                            const CPVT_WordRange& wr2) {
-  CPVT_WordRange wrRet;
-
-  if (wr2.EndPos.WordCmp(wr1.BeginPos) < 0 ||
-      wr2.BeginPos.WordCmp(wr1.EndPos) > 0)
-    return wrRet;
-  if (wr1.EndPos.WordCmp(wr2.BeginPos) < 0 ||
-      wr1.BeginPos.WordCmp(wr2.EndPos) > 0)
-    return wrRet;
-
-  if (wr1.BeginPos.WordCmp(wr2.BeginPos) < 0) {
-    wrRet.BeginPos = wr2.BeginPos;
-  } else {
-    wrRet.BeginPos = wr1.BeginPos;
-  }
-
-  if (wr1.EndPos.WordCmp(wr2.EndPos) < 0) {
-    wrRet.EndPos = wr1.EndPos;
-  } else {
-    wrRet.EndPos = wr2.EndPos;
-  }
-
-  return wrRet;
-}
-
-CFX_ByteString CPWL_Utils::GetAP_Check(const CFX_FloatRect& crBBox) {
-  const FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  const FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  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) {
-      pts[i][j].x = pts[i][j].x * fWidth + crBBox.left;
-      pts[i][j].y *= pts[i][j].y * fHeight + crBBox.bottom;
-    }
-  }
-
-  CFX_ByteTextBuf csAP;
-  csAP << pts[0][0].x << " " << pts[0][0].y << " m\n";
-
-  for (size_t i = 0; i < FX_ArraySize(pts); ++i) {
-    size_t nNext = i < FX_ArraySize(pts) - 1 ? i + 1 : 0;
-
-    FX_FLOAT px1 = pts[i][1].x - pts[i][0].x;
-    FX_FLOAT py1 = pts[i][1].y - pts[i][0].y;
-    FX_FLOAT px2 = pts[i][2].x - pts[nNext][0].x;
-    FX_FLOAT py2 = pts[i][2].y - pts[nNext][0].y;
-
-    csAP << pts[i][0].x + px1 * FX_BEZIER << " "
-         << pts[i][0].y + py1 * FX_BEZIER << " "
-         << pts[nNext][0].x + px2 * FX_BEZIER << " "
-         << pts[nNext][0].y + py2 * FX_BEZIER << " " << pts[nNext][0].x << " "
-         << pts[nNext][0].y << " c\n";
-  }
-
-  return csAP.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetAP_Circle(const CFX_FloatRect& crBBox) {
-  CFX_ByteTextBuf csAP;
-
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - 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";
-
-  FX_FLOAT px = pt2.x - pt1.x;
-  FX_FLOAT py = pt2.y - pt1.y;
-
-  csAP << pt1.x << " " << pt1.y + py * FX_BEZIER << " "
-       << pt2.x - px * FX_BEZIER << " " << pt2.y << " " << pt2.x << " " << pt2.y
-       << " c\n";
-
-  px = pt3.x - pt2.x;
-  py = pt2.y - pt3.y;
-
-  csAP << pt2.x + px * FX_BEZIER << " " << pt2.y << " " << pt3.x << " "
-       << pt3.y + py * FX_BEZIER << " " << pt3.x << " " << pt3.y << " c\n";
-
-  px = pt3.x - pt4.x;
-  py = pt3.y - pt4.y;
-
-  csAP << pt3.x << " " << pt3.y - py * FX_BEZIER << " "
-       << pt4.x + px * FX_BEZIER << " " << pt4.y << " " << pt4.x << " " << pt4.y
-       << " c\n";
-
-  px = pt4.x - pt1.x;
-  py = pt1.y - pt4.y;
-
-  csAP << pt4.x - px * FX_BEZIER << " " << pt4.y << " " << pt1.x << " "
-       << pt1.y - py * FX_BEZIER << " " << pt1.x << " " << pt1.y << " c\n";
-
-  return csAP.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetAP_Cross(const CFX_FloatRect& crBBox) {
-  CFX_ByteTextBuf csAP;
-
-  csAP << crBBox.left << " " << crBBox.top << " m\n";
-  csAP << crBBox.right << " " << crBBox.bottom << " l\n";
-  csAP << crBBox.left << " " << crBBox.bottom << " m\n";
-  csAP << crBBox.right << " " << crBBox.top << " l\n";
-
-  return csAP.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetAP_Diamond(const CFX_FloatRect& crBBox) {
-  CFX_ByteTextBuf csAP;
-
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - 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";
-  csAP << pt3.x << " " << pt3.y << " l\n";
-  csAP << pt4.x << " " << pt4.y << " l\n";
-  csAP << pt1.x << " " << pt1.y << " l\n";
-
-  return csAP.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetAP_Square(const CFX_FloatRect& crBBox) {
-  CFX_ByteTextBuf csAP;
-
-  csAP << crBBox.left << " " << crBBox.top << " m\n";
-  csAP << crBBox.right << " " << crBBox.top << " l\n";
-  csAP << crBBox.right << " " << crBBox.bottom << " l\n";
-  csAP << crBBox.left << " " << crBBox.bottom << " l\n";
-  csAP << crBBox.left << " " << crBBox.top << " l\n";
-
-  return csAP.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetAP_Star(const CFX_FloatRect& crBBox) {
-  CFX_ByteTextBuf csAP;
-
-  FX_FLOAT fRadius =
-      (crBBox.top - crBBox.bottom) / (1 + (FX_FLOAT)cos(FX_PI / 5.0f));
-  CFX_PointF ptCenter = CFX_PointF((crBBox.left + crBBox.right) / 2.0f,
-                                   (crBBox.top + crBBox.bottom) / 2.0f);
-
-  FX_FLOAT px[5], py[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);
-
-    fAngel += FX_PI * 2 / 5.0f;
-  }
-
-  csAP << px[0] << " " << py[0] << " m\n";
-
-  int32_t nNext = 0;
-  for (int32_t j = 0; j < 5; j++) {
-    nNext += 2;
-    if (nNext >= 5)
-      nNext -= 5;
-    csAP << px[nNext] << " " << py[nNext] << " l\n";
-  }
-
-  return csAP.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetAP_HalfCircle(const CFX_FloatRect& crBBox,
-                                            FX_FLOAT fRotate) {
-  CFX_ByteTextBuf csAP;
-
-  FX_FLOAT fWidth = crBBox.right - crBBox.left;
-  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
-
-  CFX_PointF pt1(-fWidth / 2, 0);
-  CFX_PointF pt2(0, fHeight / 2);
-  CFX_PointF pt3(fWidth / 2, 0);
-
-  FX_FLOAT px, py;
-
-  csAP << cos(fRotate) << " " << sin(fRotate) << " " << -sin(fRotate) << " "
-       << cos(fRotate) << " " << crBBox.left + fWidth / 2 << " "
-       << crBBox.bottom + fHeight / 2 << " cm\n";
-
-  csAP << pt1.x << " " << pt1.y << " m\n";
-
-  px = pt2.x - pt1.x;
-  py = pt2.y - pt1.y;
-
-  csAP << pt1.x << " " << pt1.y + py * FX_BEZIER << " "
-       << pt2.x - px * FX_BEZIER << " " << pt2.y << " " << pt2.x << " " << pt2.y
-       << " c\n";
-
-  px = pt3.x - pt2.x;
-  py = pt2.y - pt3.y;
-
-  csAP << pt2.x + px * FX_BEZIER << " " << pt2.y << " " << pt3.x << " "
-       << pt3.y + py * FX_BEZIER << " " << pt3.x << " " << pt3.y << " c\n";
-
-  return csAP.MakeString();
-}
-
-CFX_FloatRect CPWL_Utils::InflateRect(const CFX_FloatRect& rcRect,
-                                      FX_FLOAT fSize) {
-  if (rcRect.IsEmpty())
-    return rcRect;
-
-  CFX_FloatRect rcNew(rcRect.left - fSize, rcRect.bottom - fSize,
-                      rcRect.right + fSize, rcRect.top + fSize);
-  rcNew.Normalize();
-  return rcNew;
-}
-
-CFX_FloatRect CPWL_Utils::DeflateRect(const CFX_FloatRect& rcRect,
-                                      FX_FLOAT fSize) {
-  if (rcRect.IsEmpty())
-    return rcRect;
-
-  CFX_FloatRect rcNew(rcRect.left + fSize, rcRect.bottom + fSize,
-                      rcRect.right - fSize, rcRect.top - fSize);
-  rcNew.Normalize();
-  return rcNew;
-}
-
-CFX_FloatRect CPWL_Utils::ScaleRect(const CFX_FloatRect& rcRect,
-                                    FX_FLOAT fScale) {
-  FX_FLOAT fHalfWidth = (rcRect.right - rcRect.left) / 2.0f;
-  FX_FLOAT fHalfHeight = (rcRect.top - rcRect.bottom) / 2.0f;
-
-  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,
-      ptCenter.x + fHalfWidth * fScale, ptCenter.y + fHalfHeight * fScale);
-}
-
-CFX_ByteString CPWL_Utils::GetRectFillAppStream(const CFX_FloatRect& rect,
-                                                const CPWL_Color& color) {
-  CFX_ByteTextBuf sAppStream;
-  CFX_ByteString sColor = GetColorAppStream(color, true);
-  if (sColor.GetLength() > 0) {
-    sAppStream << "q\n" << sColor;
-    sAppStream << rect.left << " " << rect.bottom << " "
-               << rect.right - rect.left << " " << rect.top - rect.bottom
-               << " re f\nQ\n";
-  }
-
-  return sAppStream.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetCircleFillAppStream(const CFX_FloatRect& rect,
-                                                  const CPWL_Color& color) {
-  CFX_ByteTextBuf sAppStream;
-  CFX_ByteString sColor = GetColorAppStream(color, true);
-  if (sColor.GetLength() > 0) {
-    sAppStream << "q\n" << sColor << CPWL_Utils::GetAP_Circle(rect) << "f\nQ\n";
-  }
-  return sAppStream.MakeString();
-}
-
-CFX_FloatRect CPWL_Utils::GetCenterSquare(const CFX_FloatRect& rect) {
-  FX_FLOAT fWidth = rect.right - rect.left;
-  FX_FLOAT fHeight = rect.top - rect.bottom;
-
-  FX_FLOAT fCenterX = (rect.left + rect.right) / 2.0f;
-  FX_FLOAT fCenterY = (rect.top + rect.bottom) / 2.0f;
-
-  FX_FLOAT fRadius = (fWidth > fHeight) ? fHeight / 2 : fWidth / 2;
-
-  return CFX_FloatRect(fCenterX - fRadius, fCenterY - fRadius,
-                       fCenterX + fRadius, fCenterY + fRadius);
-}
-
-CFX_ByteString CPWL_Utils::GetEditAppStream(CFX_Edit* pEdit,
-                                            const CFX_PointF& ptOffset,
-                                            const CPVT_WordRange* pRange,
-                                            bool bContinuous,
-                                            uint16_t SubWord) {
-  return CFX_Edit::GetEditAppearanceStream(pEdit, ptOffset, pRange, bContinuous,
-                                           SubWord);
-}
-
-CFX_ByteString CPWL_Utils::GetEditSelAppStream(CFX_Edit* pEdit,
-                                               const CFX_PointF& ptOffset,
-                                               const CPVT_WordRange* pRange) {
-  return CFX_Edit::GetSelectAppearanceStream(pEdit, ptOffset, pRange);
-}
-
-CFX_ByteString CPWL_Utils::GetPushButtonAppStream(const CFX_FloatRect& rcBBox,
-                                                  IPVT_FontMap* pFontMap,
-                                                  CPDF_Stream* pIconStream,
-                                                  CPDF_IconFit& IconFit,
-                                                  const CFX_WideString& sLabel,
-                                                  const CPWL_Color& crText,
-                                                  FX_FLOAT fFontSize,
-                                                  int32_t nLayOut) {
-  const FX_FLOAT fAutoFontScale = 1.0f / 3.0f;
-
-  std::unique_ptr<CFX_Edit> pEdit(new CFX_Edit);
-  pEdit->SetFontMap(pFontMap);
-  pEdit->SetAlignmentH(1, true);
-  pEdit->SetAlignmentV(1, true);
-  pEdit->SetMultiLine(false, true);
-  pEdit->SetAutoReturn(false, true);
-  if (IsFloatZero(fFontSize))
-    pEdit->SetAutoFontSize(true, true);
-  else
-    pEdit->SetFontSize(fFontSize);
-
-  pEdit->Initialize();
-  pEdit->SetText(sLabel);
-
-  CFX_FloatRect rcLabelContent = pEdit->GetContentRect();
-  CPWL_Icon Icon;
-  PWL_CREATEPARAM cp;
-  cp.dwFlags = PWS_VISIBLE;
-  Icon.Create(cp);
-  Icon.SetIconFit(&IconFit);
-  Icon.SetPDFStream(pIconStream);
-
-  CFX_FloatRect rcLabel = CFX_FloatRect(0, 0, 0, 0);
-  CFX_FloatRect rcIcon = CFX_FloatRect(0, 0, 0, 0);
-  FX_FLOAT fWidth = 0.0f;
-  FX_FLOAT fHeight = 0.0f;
-
-  switch (nLayOut) {
-    case PPBL_LABEL:
-      rcLabel = rcBBox;
-      rcIcon = CFX_FloatRect(0, 0, 0, 0);
-      break;
-    case PPBL_ICON:
-      rcIcon = rcBBox;
-      rcLabel = CFX_FloatRect(0, 0, 0, 0);
-      break;
-    case PPBL_ICONTOPLABELBOTTOM:
-
-      if (pIconStream) {
-        if (IsFloatZero(fFontSize)) {
-          fHeight = rcBBox.top - rcBBox.bottom;
-          rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
-                                  rcBBox.bottom + fHeight * fAutoFontScale);
-          rcIcon =
-              CFX_FloatRect(rcBBox.left, rcLabel.top, rcBBox.right, rcBBox.top);
-        } else {
-          fHeight = rcLabelContent.Height();
-
-          if (rcBBox.bottom + fHeight > rcBBox.top) {
-            rcIcon = CFX_FloatRect(0, 0, 0, 0);
-            rcLabel = rcBBox;
-          } else {
-            rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
-                                    rcBBox.bottom + fHeight);
-            rcIcon = CFX_FloatRect(rcBBox.left, rcLabel.top, rcBBox.right,
-                                   rcBBox.top);
-          }
-        }
-      } else {
-        rcLabel = rcBBox;
-        rcIcon = CFX_FloatRect(0, 0, 0, 0);
-      }
-
-      break;
-    case PPBL_LABELTOPICONBOTTOM:
-
-      if (pIconStream) {
-        if (IsFloatZero(fFontSize)) {
-          fHeight = rcBBox.top - rcBBox.bottom;
-          rcLabel =
-              CFX_FloatRect(rcBBox.left, rcBBox.top - fHeight * fAutoFontScale,
-                            rcBBox.right, rcBBox.top);
-          rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
-                                 rcLabel.bottom);
-        } else {
-          fHeight = rcLabelContent.Height();
-
-          if (rcBBox.bottom + fHeight > rcBBox.top) {
-            rcIcon = CFX_FloatRect(0, 0, 0, 0);
-            rcLabel = rcBBox;
-          } else {
-            rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.top - fHeight,
-                                    rcBBox.right, rcBBox.top);
-            rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
-                                   rcLabel.bottom);
-          }
-        }
-      } else {
-        rcLabel = rcBBox;
-        rcIcon = CFX_FloatRect(0, 0, 0, 0);
-      }
-
-      break;
-    case PPBL_ICONLEFTLABELRIGHT:
-
-      if (pIconStream) {
-        if (IsFloatZero(fFontSize)) {
-          fWidth = rcBBox.right - rcBBox.left;
-          rcLabel = CFX_FloatRect(rcBBox.right - fWidth * fAutoFontScale,
-                                  rcBBox.bottom, rcBBox.right, rcBBox.top);
-          rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
-                                 rcBBox.top);
-
-          if (rcLabelContent.Width() < fWidth * fAutoFontScale) {
-          } else {
-            if (rcLabelContent.Width() < fWidth) {
-              rcLabel = CFX_FloatRect(rcBBox.right - rcLabelContent.Width(),
-                                      rcBBox.bottom, rcBBox.right, rcBBox.top);
-              rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
-                                     rcBBox.top);
-            } else {
-              rcLabel = rcBBox;
-              rcIcon = CFX_FloatRect(0, 0, 0, 0);
-            }
-          }
-        } else {
-          fWidth = rcLabelContent.Width();
-
-          if (rcBBox.left + fWidth > rcBBox.right) {
-            rcLabel = rcBBox;
-            rcIcon = CFX_FloatRect(0, 0, 0, 0);
-          } else {
-            rcLabel = CFX_FloatRect(rcBBox.right - fWidth, rcBBox.bottom,
-                                    rcBBox.right, rcBBox.top);
-            rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
-                                   rcBBox.top);
-          }
-        }
-      } else {
-        rcLabel = rcBBox;
-        rcIcon = CFX_FloatRect(0, 0, 0, 0);
-      }
-
-      break;
-    case PPBL_LABELLEFTICONRIGHT:
-
-      if (pIconStream) {
-        if (IsFloatZero(fFontSize)) {
-          fWidth = rcBBox.right - rcBBox.left;
-          rcLabel =
-              CFX_FloatRect(rcBBox.left, rcBBox.bottom,
-                            rcBBox.left + fWidth * fAutoFontScale, rcBBox.top);
-          rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
-                                 rcBBox.top);
-
-          if (rcLabelContent.Width() < fWidth * fAutoFontScale) {
-          } else {
-            if (rcLabelContent.Width() < fWidth) {
-              rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom,
-                                      rcBBox.left + rcLabelContent.Width(),
-                                      rcBBox.top);
-              rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
-                                     rcBBox.top);
-            } else {
-              rcLabel = rcBBox;
-              rcIcon = CFX_FloatRect(0, 0, 0, 0);
-            }
-          }
-        } else {
-          fWidth = rcLabelContent.Width();
-
-          if (rcBBox.left + fWidth > rcBBox.right) {
-            rcLabel = rcBBox;
-            rcIcon = CFX_FloatRect(0, 0, 0, 0);
-          } else {
-            rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom,
-                                    rcBBox.left + fWidth, rcBBox.top);
-            rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
-                                   rcBBox.top);
-          }
-        }
-      } else {
-        rcLabel = rcBBox;
-        rcIcon = CFX_FloatRect(0, 0, 0, 0);
-      }
-
-      break;
-    case PPBL_LABELOVERICON:
-      rcLabel = rcBBox;
-      rcIcon = rcBBox;
-      break;
-  }
-
-  CFX_ByteTextBuf sAppStream, sTemp;
-
-  if (!rcIcon.IsEmpty()) {
-    Icon.Move(rcIcon, false, false);
-    sTemp << Icon.GetImageAppStream();
-  }
-
-  Icon.Destroy();
-
-  if (!rcLabel.IsEmpty()) {
-    pEdit->SetPlateRect(rcLabel);
-    CFX_ByteString sEdit =
-        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";
-    }
-  }
-
-  if (sTemp.GetSize() > 0) {
-    sAppStream << "q\n"
-               << rcBBox.left << " " << rcBBox.bottom << " "
-               << rcBBox.right - rcBBox.left << " "
-               << rcBBox.top - rcBBox.bottom << " re W n\n";
-    sAppStream << sTemp << "Q\n";
-  }
-  return sAppStream.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetColorAppStream(const CPWL_Color& color,
-                                             const bool& bFillOrStroke) {
-  CFX_ByteTextBuf sColorStream;
-
-  switch (color.nColorType) {
-    case COLORTYPE_RGB:
-      sColorStream << color.fColor1 << " " << color.fColor2 << " "
-                   << color.fColor3 << " " << (bFillOrStroke ? "rg" : "RG")
-                   << "\n";
-      break;
-    case COLORTYPE_GRAY:
-      sColorStream << color.fColor1 << " " << (bFillOrStroke ? "g" : "G")
-                   << "\n";
-      break;
-    case COLORTYPE_CMYK:
-      sColorStream << color.fColor1 << " " << color.fColor2 << " "
-                   << color.fColor3 << " " << color.fColor4 << " "
-                   << (bFillOrStroke ? "k" : "K") << "\n";
-      break;
-  }
-
-  return sColorStream.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetBorderAppStream(const CFX_FloatRect& rect,
-                                              FX_FLOAT fWidth,
-                                              const CPWL_Color& color,
-                                              const CPWL_Color& crLeftTop,
-                                              const CPWL_Color& crRightBottom,
-                                              BorderStyle nStyle,
-                                              const CPWL_Dash& dash) {
-  CFX_ByteTextBuf sAppStream;
-  CFX_ByteString sColor;
-
-  FX_FLOAT fLeft = rect.left;
-  FX_FLOAT fRight = rect.right;
-  FX_FLOAT fTop = rect.top;
-  FX_FLOAT fBottom = rect.bottom;
-
-  if (fWidth > 0.0f) {
-    FX_FLOAT fHalfWidth = fWidth / 2.0f;
-
-    sAppStream << "q\n";
-
-    switch (nStyle) {
-      default:
-      case BorderStyle::SOLID:
-        sColor = CPWL_Utils::GetColorAppStream(color, true);
-        if (sColor.GetLength() > 0) {
-          sAppStream << sColor;
-          sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
-                     << fTop - fBottom << " re\n";
-          sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " "
-                     << fRight - fLeft - fWidth * 2 << " "
-                     << fTop - fBottom - fWidth * 2 << " re\n";
-          sAppStream << "f*\n";
-        }
-        break;
-      case BorderStyle::DASH:
-        sColor = CPWL_Utils::GetColorAppStream(color, false);
-        if (sColor.GetLength() > 0) {
-          sAppStream << sColor;
-          sAppStream << fWidth << " w"
-                     << " [" << dash.nDash << " " << dash.nGap << "] "
-                     << dash.nPhase << " d\n";
-          sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2
-                     << " m\n";
-          sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2
-                     << " l\n";
-          sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2
-                     << " l\n";
-          sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2
-                     << " l\n";
-          sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2
-                     << " l S\n";
-        }
-        break;
-      case BorderStyle::BEVELED:
-      case BorderStyle::INSET:
-        sColor = CPWL_Utils::GetColorAppStream(crLeftTop, true);
-        if (sColor.GetLength() > 0) {
-          sAppStream << sColor;
-          sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth
-                     << " m\n";
-          sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth
-                     << " l\n";
-          sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth
-                     << " l\n";
-          sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
-                     << " l\n";
-          sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
-                     << " l\n";
-          sAppStream << fLeft + fHalfWidth * 2 << " "
-                     << fBottom + fHalfWidth * 2 << " l f\n";
-        }
-
-        sColor = CPWL_Utils::GetColorAppStream(crRightBottom, true);
-        if (sColor.GetLength() > 0) {
-          sAppStream << sColor;
-          sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth
-                     << " m\n";
-          sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth
-                     << " l\n";
-          sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth
-                     << " l\n";
-          sAppStream << fLeft + fHalfWidth * 2 << " "
-                     << fBottom + fHalfWidth * 2 << " l\n";
-          sAppStream << fRight - fHalfWidth * 2 << " "
-                     << fBottom + fHalfWidth * 2 << " l\n";
-          sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
-                     << " l f\n";
-        }
-
-        sColor = CPWL_Utils::GetColorAppStream(color, true);
-        if (sColor.GetLength() > 0) {
-          sAppStream << sColor;
-          sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
-                     << fTop - fBottom << " re\n";
-          sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
-                     << fRight - fLeft - fHalfWidth * 2 << " "
-                     << fTop - fBottom - fHalfWidth * 2 << " re f*\n";
-        }
-        break;
-      case BorderStyle::UNDERLINE:
-        sColor = CPWL_Utils::GetColorAppStream(color, false);
-        if (sColor.GetLength() > 0) {
-          sAppStream << sColor;
-          sAppStream << fWidth << " w\n";
-          sAppStream << fLeft << " " << fBottom + fWidth / 2 << " m\n";
-          sAppStream << fRight << " " << fBottom + fWidth / 2 << " l S\n";
-        }
-        break;
-    }
-
-    sAppStream << "Q\n";
-  }
-
-  return sAppStream.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetCircleBorderAppStream(
-    const CFX_FloatRect& rect,
-    FX_FLOAT fWidth,
-    const CPWL_Color& color,
-    const CPWL_Color& crLeftTop,
-    const CPWL_Color& crRightBottom,
-    BorderStyle nStyle,
-    const CPWL_Dash& dash) {
-  CFX_ByteTextBuf sAppStream;
-  CFX_ByteString sColor;
-
-  if (fWidth > 0.0f) {
-    sAppStream << "q\n";
-
-    switch (nStyle) {
-      default:
-      case BorderStyle::SOLID:
-      case BorderStyle::UNDERLINE: {
-        sColor = CPWL_Utils::GetColorAppStream(color, false);
-        if (sColor.GetLength() > 0) {
-          sAppStream << "q\n" << fWidth << " w\n" << sColor
-                     << CPWL_Utils::GetAP_Circle(
-                            CPWL_Utils::DeflateRect(rect, fWidth / 2.0f))
-                     << " S\nQ\n";
-        }
-      } break;
-      case BorderStyle::DASH: {
-        sColor = CPWL_Utils::GetColorAppStream(color, false);
-        if (sColor.GetLength() > 0) {
-          sAppStream << "q\n" << fWidth << " w\n"
-                     << "[" << dash.nDash << " " << dash.nGap << "] "
-                     << dash.nPhase << " d\n" << sColor
-                     << CPWL_Utils::GetAP_Circle(
-                            CPWL_Utils::DeflateRect(rect, fWidth / 2.0f))
-                     << " S\nQ\n";
-        }
-      } break;
-      case BorderStyle::BEVELED: {
-        FX_FLOAT fHalfWidth = fWidth / 2.0f;
-
-        sColor = CPWL_Utils::GetColorAppStream(color, false);
-        if (sColor.GetLength() > 0) {
-          sAppStream << "q\n" << fHalfWidth << " w\n" << sColor
-                     << CPWL_Utils::GetAP_Circle(rect) << " S\nQ\n";
-        }
-
-        sColor = CPWL_Utils::GetColorAppStream(crLeftTop, false);
-        if (sColor.GetLength() > 0) {
-          sAppStream << "q\n" << fHalfWidth << " w\n" << sColor
-                     << CPWL_Utils::GetAP_HalfCircle(
-                            CPWL_Utils::DeflateRect(rect, fHalfWidth * 0.75f),
-                            FX_PI / 4.0f)
-                     << " S\nQ\n";
-        }
-
-        sColor = CPWL_Utils::GetColorAppStream(crRightBottom, false);
-        if (sColor.GetLength() > 0) {
-          sAppStream << "q\n" << fHalfWidth << " w\n" << sColor
-                     << CPWL_Utils::GetAP_HalfCircle(
-                            CPWL_Utils::DeflateRect(rect, fHalfWidth * 0.75f),
-                            FX_PI * 5 / 4.0f)
-                     << " S\nQ\n";
-        }
-      } break;
-      case BorderStyle::INSET: {
-        FX_FLOAT fHalfWidth = fWidth / 2.0f;
-
-        sColor = CPWL_Utils::GetColorAppStream(color, false);
-        if (sColor.GetLength() > 0) {
-          sAppStream << "q\n" << fHalfWidth << " w\n" << sColor
-                     << CPWL_Utils::GetAP_Circle(rect) << " S\nQ\n";
-        }
-
-        sColor = CPWL_Utils::GetColorAppStream(crLeftTop, false);
-        if (sColor.GetLength() > 0) {
-          sAppStream << "q\n" << fHalfWidth << " w\n" << sColor
-                     << CPWL_Utils::GetAP_HalfCircle(
-                            CPWL_Utils::DeflateRect(rect, fHalfWidth * 0.75f),
-                            FX_PI / 4.0f)
-                     << " S\nQ\n";
-        }
-
-        sColor = CPWL_Utils::GetColorAppStream(crRightBottom, false);
-        if (sColor.GetLength() > 0) {
-          sAppStream << "q\n" << fHalfWidth << " w\n" << sColor
-                     << CPWL_Utils::GetAP_HalfCircle(
-                            CPWL_Utils::DeflateRect(rect, fHalfWidth * 0.75f),
-                            FX_PI * 5 / 4.0f)
-                     << " S\nQ\n";
-        }
-      } break;
-    }
-
-    sAppStream << "Q\n";
-  }
-
-  return sAppStream.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetAppStream_Check(const CFX_FloatRect& rcBBox,
-                                              const CPWL_Color& crText) {
-  CFX_ByteTextBuf sAP;
-  sAP << "q\n"
-      << CPWL_Utils::GetColorAppStream(crText, true)
-      << CPWL_Utils::GetAP_Check(rcBBox) << "f\nQ\n";
-  return sAP.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetAppStream_Circle(const CFX_FloatRect& rcBBox,
-                                               const CPWL_Color& crText) {
-  CFX_ByteTextBuf sAP;
-  sAP << "q\n"
-      << CPWL_Utils::GetColorAppStream(crText, true)
-      << CPWL_Utils::GetAP_Circle(rcBBox) << "f\nQ\n";
-  return sAP.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetAppStream_Cross(const CFX_FloatRect& rcBBox,
-                                              const CPWL_Color& crText) {
-  CFX_ByteTextBuf sAP;
-  sAP << "q\n"
-      << CPWL_Utils::GetColorAppStream(crText, false)
-      << CPWL_Utils::GetAP_Cross(rcBBox) << "S\nQ\n";
-  return sAP.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetAppStream_Diamond(const CFX_FloatRect& rcBBox,
-                                                const CPWL_Color& crText) {
-  CFX_ByteTextBuf sAP;
-  sAP << "q\n1 w\n"
-      << CPWL_Utils::GetColorAppStream(crText, true)
-      << CPWL_Utils::GetAP_Diamond(rcBBox) << "f\nQ\n";
-  return sAP.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetAppStream_Square(const CFX_FloatRect& rcBBox,
-                                               const CPWL_Color& crText) {
-  CFX_ByteTextBuf sAP;
-  sAP << "q\n"
-      << CPWL_Utils::GetColorAppStream(crText, true)
-      << CPWL_Utils::GetAP_Square(rcBBox) << "f\nQ\n";
-  return sAP.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetAppStream_Star(const CFX_FloatRect& rcBBox,
-                                             const CPWL_Color& crText) {
-  CFX_ByteTextBuf sAP;
-  sAP << "q\n"
-      << CPWL_Utils::GetColorAppStream(crText, true)
-      << CPWL_Utils::GetAP_Star(rcBBox) << "f\nQ\n";
-  return sAP.MakeString();
-}
-
-CFX_ByteString CPWL_Utils::GetCheckBoxAppStream(const CFX_FloatRect& rcBBox,
-                                                int32_t nStyle,
-                                                const CPWL_Color& crText) {
-  CFX_FloatRect rcCenter = GetCenterSquare(rcBBox);
-  switch (nStyle) {
-    default:
-    case PCS_CHECK:
-      return GetAppStream_Check(rcCenter, crText);
-    case PCS_CIRCLE:
-      return GetAppStream_Circle(ScaleRect(rcCenter, 2.0f / 3.0f), crText);
-    case PCS_CROSS:
-      return GetAppStream_Cross(rcCenter, crText);
-    case PCS_DIAMOND:
-      return GetAppStream_Diamond(ScaleRect(rcCenter, 2.0f / 3.0f), crText);
-    case PCS_SQUARE:
-      return GetAppStream_Square(ScaleRect(rcCenter, 2.0f / 3.0f), crText);
-    case PCS_STAR:
-      return GetAppStream_Star(ScaleRect(rcCenter, 2.0f / 3.0f), crText);
-  }
-}
-
-CFX_ByteString CPWL_Utils::GetRadioButtonAppStream(const CFX_FloatRect& rcBBox,
-                                                   int32_t nStyle,
-                                                   const CPWL_Color& crText) {
-  CFX_FloatRect rcCenter = GetCenterSquare(rcBBox);
-  switch (nStyle) {
-    default:
-    case PCS_CHECK:
-      return GetAppStream_Check(rcCenter, crText);
-    case PCS_CIRCLE:
-      return GetAppStream_Circle(ScaleRect(rcCenter, 1.0f / 2.0f), crText);
-    case PCS_CROSS:
-      return GetAppStream_Cross(rcCenter, crText);
-    case PCS_DIAMOND:
-      return GetAppStream_Diamond(ScaleRect(rcCenter, 2.0f / 3.0f), crText);
-    case PCS_SQUARE:
-      return GetAppStream_Square(ScaleRect(rcCenter, 2.0f / 3.0f), crText);
-    case PCS_STAR:
-      return GetAppStream_Star(ScaleRect(rcCenter, 2.0f / 3.0f), crText);
-  }
-}
-
-CFX_ByteString CPWL_Utils::GetDropButtonAppStream(const CFX_FloatRect& rcBBox) {
-  CFX_ByteTextBuf sAppStream;
-
-  if (!rcBBox.IsEmpty()) {
-    sAppStream << "q\n"
-               << CPWL_Utils::GetColorAppStream(
-                      CPWL_Color(COLORTYPE_RGB, 220.0f / 255.0f,
-                                 220.0f / 255.0f, 220.0f / 255.0f),
-                      true);
-    sAppStream << rcBBox.left << " " << rcBBox.bottom << " "
-               << rcBBox.right - rcBBox.left << " "
-               << rcBBox.top - rcBBox.bottom << " re f\n";
-    sAppStream << "Q\n";
-
-    sAppStream << "q\n"
-               << CPWL_Utils::GetBorderAppStream(
-                      rcBBox, 2, CPWL_Color(COLORTYPE_GRAY, 0),
-                      CPWL_Color(COLORTYPE_GRAY, 1),
-                      CPWL_Color(COLORTYPE_GRAY, 0.5), BorderStyle::BEVELED,
-                      CPWL_Dash(3, 0, 0))
-               << "Q\n";
-
-    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"
-                 << " 0 g\n";
-      sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " m\n";
-      sAppStream << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " l\n";
-      sAppStream << ptCenter.x << " " << ptCenter.y - 1.5f << " l\n";
-      sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " l f\n";
-      sAppStream << "Q\n";
-    }
-  }
-
-  return sAppStream.MakeString();
-}
-
-void CPWL_Utils::DrawFillRect(CFX_RenderDevice* pDevice,
-                              CFX_Matrix* pUser2Device,
-                              const CFX_FloatRect& rect,
-                              const FX_COLORREF& color) {
-  CFX_PathData path;
-  CFX_FloatRect rcTemp(rect);
-  path.AppendRect(rcTemp.left, rcTemp.bottom, rcTemp.right, rcTemp.top);
-  pDevice->DrawPath(&path, pUser2Device, nullptr, color, 0, FXFILL_WINDING);
-}
-
-void CPWL_Utils::DrawFillArea(CFX_RenderDevice* pDevice,
-                              CFX_Matrix* pUser2Device,
-                              const CFX_PointF* pPts,
-                              int32_t nCount,
-                              const FX_COLORREF& color) {
-  CFX_PathData path;
-  path.AppendPoint(pPts[0], FXPT_TYPE::MoveTo, false);
-  for (int32_t i = 1; i < nCount; i++)
-    path.AppendPoint(pPts[i], FXPT_TYPE::LineTo, false);
-
-  pDevice->DrawPath(&path, pUser2Device, nullptr, color, 0, FXFILL_ALTERNATE);
-}
-
-void CPWL_Utils::DrawStrokeRect(CFX_RenderDevice* pDevice,
-                                CFX_Matrix* pUser2Device,
-                                const CFX_FloatRect& rect,
-                                const FX_COLORREF& color,
-                                FX_FLOAT fWidth) {
-  CFX_PathData path;
-  CFX_FloatRect rcTemp(rect);
-  path.AppendRect(rcTemp.left, rcTemp.bottom, rcTemp.right, rcTemp.top);
-
-  CFX_GraphStateData gsd;
-  gsd.m_LineWidth = fWidth;
-
-  pDevice->DrawPath(&path, pUser2Device, &gsd, 0, color, FXFILL_ALTERNATE);
-}
-
-void CPWL_Utils::DrawStrokeLine(CFX_RenderDevice* pDevice,
-                                CFX_Matrix* pUser2Device,
-                                const CFX_PointF& ptMoveTo,
-                                const CFX_PointF& ptLineTo,
-                                const FX_COLORREF& color,
-                                FX_FLOAT fWidth) {
-  CFX_PathData path;
-  path.AppendPoint(ptMoveTo, FXPT_TYPE::MoveTo, false);
-  path.AppendPoint(ptLineTo, FXPT_TYPE::LineTo, false);
-
-  CFX_GraphStateData gsd;
-  gsd.m_LineWidth = fWidth;
-
-  pDevice->DrawPath(&path, pUser2Device, &gsd, 0, color, FXFILL_ALTERNATE);
-}
-
-void CPWL_Utils::DrawFillRect(CFX_RenderDevice* pDevice,
-                              CFX_Matrix* pUser2Device,
-                              const CFX_FloatRect& rect,
-                              const CPWL_Color& color,
-                              int32_t nTransparency) {
-  CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rect,
-                           color.ToFXColor(nTransparency));
-}
-
-void CPWL_Utils::DrawShadow(CFX_RenderDevice* pDevice,
-                            CFX_Matrix* pUser2Device,
-                            bool bVertical,
-                            bool bHorizontal,
-                            CFX_FloatRect rect,
-                            int32_t nTransparency,
-                            int32_t nStartGray,
-                            int32_t nEndGray) {
-  FX_FLOAT fStepGray = 1.0f;
-
-  if (bVertical) {
-    fStepGray = (nEndGray - nStartGray) / rect.Height();
-
-    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_PointF(rect.left, fy),
-          CFX_PointF(rect.right, fy),
-          ArgbEncode(nTransparency, nGray, nGray, nGray), 1.5f);
-    }
-  }
-
-  if (bHorizontal) {
-    fStepGray = (nEndGray - nStartGray) / rect.Width();
-
-    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_PointF(fx, rect.bottom),
-          CFX_PointF(fx, rect.top),
-          ArgbEncode(nTransparency, nGray, nGray, nGray), 1.5f);
-    }
-  }
-}
-
-void CPWL_Utils::DrawBorder(CFX_RenderDevice* pDevice,
-                            CFX_Matrix* pUser2Device,
-                            const CFX_FloatRect& rect,
-                            FX_FLOAT fWidth,
-                            const CPWL_Color& color,
-                            const CPWL_Color& crLeftTop,
-                            const CPWL_Color& crRightBottom,
-                            BorderStyle nStyle,
-                            int32_t nTransparency) {
-  FX_FLOAT fLeft = rect.left;
-  FX_FLOAT fRight = rect.right;
-  FX_FLOAT fTop = rect.top;
-  FX_FLOAT fBottom = rect.bottom;
-
-  if (fWidth > 0.0f) {
-    FX_FLOAT fHalfWidth = fWidth / 2.0f;
-
-    switch (nStyle) {
-      default:
-      case BorderStyle::SOLID: {
-        CFX_PathData path;
-        path.AppendRect(fLeft, fBottom, fRight, fTop);
-        path.AppendRect(fLeft + fWidth, fBottom + fWidth, fRight - fWidth,
-                        fTop - fWidth);
-        pDevice->DrawPath(&path, pUser2Device, nullptr,
-                          color.ToFXColor(nTransparency), 0, FXFILL_ALTERNATE);
-        break;
-      }
-      case BorderStyle::DASH: {
-        CFX_PathData path;
-        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);
-        gsd.m_DashArray[0] = 3.0f;
-        gsd.m_DashArray[1] = 3.0f;
-        gsd.m_DashPhase = 0;
-
-        gsd.m_LineWidth = fWidth;
-        pDevice->DrawPath(&path, pUser2Device, &gsd, 0,
-                          color.ToFXColor(nTransparency), FXFILL_WINDING);
-        break;
-      }
-      case BorderStyle::BEVELED:
-      case BorderStyle::INSET: {
-        CFX_GraphStateData gsd;
-        gsd.m_LineWidth = fHalfWidth;
-
-        CFX_PathData pathLT;
-
-        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,
-                          crLeftTop.ToFXColor(nTransparency), 0,
-                          FXFILL_ALTERNATE);
-
-        CFX_PathData pathRB;
-        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,
-                          crRightBottom.ToFXColor(nTransparency), 0,
-                          FXFILL_ALTERNATE);
-
-        CFX_PathData path;
-
-        path.AppendRect(fLeft, fBottom, fRight, fTop);
-        path.AppendRect(fLeft + fHalfWidth, fBottom + fHalfWidth,
-                        fRight - fHalfWidth, fTop - fHalfWidth);
-
-        pDevice->DrawPath(&path, pUser2Device, &gsd,
-                          color.ToFXColor(nTransparency), 0, FXFILL_ALTERNATE);
-        break;
-      }
-      case BorderStyle::UNDERLINE: {
-        CFX_PathData path;
-        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,
-                          color.ToFXColor(nTransparency), FXFILL_ALTERNATE);
-        break;
-      }
-    }
-  }
-}
-
diff --git a/fpdfsdk/pdfwindow/PWL_Utils.h b/fpdfsdk/pdfwindow/PWL_Utils.h
deleted file mode 100644
index a4ecc19..0000000
--- a/fpdfsdk/pdfwindow/PWL_Utils.h
+++ /dev/null
@@ -1,164 +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 FPDFSDK_PDFWINDOW_PWL_UTILS_H_
-#define FPDFSDK_PDFWINDOW_PWL_UTILS_H_
-
-#include "core/fpdfdoc/cpvt_wordrange.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-
-class CFX_Edit;
-struct CPWL_Color;
-
-#define PWL_MAKEDWORD(low, high) \
-  ((uint32_t)((uint16_t)(low) | (uint32_t)(((uint16_t)(high)) << 16)))
-
-// checkbox & radiobutton style
-#define PCS_CHECK 0
-#define PCS_CIRCLE 1
-#define PCS_CROSS 2
-#define PCS_DIAMOND 3
-#define PCS_SQUARE 4
-#define PCS_STAR 5
-
-// pushbutton layout style
-#define PPBL_LABEL 0
-#define PPBL_ICON 1
-#define PPBL_ICONTOPLABELBOTTOM 2
-#define PPBL_LABELTOPICONBOTTOM 3
-#define PPBL_ICONLEFTLABELRIGHT 4
-#define PPBL_LABELLEFTICONRIGHT 5
-#define PPBL_LABELOVERICON 6
-
-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 CPVT_WordRange OverlapWordRange(const CPVT_WordRange& wr1,
-                                         const CPVT_WordRange& wr2);
-  static CFX_FloatRect GetCenterSquare(const CFX_FloatRect& rect);
-
-  static CFX_FloatRect OffsetRect(const CFX_FloatRect& rect,
-                                  FX_FLOAT x,
-                                  FX_FLOAT y);
-
-  static CFX_ByteString GetColorAppStream(const CPWL_Color& color,
-                                          const bool& bFillOrStroke = true);
-  static CFX_ByteString GetBorderAppStream(const CFX_FloatRect& rect,
-                                           FX_FLOAT fWidth,
-                                           const CPWL_Color& color,
-                                           const CPWL_Color& crLeftTop,
-                                           const CPWL_Color& crRightBottom,
-                                           BorderStyle nStyle,
-                                           const CPWL_Dash& dash);
-  static CFX_ByteString GetCircleBorderAppStream(
-      const CFX_FloatRect& rect,
-      FX_FLOAT fWidth,
-      const CPWL_Color& color,
-      const CPWL_Color& crLeftTop,
-      const CPWL_Color& crRightBottom,
-      BorderStyle nStyle,
-      const CPWL_Dash& dash);
-  static CFX_ByteString GetRectFillAppStream(const CFX_FloatRect& rect,
-                                             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,
-                                               CPDF_IconFit& IconFit,
-                                               const CFX_WideString& sLabel,
-                                               const CPWL_Color& crText,
-                                               FX_FLOAT fFontSize,
-                                               int32_t nLayOut);
-  static CFX_ByteString GetCheckBoxAppStream(const CFX_FloatRect& rcBBox,
-                                             int32_t nStyle,
-                                             const CPWL_Color& crText);
-  static CFX_ByteString GetRadioButtonAppStream(const CFX_FloatRect& rcBBox,
-                                                int32_t nStyle,
-                                                const CPWL_Color& crText);
-  static CFX_ByteString GetEditAppStream(CFX_Edit* pEdit,
-                                         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_PointF& ptOffset,
-      const CPVT_WordRange* pRange = nullptr);
-  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 nTransparency);
-  static void DrawFillRect(CFX_RenderDevice* pDevice,
-                           CFX_Matrix* pUser2Device,
-                           const CFX_FloatRect& rect,
-                           const FX_COLORREF& color);
-  static void DrawStrokeRect(CFX_RenderDevice* pDevice,
-                             CFX_Matrix* pUser2Device,
-                             const CFX_FloatRect& rect,
-                             const FX_COLORREF& color,
-                             FX_FLOAT fWidth);
-  static void DrawStrokeLine(CFX_RenderDevice* pDevice,
-                             CFX_Matrix* pUser2Device,
-                             const CFX_PointF& ptMoveTo,
-                             const CFX_PointF& ptLineTo,
-                             const FX_COLORREF& color,
-                             FX_FLOAT fWidth);
-  static void DrawBorder(CFX_RenderDevice* pDevice,
-                         CFX_Matrix* pUser2Device,
-                         const CFX_FloatRect& rect,
-                         FX_FLOAT fWidth,
-                         const CPWL_Color& color,
-                         const CPWL_Color& crLeftTop,
-                         const CPWL_Color& crRightBottom,
-                         BorderStyle nStyle,
-                         int32_t nTransparency);
-  static void DrawFillArea(CFX_RenderDevice* pDevice,
-                           CFX_Matrix* pUser2Device,
-                           const CFX_PointF* pPts,
-                           int32_t nCount,
-                           const FX_COLORREF& color);
-  static void DrawShadow(CFX_RenderDevice* pDevice,
-                         CFX_Matrix* pUser2Device,
-                         bool bVertical,
-                         bool bHorizontal,
-                         CFX_FloatRect rect,
-                         int32_t nTransparency,
-                         int32_t nStartGray,
-                         int32_t nEndGray);
-
- private:
-  static CFX_FloatRect ScaleRect(const CFX_FloatRect& rcRect, FX_FLOAT fScale);
-
-  static CFX_ByteString GetAppStream_Check(const CFX_FloatRect& rcBBox,
-                                           const CPWL_Color& crText);
-  static CFX_ByteString GetAppStream_Circle(const CFX_FloatRect& rcBBox,
-                                            const CPWL_Color& crText);
-  static CFX_ByteString GetAppStream_Cross(const CFX_FloatRect& rcBBox,
-                                           const CPWL_Color& crText);
-  static CFX_ByteString GetAppStream_Diamond(const CFX_FloatRect& rcBBox,
-                                             const CPWL_Color& crText);
-  static CFX_ByteString GetAppStream_Square(const CFX_FloatRect& rcBBox,
-                                            const CPWL_Color& crText);
-  static CFX_ByteString GetAppStream_Star(const CFX_FloatRect& rcBBox,
-                                          const CPWL_Color& crText);
-
-  static CFX_ByteString GetAP_Check(const CFX_FloatRect& crBBox);
-  static CFX_ByteString GetAP_Circle(const CFX_FloatRect& crBBox);
-  static CFX_ByteString GetAP_Cross(const CFX_FloatRect& crBBox);
-  static CFX_ByteString GetAP_Diamond(const CFX_FloatRect& crBBox);
-  static CFX_ByteString GetAP_Square(const CFX_FloatRect& crBBox);
-  static CFX_ByteString GetAP_Star(const CFX_FloatRect& crBBox);
-  static CFX_ByteString GetAP_HalfCircle(const CFX_FloatRect& crBBox,
-                                         FX_FLOAT fRotate);
-};
-
-#endif  // FPDFSDK_PDFWINDOW_PWL_UTILS_H_
diff --git a/fpdfsdk/pdfwindow/PWL_Wnd.cpp b/fpdfsdk/pdfwindow/PWL_Wnd.cpp
deleted file mode 100644
index 14024dd..0000000
--- a/fpdfsdk/pdfwindow/PWL_Wnd.cpp
+++ /dev/null
@@ -1,915 +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 <map>
-#include <vector>
-
-#include "fpdfsdk/pdfwindow/PWL_ScrollBar.h"
-#include "fpdfsdk/pdfwindow/PWL_Utils.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
-#include "third_party/base/ptr_util.h"
-#include "third_party/base/stl_util.h"
-
-static std::map<int32_t, CPWL_Timer*>& GetPWLTimeMap() {
-  // Leak the object at shutdown.
-  static auto timeMap = new std::map<int32_t, CPWL_Timer*>;
-  return *timeMap;
-}
-
-PWL_CREATEPARAM::PWL_CREATEPARAM()
-    : rcRectWnd(0, 0, 0, 0),
-      pSystemHandler(nullptr),
-      pFontMap(nullptr),
-      pProvider(nullptr),
-      pFocusHandler(nullptr),
-      dwFlags(0),
-      sBackgroundColor(),
-      pAttachedWidget(nullptr),
-      nBorderStyle(BorderStyle::SOLID),
-      dwBorderWidth(1),
-      sBorderColor(),
-      sTextColor(),
-      nTransparency(255),
-      fFontSize(PWL_DEFAULT_FONTSIZE),
-      sDash(3, 0, 0),
-      pAttachedData(nullptr),
-      pParentWnd(nullptr),
-      pMsgControl(nullptr),
-      eCursorType(FXCT_ARROW),
-      mtChild(1, 0, 0, 1, 0, 0) {}
-
-PWL_CREATEPARAM::PWL_CREATEPARAM(const PWL_CREATEPARAM& other) = default;
-
-CPWL_Timer::CPWL_Timer(CPWL_TimerHandler* pAttached,
-                       CFX_SystemHandler* pSystemHandler)
-    : m_nTimerID(0), m_pAttached(pAttached), m_pSystemHandler(pSystemHandler) {
-  ASSERT(m_pAttached);
-  ASSERT(m_pSystemHandler);
-}
-
-CPWL_Timer::~CPWL_Timer() {
-  KillPWLTimer();
-}
-
-int32_t CPWL_Timer::SetPWLTimer(int32_t nElapse) {
-  if (m_nTimerID != 0)
-    KillPWLTimer();
-  m_nTimerID = m_pSystemHandler->SetTimer(nElapse, TimerProc);
-
-  GetPWLTimeMap()[m_nTimerID] = this;
-  return m_nTimerID;
-}
-
-void CPWL_Timer::KillPWLTimer() {
-  if (m_nTimerID == 0)
-    return;
-
-  m_pSystemHandler->KillTimer(m_nTimerID);
-  GetPWLTimeMap().erase(m_nTimerID);
-  m_nTimerID = 0;
-}
-
-void CPWL_Timer::TimerProc(int32_t idEvent) {
-  auto it = GetPWLTimeMap().find(idEvent);
-  if (it == GetPWLTimeMap().end())
-    return;
-
-  CPWL_Timer* pTimer = it->second;
-  if (pTimer->m_pAttached)
-    pTimer->m_pAttached->TimerProc();
-}
-
-CPWL_TimerHandler::CPWL_TimerHandler() {}
-
-CPWL_TimerHandler::~CPWL_TimerHandler() {}
-
-void CPWL_TimerHandler::BeginTimer(int32_t nElapse) {
-  if (!m_pTimer)
-    m_pTimer = pdfium::MakeUnique<CPWL_Timer>(this, GetSystemHandler());
-
-  m_pTimer->SetPWLTimer(nElapse);
-}
-
-void CPWL_TimerHandler::EndTimer() {
-  if (m_pTimer)
-    m_pTimer->KillPWLTimer();
-}
-
-void CPWL_TimerHandler::TimerProc() {}
-
-class CPWL_MsgControl {
-  friend class CPWL_Wnd;
-
- public:
-  explicit CPWL_MsgControl(CPWL_Wnd* pWnd) {
-    m_pCreatedWnd = pWnd;
-    Default();
-  }
-
-  ~CPWL_MsgControl() { Default(); }
-
-  void Default() {
-    m_aMousePath.clear();
-    m_aKeyboardPath.clear();
-    m_pMainMouseWnd = nullptr;
-    m_pMainKeyboardWnd = nullptr;
-  }
-
-  bool IsWndCreated(const CPWL_Wnd* pWnd) const {
-    return m_pCreatedWnd == pWnd;
-  }
-
-  bool IsMainCaptureMouse(const CPWL_Wnd* pWnd) const {
-    return pWnd == m_pMainMouseWnd;
-  }
-
-  bool IsWndCaptureMouse(const CPWL_Wnd* pWnd) const {
-    return pWnd && pdfium::ContainsValue(m_aMousePath, pWnd);
-  }
-
-  bool IsMainCaptureKeyboard(const CPWL_Wnd* pWnd) const {
-    return pWnd == m_pMainKeyboardWnd;
-  }
-
-  bool IsWndCaptureKeyboard(const CPWL_Wnd* pWnd) const {
-    return pWnd && pdfium::ContainsValue(m_aKeyboardPath, pWnd);
-  }
-
-  void SetFocus(CPWL_Wnd* pWnd) {
-    m_aKeyboardPath.clear();
-    if (pWnd) {
-      m_pMainKeyboardWnd = pWnd;
-      CPWL_Wnd* pParent = pWnd;
-      while (pParent) {
-        m_aKeyboardPath.push_back(pParent);
-        pParent = pParent->GetParentWindow();
-      }
-      pWnd->OnSetFocus();
-    }
-  }
-
-  void KillFocus() {
-    if (!m_aKeyboardPath.empty())
-      if (CPWL_Wnd* pWnd = m_aKeyboardPath[0])
-        pWnd->OnKillFocus();
-
-    m_pMainKeyboardWnd = nullptr;
-    m_aKeyboardPath.clear();
-  }
-
-  void SetCapture(CPWL_Wnd* pWnd) {
-    m_aMousePath.clear();
-    if (pWnd) {
-      m_pMainMouseWnd = pWnd;
-      CPWL_Wnd* pParent = pWnd;
-      while (pParent) {
-        m_aMousePath.push_back(pParent);
-        pParent = pParent->GetParentWindow();
-      }
-    }
-  }
-
-  void ReleaseCapture() {
-    m_pMainMouseWnd = nullptr;
-    m_aMousePath.clear();
-  }
-
- private:
-  std::vector<CPWL_Wnd*> m_aMousePath;
-  std::vector<CPWL_Wnd*> m_aKeyboardPath;
-  CPWL_Wnd* m_pCreatedWnd;
-  CPWL_Wnd* m_pMainMouseWnd;
-  CPWL_Wnd* m_pMainKeyboardWnd;
-};
-
-CPWL_Wnd::CPWL_Wnd()
-    : m_pVScrollBar(nullptr),
-      m_rcWindow(),
-      m_rcClip(),
-      m_bCreated(false),
-      m_bVisible(false),
-      m_bNotifying(false),
-      m_bEnabled(true) {}
-
-CPWL_Wnd::~CPWL_Wnd() {
-  ASSERT(m_bCreated == false);
-}
-
-CFX_ByteString CPWL_Wnd::GetClassName() const {
-  return "CPWL_Wnd";
-}
-
-void CPWL_Wnd::Create(const PWL_CREATEPARAM& cp) {
-  if (!IsValid()) {
-    m_sPrivateParam = cp;
-
-    OnCreate(m_sPrivateParam);
-
-    m_sPrivateParam.rcRectWnd.Normalize();
-    m_rcWindow = m_sPrivateParam.rcRectWnd;
-    m_rcClip = CPWL_Utils::InflateRect(m_rcWindow, 1.0f);
-
-    CreateMsgControl();
-
-    if (m_sPrivateParam.pParentWnd)
-      m_sPrivateParam.pParentWnd->OnNotify(this, PNM_ADDCHILD);
-
-    PWL_CREATEPARAM ccp = m_sPrivateParam;
-
-    ccp.dwFlags &= 0xFFFF0000L;  // remove sub styles
-    ccp.mtChild = CFX_Matrix(1, 0, 0, 1, 0, 0);
-
-    CreateScrollBar(ccp);
-    CreateChildWnd(ccp);
-
-    m_bVisible = HasFlag(PWS_VISIBLE);
-
-    OnCreated();
-
-    RePosChildWnd();
-    m_bCreated = true;
-  }
-}
-
-void CPWL_Wnd::OnCreate(PWL_CREATEPARAM& cp) {}
-
-void CPWL_Wnd::OnCreated() {}
-
-void CPWL_Wnd::OnDestroy() {}
-
-void CPWL_Wnd::InvalidateFocusHandler(IPWL_FocusHandler* handler) {
-  if (m_sPrivateParam.pFocusHandler == handler)
-    m_sPrivateParam.pFocusHandler = nullptr;
-}
-
-void CPWL_Wnd::InvalidateProvider(IPWL_Provider* provider) {
-  if (m_sPrivateParam.pProvider.Get() == provider)
-    m_sPrivateParam.pProvider.Reset();
-}
-
-void CPWL_Wnd::Destroy() {
-  KillFocus();
-  OnDestroy();
-  if (m_bCreated) {
-    for (auto it = m_Children.rbegin(); it != m_Children.rend(); ++it) {
-      if (CPWL_Wnd* pChild = *it) {
-        *it = nullptr;
-        pChild->Destroy();
-        delete pChild;
-      }
-    }
-    if (m_sPrivateParam.pParentWnd)
-      m_sPrivateParam.pParentWnd->OnNotify(this, PNM_REMOVECHILD);
-
-    m_bCreated = false;
-  }
-  DestroyMsgControl();
-  m_sPrivateParam.Reset();
-  m_Children.clear();
-  m_pVScrollBar = nullptr;
-}
-
-void CPWL_Wnd::Move(const CFX_FloatRect& rcNew, bool bReset, bool bRefresh) {
-  if (IsValid()) {
-    CFX_FloatRect rcOld = GetWindowRect();
-
-    m_rcWindow = rcNew;
-    m_rcWindow.Normalize();
-
-    if (rcOld.left != rcNew.left || rcOld.right != rcNew.right ||
-        rcOld.top != rcNew.top || rcOld.bottom != rcNew.bottom) {
-      if (bReset) {
-        RePosChildWnd();
-      }
-    }
-    if (bRefresh) {
-      InvalidateRectMove(rcOld, rcNew);
-    }
-
-    m_sPrivateParam.rcRectWnd = m_rcWindow;
-  }
-}
-
-void CPWL_Wnd::InvalidateRectMove(const CFX_FloatRect& rcOld,
-                                  const CFX_FloatRect& rcNew) {
-  CFX_FloatRect rcUnion = rcOld;
-  rcUnion.Union(rcNew);
-
-  InvalidateRect(&rcUnion);
-}
-
-void CPWL_Wnd::GetAppearanceStream(CFX_ByteTextBuf& sAppStream) {
-  if (IsValid() && IsVisible()) {
-    GetThisAppearanceStream(sAppStream);
-    GetChildAppearanceStream(sAppStream);
-  }
-}
-
-// if don't set,Get default apperance stream
-void CPWL_Wnd::GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) {
-  CFX_FloatRect rectWnd = GetWindowRect();
-  if (!rectWnd.IsEmpty()) {
-    CFX_ByteTextBuf sThis;
-
-    if (HasFlag(PWS_BACKGROUND))
-      sThis << CPWL_Utils::GetRectFillAppStream(rectWnd, GetBackgroundColor());
-
-    if (HasFlag(PWS_BORDER)) {
-      sThis << CPWL_Utils::GetBorderAppStream(
-          rectWnd, (FX_FLOAT)GetBorderWidth(), GetBorderColor(),
-          GetBorderLeftTopColor(GetBorderStyle()),
-          GetBorderRightBottomColor(GetBorderStyle()), GetBorderStyle(),
-          GetBorderDash());
-    }
-
-    sAppStream << sThis;
-  }
-}
-
-void CPWL_Wnd::GetChildAppearanceStream(CFX_ByteTextBuf& sAppStream) {
-  for (CPWL_Wnd* pChild : m_Children) {
-    if (pChild)
-      pChild->GetAppearanceStream(sAppStream);
-  }
-}
-
-void CPWL_Wnd::DrawAppearance(CFX_RenderDevice* pDevice,
-                              CFX_Matrix* pUser2Device) {
-  if (IsValid() && IsVisible()) {
-    DrawThisAppearance(pDevice, pUser2Device);
-    DrawChildAppearance(pDevice, pUser2Device);
-  }
-}
-
-void CPWL_Wnd::DrawThisAppearance(CFX_RenderDevice* pDevice,
-                                  CFX_Matrix* pUser2Device) {
-  CFX_FloatRect rectWnd = GetWindowRect();
-  if (!rectWnd.IsEmpty()) {
-    if (HasFlag(PWS_BACKGROUND)) {
-      CFX_FloatRect rcClient = CPWL_Utils::DeflateRect(
-          rectWnd, (FX_FLOAT)(GetBorderWidth() + GetInnerBorderWidth()));
-      CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcClient,
-                               GetBackgroundColor(), GetTransparency());
-    }
-
-    if (HasFlag(PWS_BORDER))
-      CPWL_Utils::DrawBorder(pDevice, pUser2Device, rectWnd,
-                             (FX_FLOAT)GetBorderWidth(), GetBorderColor(),
-                             GetBorderLeftTopColor(GetBorderStyle()),
-                             GetBorderRightBottomColor(GetBorderStyle()),
-                             GetBorderStyle(), GetTransparency());
-  }
-}
-
-void CPWL_Wnd::DrawChildAppearance(CFX_RenderDevice* pDevice,
-                                   CFX_Matrix* pUser2Device) {
-  for (CPWL_Wnd* pChild : m_Children) {
-    if (!pChild)
-      continue;
-
-    CFX_Matrix mt = pChild->GetChildMatrix();
-    if (mt.IsIdentity()) {
-      pChild->DrawAppearance(pDevice, pUser2Device);
-    } else {
-      mt.Concat(*pUser2Device);
-      pChild->DrawAppearance(pDevice, &mt);
-    }
-  }
-}
-
-void CPWL_Wnd::InvalidateRect(CFX_FloatRect* pRect) {
-  if (IsValid()) {
-    CFX_FloatRect rcRefresh = pRect ? *pRect : GetWindowRect();
-
-    if (!HasFlag(PWS_NOREFRESHCLIP)) {
-      CFX_FloatRect rcClip = GetClipRect();
-      if (!rcClip.IsEmpty()) {
-        rcRefresh.Intersect(rcClip);
-      }
-    }
-
-    FX_RECT rcWin = PWLtoWnd(rcRefresh);
-    rcWin.left -= PWL_INVALIDATE_INFLATE;
-    rcWin.top -= PWL_INVALIDATE_INFLATE;
-    rcWin.right += PWL_INVALIDATE_INFLATE;
-    rcWin.bottom += PWL_INVALIDATE_INFLATE;
-
-    if (CFX_SystemHandler* pSH = GetSystemHandler()) {
-      if (CPDFSDK_Widget* widget = static_cast<CPDFSDK_Widget*>(
-              m_sPrivateParam.pAttachedWidget.Get())) {
-        pSH->InvalidateRect(widget, rcWin);
-      }
-    }
-  }
-}
-
-#define PWL_IMPLEMENT_KEY_METHOD(key_method_name)                  \
-  bool CPWL_Wnd::key_method_name(uint16_t nChar, uint32_t nFlag) { \
-    if (!IsValid() || !IsVisible() || !IsEnabled())                \
-      return false;                                                \
-    if (!IsWndCaptureKeyboard(this))                               \
-      return false;                                                \
-    for (const auto& pChild : m_Children) {                        \
-      if (pChild && IsWndCaptureKeyboard(pChild))                  \
-        return pChild->key_method_name(nChar, nFlag);              \
-    }                                                              \
-    return false;                                                  \
-  }
-
-PWL_IMPLEMENT_KEY_METHOD(OnKeyDown)
-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_PointF& point, uint32_t nFlag) {  \
-    if (!IsValid() || !IsVisible() || !IsEnabled())                            \
-      return false;                                                            \
-    if (IsWndCaptureMouse(this)) {                                             \
-      for (const auto& pChild : m_Children) {                                  \
-        if (pChild && IsWndCaptureMouse(pChild)) {                             \
-          return pChild->mouse_method_name(pChild->ParentToChild(point),       \
-                                           nFlag);                             \
-        }                                                                      \
-      }                                                                        \
-      SetCursor();                                                             \
-      return false;                                                            \
-    }                                                                          \
-    for (const auto& pChild : m_Children) {                                    \
-      if (pChild && pChild->WndHitTest(pChild->ParentToChild(point))) {        \
-        return pChild->mouse_method_name(pChild->ParentToChild(point), nFlag); \
-      }                                                                        \
-    }                                                                          \
-    if (WndHitTest(point))                                                     \
-      SetCursor();                                                             \
-    return false;                                                              \
-  }
-
-PWL_IMPLEMENT_MOUSE_METHOD(OnLButtonDblClk)
-PWL_IMPLEMENT_MOUSE_METHOD(OnLButtonDown)
-PWL_IMPLEMENT_MOUSE_METHOD(OnLButtonUp)
-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_PointF& point,
-                            uint32_t nFlag) {
-  if (!IsValid() || !IsVisible() || !IsEnabled())
-    return false;
-
-  SetCursor();
-  if (!IsWndCaptureKeyboard(this))
-    return false;
-
-  for (const auto& pChild : m_Children) {
-    if (pChild && IsWndCaptureKeyboard(pChild))
-      return pChild->OnMouseWheel(zDelta, pChild->ParentToChild(point), nFlag);
-  }
-  return false;
-}
-
-void CPWL_Wnd::AddChild(CPWL_Wnd* pWnd) {
-  m_Children.push_back(pWnd);
-}
-
-void CPWL_Wnd::RemoveChild(CPWL_Wnd* pWnd) {
-  for (auto it = m_Children.rbegin(); it != m_Children.rend(); ++it) {
-    if (*it && *it == pWnd) {
-      m_Children.erase(std::next(it).base());
-      break;
-    }
-  }
-}
-
-void CPWL_Wnd::OnNotify(CPWL_Wnd* pWnd,
-                        uint32_t msg,
-                        intptr_t wParam,
-                        intptr_t lParam) {
-  switch (msg) {
-    case PNM_ADDCHILD:
-      AddChild(pWnd);
-      break;
-    case PNM_REMOVECHILD:
-      RemoveChild(pWnd);
-      break;
-    default:
-      break;
-  }
-}
-
-bool CPWL_Wnd::IsValid() const {
-  return m_bCreated;
-}
-
-const PWL_CREATEPARAM& CPWL_Wnd::GetCreationParam() const {
-  return m_sPrivateParam;
-}
-
-CPWL_Wnd* CPWL_Wnd::GetParentWindow() const {
-  return m_sPrivateParam.pParentWnd;
-}
-
-CFX_FloatRect CPWL_Wnd::GetWindowRect() const {
-  return m_rcWindow;
-}
-
-CFX_FloatRect CPWL_Wnd::GetClientRect() const {
-  CFX_FloatRect rcWindow = GetWindowRect();
-  CFX_FloatRect rcClient = CPWL_Utils::DeflateRect(
-      rcWindow, (FX_FLOAT)(GetBorderWidth() + GetInnerBorderWidth()));
-  if (CPWL_ScrollBar* pVSB = GetVScrollBar())
-    rcClient.right -= pVSB->GetScrollBarWidth();
-
-  rcClient.Normalize();
-  return rcWindow.Contains(rcClient) ? rcClient : CFX_FloatRect();
-}
-
-CFX_PointF CPWL_Wnd::GetCenterPoint() const {
-  CFX_FloatRect rcClient = GetClientRect();
-  return CFX_PointF((rcClient.left + rcClient.right) * 0.5f,
-                    (rcClient.top + rcClient.bottom) * 0.5f);
-}
-
-bool CPWL_Wnd::HasFlag(uint32_t dwFlags) const {
-  return (m_sPrivateParam.dwFlags & dwFlags) != 0;
-}
-
-void CPWL_Wnd::RemoveFlag(uint32_t dwFlags) {
-  m_sPrivateParam.dwFlags &= ~dwFlags;
-}
-
-void CPWL_Wnd::AddFlag(uint32_t dwFlags) {
-  m_sPrivateParam.dwFlags |= dwFlags;
-}
-
-CPWL_Color CPWL_Wnd::GetBackgroundColor() const {
-  return m_sPrivateParam.sBackgroundColor;
-}
-
-void CPWL_Wnd::SetBackgroundColor(const CPWL_Color& color) {
-  m_sPrivateParam.sBackgroundColor = color;
-}
-
-CPWL_Color CPWL_Wnd::GetTextColor() const {
-  return m_sPrivateParam.sTextColor;
-}
-
-BorderStyle CPWL_Wnd::GetBorderStyle() const {
-  return m_sPrivateParam.nBorderStyle;
-}
-
-void CPWL_Wnd::SetBorderStyle(BorderStyle nBorderStyle) {
-  if (HasFlag(PWS_BORDER))
-    m_sPrivateParam.nBorderStyle = nBorderStyle;
-}
-
-int32_t CPWL_Wnd::GetBorderWidth() const {
-  if (HasFlag(PWS_BORDER))
-    return m_sPrivateParam.dwBorderWidth;
-
-  return 0;
-}
-
-int32_t CPWL_Wnd::GetInnerBorderWidth() const {
-  return 0;
-}
-
-CPWL_Color CPWL_Wnd::GetBorderColor() const {
-  if (HasFlag(PWS_BORDER))
-    return m_sPrivateParam.sBorderColor;
-
-  return CPWL_Color();
-}
-
-const CPWL_Dash& CPWL_Wnd::GetBorderDash() const {
-  return m_sPrivateParam.sDash;
-}
-
-void* CPWL_Wnd::GetAttachedData() const {
-  return m_sPrivateParam.pAttachedData;
-}
-
-CPWL_ScrollBar* CPWL_Wnd::GetVScrollBar() const {
-  if (HasFlag(PWS_VSCROLL))
-    return m_pVScrollBar;
-
-  return nullptr;
-}
-
-void CPWL_Wnd::CreateScrollBar(const PWL_CREATEPARAM& cp) {
-  CreateVScrollBar(cp);
-}
-
-void CPWL_Wnd::CreateVScrollBar(const PWL_CREATEPARAM& cp) {
-  if (!m_pVScrollBar && HasFlag(PWS_VSCROLL)) {
-    PWL_CREATEPARAM scp = cp;
-
-    // flags
-    scp.dwFlags =
-        PWS_CHILD | PWS_BACKGROUND | PWS_AUTOTRANSPARENT | PWS_NOREFRESHCLIP;
-
-    scp.pParentWnd = this;
-    scp.sBackgroundColor = PWL_DEFAULT_WHITECOLOR;
-    scp.eCursorType = FXCT_ARROW;
-    scp.nTransparency = PWL_SCROLLBAR_TRANSPARENCY;
-
-    m_pVScrollBar = new CPWL_ScrollBar(SBT_VSCROLL);
-    m_pVScrollBar->Create(scp);
-  }
-}
-
-void CPWL_Wnd::SetCapture() {
-  if (CPWL_MsgControl* pMsgCtrl = GetMsgControl())
-    pMsgCtrl->SetCapture(this);
-}
-
-void CPWL_Wnd::ReleaseCapture() {
-  for (const auto& pChild : m_Children) {
-    if (pChild)
-      pChild->ReleaseCapture();
-  }
-  if (CPWL_MsgControl* pMsgCtrl = GetMsgControl())
-    pMsgCtrl->ReleaseCapture();
-}
-
-void CPWL_Wnd::SetFocus() {
-  if (CPWL_MsgControl* pMsgCtrl = GetMsgControl()) {
-    if (!pMsgCtrl->IsMainCaptureKeyboard(this))
-      pMsgCtrl->KillFocus();
-    pMsgCtrl->SetFocus(this);
-  }
-}
-
-void CPWL_Wnd::KillFocus() {
-  if (CPWL_MsgControl* pMsgCtrl = GetMsgControl()) {
-    if (pMsgCtrl->IsWndCaptureKeyboard(this))
-      pMsgCtrl->KillFocus();
-  }
-}
-
-void CPWL_Wnd::OnSetFocus() {}
-
-void CPWL_Wnd::OnKillFocus() {}
-
-bool CPWL_Wnd::WndHitTest(const CFX_PointF& point) const {
-  return IsValid() && IsVisible() && GetWindowRect().Contains(point);
-}
-
-bool CPWL_Wnd::ClientHitTest(const CFX_PointF& point) const {
-  return IsValid() && IsVisible() && GetClientRect().Contains(point);
-}
-
-const CPWL_Wnd* CPWL_Wnd::GetRootWnd() const {
-  if (m_sPrivateParam.pParentWnd)
-    return m_sPrivateParam.pParentWnd->GetRootWnd();
-
-  return this;
-}
-
-void CPWL_Wnd::SetVisible(bool bVisible) {
-  if (!IsValid())
-    return;
-
-  for (const auto& pChild : m_Children) {
-    if (pChild)
-      pChild->SetVisible(bVisible);
-  }
-  if (bVisible != m_bVisible) {
-    m_bVisible = bVisible;
-    RePosChildWnd();
-    InvalidateRect();
-  }
-}
-
-void CPWL_Wnd::SetClipRect(const CFX_FloatRect& rect) {
-  m_rcClip = rect;
-  m_rcClip.Normalize();
-}
-
-const CFX_FloatRect& CPWL_Wnd::GetClipRect() const {
-  return m_rcClip;
-}
-
-bool CPWL_Wnd::IsReadOnly() const {
-  return HasFlag(PWS_READONLY);
-}
-
-void CPWL_Wnd::RePosChildWnd() {
-  CFX_FloatRect rcContent = CPWL_Utils::DeflateRect(
-      GetWindowRect(), (FX_FLOAT)(GetBorderWidth() + GetInnerBorderWidth()));
-
-  CPWL_ScrollBar* pVSB = GetVScrollBar();
-
-  CFX_FloatRect rcVScroll =
-      CFX_FloatRect(rcContent.right - PWL_SCROLLBAR_WIDTH, rcContent.bottom,
-                    rcContent.right - 1.0f, rcContent.top);
-
-  if (pVSB)
-    pVSB->Move(rcVScroll, true, false);
-}
-
-void CPWL_Wnd::CreateChildWnd(const PWL_CREATEPARAM& cp) {}
-
-void CPWL_Wnd::SetCursor() {
-  if (IsValid()) {
-    if (CFX_SystemHandler* pSH = GetSystemHandler()) {
-      int32_t nCursorType = GetCreationParam().eCursorType;
-      pSH->SetCursor(nCursorType);
-    }
-  }
-}
-
-void CPWL_Wnd::CreateMsgControl() {
-  if (!m_sPrivateParam.pMsgControl)
-    m_sPrivateParam.pMsgControl = new CPWL_MsgControl(this);
-}
-
-void CPWL_Wnd::DestroyMsgControl() {
-  if (CPWL_MsgControl* pMsgControl = GetMsgControl())
-    if (pMsgControl->IsWndCreated(this))
-      delete pMsgControl;
-}
-
-CPWL_MsgControl* CPWL_Wnd::GetMsgControl() const {
-  return m_sPrivateParam.pMsgControl;
-}
-
-bool CPWL_Wnd::IsCaptureMouse() const {
-  return IsWndCaptureMouse(this);
-}
-
-bool CPWL_Wnd::IsWndCaptureMouse(const CPWL_Wnd* pWnd) const {
-  if (CPWL_MsgControl* pCtrl = GetMsgControl())
-    return pCtrl->IsWndCaptureMouse(pWnd);
-
-  return false;
-}
-
-bool CPWL_Wnd::IsWndCaptureKeyboard(const CPWL_Wnd* pWnd) const {
-  if (CPWL_MsgControl* pCtrl = GetMsgControl())
-    return pCtrl->IsWndCaptureKeyboard(pWnd);
-
-  return false;
-}
-
-bool CPWL_Wnd::IsFocused() const {
-  if (CPWL_MsgControl* pCtrl = GetMsgControl())
-    return pCtrl->IsMainCaptureKeyboard(this);
-
-  return false;
-}
-
-CFX_FloatRect CPWL_Wnd::GetFocusRect() const {
-  return CPWL_Utils::InflateRect(GetWindowRect(), 1);
-}
-
-FX_FLOAT CPWL_Wnd::GetFontSize() const {
-  return m_sPrivateParam.fFontSize;
-}
-
-void CPWL_Wnd::SetFontSize(FX_FLOAT fFontSize) {
-  m_sPrivateParam.fFontSize = fFontSize;
-}
-
-CFX_SystemHandler* CPWL_Wnd::GetSystemHandler() const {
-  return m_sPrivateParam.pSystemHandler;
-}
-
-IPWL_FocusHandler* CPWL_Wnd::GetFocusHandler() const {
-  return m_sPrivateParam.pFocusHandler;
-}
-
-IPWL_Provider* CPWL_Wnd::GetProvider() const {
-  return m_sPrivateParam.pProvider.Get();
-}
-
-IPVT_FontMap* CPWL_Wnd::GetFontMap() const {
-  return m_sPrivateParam.pFontMap;
-}
-
-CPWL_Color CPWL_Wnd::GetBorderLeftTopColor(BorderStyle nBorderStyle) const {
-  switch (nBorderStyle) {
-    case BorderStyle::BEVELED:
-      return CPWL_Color(COLORTYPE_GRAY, 1);
-    case BorderStyle::INSET:
-      return CPWL_Color(COLORTYPE_GRAY, 0.5f);
-    default:
-      return CPWL_Color();
-  }
-}
-
-CPWL_Color CPWL_Wnd::GetBorderRightBottomColor(BorderStyle nBorderStyle) const {
-  switch (nBorderStyle) {
-    case BorderStyle::BEVELED:
-      return GetBackgroundColor() / 2.0f;
-    case BorderStyle::INSET:
-      return CPWL_Color(COLORTYPE_GRAY, 0.75f);
-    default:
-      return CPWL_Color();
-  }
-}
-
-int32_t CPWL_Wnd::GetTransparency() {
-  return m_sPrivateParam.nTransparency;
-}
-
-void CPWL_Wnd::SetTransparency(int32_t nTransparency) {
-  for (const auto& pChild : m_Children) {
-    if (pChild)
-      pChild->SetTransparency(nTransparency);
-  }
-  m_sPrivateParam.nTransparency = nTransparency;
-}
-
-CFX_Matrix CPWL_Wnd::GetWindowMatrix() const {
-  CFX_Matrix mt = GetChildToRoot();
-  if (IPWL_Provider* pProvider = GetProvider())
-    mt.Concat(pProvider->GetWindowMatrix(GetAttachedData()));
-  return mt;
-}
-
-FX_RECT CPWL_Wnd::PWLtoWnd(const CFX_FloatRect& rect) const {
-  CFX_FloatRect rcTemp = rect;
-  CFX_Matrix mt = GetWindowMatrix();
-  mt.TransformRect(rcTemp);
-  return FX_RECT((int32_t)(rcTemp.left + 0.5), (int32_t)(rcTemp.bottom + 0.5),
-                 (int32_t)(rcTemp.right + 0.5), (int32_t)(rcTemp.top + 0.5));
-}
-
-CFX_PointF CPWL_Wnd::ParentToChild(const CFX_PointF& point) const {
-  CFX_Matrix mt = GetChildMatrix();
-  if (mt.IsIdentity())
-    return point;
-
-  mt.SetReverse(mt);
-  return mt.Transform(point);
-}
-
-CFX_FloatRect CPWL_Wnd::ParentToChild(const CFX_FloatRect& rect) const {
-  CFX_Matrix mt = GetChildMatrix();
-  if (mt.IsIdentity())
-    return rect;
-
-  mt.SetReverse(mt);
-  CFX_FloatRect rc = rect;
-  mt.TransformRect(rc);
-  return rc;
-}
-
-CFX_Matrix CPWL_Wnd::GetChildToRoot() const {
-  CFX_Matrix mt(1, 0, 0, 1, 0, 0);
-  if (HasFlag(PWS_CHILD)) {
-    const CPWL_Wnd* pParent = this;
-    while (pParent) {
-      mt.Concat(pParent->GetChildMatrix());
-      pParent = pParent->GetParentWindow();
-    }
-  }
-  return mt;
-}
-
-CFX_Matrix CPWL_Wnd::GetChildMatrix() const {
-  if (HasFlag(PWS_CHILD))
-    return m_sPrivateParam.mtChild;
-
-  return CFX_Matrix(1, 0, 0, 1, 0, 0);
-}
-
-void CPWL_Wnd::SetChildMatrix(const CFX_Matrix& mt) {
-  m_sPrivateParam.mtChild = mt;
-}
-
-const CPWL_Wnd* CPWL_Wnd::GetFocused() const {
-  CPWL_MsgControl* pMsgCtrl = GetMsgControl();
-  return pMsgCtrl ? pMsgCtrl->m_pMainKeyboardWnd : nullptr;
-}
-
-void CPWL_Wnd::EnableWindow(bool bEnable) {
-  if (m_bEnabled == bEnable)
-    return;
-
-  for (const auto& pChild : m_Children) {
-    if (pChild)
-      pChild->EnableWindow(bEnable);
-  }
-  m_bEnabled = bEnable;
-}
-
-bool CPWL_Wnd::IsCTRLpressed(uint32_t nFlag) const {
-  CFX_SystemHandler* pSystemHandler = GetSystemHandler();
-  return pSystemHandler && pSystemHandler->IsCTRLKeyDown(nFlag);
-}
-
-bool CPWL_Wnd::IsSHIFTpressed(uint32_t nFlag) const {
-  CFX_SystemHandler* pSystemHandler = GetSystemHandler();
-  return pSystemHandler && pSystemHandler->IsSHIFTKeyDown(nFlag);
-}
-
-bool CPWL_Wnd::IsALTpressed(uint32_t nFlag) const {
-  CFX_SystemHandler* pSystemHandler = GetSystemHandler();
-  return pSystemHandler && pSystemHandler->IsALTKeyDown(nFlag);
-}
diff --git a/fpdfsdk/pdfwindow/PWL_Wnd.h b/fpdfsdk/pdfwindow/PWL_Wnd.h
deleted file mode 100644
index 55836d4..0000000
--- a/fpdfsdk/pdfwindow/PWL_Wnd.h
+++ /dev/null
@@ -1,410 +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 FPDFSDK_PDFWINDOW_PWL_WND_H_
-#define FPDFSDK_PDFWINDOW_PWL_WND_H_
-
-#include <memory>
-#include <vector>
-
-#include "core/fpdfdoc/cpdf_formcontrol.h"
-#include "core/fxcrt/cfx_observable.h"
-#include "core/fxcrt/fx_basic.h"
-#include "fpdfsdk/cfx_systemhandler.h"
-#include "fpdfsdk/cpdfsdk_widget.h"
-#include "fpdfsdk/pdfwindow/cpwl_color.h"
-
-class CPWL_MsgControl;
-class CPWL_ScrollBar;
-class CPWL_Timer;
-class CPWL_TimerHandler;
-class CPWL_Wnd;
-class CFX_SystemHandler;
-class IPVT_FontMap;
-class IPWL_Provider;
-
-// window styles
-#define PWS_CHILD 0x80000000L
-#define PWS_BORDER 0x40000000L
-#define PWS_BACKGROUND 0x20000000L
-#define PWS_HSCROLL 0x10000000L
-#define PWS_VSCROLL 0x08000000L
-#define PWS_VISIBLE 0x04000000L
-#define PWS_DISABLE 0x02000000L
-#define PWS_READONLY 0x01000000L
-#define PWS_AUTOFONTSIZE 0x00800000L
-#define PWS_AUTOTRANSPARENT 0x00400000L
-#define PWS_NOREFRESHCLIP 0x00200000L
-
-// edit and label styles
-#define PES_MULTILINE 0x0001L
-#define PES_PASSWORD 0x0002L
-#define PES_LEFT 0x0004L
-#define PES_RIGHT 0x0008L
-#define PES_MIDDLE 0x0010L
-#define PES_TOP 0x0020L
-#define PES_BOTTOM 0x0040L
-#define PES_CENTER 0x0080L
-#define PES_CHARARRAY 0x0100L
-#define PES_AUTOSCROLL 0x0200L
-#define PES_AUTORETURN 0x0400L
-#define PES_UNDO 0x0800L
-#define PES_RICH 0x1000L
-#define PES_SPELLCHECK 0x2000L
-#define PES_TEXTOVERFLOW 0x4000L
-#define PES_NOREAD 0x8000L
-
-// listbox styles
-#define PLBS_MULTIPLESEL 0x0001L
-#define PLBS_HOVERSEL 0x0008L
-
-// combobox styles
-#define PCBS_ALLOWCUSTOMTEXT 0x0001L
-
-// richedit styles
-#define PRES_MULTILINE 0x0001L
-#define PRES_AUTORETURN 0x0002L
-#define PRES_AUTOSCROLL 0x0004L
-#define PRES_UNDO 0x0100L
-#define PRES_MULTIPAGES 0x0200L
-#define PRES_TEXTOVERFLOW 0x0400L
-
-// notification messages
-#define PNM_ADDCHILD 0x00000000L
-#define PNM_REMOVECHILD 0x00000001L
-#define PNM_SETSCROLLINFO 0x00000002L
-#define PNM_SETSCROLLPOS 0x00000003L
-#define PNM_SCROLLWINDOW 0x00000004L
-#define PNM_LBUTTONDOWN 0x00000005L
-#define PNM_LBUTTONUP 0x00000006L
-#define PNM_MOUSEMOVE 0x00000007L
-#define PNM_NOTERESET 0x00000008L
-#define PNM_SETCARETINFO 0x00000009L
-#define PNM_SELCHANGED 0x0000000AL
-#define PNM_NOTEEDITCHANGED 0x0000000BL
-
-#define PWL_CLASSNAME_EDIT "CPWL_Edit"
-
-struct CPWL_Dash {
-  CPWL_Dash() : nDash(0), nGap(0), nPhase(0) {}
-  CPWL_Dash(int32_t dash, int32_t gap, int32_t phase)
-      : nDash(dash), nGap(gap), nPhase(phase) {}
-
-  void Reset() {
-    nDash = 0;
-    nGap = 0;
-    nPhase = 0;
-  }
-
-  int32_t nDash;
-  int32_t nGap;
-  int32_t nPhase;
-};
-
-inline bool operator==(const CPWL_Color& c1, const CPWL_Color& c2) {
-  return c1.nColorType == c2.nColorType && c1.fColor1 - c2.fColor1 < 0.0001 &&
-         c1.fColor1 - c2.fColor1 > -0.0001 &&
-         c1.fColor2 - c2.fColor2 < 0.0001 &&
-         c1.fColor2 - c2.fColor2 > -0.0001 &&
-         c1.fColor3 - c2.fColor3 < 0.0001 &&
-         c1.fColor3 - c2.fColor3 > -0.0001 &&
-         c1.fColor4 - c2.fColor4 < 0.0001 && c1.fColor4 - c2.fColor4 > -0.0001;
-}
-
-inline bool operator!=(const CPWL_Color& c1, const CPWL_Color& c2) {
-  return !(c1 == c2);
-}
-
-#define PWL_SCROLLBAR_WIDTH 12.0f
-#define PWL_SCROLLBAR_BUTTON_WIDTH 9.0f
-#define PWL_SCROLLBAR_POSBUTTON_MINWIDTH 2.0f
-#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)
-#define PWL_DEFAULT_SELBACKCOLOR \
-  CPWL_Color(COLORTYPE_RGB, 0, 51.0f / 255.0f, 113.0f / 255.0f)
-#define PWL_DEFAULT_BACKCOLOR PWL_DEFAULT_SELTEXTCOLOR
-#define PWL_DEFAULT_TEXTCOLOR CPWL_Color(COLORTYPE_RGB, 0, 0, 0)
-#define PWL_DEFAULT_FONTSIZE 9.0f
-#define PWL_DEFAULT_BLACKCOLOR CPWL_Color(COLORTYPE_GRAY, 0)
-#define PWL_DEFAULT_WHITECOLOR CPWL_Color(COLORTYPE_GRAY, 1)
-#define PWL_DEFAULT_HEAVYGRAYCOLOR CPWL_Color(COLORTYPE_GRAY, 0.50)
-#define PWL_DEFAULT_LIGHTGRAYCOLOR CPWL_Color(COLORTYPE_GRAY, 0.75)
-#define PWL_TRIANGLE_HALFLEN 2.0f
-#define PWL_CBBUTTON_TRIANGLE_HALFLEN 3.0f
-#define PWL_INVALIDATE_INFLATE 2
-
-class IPWL_Provider : public CFX_Observable<IPWL_Provider> {
- public:
-  virtual ~IPWL_Provider() {}
-
-  // get a matrix which map user space to CWnd client space
-  virtual CFX_Matrix GetWindowMatrix(void* pAttachedData) = 0;
-
-  /*
-  0 L"&Undo\tCtrl+Z"
-  1 L"&Redo\tCtrl+Shift+Z"
-  2 L"Cu&t\tCtrl+X"
-  3 L"&Copy\tCtrl+C"
-  4 L"&Paste\tCtrl+V"
-  5 L"&Delete"
-  6  L"&Select All\tCtrl+A"
-  */
-  virtual CFX_WideString LoadPopupMenuString(int32_t nIndex) = 0;
-};
-
-class IPWL_FocusHandler {
- public:
-  virtual ~IPWL_FocusHandler() {}
-  virtual void OnSetFocus(CPWL_Wnd* pWnd) = 0;
-};
-
-struct PWL_CREATEPARAM {
- public:
-  PWL_CREATEPARAM();
-  PWL_CREATEPARAM(const PWL_CREATEPARAM& other);
-
-  void Reset() {
-    rcRectWnd.Reset();
-    pSystemHandler = nullptr;
-    pFontMap = nullptr;
-    pProvider.Reset();
-    pFocusHandler = nullptr;
-    dwFlags = 0;
-    sBackgroundColor.Reset();
-    pAttachedWidget.Reset();
-    nBorderStyle = BorderStyle::SOLID;
-    dwBorderWidth = 0;
-    sBorderColor.Reset();
-    sTextColor.Reset();
-    nTransparency = 0;
-    fFontSize = 0.0f;
-    sDash.Reset();
-    pAttachedData = nullptr;
-    pParentWnd = nullptr;
-    pMsgControl = nullptr;
-    eCursorType = 0;
-    mtChild.SetIdentity();
-  }
-
-  CFX_FloatRect rcRectWnd;            // required
-  CFX_SystemHandler* pSystemHandler;  // required
-  IPVT_FontMap* pFontMap;             // required
-  IPWL_Provider::ObservedPtr pProvider;  // required
-  IPWL_FocusHandler* pFocusHandler;   // optional
-  uint32_t dwFlags;                   // optional
-  CPWL_Color sBackgroundColor;        // optional
-  CPDFSDK_Widget::ObservedPtr pAttachedWidget;  // required
-  BorderStyle nBorderStyle;           // optional
-  int32_t dwBorderWidth;              // optional
-  CPWL_Color sBorderColor;            // optional
-  CPWL_Color sTextColor;              // optional
-  int32_t nTransparency;              // optional
-  FX_FLOAT fFontSize;                 // optional
-  CPWL_Dash sDash;                    // optional
-  void* pAttachedData;                // optional
-  CPWL_Wnd* pParentWnd;               // ignore
-  CPWL_MsgControl* pMsgControl;       // ignore
-  int32_t eCursorType;                // ignore
-  CFX_Matrix mtChild;                 // ignore
-};
-
-class CPWL_Timer {
- public:
-  CPWL_Timer(CPWL_TimerHandler* pAttached, CFX_SystemHandler* pSystemHandler);
-  virtual ~CPWL_Timer();
-
-  int32_t SetPWLTimer(int32_t nElapse);
-  void KillPWLTimer();
-  static void TimerProc(int32_t idEvent);
-
- private:
-  int32_t m_nTimerID;
-  CPWL_TimerHandler* m_pAttached;
-  CFX_SystemHandler* m_pSystemHandler;
-};
-
-class CPWL_TimerHandler {
- public:
-  CPWL_TimerHandler();
-  virtual ~CPWL_TimerHandler();
-
-  void BeginTimer(int32_t nElapse);
-  void EndTimer();
-  virtual void TimerProc();
-  virtual CFX_SystemHandler* GetSystemHandler() const = 0;
-
- private:
-  std::unique_ptr<CPWL_Timer> m_pTimer;
-};
-
-class CPWL_Wnd : public CPWL_TimerHandler {
- public:
-  CPWL_Wnd();
-  ~CPWL_Wnd() override;
-
-  virtual CFX_ByteString GetClassName() const;
-  virtual void InvalidateRect(CFX_FloatRect* pRect = nullptr);
-
-  virtual bool OnKeyDown(uint16_t nChar, uint32_t nFlag);
-  virtual bool OnChar(uint16_t nChar, 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_PointF& point,
-                            uint32_t nFlag);
-  virtual void OnNotify(CPWL_Wnd* pWnd,
-                        uint32_t msg,
-                        intptr_t wParam = 0,
-                        intptr_t lParam = 0);
-  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 CFX_FloatRect GetClientRect() 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;
-  void* GetAttachedData() 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;
-  CPWL_ScrollBar* GetVScrollBar() const;
-
-  IPVT_FontMap* GetFontMap() const;
-  IPWL_Provider* GetProvider() const;
-  IPWL_FocusHandler* GetFocusHandler() const;
-
-  int32_t GetTransparency();
-  void SetTransparency(int32_t nTransparency);
-
-  CFX_Matrix GetChildToRoot() const;
-  CFX_Matrix GetChildMatrix() const;
-  void SetChildMatrix(const CFX_Matrix& mt);
-  CFX_Matrix GetWindowMatrix() const;
-
- protected:
-  friend class CPWL_MsgControl;
-
-  // CPWL_TimerHandler
-  CFX_SystemHandler* GetSystemHandler() const override;
-
-  virtual void CreateChildWnd(const PWL_CREATEPARAM& cp);
-  virtual void RePosChildWnd();
-  virtual void GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream);
-
-  virtual void DrawThisAppearance(CFX_RenderDevice* pDevice,
-                                  CFX_Matrix* pUser2Device);
-
-  virtual void OnCreate(PWL_CREATEPARAM& cp);
-  virtual void OnCreated();
-  virtual void OnDestroy();
-
-  virtual void OnSetFocus();
-  virtual void OnKillFocus();
-
-  void GetAppearanceStream(CFX_ByteTextBuf& sAppStream);
-  void SetNotifyFlag(bool bNotifying = true) { m_bNotifying = bNotifying; }
-
-  bool IsValid() const;
-  const PWL_CREATEPARAM& GetCreationParam() const;
-  bool IsNotifying() const { return m_bNotifying; }
-
-  void InvalidateRectMove(const CFX_FloatRect& rcOld,
-                          const CFX_FloatRect& rcNew);
-
-  bool IsWndCaptureMouse(const CPWL_Wnd* pWnd) const;
-  bool IsWndCaptureKeyboard(const CPWL_Wnd* pWnd) const;
-  const CPWL_Wnd* GetRootWnd() const;
-
-  bool IsCTRLpressed(uint32_t nFlag) const;
-  bool IsSHIFTpressed(uint32_t nFlag) const;
-  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);
-
-  void CreateScrollBar(const PWL_CREATEPARAM& cp);
-  void CreateVScrollBar(const PWL_CREATEPARAM& cp);
-
-  void AdjustStyle();
-  void CreateMsgControl();
-  void DestroyMsgControl();
-
-  CPWL_MsgControl* GetMsgControl() const;
-
-  std::vector<CPWL_Wnd*> m_Children;
-  PWL_CREATEPARAM m_sPrivateParam;
-  CPWL_ScrollBar* m_pVScrollBar;
-  CFX_FloatRect m_rcWindow;
-  CFX_FloatRect m_rcClip;
-  bool m_bCreated;
-  bool m_bVisible;
-  bool m_bNotifying;
-  bool m_bEnabled;
-};
-
-#endif  // FPDFSDK_PDFWINDOW_PWL_WND_H_
diff --git a/fpdfsdk/pdfwindow/cpwl_color.cpp b/fpdfsdk/pdfwindow/cpwl_color.cpp
deleted file mode 100644
index 9c9ca3e..0000000
--- a/fpdfsdk/pdfwindow/cpwl_color.cpp
+++ /dev/null
@@ -1,179 +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 "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
deleted file mode 100644
index f1b34c7..0000000
--- a/fpdfsdk/pdfwindow/cpwl_color.h
+++ /dev/null
@@ -1,53 +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 FPDFSDK_PDFWINDOW_CPWL_COLOR_H_
-#define FPDFSDK_PDFWINDOW_CPWL_COLOR_H_
-
-#include "core/fpdfdoc/cpdf_formcontrol.h"
-
-struct CPWL_Color {
-  CPWL_Color(int32_t type = COLORTYPE_TRANSPARENT,
-             FX_FLOAT color1 = 0.0f,
-             FX_FLOAT color2 = 0.0f,
-             FX_FLOAT color3 = 0.0f,
-             FX_FLOAT color4 = 0.0f)
-      : nColorType(type),
-        fColor1(color1),
-        fColor2(color2),
-        fColor3(color3),
-        fColor4(color4) {}
-
-  CPWL_Color(int32_t r, int32_t g, int32_t b)
-      : nColorType(COLORTYPE_RGB),
-        fColor1(r / 255.0f),
-        fColor2(g / 255.0f),
-        fColor3(b / 255.0f),
-        fColor4(0) {}
-
-  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;
-    fColor1 = 0.0f;
-    fColor2 = 0.0f;
-    fColor3 = 0.0f;
-    fColor4 = 0.0f;
-  }
-
-  int32_t nColorType;
-  FX_FLOAT fColor1;
-  FX_FLOAT fColor2;
-  FX_FLOAT fColor3;
-  FX_FLOAT fColor4;
-};
-
-#endif  // FPDFSDK_PDFWINDOW_CPWL_COLOR_H_
diff --git a/fpdfsdk/pwl/README.md b/fpdfsdk/pwl/README.md
new file mode 100644
index 0000000..1a73250
--- /dev/null
+++ b/fpdfsdk/pwl/README.md
@@ -0,0 +1,21 @@
+fpdfsdk/pwl is a Widget Library for AcroForms.
+
+CPWL_Wnd is the base class that widget classes extend. The derived widget
+classes are controllers for each widget. The hierarchy is:
+
+* CPWL_Wnd
+    * CPWL_Button
+        * CPWL_CheckBox
+        * CPWL_PushButton
+        * CPWL_RadioButton
+    * CPWL_Caret
+    * CPWL_EditCtrl
+        * CPWL_Edit
+    * CPWL_Icon
+    * CPWL_ListBox
+        * CPWL_CBListBox (combo box)
+    * CPWL_ScrollBar
+
+Widgets are rendered to Appearance Streams, with the case all centralized in
+CPWL_AppStream.
+
diff --git a/fpdfsdk/pwl/cpwl_appstream.cpp b/fpdfsdk/pwl/cpwl_appstream.cpp
new file mode 100644
index 0000000..203a634
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_appstream.cpp
@@ -0,0 +1,1993 @@
+// 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/pwl/cpwl_appstream.h"
+
+#include <utility>
+
+#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/cpdf_string.h"
+#include "core/fpdfapi/parser/fpdf_parser_decode.h"
+#include "core/fpdfdoc/cpvt_word.h"
+#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
+#include "fpdfsdk/cpdfsdk_interform.h"
+#include "fpdfsdk/cpdfsdk_pageview.h"
+#include "fpdfsdk/cpdfsdk_widget.h"
+#include "fpdfsdk/formfiller/cba_fontmap.h"
+#include "fpdfsdk/pwl/cpwl_edit.h"
+#include "fpdfsdk/pwl/cpwl_edit_impl.h"
+#include "fpdfsdk/pwl/cpwl_icon.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
+
+namespace {
+
+// Checkbox & radiobutton styles.
+enum class CheckStyle { kCheck = 0, kCircle, kCross, kDiamond, kSquare, kStar };
+
+// Pushbutton layout styles.
+enum class ButtonStyle {
+  kLabel = 0,
+  kIcon,
+  kIconTopLabelBottom,
+  kIconBottomLabelTop,
+  kIconLeftLabelRight,
+  kIconRightLabelLeft,
+  kLabelOverIcon
+};
+
+const char kAppendRectOperator[] = "re";
+const char kConcatMatrixOperator[] = "cm";
+const char kCurveToOperator[] = "c";
+const char kEndPathNoFillOrStrokeOperator[] = "n";
+const char kFillOperator[] = "f";
+const char kFillEvenOddOperator[] = "f*";
+const char kInvokeNamedXObjectOperator[] = "Do";
+const char kLineToOperator[] = "l";
+const char kMarkedSequenceBeginOperator[] = "BMC";
+const char kMarkedSequenceEndOperator[] = "EMC";
+const char kMoveTextPositionOperator[] = "Td";
+const char kMoveToOperator[] = "m";
+const char kSetCharacterSpacingOperator[] = "Tc";
+const char kSetCMYKOperator[] = "k";
+const char kSetCMKYStrokedOperator[] = "K";
+const char kSetDashOperator[] = "d";
+const char kSetGrayOperator[] = "g";
+const char kSetGrayStrokedOperator[] = "G";
+const char kSetLineCapStyleOperator[] = "J";
+const char kSetLineJoinStyleOperator[] = "j";
+const char kSetLineWidthOperator[] = "w";
+const char kSetNonZeroWindingClipOperator[] = "W";
+const char kSetRGBOperator[] = "rg";
+const char kSetRGBStrokedOperator[] = "RG";
+const char kSetTextFontAndSizeOperator[] = "Tf";
+const char kSetTextScaleHorizontalOperator[] = "Tz";
+const char kShowTextOperator[] = "Tj";
+const char kStateRestoreOperator[] = "Q";
+const char kStateSaveOperator[] = "q";
+const char kStrokeOperator[] = "S";
+const char kTextBeginOperator[] = "BT";
+const char kTextEndOperator[] = "ET";
+
+class AutoClosedCommand {
+ public:
+  AutoClosedCommand(std::ostringstream* stream,
+                    ByteString open,
+                    ByteString close)
+      : stream_(stream), close_(close) {
+    *stream_ << open << "\n";
+  }
+
+  virtual ~AutoClosedCommand() { *stream_ << close_ << "\n"; }
+
+ private:
+  std::ostringstream* stream_;
+  ByteString close_;
+};
+
+class AutoClosedQCommand : public AutoClosedCommand {
+ public:
+  explicit AutoClosedQCommand(std::ostringstream* stream)
+      : AutoClosedCommand(stream, kStateSaveOperator, kStateRestoreOperator) {}
+  ~AutoClosedQCommand() override {}
+};
+
+ByteString GetColorAppStream(const CFX_Color& color,
+                             const bool& bFillOrStroke) {
+  std::ostringstream sColorStream;
+
+  switch (color.nColorType) {
+    case CFX_Color::kRGB:
+      sColorStream << color.fColor1 << " " << color.fColor2 << " "
+                   << color.fColor3 << " "
+                   << (bFillOrStroke ? kSetRGBOperator : kSetRGBStrokedOperator)
+                   << "\n";
+      break;
+    case CFX_Color::kGray:
+      sColorStream << color.fColor1 << " "
+                   << (bFillOrStroke ? kSetGrayOperator
+                                     : kSetGrayStrokedOperator)
+                   << "\n";
+      break;
+    case CFX_Color::kCMYK:
+      sColorStream << color.fColor1 << " " << color.fColor2 << " "
+                   << color.fColor3 << " " << color.fColor4 << " "
+                   << (bFillOrStroke ? kSetCMYKOperator
+                                     : kSetCMKYStrokedOperator)
+                   << "\n";
+      break;
+  }
+
+  return ByteString(sColorStream);
+}
+
+ByteString GetAP_Check(const CFX_FloatRect& crBBox) {
+  const float fWidth = crBBox.right - crBBox.left;
+  const float fHeight = crBBox.top - crBBox.bottom;
+
+  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) {
+      pts[i][j].x = pts[i][j].x * fWidth + crBBox.left;
+      pts[i][j].y *= pts[i][j].y * fHeight + crBBox.bottom;
+    }
+  }
+
+  std::ostringstream csAP;
+  csAP << pts[0][0].x << " " << pts[0][0].y << " " << kMoveToOperator << "\n";
+
+  for (size_t i = 0; i < FX_ArraySize(pts); ++i) {
+    size_t nNext = i < FX_ArraySize(pts) - 1 ? i + 1 : 0;
+
+    float px1 = pts[i][1].x - pts[i][0].x;
+    float py1 = pts[i][1].y - pts[i][0].y;
+    float px2 = pts[i][2].x - pts[nNext][0].x;
+    float py2 = pts[i][2].y - pts[nNext][0].y;
+
+    csAP << pts[i][0].x + px1 * FX_BEZIER << " "
+         << pts[i][0].y + py1 * FX_BEZIER << " "
+         << pts[nNext][0].x + px2 * FX_BEZIER << " "
+         << pts[nNext][0].y + py2 * FX_BEZIER << " " << pts[nNext][0].x << " "
+         << pts[nNext][0].y << " " << kCurveToOperator << "\n";
+  }
+
+  return ByteString(csAP);
+}
+
+ByteString GetAP_Circle(const CFX_FloatRect& crBBox) {
+  std::ostringstream csAP;
+
+  float fWidth = crBBox.right - crBBox.left;
+  float fHeight = crBBox.top - 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 << " " << kMoveToOperator << "\n";
+
+  float px = pt2.x - pt1.x;
+  float py = pt2.y - pt1.y;
+
+  csAP << pt1.x << " " << pt1.y + py * FX_BEZIER << " "
+       << pt2.x - px * FX_BEZIER << " " << pt2.y << " " << pt2.x << " " << pt2.y
+       << " " << kCurveToOperator << "\n";
+
+  px = pt3.x - pt2.x;
+  py = pt2.y - pt3.y;
+
+  csAP << pt2.x + px * FX_BEZIER << " " << pt2.y << " " << pt3.x << " "
+       << pt3.y + py * FX_BEZIER << " " << pt3.x << " " << pt3.y << " "
+       << kCurveToOperator << "\n";
+
+  px = pt3.x - pt4.x;
+  py = pt3.y - pt4.y;
+
+  csAP << pt3.x << " " << pt3.y - py * FX_BEZIER << " "
+       << pt4.x + px * FX_BEZIER << " " << pt4.y << " " << pt4.x << " " << pt4.y
+       << " " << kCurveToOperator << "\n";
+
+  px = pt4.x - pt1.x;
+  py = pt1.y - pt4.y;
+
+  csAP << pt4.x - px * FX_BEZIER << " " << pt4.y << " " << pt1.x << " "
+       << pt1.y - py * FX_BEZIER << " " << pt1.x << " " << pt1.y << " "
+       << kCurveToOperator << "\n";
+
+  return ByteString(csAP);
+}
+
+ByteString GetAP_Cross(const CFX_FloatRect& crBBox) {
+  std::ostringstream csAP;
+
+  csAP << crBBox.left << " " << crBBox.top << " " << kMoveToOperator << "\n";
+  csAP << crBBox.right << " " << crBBox.bottom << " " << kLineToOperator
+       << "\n";
+  csAP << crBBox.left << " " << crBBox.bottom << " " << kMoveToOperator << "\n";
+  csAP << crBBox.right << " " << crBBox.top << " " << kLineToOperator << "\n";
+
+  return ByteString(csAP);
+}
+
+ByteString GetAP_Diamond(const CFX_FloatRect& crBBox) {
+  std::ostringstream csAP;
+
+  float fWidth = crBBox.right - crBBox.left;
+  float fHeight = crBBox.top - 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 << " " << kMoveToOperator << "\n";
+  csAP << pt2.x << " " << pt2.y << " " << kLineToOperator << "\n";
+  csAP << pt3.x << " " << pt3.y << " " << kLineToOperator << "\n";
+  csAP << pt4.x << " " << pt4.y << " " << kLineToOperator << "\n";
+  csAP << pt1.x << " " << pt1.y << " " << kLineToOperator << "\n";
+
+  return ByteString(csAP);
+}
+
+ByteString GetAP_Square(const CFX_FloatRect& crBBox) {
+  std::ostringstream csAP;
+
+  csAP << crBBox.left << " " << crBBox.top << " " << kMoveToOperator << "\n";
+  csAP << crBBox.right << " " << crBBox.top << " " << kLineToOperator << "\n";
+  csAP << crBBox.right << " " << crBBox.bottom << " " << kLineToOperator
+       << "\n";
+  csAP << crBBox.left << " " << crBBox.bottom << " " << kLineToOperator << "\n";
+  csAP << crBBox.left << " " << crBBox.top << " " << kLineToOperator << "\n";
+
+  return ByteString(csAP);
+}
+
+ByteString GetAP_Star(const CFX_FloatRect& crBBox) {
+  std::ostringstream csAP;
+
+  float fRadius = (crBBox.top - crBBox.bottom) / (1 + (float)cos(FX_PI / 5.0f));
+  CFX_PointF ptCenter = CFX_PointF((crBBox.left + crBBox.right) / 2.0f,
+                                   (crBBox.top + crBBox.bottom) / 2.0f);
+
+  float px[5];
+  float py[5];
+  float fAngel = FX_PI / 10.0f;
+  for (int32_t i = 0; i < 5; i++) {
+    px[i] = ptCenter.x + fRadius * (float)cos(fAngel);
+    py[i] = ptCenter.y + fRadius * (float)sin(fAngel);
+    fAngel += FX_PI * 2 / 5.0f;
+  }
+
+  csAP << px[0] << " " << py[0] << " " << kMoveToOperator << "\n";
+
+  int32_t nNext = 0;
+  for (int32_t j = 0; j < 5; j++) {
+    nNext += 2;
+    if (nNext >= 5)
+      nNext -= 5;
+    csAP << px[nNext] << " " << py[nNext] << " " << kLineToOperator << "\n";
+  }
+
+  return ByteString(csAP);
+}
+
+ByteString GetAP_HalfCircle(const CFX_FloatRect& crBBox, float fRotate) {
+  std::ostringstream csAP;
+
+  float fWidth = crBBox.right - crBBox.left;
+  float fHeight = crBBox.top - crBBox.bottom;
+
+  CFX_PointF pt1(-fWidth / 2, 0);
+  CFX_PointF pt2(0, fHeight / 2);
+  CFX_PointF pt3(fWidth / 2, 0);
+
+  float px;
+  float py;
+
+  csAP << cos(fRotate) << " " << sin(fRotate) << " " << -sin(fRotate) << " "
+       << cos(fRotate) << " " << crBBox.left + fWidth / 2 << " "
+       << crBBox.bottom + fHeight / 2 << " " << kConcatMatrixOperator << "\n";
+
+  csAP << pt1.x << " " << pt1.y << " " << kMoveToOperator << "\n";
+
+  px = pt2.x - pt1.x;
+  py = pt2.y - pt1.y;
+
+  csAP << pt1.x << " " << pt1.y + py * FX_BEZIER << " "
+       << pt2.x - px * FX_BEZIER << " " << pt2.y << " " << pt2.x << " " << pt2.y
+       << " " << kCurveToOperator << "\n";
+
+  px = pt3.x - pt2.x;
+  py = pt2.y - pt3.y;
+
+  csAP << pt2.x + px * FX_BEZIER << " " << pt2.y << " " << pt3.x << " "
+       << pt3.y + py * FX_BEZIER << " " << pt3.x << " " << pt3.y << " "
+       << kCurveToOperator << "\n";
+
+  return ByteString(csAP);
+}
+
+ByteString GetAppStream_Check(const CFX_FloatRect& rcBBox,
+                              const CFX_Color& crText) {
+  std::ostringstream sAP;
+  {
+    AutoClosedQCommand q(&sAP);
+    sAP << GetColorAppStream(crText, true) << GetAP_Check(rcBBox)
+        << kFillOperator << "\n";
+  }
+  return ByteString(sAP);
+}
+
+ByteString GetAppStream_Circle(const CFX_FloatRect& rcBBox,
+                               const CFX_Color& crText) {
+  std::ostringstream sAP;
+  {
+    AutoClosedQCommand q(&sAP);
+    sAP << GetColorAppStream(crText, true) << GetAP_Circle(rcBBox)
+        << kFillOperator << "\n";
+  }
+  return ByteString(sAP);
+}
+
+ByteString GetAppStream_Cross(const CFX_FloatRect& rcBBox,
+                              const CFX_Color& crText) {
+  std::ostringstream sAP;
+  {
+    AutoClosedQCommand q(&sAP);
+    sAP << GetColorAppStream(crText, false) << GetAP_Cross(rcBBox)
+        << kStrokeOperator << "\n";
+  }
+  return ByteString(sAP);
+}
+
+ByteString GetAppStream_Diamond(const CFX_FloatRect& rcBBox,
+                                const CFX_Color& crText) {
+  std::ostringstream sAP;
+  {
+    AutoClosedQCommand q(&sAP);
+    sAP << "1 " << kSetLineWidthOperator << "\n"
+        << GetColorAppStream(crText, true) << GetAP_Diamond(rcBBox)
+        << kFillOperator << "\n";
+  }
+  return ByteString(sAP);
+}
+
+ByteString GetAppStream_Square(const CFX_FloatRect& rcBBox,
+                               const CFX_Color& crText) {
+  std::ostringstream sAP;
+  {
+    AutoClosedQCommand q(&sAP);
+    sAP << GetColorAppStream(crText, true) << GetAP_Square(rcBBox)
+        << kFillOperator << "\n";
+  }
+  return ByteString(sAP);
+}
+
+ByteString GetAppStream_Star(const CFX_FloatRect& rcBBox,
+                             const CFX_Color& crText) {
+  std::ostringstream sAP;
+  {
+    AutoClosedQCommand q(&sAP);
+    sAP << GetColorAppStream(crText, true) << GetAP_Star(rcBBox)
+        << kFillOperator << "\n";
+  }
+  return ByteString(sAP);
+}
+
+ByteString GetCircleFillAppStream(const CFX_FloatRect& rect,
+                                  const CFX_Color& color) {
+  std::ostringstream sAppStream;
+  ByteString sColor = GetColorAppStream(color, true);
+  if (sColor.GetLength() > 0) {
+    AutoClosedQCommand q(&sAppStream);
+    sAppStream << sColor << GetAP_Circle(rect) << kFillOperator << "\n";
+  }
+  return ByteString(sAppStream);
+}
+
+ByteString GetCircleBorderAppStream(const CFX_FloatRect& rect,
+                                    float fWidth,
+                                    const CFX_Color& color,
+                                    const CFX_Color& crLeftTop,
+                                    const CFX_Color& crRightBottom,
+                                    BorderStyle nStyle,
+                                    const CPWL_Dash& dash) {
+  std::ostringstream sAppStream;
+  ByteString sColor;
+
+  if (fWidth > 0.0f) {
+    AutoClosedQCommand q(&sAppStream);
+
+    float fHalfWidth = fWidth / 2.0f;
+    CFX_FloatRect rect_by_2 = rect.GetDeflated(fHalfWidth, fHalfWidth);
+
+    float div = fHalfWidth * 0.75f;
+    CFX_FloatRect rect_by_75 = rect.GetDeflated(div, div);
+    switch (nStyle) {
+      default:
+      case BorderStyle::SOLID:
+      case BorderStyle::UNDERLINE: {
+        sColor = GetColorAppStream(color, false);
+        if (sColor.GetLength() > 0) {
+          AutoClosedQCommand q2(&sAppStream);
+          sAppStream << fWidth << " " << kSetLineWidthOperator << "\n"
+                     << sColor << GetAP_Circle(rect_by_2) << " "
+                     << kStrokeOperator << "\n";
+        }
+      } break;
+      case BorderStyle::DASH: {
+        sColor = GetColorAppStream(color, false);
+        if (sColor.GetLength() > 0) {
+          AutoClosedQCommand q2(&sAppStream);
+          sAppStream << fWidth << " " << kSetLineWidthOperator << "\n"
+                     << "[" << dash.nDash << " " << dash.nGap << "] "
+                     << dash.nPhase << " " << kSetDashOperator << "\n"
+                     << sColor << GetAP_Circle(rect_by_2) << " "
+                     << kStrokeOperator << "\n";
+        }
+      } break;
+      case BorderStyle::BEVELED: {
+        sColor = GetColorAppStream(color, false);
+        if (sColor.GetLength() > 0) {
+          AutoClosedQCommand q2(&sAppStream);
+          sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
+                     << sColor << GetAP_Circle(rect) << " " << kStrokeOperator
+                     << "\n";
+        }
+
+        sColor = GetColorAppStream(crLeftTop, false);
+        if (sColor.GetLength() > 0) {
+          AutoClosedQCommand q2(&sAppStream);
+          sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
+                     << sColor << GetAP_HalfCircle(rect_by_75, FX_PI / 4.0f)
+                     << " " << kStrokeOperator << "\n";
+        }
+
+        sColor = GetColorAppStream(crRightBottom, false);
+        if (sColor.GetLength() > 0) {
+          AutoClosedQCommand q2(&sAppStream);
+          sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
+                     << sColor << GetAP_HalfCircle(rect_by_75, FX_PI * 5 / 4.0f)
+                     << " " << kStrokeOperator << "\n";
+        }
+      } break;
+      case BorderStyle::INSET: {
+        sColor = GetColorAppStream(color, false);
+        if (sColor.GetLength() > 0) {
+          AutoClosedQCommand q2(&sAppStream);
+          sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
+                     << sColor << GetAP_Circle(rect) << " " << kStrokeOperator
+                     << "\n";
+        }
+
+        sColor = GetColorAppStream(crLeftTop, false);
+        if (sColor.GetLength() > 0) {
+          AutoClosedQCommand q2(&sAppStream);
+          sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
+                     << sColor << GetAP_HalfCircle(rect_by_75, FX_PI / 4.0f)
+                     << " " << kStrokeOperator << "\n";
+        }
+
+        sColor = GetColorAppStream(crRightBottom, false);
+        if (sColor.GetLength() > 0) {
+          AutoClosedQCommand q2(&sAppStream);
+          sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
+                     << sColor << GetAP_HalfCircle(rect_by_75, FX_PI * 5 / 4.0f)
+                     << " " << kStrokeOperator << "\n";
+        }
+      } break;
+    }
+  }
+  return ByteString(sAppStream);
+}
+
+ByteString GetCheckBoxAppStream(const CFX_FloatRect& rcBBox,
+                                CheckStyle nStyle,
+                                const CFX_Color& crText) {
+  CFX_FloatRect rcCenter = rcBBox.GetCenterSquare();
+  switch (nStyle) {
+    default:
+    case CheckStyle::kCheck:
+      return GetAppStream_Check(rcCenter, crText);
+    case CheckStyle::kCircle:
+      rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
+      return GetAppStream_Circle(rcCenter, crText);
+    case CheckStyle::kCross:
+      return GetAppStream_Cross(rcCenter, crText);
+    case CheckStyle::kDiamond:
+      rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
+      return GetAppStream_Diamond(rcCenter, crText);
+    case CheckStyle::kSquare:
+      rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
+      return GetAppStream_Square(rcCenter, crText);
+    case CheckStyle::kStar:
+      rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
+      return GetAppStream_Star(rcCenter, crText);
+  }
+}
+
+ByteString GetRadioButtonAppStream(const CFX_FloatRect& rcBBox,
+                                   CheckStyle nStyle,
+                                   const CFX_Color& crText) {
+  CFX_FloatRect rcCenter = rcBBox.GetCenterSquare();
+  switch (nStyle) {
+    default:
+    case CheckStyle::kCheck:
+      return GetAppStream_Check(rcCenter, crText);
+    case CheckStyle::kCircle:
+      rcCenter.ScaleFromCenterPoint(1.0f / 2.0f);
+      return GetAppStream_Circle(rcCenter, crText);
+    case CheckStyle::kCross:
+      return GetAppStream_Cross(rcCenter, crText);
+    case CheckStyle::kDiamond:
+      rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
+      return GetAppStream_Diamond(rcCenter, crText);
+    case CheckStyle::kSquare:
+      rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
+      return GetAppStream_Square(rcCenter, crText);
+    case CheckStyle::kStar:
+      rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
+      return GetAppStream_Star(rcCenter, crText);
+  }
+}
+
+ByteString GetFontSetString(IPVT_FontMap* pFontMap,
+                            int32_t nFontIndex,
+                            float fFontSize) {
+  if (!pFontMap)
+    return ByteString();
+
+  ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex);
+  if (sFontAlias.GetLength() <= 0 || fFontSize <= 0)
+    return ByteString();
+
+  std::ostringstream sRet;
+  sRet << "/" << sFontAlias << " " << fFontSize << " "
+       << kSetTextFontAndSizeOperator << "\n";
+  return ByteString(sRet);
+}
+
+ByteString GetWordRenderString(const ByteString& strWords) {
+  if (strWords.GetLength() > 0) {
+    return PDF_EncodeString(strWords, false) + " " + kShowTextOperator + "\n";
+  }
+  return ByteString();
+}
+
+ByteString GetEditAppStream(CPWL_EditImpl* pEdit,
+                            const CFX_PointF& ptOffset,
+                            bool bContinuous,
+                            uint16_t SubWord) {
+  CPWL_EditImpl_Iterator* pIterator = pEdit->GetIterator();
+  pIterator->SetAt(0);
+
+  std::ostringstream sEditStream;
+  std::ostringstream sWords;
+  int32_t nCurFontIndex = -1;
+  CFX_PointF ptOld;
+  CFX_PointF ptNew;
+  CPVT_WordPlace oldplace;
+
+  while (pIterator->NextWord()) {
+    CPVT_WordPlace place = pIterator->GetAt();
+    if (bContinuous) {
+      if (place.LineCmp(oldplace) != 0) {
+        if (sWords.tellp() > 0) {
+          sEditStream << GetWordRenderString(ByteString(sWords));
+          sWords.str("");
+        }
+
+        CPVT_Word word;
+        if (pIterator->GetWord(word)) {
+          ptNew = CFX_PointF(word.ptWord.x + ptOffset.x,
+                             word.ptWord.y + ptOffset.y);
+        } else {
+          CPVT_Line line;
+          pIterator->GetLine(line);
+          ptNew = CFX_PointF(line.ptLine.x + ptOffset.x,
+                             line.ptLine.y + ptOffset.y);
+        }
+
+        if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
+          sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y << " "
+                      << kMoveTextPositionOperator << "\n";
+
+          ptOld = ptNew;
+        }
+      }
+
+      CPVT_Word word;
+      if (pIterator->GetWord(word)) {
+        if (word.nFontIndex != nCurFontIndex) {
+          if (sWords.tellp() > 0) {
+            sEditStream << GetWordRenderString(ByteString(sWords));
+            sWords.str("");
+          }
+          sEditStream << GetFontSetString(pEdit->GetFontMap(), word.nFontIndex,
+                                          word.fFontSize);
+          nCurFontIndex = word.nFontIndex;
+        }
+
+        sWords << pEdit->GetPDFWordString(nCurFontIndex, word.Word, SubWord);
+      }
+
+      oldplace = place;
+    } else {
+      CPVT_Word word;
+      if (pIterator->GetWord(word)) {
+        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 << " "
+                      << kMoveTextPositionOperator << "\n";
+          ptOld = ptNew;
+        }
+
+        if (word.nFontIndex != nCurFontIndex) {
+          sEditStream << GetFontSetString(pEdit->GetFontMap(), word.nFontIndex,
+                                          word.fFontSize);
+          nCurFontIndex = word.nFontIndex;
+        }
+
+        sEditStream << GetWordRenderString(
+            pEdit->GetPDFWordString(nCurFontIndex, word.Word, SubWord));
+      }
+    }
+  }
+
+  if (sWords.tellp() > 0) {
+    sEditStream << GetWordRenderString(ByteString(sWords));
+    sWords.str("");
+  }
+
+  std::ostringstream sAppStream;
+  if (sEditStream.tellp() > 0) {
+    int32_t nHorzScale = pEdit->GetHorzScale();
+    if (nHorzScale != 100) {
+      sAppStream << nHorzScale << " " << kSetTextScaleHorizontalOperator
+                 << "\n";
+    }
+
+    float fCharSpace = pEdit->GetCharSpace();
+    if (!IsFloatZero(fCharSpace)) {
+      sAppStream << fCharSpace << " " << kSetCharacterSpacingOperator << "\n";
+    }
+
+    sAppStream << sEditStream.str();
+  }
+
+  return ByteString(sAppStream);
+}
+
+ByteString GenerateIconAppStream(CPDF_IconFit& fit,
+                                 CPDF_Stream* pIconStream,
+                                 const CFX_FloatRect& rcIcon) {
+  if (rcIcon.IsEmpty() || !pIconStream)
+    return ByteString();
+
+  CPWL_Icon icon;
+  CPWL_Wnd::CreateParams cp;
+  cp.dwFlags = PWS_VISIBLE;
+  icon.Create(cp);
+  icon.SetIconFit(&fit);
+  icon.SetPDFStream(pIconStream);
+  if (!icon.Move(rcIcon, false, false))
+    return ByteString();
+
+  ByteString sAlias = icon.GetImageAlias();
+  if (sAlias.GetLength() <= 0)
+    return ByteString();
+
+  CFX_FloatRect rcPlate = icon.GetClientRect();
+  CFX_Matrix mt = icon.GetImageMatrix().GetInverse();
+
+  float fHScale;
+  float fVScale;
+  std::tie(fHScale, fVScale) = icon.GetScale();
+
+  float fx;
+  float fy;
+  std::tie(fx, fy) = icon.GetImageOffset();
+
+  std::ostringstream str;
+  {
+    AutoClosedQCommand q(&str);
+    str << rcPlate.left << " " << rcPlate.bottom << " "
+        << rcPlate.right - rcPlate.left << " " << rcPlate.top - rcPlate.bottom
+        << " " << kAppendRectOperator << " " << kSetNonZeroWindingClipOperator
+        << " " << kEndPathNoFillOrStrokeOperator << "\n";
+
+    str << fHScale << " 0 0 " << fVScale << " " << rcPlate.left + fx << " "
+        << rcPlate.bottom + fy << " " << kConcatMatrixOperator << "\n";
+    str << mt.a << " " << mt.b << " " << mt.c << " " << mt.d << " " << mt.e
+        << " " << mt.f << " " << kConcatMatrixOperator << "\n";
+
+    str << "0 " << kSetGrayOperator << " 0 " << kSetGrayStrokedOperator << " 1 "
+        << kSetLineWidthOperator << " /" << sAlias << " "
+        << kInvokeNamedXObjectOperator << "\n";
+  }
+  icon.Destroy();
+
+  return ByteString(str);
+}
+
+ByteString GetPushButtonAppStream(const CFX_FloatRect& rcBBox,
+                                  IPVT_FontMap* pFontMap,
+                                  CPDF_Stream* pIconStream,
+                                  CPDF_IconFit& IconFit,
+                                  const WideString& sLabel,
+                                  const CFX_Color& crText,
+                                  float fFontSize,
+                                  ButtonStyle nLayOut) {
+  const float fAutoFontScale = 1.0f / 3.0f;
+
+  auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>();
+  pEdit->SetFontMap(pFontMap);
+  pEdit->SetAlignmentH(1, true);
+  pEdit->SetAlignmentV(1, true);
+  pEdit->SetMultiLine(false, true);
+  pEdit->SetAutoReturn(false, true);
+  if (IsFloatZero(fFontSize))
+    pEdit->SetAutoFontSize(true, true);
+  else
+    pEdit->SetFontSize(fFontSize);
+
+  pEdit->Initialize();
+  pEdit->SetText(sLabel);
+
+  CFX_FloatRect rcLabelContent = pEdit->GetContentRect();
+  CFX_FloatRect rcLabel;
+  CFX_FloatRect rcIcon;
+  float fWidth = 0.0f;
+  float fHeight = 0.0f;
+
+  switch (nLayOut) {
+    case ButtonStyle::kLabel:
+      rcLabel = rcBBox;
+      break;
+    case ButtonStyle::kIcon:
+      rcIcon = rcBBox;
+      break;
+    case ButtonStyle::kIconTopLabelBottom:
+      if (pIconStream) {
+        if (IsFloatZero(fFontSize)) {
+          fHeight = rcBBox.top - rcBBox.bottom;
+          rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
+                                  rcBBox.bottom + fHeight * fAutoFontScale);
+          rcIcon =
+              CFX_FloatRect(rcBBox.left, rcLabel.top, rcBBox.right, rcBBox.top);
+        } else {
+          fHeight = rcLabelContent.Height();
+
+          if (rcBBox.bottom + fHeight > rcBBox.top) {
+            rcLabel = rcBBox;
+          } else {
+            rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
+                                    rcBBox.bottom + fHeight);
+            rcIcon = CFX_FloatRect(rcBBox.left, rcLabel.top, rcBBox.right,
+                                   rcBBox.top);
+          }
+        }
+      } else {
+        rcLabel = rcBBox;
+      }
+      break;
+    case ButtonStyle::kIconBottomLabelTop:
+      if (pIconStream) {
+        if (IsFloatZero(fFontSize)) {
+          fHeight = rcBBox.top - rcBBox.bottom;
+          rcLabel =
+              CFX_FloatRect(rcBBox.left, rcBBox.top - fHeight * fAutoFontScale,
+                            rcBBox.right, rcBBox.top);
+          rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
+                                 rcLabel.bottom);
+        } else {
+          fHeight = rcLabelContent.Height();
+
+          if (rcBBox.bottom + fHeight > rcBBox.top) {
+            rcLabel = rcBBox;
+          } else {
+            rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.top - fHeight,
+                                    rcBBox.right, rcBBox.top);
+            rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
+                                   rcLabel.bottom);
+          }
+        }
+      } else {
+        rcLabel = rcBBox;
+      }
+      break;
+    case ButtonStyle::kIconLeftLabelRight:
+      if (pIconStream) {
+        if (IsFloatZero(fFontSize)) {
+          fWidth = rcBBox.right - rcBBox.left;
+          if (rcLabelContent.Width() < fWidth * fAutoFontScale) {
+            rcLabel = CFX_FloatRect(rcBBox.right - fWidth * fAutoFontScale,
+                                    rcBBox.bottom, rcBBox.right, rcBBox.top);
+            rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
+                                   rcBBox.top);
+          } else {
+            if (rcLabelContent.Width() < fWidth) {
+              rcLabel = CFX_FloatRect(rcBBox.right - rcLabelContent.Width(),
+                                      rcBBox.bottom, rcBBox.right, rcBBox.top);
+              rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
+                                     rcBBox.top);
+            } else {
+              rcLabel = rcBBox;
+            }
+          }
+        } else {
+          fWidth = rcLabelContent.Width();
+          if (rcBBox.left + fWidth > rcBBox.right) {
+            rcLabel = rcBBox;
+          } else {
+            rcLabel = CFX_FloatRect(rcBBox.right - fWidth, rcBBox.bottom,
+                                    rcBBox.right, rcBBox.top);
+            rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
+                                   rcBBox.top);
+          }
+        }
+      } else {
+        rcLabel = rcBBox;
+      }
+      break;
+    case ButtonStyle::kIconRightLabelLeft:
+      if (pIconStream) {
+        if (IsFloatZero(fFontSize)) {
+          fWidth = rcBBox.right - rcBBox.left;
+          if (rcLabelContent.Width() < fWidth * fAutoFontScale) {
+            rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom,
+                                    rcBBox.left + fWidth * fAutoFontScale,
+                                    rcBBox.top);
+            rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
+                                   rcBBox.top);
+          } else {
+            if (rcLabelContent.Width() < fWidth) {
+              rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom,
+                                      rcBBox.left + rcLabelContent.Width(),
+                                      rcBBox.top);
+              rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
+                                     rcBBox.top);
+            } else {
+              rcLabel = rcBBox;
+            }
+          }
+        } else {
+          fWidth = rcLabelContent.Width();
+          if (rcBBox.left + fWidth > rcBBox.right) {
+            rcLabel = rcBBox;
+          } else {
+            rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom,
+                                    rcBBox.left + fWidth, rcBBox.top);
+            rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
+                                   rcBBox.top);
+          }
+        }
+      } else {
+        rcLabel = rcBBox;
+      }
+      break;
+    case ButtonStyle::kLabelOverIcon:
+      rcLabel = rcBBox;
+      rcIcon = rcBBox;
+      break;
+  }
+
+  std::ostringstream sTemp;
+  sTemp << GenerateIconAppStream(IconFit, pIconStream, rcIcon);
+
+  if (!rcLabel.IsEmpty()) {
+    pEdit->SetPlateRect(rcLabel);
+    ByteString sEdit =
+        GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, 0.0f), true, 0);
+    if (sEdit.GetLength() > 0) {
+      AutoClosedCommand bt(&sTemp, kTextBeginOperator, kTextEndOperator);
+      sTemp << GetColorAppStream(crText, true) << sEdit;
+    }
+  }
+
+  if (sTemp.tellp() <= 0)
+    return ByteString();
+
+  std::ostringstream sAppStream;
+  {
+    AutoClosedQCommand q(&sAppStream);
+    sAppStream << rcBBox.left << " " << rcBBox.bottom << " "
+               << rcBBox.right - rcBBox.left << " "
+               << rcBBox.top - rcBBox.bottom << " " << kAppendRectOperator
+               << " " << kSetNonZeroWindingClipOperator << " "
+               << kEndPathNoFillOrStrokeOperator << "\n";
+    sAppStream << sTemp.str().c_str();
+  }
+  return ByteString(sAppStream);
+}
+
+ByteString GetBorderAppStreamInternal(const CFX_FloatRect& rect,
+                                      float fWidth,
+                                      const CFX_Color& color,
+                                      const CFX_Color& crLeftTop,
+                                      const CFX_Color& crRightBottom,
+                                      BorderStyle nStyle,
+                                      const CPWL_Dash& dash) {
+  std::ostringstream sAppStream;
+  ByteString sColor;
+
+  float fLeft = rect.left;
+  float fRight = rect.right;
+  float fTop = rect.top;
+  float fBottom = rect.bottom;
+
+  if (fWidth > 0.0f) {
+    float fHalfWidth = fWidth / 2.0f;
+    AutoClosedQCommand q(&sAppStream);
+
+    switch (nStyle) {
+      default:
+      case BorderStyle::SOLID:
+        sColor = GetColorAppStream(color, true);
+        if (sColor.GetLength() > 0) {
+          sAppStream << sColor;
+          sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
+                     << fTop - fBottom << " " << kAppendRectOperator << "\n";
+          sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " "
+                     << fRight - fLeft - fWidth * 2 << " "
+                     << fTop - fBottom - fWidth * 2 << " "
+                     << kAppendRectOperator << "\n";
+          sAppStream << kFillEvenOddOperator << "\n";
+        }
+        break;
+      case BorderStyle::DASH:
+        sColor = GetColorAppStream(color, false);
+        if (sColor.GetLength() > 0) {
+          sAppStream << sColor;
+          sAppStream << fWidth << " " << kSetLineWidthOperator << " ["
+                     << dash.nDash << " " << dash.nGap << "] " << dash.nPhase
+                     << " " << kSetDashOperator << "\n";
+          sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 << " "
+                     << kMoveToOperator << "\n";
+          sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2 << " "
+                     << kLineToOperator << "\n";
+          sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2 << " "
+                     << kLineToOperator << "\n";
+          sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2
+                     << " " << kLineToOperator << "\n";
+          sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 << " "
+                     << kLineToOperator << " " << kStrokeOperator << "\n";
+        }
+        break;
+      case BorderStyle::BEVELED:
+      case BorderStyle::INSET:
+        sColor = GetColorAppStream(crLeftTop, true);
+        if (sColor.GetLength() > 0) {
+          sAppStream << sColor;
+          sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
+                     << kMoveToOperator << "\n";
+          sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth << " "
+                     << kLineToOperator << "\n";
+          sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth << " "
+                     << kLineToOperator << "\n";
+          sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
+                     << " " << kLineToOperator << "\n";
+          sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
+                     << " " << kLineToOperator << "\n";
+          sAppStream << fLeft + fHalfWidth * 2 << " "
+                     << fBottom + fHalfWidth * 2 << " " << kLineToOperator
+                     << " " << kFillOperator << "\n";
+        }
+
+        sColor = GetColorAppStream(crRightBottom, true);
+        if (sColor.GetLength() > 0) {
+          sAppStream << sColor;
+          sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth << " "
+                     << kMoveToOperator << "\n";
+          sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth
+                     << " " << kLineToOperator << "\n";
+          sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
+                     << kLineToOperator << "\n";
+          sAppStream << fLeft + fHalfWidth * 2 << " "
+                     << fBottom + fHalfWidth * 2 << " " << kLineToOperator
+                     << "\n";
+          sAppStream << fRight - fHalfWidth * 2 << " "
+                     << fBottom + fHalfWidth * 2 << " " << kLineToOperator
+                     << "\n";
+          sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
+                     << " " << kLineToOperator << " " << kFillOperator << "\n";
+        }
+
+        sColor = GetColorAppStream(color, true);
+        if (sColor.GetLength() > 0) {
+          sAppStream << sColor;
+          sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
+                     << fTop - fBottom << " " << kAppendRectOperator << "\n";
+          sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
+                     << fRight - fLeft - fHalfWidth * 2 << " "
+                     << fTop - fBottom - fHalfWidth * 2 << " "
+                     << kAppendRectOperator << " " << kFillEvenOddOperator
+                     << "\n";
+        }
+        break;
+      case BorderStyle::UNDERLINE:
+        sColor = GetColorAppStream(color, false);
+        if (sColor.GetLength() > 0) {
+          sAppStream << sColor;
+          sAppStream << fWidth << " " << kSetLineWidthOperator << "\n";
+          sAppStream << fLeft << " " << fBottom + fWidth / 2 << " "
+                     << kMoveToOperator << "\n";
+          sAppStream << fRight << " " << fBottom + fWidth / 2 << " "
+                     << kLineToOperator << " " << kStrokeOperator << "\n";
+        }
+        break;
+    }
+  }
+
+  return ByteString(sAppStream);
+}
+
+ByteString GetDropButtonAppStream(const CFX_FloatRect& rcBBox) {
+  if (rcBBox.IsEmpty())
+    return ByteString();
+
+  std::ostringstream sAppStream;
+  {
+    AutoClosedQCommand q(&sAppStream);
+    sAppStream << GetColorAppStream(CFX_Color(CFX_Color::kRGB, 220.0f / 255.0f,
+                                              220.0f / 255.0f, 220.0f / 255.0f),
+                                    true)
+               << rcBBox.left << " " << rcBBox.bottom << " "
+               << rcBBox.right - rcBBox.left << " "
+               << rcBBox.top - rcBBox.bottom << " " << kAppendRectOperator
+               << " " << kFillOperator << "\n";
+  }
+
+  {
+    AutoClosedQCommand q(&sAppStream);
+    sAppStream << GetBorderAppStreamInternal(
+        rcBBox, 2, CFX_Color(CFX_Color::kGray, 0),
+        CFX_Color(CFX_Color::kGray, 1), CFX_Color(CFX_Color::kGray, 0.5),
+        BorderStyle::BEVELED, CPWL_Dash(3, 0, 0));
+  }
+
+  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)) {
+    AutoClosedQCommand q(&sAppStream);
+    sAppStream << " 0 " << kSetGrayOperator << "\n"
+               << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " "
+               << kMoveToOperator << "\n"
+               << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " "
+               << kLineToOperator << "\n"
+               << ptCenter.x << " " << ptCenter.y - 1.5f << " "
+               << kLineToOperator << "\n"
+               << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " "
+               << kLineToOperator << " " << kFillOperator << "\n";
+  }
+
+  return ByteString(sAppStream);
+}
+
+ByteString GetRectFillAppStream(const CFX_FloatRect& rect,
+                                const CFX_Color& color) {
+  std::ostringstream sAppStream;
+  ByteString sColor = GetColorAppStream(color, true);
+  if (sColor.GetLength() > 0) {
+    AutoClosedQCommand q(&sAppStream);
+    sAppStream << sColor << rect.left << " " << rect.bottom << " "
+               << rect.right - rect.left << " " << rect.top - rect.bottom << " "
+               << kAppendRectOperator << " " << kFillOperator << "\n";
+  }
+
+  return ByteString(sAppStream);
+}
+
+}  // namespace
+
+CPWL_AppStream::CPWL_AppStream(CPDFSDK_Widget* widget, CPDF_Dictionary* dict)
+    : widget_(widget), dict_(dict) {}
+
+CPWL_AppStream::~CPWL_AppStream() {}
+
+void CPWL_AppStream::SetAsPushButton() {
+  CPDF_FormControl* pControl = widget_->GetFormControl();
+  CFX_FloatRect rcWindow = widget_->GetRotatedRect();
+  ButtonStyle nLayout = ButtonStyle::kLabel;
+  switch (pControl->GetTextPosition()) {
+    case TEXTPOS_ICON:
+      nLayout = ButtonStyle::kIcon;
+      break;
+    case TEXTPOS_BELOW:
+      nLayout = ButtonStyle::kIconTopLabelBottom;
+      break;
+    case TEXTPOS_ABOVE:
+      nLayout = ButtonStyle::kIconBottomLabelTop;
+      break;
+    case TEXTPOS_RIGHT:
+      nLayout = ButtonStyle::kIconLeftLabelRight;
+      break;
+    case TEXTPOS_LEFT:
+      nLayout = ButtonStyle::kIconRightLabelLeft;
+      break;
+    case TEXTPOS_OVERLAID:
+      nLayout = ButtonStyle::kLabelOverIcon;
+      break;
+    default:
+      nLayout = ButtonStyle::kLabel;
+      break;
+  }
+
+  CFX_Color crBackground;
+  CFX_Color crBorder;
+  int iColorType;
+  float fc[4];
+  pControl->GetOriginalBackgroundColor(iColorType, fc);
+  if (iColorType > 0)
+    crBackground = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
+
+  pControl->GetOriginalBorderColor(iColorType, fc);
+  if (iColorType > 0)
+    crBorder = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
+
+  float fBorderWidth = static_cast<float>(widget_->GetBorderWidth());
+  CPWL_Dash dsBorder(3, 0, 0);
+  CFX_Color crLeftTop;
+  CFX_Color crRightBottom;
+
+  BorderStyle nBorderStyle = widget_->GetBorderStyle();
+  switch (nBorderStyle) {
+    case BorderStyle::DASH:
+      dsBorder = CPWL_Dash(3, 3, 0);
+      break;
+    case BorderStyle::BEVELED:
+      fBorderWidth *= 2;
+      crLeftTop = CFX_Color(CFX_Color::kGray, 1);
+      crRightBottom = crBackground / 2.0f;
+      break;
+    case BorderStyle::INSET:
+      fBorderWidth *= 2;
+      crLeftTop = CFX_Color(CFX_Color::kGray, 0.5);
+      crRightBottom = CFX_Color(CFX_Color::kGray, 0.75);
+      break;
+    default:
+      break;
+  }
+
+  CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth);
+  CFX_Color crText(CFX_Color::kGray, 0);
+  ByteString csNameTag;
+  CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
+  if (da.HasColor()) {
+    da.GetColor(iColorType, fc);
+    crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
+  }
+  float fFontSize = 12.0f;
+  if (da.HasFont())
+    csNameTag = da.GetFont(&fFontSize);
+
+  WideString csWCaption;
+  WideString csNormalCaption;
+  WideString csRolloverCaption;
+  WideString csDownCaption;
+  if (pControl->HasMKEntry("CA"))
+    csNormalCaption = pControl->GetNormalCaption();
+
+  if (pControl->HasMKEntry("RC"))
+    csRolloverCaption = pControl->GetRolloverCaption();
+
+  if (pControl->HasMKEntry("AC"))
+    csDownCaption = pControl->GetDownCaption();
+
+  CPDF_Stream* pNormalIcon = nullptr;
+  CPDF_Stream* pRolloverIcon = nullptr;
+  CPDF_Stream* pDownIcon = nullptr;
+  if (pControl->HasMKEntry("I"))
+    pNormalIcon = pControl->GetNormalIcon();
+
+  if (pControl->HasMKEntry("RI"))
+    pRolloverIcon = pControl->GetRolloverIcon();
+
+  if (pControl->HasMKEntry("IX"))
+    pDownIcon = pControl->GetDownIcon();
+
+  if (pNormalIcon) {
+    if (CPDF_Dictionary* pImageDict = pNormalIcon->GetDict()) {
+      if (pImageDict->GetStringFor("Name").IsEmpty())
+        pImageDict->SetNewFor<CPDF_String>("Name", "ImgA", false);
+    }
+  }
+
+  if (pRolloverIcon) {
+    if (CPDF_Dictionary* pImageDict = pRolloverIcon->GetDict()) {
+      if (pImageDict->GetStringFor("Name").IsEmpty())
+        pImageDict->SetNewFor<CPDF_String>("Name", "ImgB", false);
+    }
+  }
+
+  if (pDownIcon) {
+    if (CPDF_Dictionary* pImageDict = pDownIcon->GetDict()) {
+      if (pImageDict->GetStringFor("Name").IsEmpty())
+        pImageDict->SetNewFor<CPDF_String>("Name", "ImgC", false);
+    }
+  }
+
+  CPDF_IconFit iconFit = pControl->GetIconFit();
+
+  CBA_FontMap font_map(
+      widget_.Get(),
+      widget_->GetInterForm()->GetFormFillEnv()->GetSysHandler());
+  font_map.SetAPType("N");
+
+  ByteString csAP =
+      GetRectFillAppStream(rcWindow, crBackground) +
+      GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
+                                 crRightBottom, nBorderStyle, dsBorder) +
+      GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
+                             &font_map, pNormalIcon, iconFit, csNormalCaption,
+                             crText, fFontSize, nLayout);
+
+  Write("N", csAP, "");
+  if (pNormalIcon)
+    AddImage("N", pNormalIcon);
+
+  CPDF_FormControl::HighlightingMode eHLM = pControl->GetHighlightingMode();
+  if (eHLM == CPDF_FormControl::Push || eHLM == CPDF_FormControl::Toggle) {
+    if (csRolloverCaption.IsEmpty() && !pRolloverIcon) {
+      csRolloverCaption = csNormalCaption;
+      pRolloverIcon = pNormalIcon;
+    }
+
+    font_map.SetAPType("R");
+
+    csAP =
+        GetRectFillAppStream(rcWindow, crBackground) +
+        GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
+                                   crRightBottom, nBorderStyle, dsBorder) +
+        GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
+                               &font_map, pRolloverIcon, iconFit,
+                               csRolloverCaption, crText, fFontSize, nLayout);
+
+    Write("R", csAP, "");
+    if (pRolloverIcon)
+      AddImage("R", pRolloverIcon);
+
+    if (csDownCaption.IsEmpty() && !pDownIcon) {
+      csDownCaption = csNormalCaption;
+      pDownIcon = pNormalIcon;
+    }
+
+    switch (nBorderStyle) {
+      case BorderStyle::BEVELED: {
+        CFX_Color crTemp = crLeftTop;
+        crLeftTop = crRightBottom;
+        crRightBottom = crTemp;
+        break;
+      }
+      case BorderStyle::INSET: {
+        crLeftTop = CFX_Color(CFX_Color::kGray, 0);
+        crRightBottom = CFX_Color(CFX_Color::kGray, 1);
+        break;
+      }
+      default:
+        break;
+    }
+
+    font_map.SetAPType("D");
+
+    csAP =
+        GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
+        GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
+                                   crRightBottom, nBorderStyle, dsBorder) +
+        GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
+                               &font_map, pDownIcon, iconFit, csDownCaption,
+                               crText, fFontSize, nLayout);
+
+    Write("D", csAP, "");
+    if (pDownIcon)
+      AddImage("D", pDownIcon);
+  } else {
+    Remove("D");
+    Remove("R");
+  }
+}
+
+void CPWL_AppStream::SetAsCheckBox() {
+  CPDF_FormControl* pControl = widget_->GetFormControl();
+  CFX_Color crBackground, crBorder, crText;
+  int iColorType;
+  float fc[4];
+
+  pControl->GetOriginalBackgroundColor(iColorType, fc);
+  if (iColorType > 0)
+    crBackground = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
+
+  pControl->GetOriginalBorderColor(iColorType, fc);
+  if (iColorType > 0)
+    crBorder = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
+
+  float fBorderWidth = static_cast<float>(widget_->GetBorderWidth());
+  CPWL_Dash dsBorder(3, 0, 0);
+  CFX_Color crLeftTop, crRightBottom;
+
+  BorderStyle nBorderStyle = widget_->GetBorderStyle();
+  switch (nBorderStyle) {
+    case BorderStyle::DASH:
+      dsBorder = CPWL_Dash(3, 3, 0);
+      break;
+    case BorderStyle::BEVELED:
+      fBorderWidth *= 2;
+      crLeftTop = CFX_Color(CFX_Color::kGray, 1);
+      crRightBottom = crBackground / 2.0f;
+      break;
+    case BorderStyle::INSET:
+      fBorderWidth *= 2;
+      crLeftTop = CFX_Color(CFX_Color::kGray, 0.5);
+      crRightBottom = CFX_Color(CFX_Color::kGray, 0.75);
+      break;
+    default:
+      break;
+  }
+
+  CFX_FloatRect rcWindow = widget_->GetRotatedRect();
+  CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth);
+  CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
+  if (da.HasColor()) {
+    da.GetColor(iColorType, fc);
+    crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
+  }
+
+  CheckStyle nStyle = CheckStyle::kCheck;
+  WideString csWCaption = pControl->GetNormalCaption();
+  if (csWCaption.GetLength() > 0) {
+    switch (csWCaption[0]) {
+      case L'l':
+        nStyle = CheckStyle::kCircle;
+        break;
+      case L'8':
+        nStyle = CheckStyle::kCross;
+        break;
+      case L'u':
+        nStyle = CheckStyle::kDiamond;
+        break;
+      case L'n':
+        nStyle = CheckStyle::kSquare;
+        break;
+      case L'H':
+        nStyle = CheckStyle::kStar;
+        break;
+      case L'4':
+      default:
+        nStyle = CheckStyle::kCheck;
+    }
+  }
+
+  ByteString csAP_N_ON =
+      GetRectFillAppStream(rcWindow, crBackground) +
+      GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
+                                 crRightBottom, nBorderStyle, dsBorder);
+
+  ByteString csAP_N_OFF = csAP_N_ON;
+
+  switch (nBorderStyle) {
+    case BorderStyle::BEVELED: {
+      CFX_Color crTemp = crLeftTop;
+      crLeftTop = crRightBottom;
+      crRightBottom = crTemp;
+      break;
+    }
+    case BorderStyle::INSET: {
+      crLeftTop = CFX_Color(CFX_Color::kGray, 0);
+      crRightBottom = CFX_Color(CFX_Color::kGray, 1);
+      break;
+    }
+    default:
+      break;
+  }
+
+  ByteString csAP_D_ON =
+      GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
+      GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
+                                 crRightBottom, nBorderStyle, dsBorder);
+
+  ByteString csAP_D_OFF = csAP_D_ON;
+
+  csAP_N_ON += GetCheckBoxAppStream(rcClient, nStyle, crText);
+  csAP_D_ON += GetCheckBoxAppStream(rcClient, nStyle, crText);
+
+  Write("N", csAP_N_ON, pControl->GetCheckedAPState());
+  Write("N", csAP_N_OFF, "Off");
+
+  Write("D", csAP_D_ON, pControl->GetCheckedAPState());
+  Write("D", csAP_D_OFF, "Off");
+
+  ByteString csAS = widget_->GetAppState();
+  if (csAS.IsEmpty())
+    widget_->SetAppState("Off");
+}
+
+void CPWL_AppStream::SetAsRadioButton() {
+  CPDF_FormControl* pControl = widget_->GetFormControl();
+  CFX_Color crBackground;
+  CFX_Color crBorder;
+  CFX_Color crText;
+  int iColorType;
+  float fc[4];
+
+  pControl->GetOriginalBackgroundColor(iColorType, fc);
+  if (iColorType > 0)
+    crBackground = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
+
+  pControl->GetOriginalBorderColor(iColorType, fc);
+  if (iColorType > 0)
+    crBorder = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
+
+  float fBorderWidth = static_cast<float>(widget_->GetBorderWidth());
+  CPWL_Dash dsBorder(3, 0, 0);
+  CFX_Color crLeftTop;
+  CFX_Color crRightBottom;
+  BorderStyle nBorderStyle = widget_->GetBorderStyle();
+  switch (nBorderStyle) {
+    case BorderStyle::DASH:
+      dsBorder = CPWL_Dash(3, 3, 0);
+      break;
+    case BorderStyle::BEVELED:
+      fBorderWidth *= 2;
+      crLeftTop = CFX_Color(CFX_Color::kGray, 1);
+      crRightBottom = crBackground / 2.0f;
+      break;
+    case BorderStyle::INSET:
+      fBorderWidth *= 2;
+      crLeftTop = CFX_Color(CFX_Color::kGray, 0.5);
+      crRightBottom = CFX_Color(CFX_Color::kGray, 0.75);
+      break;
+    default:
+      break;
+  }
+
+  CFX_FloatRect rcWindow = widget_->GetRotatedRect();
+  CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth);
+  CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
+  if (da.HasColor()) {
+    da.GetColor(iColorType, fc);
+    crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
+  }
+
+  CheckStyle nStyle = CheckStyle::kCircle;
+  WideString csWCaption = pControl->GetNormalCaption();
+  if (csWCaption.GetLength() > 0) {
+    switch (csWCaption[0]) {
+      case L'8':
+        nStyle = CheckStyle::kCross;
+        break;
+      case L'u':
+        nStyle = CheckStyle::kDiamond;
+        break;
+      case L'n':
+        nStyle = CheckStyle::kSquare;
+        break;
+      case L'H':
+        nStyle = CheckStyle::kStar;
+        break;
+      case L'4':
+        nStyle = CheckStyle::kCheck;
+        break;
+      case L'l':
+      default:
+        nStyle = CheckStyle::kCircle;
+    }
+  }
+
+  ByteString csAP_N_ON;
+  CFX_FloatRect rcCenter = rcWindow.GetCenterSquare().GetDeflated(1.0f, 1.0f);
+  if (nStyle == CheckStyle::kCircle) {
+    if (nBorderStyle == BorderStyle::BEVELED) {
+      crLeftTop = CFX_Color(CFX_Color::kGray, 1);
+      crRightBottom = crBackground - 0.25f;
+    } else if (nBorderStyle == BorderStyle::INSET) {
+      crLeftTop = CFX_Color(CFX_Color::kGray, 0.5f);
+      crRightBottom = CFX_Color(CFX_Color::kGray, 0.75f);
+    }
+
+    csAP_N_ON =
+        GetCircleFillAppStream(rcCenter, crBackground) +
+        GetCircleBorderAppStream(rcCenter, fBorderWidth, crBorder, crLeftTop,
+                                 crRightBottom, nBorderStyle, dsBorder);
+  } else {
+    csAP_N_ON =
+        GetRectFillAppStream(rcWindow, crBackground) +
+        GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
+                                   crRightBottom, nBorderStyle, dsBorder);
+  }
+
+  ByteString csAP_N_OFF = csAP_N_ON;
+
+  switch (nBorderStyle) {
+    case BorderStyle::BEVELED: {
+      CFX_Color crTemp = crLeftTop;
+      crLeftTop = crRightBottom;
+      crRightBottom = crTemp;
+      break;
+    }
+    case BorderStyle::INSET: {
+      crLeftTop = CFX_Color(CFX_Color::kGray, 0);
+      crRightBottom = CFX_Color(CFX_Color::kGray, 1);
+      break;
+    }
+    default:
+      break;
+  }
+
+  ByteString csAP_D_ON;
+
+  if (nStyle == CheckStyle::kCircle) {
+    CFX_Color crBK = crBackground - 0.25f;
+    if (nBorderStyle == BorderStyle::BEVELED) {
+      crLeftTop = crBackground - 0.25f;
+      crRightBottom = CFX_Color(CFX_Color::kGray, 1);
+      crBK = crBackground;
+    } else if (nBorderStyle == BorderStyle::INSET) {
+      crLeftTop = CFX_Color(CFX_Color::kGray, 0);
+      crRightBottom = CFX_Color(CFX_Color::kGray, 1);
+    }
+
+    csAP_D_ON =
+        GetCircleFillAppStream(rcCenter, crBK) +
+        GetCircleBorderAppStream(rcCenter, fBorderWidth, crBorder, crLeftTop,
+                                 crRightBottom, nBorderStyle, dsBorder);
+  } else {
+    csAP_D_ON =
+        GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
+        GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
+                                   crRightBottom, nBorderStyle, dsBorder);
+  }
+
+  ByteString csAP_D_OFF = csAP_D_ON;
+
+  csAP_N_ON += GetRadioButtonAppStream(rcClient, nStyle, crText);
+  csAP_D_ON += GetRadioButtonAppStream(rcClient, nStyle, crText);
+
+  Write("N", csAP_N_ON, pControl->GetCheckedAPState());
+  Write("N", csAP_N_OFF, "Off");
+
+  Write("D", csAP_D_ON, pControl->GetCheckedAPState());
+  Write("D", csAP_D_OFF, "Off");
+
+  ByteString csAS = widget_->GetAppState();
+  if (csAS.IsEmpty())
+    widget_->SetAppState("Off");
+}
+
+void CPWL_AppStream::SetAsComboBox(const WideString* sValue) {
+  CPDF_FormControl* pControl = widget_->GetFormControl();
+  CPDF_FormField* pField = pControl->GetField();
+  std::ostringstream sBody;
+
+  CFX_FloatRect rcClient = widget_->GetClientRect();
+  CFX_FloatRect rcButton = rcClient;
+  rcButton.left = rcButton.right - 13;
+  rcButton.Normalize();
+
+  auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>();
+  pEdit->EnableRefresh(false);
+
+  CBA_FontMap font_map(
+      widget_.Get(),
+      widget_->GetInterForm()->GetFormFillEnv()->GetSysHandler());
+  pEdit->SetFontMap(&font_map);
+
+  CFX_FloatRect rcEdit = rcClient;
+  rcEdit.right = rcButton.left;
+  rcEdit.Normalize();
+
+  pEdit->SetPlateRect(rcEdit);
+  pEdit->SetAlignmentV(1, true);
+
+  float fFontSize = widget_->GetFontSize();
+  if (IsFloatZero(fFontSize))
+    pEdit->SetAutoFontSize(true, true);
+  else
+    pEdit->SetFontSize(fFontSize);
+
+  pEdit->Initialize();
+
+  if (sValue) {
+    pEdit->SetText(*sValue);
+  } else {
+    int32_t nCurSel = pField->GetSelectedIndex(0);
+    if (nCurSel < 0)
+      pEdit->SetText(pField->GetValue());
+    else
+      pEdit->SetText(pField->GetOptionLabel(nCurSel));
+  }
+
+  CFX_FloatRect rcContent = pEdit->GetContentRect();
+  ByteString sEdit = GetEditAppStream(pEdit.get(), CFX_PointF(), true, 0);
+  if (sEdit.GetLength() > 0) {
+    sBody << "/Tx ";
+    AutoClosedCommand bmc(&sBody, kMarkedSequenceBeginOperator,
+                          kMarkedSequenceEndOperator);
+    AutoClosedQCommand q(&sBody);
+
+    if (rcContent.Width() > rcEdit.Width() ||
+        rcContent.Height() > rcEdit.Height()) {
+      sBody << rcEdit.left << " " << rcEdit.bottom << " " << rcEdit.Width()
+            << " " << rcEdit.Height() << " " << kAppendRectOperator << "\n"
+            << kSetNonZeroWindingClipOperator << "\n"
+            << kEndPathNoFillOrStrokeOperator << "\n";
+    }
+
+    CFX_Color crText = widget_->GetTextPWLColor();
+    AutoClosedCommand bt(&sBody, kTextBeginOperator, kTextEndOperator);
+    sBody << GetColorAppStream(crText, true) << sEdit;
+  }
+
+  sBody << GetDropButtonAppStream(rcButton);
+  Write("N",
+        GetBackgroundAppStream() + GetBorderAppStream() + ByteString(sBody),
+        "");
+}
+
+void CPWL_AppStream::SetAsListBox() {
+  CPDF_FormControl* pControl = widget_->GetFormControl();
+  CPDF_FormField* pField = pControl->GetField();
+  CFX_FloatRect rcClient = widget_->GetClientRect();
+  std::ostringstream sBody;
+
+  auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>();
+  pEdit->EnableRefresh(false);
+
+  CBA_FontMap font_map(
+      widget_.Get(),
+      widget_->GetInterForm()->GetFormFillEnv()->GetSysHandler());
+  pEdit->SetFontMap(&font_map);
+  pEdit->SetPlateRect(CFX_FloatRect(rcClient.left, 0.0f, rcClient.right, 0.0f));
+
+  float fFontSize = widget_->GetFontSize();
+  pEdit->SetFontSize(IsFloatZero(fFontSize) ? 12.0f : fFontSize);
+  pEdit->Initialize();
+
+  std::ostringstream sList;
+  float fy = rcClient.top;
+
+  int32_t nTop = pField->GetTopVisibleIndex();
+  int32_t nCount = pField->CountOptions();
+  int32_t nSelCount = pField->CountSelectedItems();
+
+  for (int32_t i = nTop; i < nCount; ++i) {
+    bool bSelected = false;
+    for (int32_t j = 0; j < nSelCount; ++j) {
+      if (pField->GetSelectedIndex(j) == i) {
+        bSelected = true;
+        break;
+      }
+    }
+
+    pEdit->SetText(pField->GetOptionLabel(i));
+
+    CFX_FloatRect rcContent = pEdit->GetContentRect();
+    float fItemHeight = rcContent.Height();
+
+    if (bSelected) {
+      CFX_FloatRect rcItem =
+          CFX_FloatRect(rcClient.left, fy - fItemHeight, rcClient.right, fy);
+      {
+        AutoClosedQCommand q(&sList);
+        sList << GetColorAppStream(CFX_Color(CFX_Color::kRGB, 0, 51.0f / 255.0f,
+                                             113.0f / 255.0f),
+                                   true)
+              << rcItem.left << " " << rcItem.bottom << " " << rcItem.Width()
+              << " " << rcItem.Height() << " " << kAppendRectOperator << " "
+              << kFillOperator << "\n";
+      }
+
+      AutoClosedCommand bt(&sList, kTextBeginOperator, kTextEndOperator);
+      sList << GetColorAppStream(CFX_Color(CFX_Color::kGray, 1), true)
+            << GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, fy), true, 0);
+    } else {
+      CFX_Color crText = widget_->GetTextPWLColor();
+
+      AutoClosedCommand bt(&sList, kTextBeginOperator, kTextEndOperator);
+      sList << GetColorAppStream(crText, true)
+            << GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, fy), true, 0);
+    }
+
+    fy -= fItemHeight;
+  }
+
+  if (sList.tellp() > 0) {
+    sBody << "/Tx ";
+    AutoClosedCommand bmc(&sBody, kMarkedSequenceBeginOperator,
+                          kMarkedSequenceEndOperator);
+    AutoClosedQCommand q(&sBody);
+
+    sBody << rcClient.left << " " << rcClient.bottom << " " << rcClient.Width()
+          << " " << rcClient.Height() << " " << kAppendRectOperator << "\n"
+          << kSetNonZeroWindingClipOperator << "\n"
+          << kEndPathNoFillOrStrokeOperator << "\n"
+          << sList.str();
+  }
+  Write("N",
+        GetBackgroundAppStream() + GetBorderAppStream() + ByteString(sBody),
+        "");
+}
+
+void CPWL_AppStream::SetAsTextField(const WideString* sValue) {
+  CPDF_FormControl* pControl = widget_->GetFormControl();
+  CPDF_FormField* pField = pControl->GetField();
+  std::ostringstream sBody;
+  std::ostringstream sLines;
+
+  auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>();
+  pEdit->EnableRefresh(false);
+
+  CBA_FontMap font_map(
+      widget_.Get(),
+      widget_->GetInterForm()->GetFormFillEnv()->GetSysHandler());
+  pEdit->SetFontMap(&font_map);
+
+  CFX_FloatRect rcClient = widget_->GetClientRect();
+  pEdit->SetPlateRect(rcClient);
+  pEdit->SetAlignmentH(pControl->GetControlAlignment(), true);
+
+  uint32_t dwFieldFlags = pField->GetFieldFlags();
+  bool bMultiLine = (dwFieldFlags >> 12) & 1;
+  if (bMultiLine) {
+    pEdit->SetMultiLine(true, true);
+    pEdit->SetAutoReturn(true, true);
+  } else {
+    pEdit->SetAlignmentV(1, true);
+  }
+
+  uint16_t subWord = 0;
+  if ((dwFieldFlags >> 13) & 1) {
+    subWord = '*';
+    pEdit->SetPasswordChar(subWord, true);
+  }
+
+  int nMaxLen = pField->GetMaxLen();
+  bool bCharArray = (dwFieldFlags >> 24) & 1;
+  float fFontSize = widget_->GetFontSize();
+
+#ifdef PDF_ENABLE_XFA
+  WideString sValueTmp;
+  if (!sValue && widget_->GetMixXFAWidget()) {
+    sValueTmp = widget_->GetValue(true);
+    sValue = &sValueTmp;
+  }
+#endif  // PDF_ENABLE_XFA
+
+  if (nMaxLen > 0) {
+    if (bCharArray) {
+      pEdit->SetCharArray(nMaxLen);
+
+      if (IsFloatZero(fFontSize)) {
+        fFontSize = CPWL_Edit::GetCharArrayAutoFontSize(font_map.GetPDFFont(0),
+                                                        rcClient, nMaxLen);
+      }
+    } else {
+      if (sValue)
+        nMaxLen = sValue->GetLength();
+      pEdit->SetLimitChar(nMaxLen);
+    }
+  }
+
+  if (IsFloatZero(fFontSize))
+    pEdit->SetAutoFontSize(true, true);
+  else
+    pEdit->SetFontSize(fFontSize);
+
+  pEdit->Initialize();
+  pEdit->SetText(sValue ? *sValue : pField->GetValue());
+
+  CFX_FloatRect rcContent = pEdit->GetContentRect();
+  ByteString sEdit =
+      GetEditAppStream(pEdit.get(), CFX_PointF(), !bCharArray, subWord);
+
+  if (sEdit.GetLength() > 0) {
+    sBody << "/Tx ";
+    AutoClosedCommand bmc(&sBody, kMarkedSequenceBeginOperator,
+                          kMarkedSequenceEndOperator);
+    AutoClosedQCommand q(&sBody);
+
+    if (rcContent.Width() > rcClient.Width() ||
+        rcContent.Height() > rcClient.Height()) {
+      sBody << rcClient.left << " " << rcClient.bottom << " "
+            << rcClient.Width() << " " << rcClient.Height() << " "
+            << kAppendRectOperator << "\n"
+            << kSetNonZeroWindingClipOperator << "\n"
+            << kEndPathNoFillOrStrokeOperator << "\n";
+    }
+    CFX_Color crText = widget_->GetTextPWLColor();
+
+    AutoClosedCommand bt(&sBody, kTextBeginOperator, kTextEndOperator);
+    sBody << GetColorAppStream(crText, true) << sEdit;
+  }
+
+  if (bCharArray) {
+    switch (widget_->GetBorderStyle()) {
+      case BorderStyle::SOLID: {
+        ByteString sColor =
+            GetColorAppStream(widget_->GetBorderPWLColor(), false);
+        if (sColor.GetLength() > 0) {
+          AutoClosedQCommand q(&sLines);
+          sLines << widget_->GetBorderWidth() << " " << kSetLineWidthOperator
+                 << "\n"
+                 << GetColorAppStream(widget_->GetBorderPWLColor(), false)
+                 << " 2 " << kSetLineCapStyleOperator << " 0 "
+                 << kSetLineJoinStyleOperator << "\n";
+
+          for (int32_t i = 1; i < nMaxLen; ++i) {
+            sLines << rcClient.left +
+                          ((rcClient.right - rcClient.left) / nMaxLen) * i
+                   << " " << rcClient.bottom << " " << kMoveToOperator << "\n"
+                   << rcClient.left +
+                          ((rcClient.right - rcClient.left) / nMaxLen) * i
+                   << " " << rcClient.top << " " << kLineToOperator << " "
+                   << kStrokeOperator << "\n";
+          }
+        }
+        break;
+      }
+      case BorderStyle::DASH: {
+        ByteString sColor =
+            GetColorAppStream(widget_->GetBorderPWLColor(), false);
+        if (sColor.GetLength() > 0) {
+          CPWL_Dash dsBorder = CPWL_Dash(3, 3, 0);
+          AutoClosedQCommand q(&sLines);
+          sLines << widget_->GetBorderWidth() << " " << kSetLineWidthOperator
+                 << "\n"
+                 << GetColorAppStream(widget_->GetBorderPWLColor(), false)
+                 << "[" << dsBorder.nDash << " " << dsBorder.nGap << "] "
+                 << dsBorder.nPhase << " " << kSetDashOperator << "\n";
+
+          for (int32_t i = 1; i < nMaxLen; ++i) {
+            sLines << rcClient.left +
+                          ((rcClient.right - rcClient.left) / nMaxLen) * i
+                   << " " << rcClient.bottom << " " << kMoveToOperator << "\n"
+                   << rcClient.left +
+                          ((rcClient.right - rcClient.left) / nMaxLen) * i
+                   << " " << rcClient.top << " " << kLineToOperator << " "
+                   << kStrokeOperator << "\n";
+          }
+        }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+
+  Write("N",
+        GetBackgroundAppStream() + GetBorderAppStream() + ByteString(sLines) +
+            ByteString(sBody),
+        "");
+}
+
+void CPWL_AppStream::AddImage(const ByteString& sAPType, CPDF_Stream* pImage) {
+  CPDF_Stream* pStream = dict_->GetStreamFor(sAPType);
+  CPDF_Dictionary* pStreamDict = pStream->GetDict();
+  ByteString sImageAlias = "IMG";
+
+  if (CPDF_Dictionary* pImageDict = pImage->GetDict()) {
+    sImageAlias = pImageDict->GetStringFor("Name");
+    if (sImageAlias.IsEmpty())
+      sImageAlias = "IMG";
+  }
+
+  CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
+  if (!pStreamResList)
+    pStreamResList = pStreamDict->SetNewFor<CPDF_Dictionary>("Resources");
+
+  CPDF_Dictionary* pXObject =
+      pStreamResList->SetNewFor<CPDF_Dictionary>("XObject");
+  pXObject->SetNewFor<CPDF_Reference>(sImageAlias,
+                                      widget_->GetPageView()->GetPDFDocument(),
+                                      pImage->GetObjNum());
+}
+
+void CPWL_AppStream::Write(const ByteString& sAPType,
+                           const ByteString& sContents,
+                           const ByteString& sAPState) {
+  CPDF_Stream* pStream = nullptr;
+  CPDF_Dictionary* pParentDict = nullptr;
+  if (sAPState.IsEmpty()) {
+    pParentDict = dict_.Get();
+    pStream = dict_->GetStreamFor(sAPType);
+  } else {
+    CPDF_Dictionary* pAPTypeDict = dict_->GetDictFor(sAPType);
+    if (!pAPTypeDict)
+      pAPTypeDict = dict_->SetNewFor<CPDF_Dictionary>(sAPType);
+
+    pParentDict = pAPTypeDict;
+    pStream = pAPTypeDict->GetStreamFor(sAPState);
+  }
+
+  if (!pStream) {
+    CPDF_Document* doc = widget_->GetPageView()->GetPDFDocument();
+    pStream = doc->NewIndirect<CPDF_Stream>();
+    pParentDict->SetNewFor<CPDF_Reference>(sAPType, doc, pStream->GetObjNum());
+  }
+
+  CPDF_Dictionary* pStreamDict = pStream->GetDict();
+  if (!pStreamDict) {
+    auto pNewDict = pdfium::MakeUnique<CPDF_Dictionary>(
+        widget_->GetPDFAnnot()->GetDocument()->GetByteStringPool());
+    pStreamDict = pNewDict.get();
+    pStreamDict->SetNewFor<CPDF_Name>("Type", "XObject");
+    pStreamDict->SetNewFor<CPDF_Name>("Subtype", "Form");
+    pStreamDict->SetNewFor<CPDF_Number>("FormType", 1);
+    pStream->InitStream(nullptr, 0, std::move(pNewDict));
+  }
+  pStreamDict->SetMatrixFor("Matrix", widget_->GetMatrix());
+  pStreamDict->SetRectFor("BBox", widget_->GetRotatedRect());
+  pStream->SetDataAndRemoveFilter((uint8_t*)(sContents.c_str()),
+                                  sContents.GetLength());
+}
+
+void CPWL_AppStream::Remove(const ByteString& sAPType) {
+  dict_->RemoveFor(sAPType);
+}
+
+ByteString CPWL_AppStream::GetBackgroundAppStream() const {
+  CFX_Color crBackground = widget_->GetFillPWLColor();
+  if (crBackground.nColorType != CFX_Color::kTransparent)
+    return GetRectFillAppStream(widget_->GetRotatedRect(), crBackground);
+
+  return ByteString();
+}
+
+ByteString CPWL_AppStream::GetBorderAppStream() const {
+  CFX_FloatRect rcWindow = widget_->GetRotatedRect();
+  CFX_Color crBorder = widget_->GetBorderPWLColor();
+  CFX_Color crBackground = widget_->GetFillPWLColor();
+  CFX_Color crLeftTop;
+  CFX_Color crRightBottom;
+
+  float fBorderWidth = static_cast<float>(widget_->GetBorderWidth());
+  CPWL_Dash dsBorder(3, 0, 0);
+
+  BorderStyle nBorderStyle = widget_->GetBorderStyle();
+  switch (nBorderStyle) {
+    case BorderStyle::DASH:
+      dsBorder = CPWL_Dash(3, 3, 0);
+      break;
+    case BorderStyle::BEVELED:
+      fBorderWidth *= 2;
+      crLeftTop = CFX_Color(CFX_Color::kGray, 1);
+      crRightBottom = crBackground / 2.0f;
+      break;
+    case BorderStyle::INSET:
+      fBorderWidth *= 2;
+      crLeftTop = CFX_Color(CFX_Color::kGray, 0.5);
+      crRightBottom = CFX_Color(CFX_Color::kGray, 0.75);
+      break;
+    default:
+      break;
+  }
+
+  return GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
+                                    crRightBottom, nBorderStyle, dsBorder);
+}
diff --git a/fpdfsdk/pwl/cpwl_appstream.h b/fpdfsdk/pwl/cpwl_appstream.h
new file mode 100644
index 0000000..810e79c
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_appstream.h
@@ -0,0 +1,43 @@
+// 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_PWL_CPWL_APPSTREAM_H_
+#define FPDFSDK_PWL_CPWL_APPSTREAM_H_
+
+#include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/unowned_ptr.h"
+
+class CPDFSDK_Widget;
+class CPDF_Dictionary;
+class CPDF_Stream;
+
+class CPWL_AppStream {
+ public:
+  CPWL_AppStream(CPDFSDK_Widget* widget, CPDF_Dictionary* dict);
+  ~CPWL_AppStream();
+
+  void SetAsPushButton();
+  void SetAsCheckBox();
+  void SetAsRadioButton();
+  void SetAsComboBox(const WideString* sValue);
+  void SetAsListBox();
+  void SetAsTextField(const WideString* sValue);
+
+ private:
+  void AddImage(const ByteString& sAPType, CPDF_Stream* pImage);
+  void Write(const ByteString& sAPType,
+             const ByteString& sContents,
+             const ByteString& sAPState);
+  void Remove(const ByteString& sAPType);
+
+  ByteString GetBackgroundAppStream() const;
+  ByteString GetBorderAppStream() const;
+
+  UnownedPtr<CPDFSDK_Widget> widget_;
+  UnownedPtr<CPDF_Dictionary> dict_;
+};
+
+#endif  // FPDFSDK_PWL_CPWL_APPSTREAM_H_
diff --git a/fpdfsdk/pdfwindow/PWL_Button.cpp b/fpdfsdk/pwl/cpwl_button.cpp
similarity index 72%
rename from fpdfsdk/pdfwindow/PWL_Button.cpp
rename to fpdfsdk/pwl/cpwl_button.cpp
index 96be469..5c06a98 100644
--- a/fpdfsdk/pdfwindow/PWL_Button.cpp
+++ b/fpdfsdk/pwl/cpwl_button.cpp
@@ -4,36 +4,31 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
-#include "fpdfsdk/pdfwindow/PWL_Button.h"
-#include "fpdfsdk/pdfwindow/PWL_Utils.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
+#include "fpdfsdk/pwl/cpwl_button.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
 
 CPWL_Button::CPWL_Button() : m_bMouseDown(false) {}
 
 CPWL_Button::~CPWL_Button() {}
 
-CFX_ByteString CPWL_Button::GetClassName() const {
+ByteString CPWL_Button::GetClassName() const {
   return "CPWL_Button";
 }
 
-void CPWL_Button::OnCreate(PWL_CREATEPARAM& cp) {
-  cp.eCursorType = FXCT_HAND;
+void CPWL_Button::OnCreate(CreateParams* pParamsToAdjust) {
+  pParamsToAdjust->eCursorType = FXCT_HAND;
 }
 
 bool CPWL_Button::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonDown(point, nFlag);
-
   m_bMouseDown = true;
   SetCapture();
-
   return true;
 }
 
 bool CPWL_Button::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
   CPWL_Wnd::OnLButtonUp(point, nFlag);
-
   ReleaseCapture();
   m_bMouseDown = false;
-
   return true;
 }
diff --git a/fpdfsdk/pdfwindow/PWL_Button.h b/fpdfsdk/pwl/cpwl_button.h
similarity index 67%
rename from fpdfsdk/pdfwindow/PWL_Button.h
rename to fpdfsdk/pwl/cpwl_button.h
index 2d1193f..70f5ef1 100644
--- a/fpdfsdk/pdfwindow/PWL_Button.h
+++ b/fpdfsdk/pwl/cpwl_button.h
@@ -4,10 +4,10 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
-#ifndef FPDFSDK_PDFWINDOW_PWL_BUTTON_H_
-#define FPDFSDK_PDFWINDOW_PWL_BUTTON_H_
+#ifndef FPDFSDK_PWL_CPWL_BUTTON_H_
+#define FPDFSDK_PWL_CPWL_BUTTON_H_
 
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
 
 class CPWL_Button : public CPWL_Wnd {
  public:
@@ -15,8 +15,8 @@
   ~CPWL_Button() override;
 
   // CPWL_Wnd
-  CFX_ByteString GetClassName() const override;
-  void OnCreate(PWL_CREATEPARAM& cp) override;
+  ByteString GetClassName() const override;
+  void OnCreate(CreateParams* pParamsToAdjust) override;
   bool OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) override;
   bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) override;
 
@@ -24,4 +24,4 @@
   bool m_bMouseDown;
 };
 
-#endif  // FPDFSDK_PDFWINDOW_PWL_BUTTON_H_
+#endif  // FPDFSDK_PWL_CPWL_BUTTON_H_
diff --git a/fpdfsdk/pwl/cpwl_caret.cpp b/fpdfsdk/pwl/cpwl_caret.cpp
new file mode 100644
index 0000000..77a768a
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_caret.cpp
@@ -0,0 +1,134 @@
+// 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/pwl/cpwl_caret.h"
+
+#include <sstream>
+
+#include "core/fxge/cfx_graphstatedata.h"
+#include "core/fxge/cfx_pathdata.h"
+#include "core/fxge/cfx_renderdevice.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
+
+#define PWL_CARET_FLASHINTERVAL 500
+
+CPWL_Caret::CPWL_Caret() : m_bFlash(false), m_fWidth(0.4f), m_nDelay(0) {}
+
+CPWL_Caret::~CPWL_Caret() {}
+
+ByteString CPWL_Caret::GetClassName() const {
+  return "CPWL_Caret";
+}
+
+void CPWL_Caret::DrawThisAppearance(CFX_RenderDevice* pDevice,
+                                    const CFX_Matrix& mtUser2Device) {
+  if (!IsVisible() || !m_bFlash)
+    return;
+
+  CFX_FloatRect rcRect = GetCaretRect();
+  CFX_FloatRect rcClip = GetClipRect();
+  CFX_PathData path;
+
+  float fCaretX = rcRect.left + m_fWidth * 0.5f;
+  float fCaretTop = rcRect.top;
+  float fCaretBottom = rcRect.bottom;
+  if (!rcClip.IsEmpty()) {
+    rcRect.Intersect(rcClip);
+    if (rcRect.IsEmpty())
+      return;
+
+    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, &mtUser2Device, &gsd, 0, ArgbEncode(255, 0, 0, 0),
+                    FXFILL_ALTERNATE);
+}
+
+void CPWL_Caret::TimerProc() {
+  if (m_nDelay > 0) {
+    --m_nDelay;
+    return;
+  }
+
+  m_bFlash = !m_bFlash;
+  InvalidateRect(nullptr);
+  // Note, |this| may no longer be viable at this point. If more work needs
+  // to be done, add an observer.
+}
+
+CFX_FloatRect CPWL_Caret::GetCaretRect() const {
+  return CFX_FloatRect(m_ptFoot.x, m_ptFoot.y, m_ptHead.x + m_fWidth,
+                       m_ptHead.y);
+}
+
+void CPWL_Caret::SetCaret(bool bVisible,
+                          const CFX_PointF& ptHead,
+                          const CFX_PointF& ptFoot) {
+  if (!bVisible) {
+    m_ptHead = CFX_PointF();
+    m_ptFoot = CFX_PointF();
+    m_bFlash = false;
+    if (!IsVisible())
+      return;
+
+    EndTimer();
+    CPWL_Wnd::SetVisible(false);
+    // Note, |this| may no longer be viable at this point. If more work needs
+    // to be done, check the return value of SetVisible().
+    return;
+  }
+
+  if (!IsVisible()) {
+    m_ptHead = ptHead;
+    m_ptFoot = ptFoot;
+    EndTimer();
+    BeginTimer(PWL_CARET_FLASHINTERVAL);
+
+    if (!CPWL_Wnd::SetVisible(true))
+      return;
+
+    m_bFlash = true;
+    Move(m_rcInvalid, false, true);
+    // Note, |this| may no longer be viable at this point. If more work needs
+    // to be done, check the return value of Move().
+    return;
+  }
+
+  if (m_ptHead == ptHead && m_ptFoot == ptFoot)
+    return;
+
+  m_ptHead = ptHead;
+  m_ptFoot = ptFoot;
+  m_bFlash = true;
+  Move(m_rcInvalid, false, true);
+  // Note, |this| may no longer be viable at this point. If more work
+  // needs to be done, check the return value of Move().
+}
+
+bool CPWL_Caret::InvalidateRect(CFX_FloatRect* pRect) {
+  if (!pRect) {
+    return CPWL_Wnd::InvalidateRect(nullptr);
+  }
+
+  CFX_FloatRect rcRefresh = *pRect;
+  if (!rcRefresh.IsEmpty()) {
+    rcRefresh.Inflate(0.5f, 0.5f);
+    rcRefresh.Normalize();
+  }
+  rcRefresh.top += 1;
+  rcRefresh.bottom -= 1;
+  return CPWL_Wnd::InvalidateRect(&rcRefresh);
+}
+
+bool CPWL_Caret::SetVisible(bool bVisible) {
+  return true;
+}
diff --git a/fpdfsdk/pwl/cpwl_caret.h b/fpdfsdk/pwl/cpwl_caret.h
new file mode 100644
index 0000000..d60a964
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_caret.h
@@ -0,0 +1,41 @@
+// 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 FPDFSDK_PWL_CPWL_CARET_H_
+#define FPDFSDK_PWL_CPWL_CARET_H_
+
+#include "fpdfsdk/pwl/cpwl_wnd.h"
+
+class CPWL_Caret : public CPWL_Wnd {
+ public:
+  CPWL_Caret();
+  ~CPWL_Caret() override;
+
+  // CPWL_Wnd
+  ByteString GetClassName() const override;
+  void DrawThisAppearance(CFX_RenderDevice* pDevice,
+                          const CFX_Matrix& mtUser2Device) override;
+  bool InvalidateRect(CFX_FloatRect* pRect) override;
+  bool SetVisible(bool bVisible) override;
+  void TimerProc() override;
+
+  void SetCaret(bool bVisible,
+                const CFX_PointF& ptHead,
+                const CFX_PointF& ptFoot);
+  void SetInvalidRect(CFX_FloatRect rc) { m_rcInvalid = rc; }
+
+ private:
+  CFX_FloatRect GetCaretRect() const;
+
+  bool m_bFlash;
+  CFX_PointF m_ptHead;
+  CFX_PointF m_ptFoot;
+  float m_fWidth;
+  int32_t m_nDelay;
+  CFX_FloatRect m_rcInvalid;
+};
+
+#endif  // FPDFSDK_PWL_CPWL_CARET_H_
diff --git a/fpdfsdk/pwl/cpwl_combo_box.cpp b/fpdfsdk/pwl/cpwl_combo_box.cpp
new file mode 100644
index 0000000..3adbebc
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_combo_box.cpp
@@ -0,0 +1,584 @@
+// 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/pwl/cpwl_combo_box.h"
+
+#include <algorithm>
+#include <sstream>
+
+#include "core/fxge/cfx_pathdata.h"
+#include "core/fxge/cfx_renderdevice.h"
+#include "fpdfsdk/pwl/cpwl_edit.h"
+#include "fpdfsdk/pwl/cpwl_edit_ctrl.h"
+#include "fpdfsdk/pwl/cpwl_list_box.h"
+#include "fpdfsdk/pwl/cpwl_list_impl.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
+#include "public/fpdf_fwlevent.h"
+
+namespace {
+
+constexpr float kComboBoxDefaultFontSize = 12.0f;
+constexpr float kComboBoxTriangleHalfLength = 3.0f;
+constexpr int kDefaultButtonWidth = 13;
+
+}  // namespace
+
+bool CPWL_CBListBox::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
+  CPWL_Wnd::OnLButtonUp(point, nFlag);
+
+  if (!m_bMouseDown)
+    return true;
+
+  ReleaseCapture();
+  m_bMouseDown = false;
+
+  if (!ClientHitTest(point))
+    return true;
+  if (CPWL_Wnd* pParent = GetParentWindow())
+    pParent->NotifyLButtonUp(this, point);
+
+  return !OnNotifySelectionChanged(false, nFlag);
+}
+
+bool CPWL_CBListBox::IsMovementKey(uint16_t nChar) const {
+  switch (nChar) {
+    case FWL_VKEY_Up:
+    case FWL_VKEY_Down:
+    case FWL_VKEY_Home:
+    case FWL_VKEY_Left:
+    case FWL_VKEY_End:
+    case FWL_VKEY_Right:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool CPWL_CBListBox::OnMovementKeyDown(uint16_t nChar, uint32_t nFlag) {
+  ASSERT(IsMovementKey(nChar));
+
+  switch (nChar) {
+    case FWL_VKEY_Up:
+      m_pList->OnVK_UP(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+      break;
+    case FWL_VKEY_Down:
+      m_pList->OnVK_DOWN(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+      break;
+    case FWL_VKEY_Home:
+      m_pList->OnVK_HOME(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+      break;
+    case FWL_VKEY_Left:
+      m_pList->OnVK_LEFT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+      break;
+    case FWL_VKEY_End:
+      m_pList->OnVK_END(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+      break;
+    case FWL_VKEY_Right:
+      m_pList->OnVK_RIGHT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+      break;
+  }
+  return OnNotifySelectionChanged(true, nFlag);
+}
+
+bool CPWL_CBListBox::IsChar(uint16_t nChar, uint32_t nFlag) const {
+  return m_pList->OnChar(nChar, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+}
+
+bool CPWL_CBListBox::OnCharNotify(uint16_t nChar, uint32_t nFlag) {
+  if (CPWL_ComboBox* pComboBox = (CPWL_ComboBox*)GetParentWindow())
+    pComboBox->SetSelectText();
+
+  return OnNotifySelectionChanged(true, nFlag);
+}
+
+void CPWL_CBButton::DrawThisAppearance(CFX_RenderDevice* pDevice,
+                                       const CFX_Matrix& mtUser2Device) {
+  CPWL_Wnd::DrawThisAppearance(pDevice, mtUser2Device);
+
+  CFX_FloatRect rectWnd = CPWL_Wnd::GetWindowRect();
+
+  if (!IsVisible() || rectWnd.IsEmpty())
+    return;
+
+  CFX_PointF ptCenter = GetCenterPoint();
+
+  static constexpr float kComboBoxTriangleQuarterLength =
+      kComboBoxTriangleHalfLength * 0.5;
+  CFX_PointF pt1(ptCenter.x - kComboBoxTriangleHalfLength,
+                 ptCenter.y + kComboBoxTriangleQuarterLength);
+  CFX_PointF pt2(ptCenter.x + kComboBoxTriangleHalfLength,
+                 ptCenter.y + kComboBoxTriangleQuarterLength);
+  CFX_PointF pt3(ptCenter.x, ptCenter.y - kComboBoxTriangleQuarterLength);
+
+  if (IsFloatBigger(rectWnd.right - rectWnd.left,
+                    kComboBoxTriangleHalfLength * 2) &&
+      IsFloatBigger(rectWnd.top - rectWnd.bottom,
+                    kComboBoxTriangleHalfLength)) {
+    CFX_PathData path;
+    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, &mtUser2Device, nullptr,
+                      PWL_DEFAULT_BLACKCOLOR.ToFXColor(GetTransparency()), 0,
+                      FXFILL_ALTERNATE);
+  }
+}
+
+bool CPWL_CBButton::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
+  CPWL_Wnd::OnLButtonDown(point, nFlag);
+
+  SetCapture();
+
+  if (CPWL_Wnd* pParent = GetParentWindow())
+    pParent->NotifyLButtonDown(this, point);
+
+  return true;
+}
+
+bool CPWL_CBButton::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
+  CPWL_Wnd::OnLButtonUp(point, nFlag);
+
+  ReleaseCapture();
+
+  return true;
+}
+
+CPWL_ComboBox::CPWL_ComboBox() {}
+
+CPWL_ComboBox::~CPWL_ComboBox() {}
+
+ByteString CPWL_ComboBox::GetClassName() const {
+  return "CPWL_ComboBox";
+}
+
+void CPWL_ComboBox::OnCreate(CreateParams* pParamsToAdjust) {
+  pParamsToAdjust->dwFlags &= ~PWS_HSCROLL;
+  pParamsToAdjust->dwFlags &= ~PWS_VSCROLL;
+}
+
+void CPWL_ComboBox::OnDestroy() {
+  // Until cleanup takes place in the virtual destructor for CPWL_Wnd
+  // subclasses, implement the virtual OnDestroy method that does the
+  // cleanup first, then invokes the superclass OnDestroy ... gee,
+  // like a dtor would.
+  m_pList.Release();
+  m_pButton.Release();
+  m_pEdit.Release();
+  CPWL_Wnd::OnDestroy();
+}
+
+void CPWL_ComboBox::SetFocus() {
+  if (m_pEdit)
+    m_pEdit->SetFocus();
+}
+
+void CPWL_ComboBox::KillFocus() {
+  if (!SetPopup(false))
+    return;
+
+  CPWL_Wnd::KillFocus();
+}
+
+WideString CPWL_ComboBox::GetSelectedText() {
+  if (m_pEdit)
+    return m_pEdit->GetSelectedText();
+
+  return WideString();
+}
+
+void CPWL_ComboBox::ReplaceSelection(const WideString& text) {
+  if (m_pEdit)
+    m_pEdit->ReplaceSelection(text);
+}
+
+WideString CPWL_ComboBox::GetText() const {
+  if (m_pEdit) {
+    return m_pEdit->GetText();
+  }
+  return WideString();
+}
+
+void CPWL_ComboBox::SetText(const WideString& text) {
+  if (m_pEdit)
+    m_pEdit->SetText(text);
+}
+
+void CPWL_ComboBox::AddString(const WideString& str) {
+  if (m_pList)
+    m_pList->AddString(str);
+}
+
+int32_t CPWL_ComboBox::GetSelect() const {
+  return m_nSelectItem;
+}
+
+void CPWL_ComboBox::SetSelect(int32_t nItemIndex) {
+  if (m_pList)
+    m_pList->Select(nItemIndex);
+
+  m_pEdit->SetText(m_pList->GetText());
+  m_nSelectItem = nItemIndex;
+}
+
+void CPWL_ComboBox::SetEditSelection(int32_t nStartChar, int32_t nEndChar) {
+  if (m_pEdit)
+    m_pEdit->SetSelection(nStartChar, nEndChar);
+}
+
+void CPWL_ComboBox::GetEditSelection(int32_t& nStartChar,
+                                     int32_t& nEndChar) const {
+  nStartChar = -1;
+  nEndChar = -1;
+
+  if (m_pEdit)
+    m_pEdit->GetSelection(nStartChar, nEndChar);
+}
+
+void CPWL_ComboBox::ClearSelection() {
+  if (m_pEdit)
+    m_pEdit->ClearSelection();
+}
+
+void CPWL_ComboBox::CreateChildWnd(const CreateParams& cp) {
+  CreateEdit(cp);
+  CreateButton(cp);
+  CreateListBox(cp);
+}
+
+void CPWL_ComboBox::CreateEdit(const CreateParams& cp) {
+  if (m_pEdit)
+    return;
+
+  m_pEdit = new CPWL_Edit();
+  m_pEdit->AttachFFLData(m_pFormFiller.Get());
+
+  CreateParams ecp = cp;
+  ecp.pParentWnd = this;
+  ecp.dwFlags = PWS_VISIBLE | PWS_CHILD | PWS_BORDER | PES_CENTER |
+                PES_AUTOSCROLL | PES_UNDO;
+
+  if (HasFlag(PWS_AUTOFONTSIZE))
+    ecp.dwFlags |= PWS_AUTOFONTSIZE;
+
+  if (!HasFlag(PCBS_ALLOWCUSTOMTEXT))
+    ecp.dwFlags |= PWS_READONLY;
+
+  ecp.rcRectWnd = CFX_FloatRect();
+  ecp.dwBorderWidth = 0;
+  ecp.nBorderStyle = BorderStyle::SOLID;
+  m_pEdit->Create(ecp);
+}
+
+void CPWL_ComboBox::CreateButton(const CreateParams& cp) {
+  if (m_pButton)
+    return;
+
+  m_pButton = new CPWL_CBButton;
+
+  CreateParams bcp = cp;
+  bcp.pParentWnd = this;
+  bcp.dwFlags = PWS_VISIBLE | PWS_CHILD | PWS_BORDER | PWS_BACKGROUND;
+  bcp.sBackgroundColor = CFX_Color(CFX_Color::kRGB, 220.0f / 255.0f,
+                                   220.0f / 255.0f, 220.0f / 255.0f);
+  bcp.sBorderColor = PWL_DEFAULT_BLACKCOLOR;
+  bcp.dwBorderWidth = 2;
+  bcp.nBorderStyle = BorderStyle::BEVELED;
+  bcp.eCursorType = FXCT_ARROW;
+  m_pButton->Create(bcp);
+}
+
+void CPWL_ComboBox::CreateListBox(const CreateParams& cp) {
+  if (m_pList)
+    return;
+
+  m_pList = new CPWL_CBListBox();
+  m_pList->AttachFFLData(m_pFormFiller.Get());
+
+  CreateParams lcp = cp;
+  lcp.pParentWnd = this;
+  lcp.dwFlags =
+      PWS_CHILD | PWS_BORDER | PWS_BACKGROUND | PLBS_HOVERSEL | PWS_VSCROLL;
+  lcp.nBorderStyle = BorderStyle::SOLID;
+  lcp.dwBorderWidth = 1;
+  lcp.eCursorType = FXCT_ARROW;
+  lcp.rcRectWnd = CFX_FloatRect();
+
+  lcp.fFontSize =
+      (cp.dwFlags & PWS_AUTOFONTSIZE) ? kComboBoxDefaultFontSize : cp.fFontSize;
+
+  if (cp.sBorderColor.nColorType == CFX_Color::kTransparent)
+    lcp.sBorderColor = PWL_DEFAULT_BLACKCOLOR;
+
+  if (cp.sBackgroundColor.nColorType == CFX_Color::kTransparent)
+    lcp.sBackgroundColor = PWL_DEFAULT_WHITECOLOR;
+
+  m_pList->Create(lcp);
+}
+
+bool CPWL_ComboBox::RePosChildWnd() {
+  ObservedPtr thisObserved(this);
+
+  const CFX_FloatRect rcClient = GetClientRect();
+  if (m_bPopup) {
+    const float fOldWindowHeight = m_rcOldWindow.Height();
+    const float fOldClientHeight = fOldWindowHeight - GetBorderWidth() * 2;
+
+    CFX_FloatRect rcList = CPWL_Wnd::GetWindowRect();
+    CFX_FloatRect rcButton = rcClient;
+    rcButton.left =
+        std::max(rcButton.right - kDefaultButtonWidth, rcClient.left);
+    CFX_FloatRect rcEdit = rcClient;
+    rcEdit.right = std::max(rcButton.left - 1.0f, rcEdit.left);
+    if (m_bBottom) {
+      rcButton.bottom = rcButton.top - fOldClientHeight;
+      rcEdit.bottom = rcEdit.top - fOldClientHeight;
+      rcList.top -= fOldWindowHeight;
+    } else {
+      rcButton.top = rcButton.bottom + fOldClientHeight;
+      rcEdit.top = rcEdit.bottom + fOldClientHeight;
+      rcList.bottom += fOldWindowHeight;
+    }
+
+    if (m_pButton) {
+      m_pButton->Move(rcButton, true, false);
+      if (!thisObserved)
+        return false;
+    }
+
+    if (m_pEdit) {
+      m_pEdit->Move(rcEdit, true, false);
+      if (!thisObserved)
+        return false;
+    }
+
+    if (m_pList) {
+      if (!m_pList->SetVisible(true) || !thisObserved)
+        return false;
+
+      if (!m_pList->Move(rcList, true, false) || !thisObserved)
+        return false;
+
+      m_pList->ScrollToListItem(m_nSelectItem);
+      if (!thisObserved)
+        return false;
+    }
+    return true;
+  }
+
+  CFX_FloatRect rcButton = rcClient;
+  rcButton.left = std::max(rcButton.right - kDefaultButtonWidth, rcClient.left);
+
+  if (m_pButton) {
+    m_pButton->Move(rcButton, true, false);
+    if (!thisObserved)
+      return false;
+  }
+
+  CFX_FloatRect rcEdit = rcClient;
+  rcEdit.right = std::max(rcButton.left - 1.0f, rcEdit.left);
+
+  if (m_pEdit) {
+    m_pEdit->Move(rcEdit, true, false);
+    if (!thisObserved)
+      return false;
+  }
+
+  if (m_pList) {
+    m_pList->SetVisible(false);
+    if (!thisObserved)
+      return false;
+  }
+
+  return true;
+}
+
+void CPWL_ComboBox::SelectAll() {
+  if (m_pEdit && HasFlag(PCBS_ALLOWCUSTOMTEXT))
+    m_pEdit->SelectAll();
+}
+
+CFX_FloatRect CPWL_ComboBox::GetFocusRect() const {
+  return CFX_FloatRect();
+}
+
+bool CPWL_ComboBox::SetPopup(bool bPopup) {
+  if (!m_pList)
+    return true;
+  if (bPopup == m_bPopup)
+    return true;
+  float fListHeight = m_pList->GetContentRect().Height();
+  if (!IsFloatBigger(fListHeight, 0.0f))
+    return true;
+
+  if (!bPopup) {
+    m_bPopup = bPopup;
+    return Move(m_rcOldWindow, true, true);
+  }
+
+  if (!m_pFillerNotify)
+    return true;
+
+  ObservedPtr thisObserved(this);
+
+#ifdef PDF_ENABLE_XFA
+  if (m_pFillerNotify->OnPopupPreOpen(GetAttachedData(), 0))
+    return !!thisObserved;
+  if (!thisObserved)
+    return false;
+#endif  // PDF_ENABLE_XFA
+
+  float fBorderWidth = m_pList->GetBorderWidth() * 2;
+  float fPopupMin = 0.0f;
+  if (m_pList->GetCount() > 3)
+    fPopupMin = m_pList->GetFirstHeight() * 3 + fBorderWidth;
+  float fPopupMax = fListHeight + fBorderWidth;
+
+  bool bBottom;
+  float fPopupRet;
+  m_pFillerNotify->QueryWherePopup(GetAttachedData(), fPopupMin, fPopupMax,
+                                   &bBottom, &fPopupRet);
+  if (!IsFloatBigger(fPopupRet, 0.0f))
+    return true;
+
+  m_rcOldWindow = CPWL_Wnd::GetWindowRect();
+  m_bPopup = bPopup;
+  m_bBottom = bBottom;
+
+  CFX_FloatRect rcWindow = m_rcOldWindow;
+  if (bBottom)
+    rcWindow.bottom -= fPopupRet;
+  else
+    rcWindow.top += fPopupRet;
+
+  if (!Move(rcWindow, true, true))
+    return false;
+
+#ifdef PDF_ENABLE_XFA
+  m_pFillerNotify->OnPopupPostOpen(GetAttachedData(), 0);
+  if (!thisObserved)
+    return false;
+#endif  // PDF_ENABLE_XFA
+
+  return !!thisObserved;
+}
+
+bool CPWL_ComboBox::OnKeyDown(uint16_t nChar, uint32_t nFlag) {
+  if (!m_pList)
+    return false;
+  if (!m_pEdit)
+    return false;
+
+  m_nSelectItem = -1;
+
+  switch (nChar) {
+    case FWL_VKEY_Up:
+      if (m_pList->GetCurSel() > 0) {
+#ifdef PDF_ENABLE_XFA
+        if (m_pFillerNotify) {
+          if (m_pFillerNotify->OnPopupPreOpen(GetAttachedData(), nFlag))
+            return false;
+          if (m_pFillerNotify->OnPopupPostOpen(GetAttachedData(), nFlag))
+            return false;
+        }
+#endif  // PDF_ENABLE_XFA
+        if (m_pList->IsMovementKey(nChar)) {
+          if (m_pList->OnMovementKeyDown(nChar, nFlag))
+            return false;
+          SetSelectText();
+        }
+      }
+      return true;
+    case FWL_VKEY_Down:
+      if (m_pList->GetCurSel() < m_pList->GetCount() - 1) {
+#ifdef PDF_ENABLE_XFA
+        if (m_pFillerNotify) {
+          if (m_pFillerNotify->OnPopupPreOpen(GetAttachedData(), nFlag))
+            return false;
+          if (m_pFillerNotify->OnPopupPostOpen(GetAttachedData(), nFlag))
+            return false;
+        }
+#endif  // PDF_ENABLE_XFA
+        if (m_pList->IsMovementKey(nChar)) {
+          if (m_pList->OnMovementKeyDown(nChar, nFlag))
+            return false;
+          SetSelectText();
+        }
+      }
+      return true;
+  }
+
+  if (HasFlag(PCBS_ALLOWCUSTOMTEXT))
+    return m_pEdit->OnKeyDown(nChar, nFlag);
+
+  return false;
+}
+
+bool CPWL_ComboBox::OnChar(uint16_t nChar, uint32_t nFlag) {
+  if (!m_pList)
+    return false;
+
+  if (!m_pEdit)
+    return false;
+
+  m_nSelectItem = -1;
+  if (HasFlag(PCBS_ALLOWCUSTOMTEXT))
+    return m_pEdit->OnChar(nChar, nFlag);
+
+#ifdef PDF_ENABLE_XFA
+  if (m_pFillerNotify) {
+    if (m_pFillerNotify->OnPopupPreOpen(GetAttachedData(), nFlag))
+      return false;
+    if (m_pFillerNotify->OnPopupPostOpen(GetAttachedData(), nFlag))
+      return false;
+  }
+#endif  // PDF_ENABLE_XFA
+  if (!m_pList->IsChar(nChar, nFlag))
+    return false;
+  return m_pList->OnCharNotify(nChar, nFlag);
+}
+
+void CPWL_ComboBox::NotifyLButtonDown(CPWL_Wnd* child, const CFX_PointF& pos) {
+  if (child == m_pButton) {
+    SetPopup(!m_bPopup);
+    // Note, |this| may no longer be viable at this point. If more work needs to
+    // be done, check the return value of SetPopup().
+  }
+}
+
+void CPWL_ComboBox::NotifyLButtonUp(CPWL_Wnd* child, const CFX_PointF& pos) {
+  if (!m_pEdit || !m_pList || child != m_pList)
+    return;
+
+  SetSelectText();
+  SelectAll();
+  m_pEdit->SetFocus();
+  SetPopup(false);
+  // Note, |this| may no longer be viable at this point. If more work needs to
+  // be done, check the return value of SetPopup().
+}
+
+bool CPWL_ComboBox::IsPopup() const {
+  return m_bPopup;
+}
+
+void CPWL_ComboBox::SetSelectText() {
+  m_pEdit->SelectAll();
+  m_pEdit->ReplaceSel(m_pList->GetText());
+  m_pEdit->SelectAll();
+  m_nSelectItem = m_pList->GetCurSel();
+}
+
+void CPWL_ComboBox::SetFillerNotify(IPWL_Filler_Notify* pNotify) {
+  m_pFillerNotify = pNotify;
+
+  if (m_pEdit)
+    m_pEdit->SetFillerNotify(pNotify);
+
+  if (m_pList)
+    m_pList->SetFillerNotify(pNotify);
+}
diff --git a/fpdfsdk/pwl/cpwl_combo_box.h b/fpdfsdk/pwl/cpwl_combo_box.h
new file mode 100644
index 0000000..6db7213
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_combo_box.h
@@ -0,0 +1,103 @@
+// 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 FPDFSDK_PWL_CPWL_COMBO_BOX_H_
+#define FPDFSDK_PWL_CPWL_COMBO_BOX_H_
+
+#include <memory>
+
+#include "core/fxcrt/unowned_ptr.h"
+#include "fpdfsdk/pwl/cpwl_edit.h"
+#include "fpdfsdk/pwl/cpwl_list_box.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
+
+class CPWL_CBListBox : public CPWL_ListBox {
+ public:
+  CPWL_CBListBox() {}
+  ~CPWL_CBListBox() override {}
+
+  // CPWL_ListBox
+  bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) override;
+
+  bool IsMovementKey(uint16_t nChar) const;
+  bool OnMovementKeyDown(uint16_t nChar, uint32_t nFlag);
+  bool IsChar(uint16_t nChar, uint32_t nFlag) const;
+  bool OnCharNotify(uint16_t nChar, uint32_t nFlag);
+};
+
+class CPWL_CBButton : public CPWL_Wnd {
+ public:
+  CPWL_CBButton() {}
+  ~CPWL_CBButton() override {}
+
+  // CPWL_Wnd
+  void DrawThisAppearance(CFX_RenderDevice* pDevice,
+                          const CFX_Matrix& mtUser2Device) 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 {
+ public:
+  CPWL_ComboBox();
+  ~CPWL_ComboBox() override;
+
+  CPWL_Edit* GetEdit() const { return m_pEdit.Get(); }
+
+  // CPWL_Wnd:
+  ByteString GetClassName() const override;
+  void OnCreate(CreateParams* pParamsToAdjust) override;
+  void OnDestroy() override;
+  bool OnKeyDown(uint16_t nChar, uint32_t nFlag) override;
+  bool OnChar(uint16_t nChar, uint32_t nFlag) override;
+  void NotifyLButtonDown(CPWL_Wnd* child, const CFX_PointF& pos) override;
+  void NotifyLButtonUp(CPWL_Wnd* child, const CFX_PointF& pos) override;
+  void CreateChildWnd(const CreateParams& cp) override;
+  bool RePosChildWnd() override;
+  CFX_FloatRect GetFocusRect() const override;
+  void SetFocus() override;
+  void KillFocus() override;
+  WideString GetSelectedText() override;
+  void ReplaceSelection(const WideString& text) override;
+
+  void SetFillerNotify(IPWL_Filler_Notify* pNotify);
+
+  WideString GetText() const;
+  void SetText(const WideString& text);
+  void AddString(const WideString& str);
+  int32_t GetSelect() const;
+  void SetSelect(int32_t nItemIndex);
+
+  void SetEditSelection(int32_t nStartChar, int32_t nEndChar);
+  void GetEditSelection(int32_t& nStartChar, int32_t& nEndChar) const;
+  void ClearSelection();
+  void SelectAll();
+  bool IsPopup() const;
+
+  void SetSelectText();
+
+  void AttachFFLData(CFFL_FormFiller* pData) { m_pFormFiller = pData; }
+
+ private:
+  void CreateEdit(const CreateParams& cp);
+  void CreateButton(const CreateParams& cp);
+  void CreateListBox(const CreateParams& cp);
+
+  // Returns |true| iff this instance is still allocated.
+  bool SetPopup(bool bPopup);
+
+  UnownedPtr<CPWL_Edit> m_pEdit;
+  UnownedPtr<CPWL_CBButton> m_pButton;
+  UnownedPtr<CPWL_CBListBox> m_pList;
+  CFX_FloatRect m_rcOldWindow;
+  bool m_bPopup = false;
+  bool m_bBottom = true;
+  int32_t m_nSelectItem = -1;
+  UnownedPtr<IPWL_Filler_Notify> m_pFillerNotify;
+  UnownedPtr<CFFL_FormFiller> m_pFormFiller;
+};
+
+#endif  // FPDFSDK_PWL_CPWL_COMBO_BOX_H_
diff --git a/fpdfsdk/pwl/cpwl_combo_box_embeddertest.cpp b/fpdfsdk/pwl/cpwl_combo_box_embeddertest.cpp
new file mode 100644
index 0000000..9fd8eec
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_combo_box_embeddertest.cpp
@@ -0,0 +1,348 @@
+// 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 "fpdfsdk/cba_annotiterator.h"
+#include "fpdfsdk/cpdfsdk_annot.h"
+#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
+#include "fpdfsdk/formfiller/cffl_formfiller.h"
+#include "fpdfsdk/formfiller/cffl_interactiveformfiller.h"
+#include "fpdfsdk/pwl/cpwl_combo_box.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
+#include "testing/embedder_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class CPWLComboBoxEditEmbeddertest : public EmbedderTest {
+ protected:
+  void SetUp() override {
+    EmbedderTest::SetUp();
+    CreateAndInitializeFormComboboxPDF();
+  }
+
+  void TearDown() override {
+    UnloadPage(GetPage());
+    EmbedderTest::TearDown();
+  }
+
+  void CreateAndInitializeFormComboboxPDF() {
+    EXPECT_TRUE(OpenDocument("combobox_form.pdf"));
+    m_page = LoadPage(0);
+    ASSERT_TRUE(m_page);
+
+    m_pFormFillEnv = static_cast<CPDFSDK_FormFillEnvironment*>(form_handle());
+    CBA_AnnotIterator iter(m_pFormFillEnv->GetPageView(0),
+                           CPDF_Annot::Subtype::WIDGET);
+
+    // User editable combobox.
+    m_pAnnotEditable = iter.GetFirstAnnot();
+    ASSERT_TRUE(m_pAnnotEditable);
+    ASSERT_EQ(CPDF_Annot::Subtype::WIDGET, m_pAnnotEditable->GetAnnotSubtype());
+
+    // Normal combobox with pre-selected value.
+    m_pAnnotNormal = iter.GetNextAnnot(m_pAnnotEditable);
+    ASSERT_TRUE(m_pAnnotNormal);
+    ASSERT_EQ(CPDF_Annot::Subtype::WIDGET, m_pAnnotNormal->GetAnnotSubtype());
+
+    // Read-only combobox.
+    CPDFSDK_Annot* pAnnotReadOnly = iter.GetNextAnnot(m_pAnnotNormal);
+    CPDFSDK_Annot* pLastAnnot = iter.GetLastAnnot();
+    ASSERT_EQ(pAnnotReadOnly, pLastAnnot);
+  }
+
+  void FormFillerAndWindowSetup(CPDFSDK_Annot* pAnnotCombobox) {
+    CFFL_InteractiveFormFiller* pInteractiveFormFiller =
+        m_pFormFillEnv->GetInteractiveFormFiller();
+    {
+      CPDFSDK_Annot::ObservedPtr pObserved(pAnnotCombobox);
+      EXPECT_TRUE(pInteractiveFormFiller->OnSetFocus(&pObserved, 0));
+    }
+
+    m_pFormFiller =
+        pInteractiveFormFiller->GetFormFiller(pAnnotCombobox, false);
+    ASSERT_TRUE(m_pFormFiller);
+
+    CPWL_Wnd* pWindow =
+        m_pFormFiller->GetPDFWindow(m_pFormFillEnv->GetPageView(0), false);
+    ASSERT_TRUE(pWindow);
+    ASSERT_EQ("CPWL_ComboBox", pWindow->GetClassName());
+    m_pComboBox = static_cast<CPWL_ComboBox*>(pWindow);
+  }
+
+  void TypeTextIntoTextField(int num_chars) {
+    // Type text starting with 'A' to as many chars as specified by |num_chars|.
+    for (int i = 0; i < num_chars; ++i) {
+      EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnotUserEditable(),
+                                              i + 'A', 0));
+    }
+  }
+
+  FPDF_PAGE GetPage() const { return m_page; }
+  CPWL_ComboBox* GetCPWLComboBox() const { return m_pComboBox; }
+  CFFL_FormFiller* GetCFFLFormFiller() const { return m_pFormFiller; }
+  CPDFSDK_Annot* GetCPDFSDKAnnotNormal() const { return m_pAnnotNormal; }
+  CPDFSDK_Annot* GetCPDFSDKAnnotUserEditable() const {
+    return m_pAnnotEditable;
+  }
+  CPDFSDK_FormFillEnvironment* GetCPDFSDKFormFillEnv() const {
+    return m_pFormFillEnv;
+  }
+
+ private:
+  FPDF_PAGE m_page;
+  CPWL_ComboBox* m_pComboBox;
+  CFFL_FormFiller* m_pFormFiller;
+  CPDFSDK_Annot* m_pAnnotNormal;
+  CPDFSDK_Annot* m_pAnnotEditable;
+  CPDFSDK_FormFillEnvironment* m_pFormFillEnv;
+};
+
+TEST_F(CPWLComboBoxEditEmbeddertest, GetSelectedTextEmptyAndBasicNormal) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotNormal());
+
+  // Automatically pre-filled with "Banana".
+  EXPECT_FALSE(GetCPWLComboBox()->GetText().IsEmpty());
+  EXPECT_STREQ(L"Banana", GetCPWLComboBox()->GetText().c_str());
+
+  // Check that selection is intially empty, then select entire word.
+  EXPECT_TRUE(GetCPWLComboBox()->GetSelectedText().IsEmpty());
+  GetCPWLComboBox()->SetSelectText();
+  EXPECT_STREQ(L"Banana", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  // Select other options.
+  GetCPWLComboBox()->SetSelect(0);
+  EXPECT_STREQ(L"Apple", GetCPWLComboBox()->GetSelectedText().c_str());
+  GetCPWLComboBox()->SetSelect(2);
+  EXPECT_STREQ(L"Cherry", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  // Verify that combobox text cannot be edited.
+  EXPECT_FALSE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnotNormal(), 'a', 0));
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest, GetSelectedTextFragmentsNormal) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotNormal());
+  EXPECT_STREQ(L"Banana", GetCPWLComboBox()->GetText().c_str());
+
+  GetCPWLComboBox()->SetEditSelection(0, 0);
+  EXPECT_TRUE(GetCPWLComboBox()->GetSelectedText().IsEmpty());
+
+  GetCPWLComboBox()->SetEditSelection(0, 1);
+  EXPECT_STREQ(L"B", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->SetEditSelection(0, -1);
+  EXPECT_STREQ(L"Banana", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->SetEditSelection(-8, -1);
+  EXPECT_TRUE(GetCPWLComboBox()->GetSelectedText().IsEmpty());
+
+  GetCPWLComboBox()->SetEditSelection(4, 1);
+  EXPECT_STREQ(L"ana", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->SetEditSelection(1, 4);
+  EXPECT_STREQ(L"ana", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->SetEditSelection(5, 6);
+  EXPECT_STREQ(L"a", GetCPWLComboBox()->GetSelectedText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest, GetSelectedTextEmptyAndBasicEditable) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  EXPECT_TRUE(GetCPWLComboBox()->GetText().IsEmpty());
+
+  // Check selection is intially empty, then select a provided option.
+  EXPECT_TRUE(GetCPWLComboBox()->GetSelectedText().IsEmpty());
+  GetCPWLComboBox()->SetSelect(0);
+  GetCPWLComboBox()->SetSelectText();
+  EXPECT_STREQ(L"Foo", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  // Select another option and then select last char of that option.
+  GetCPWLComboBox()->SetSelect(1);
+  EXPECT_STREQ(L"Bar", GetCPWLComboBox()->GetSelectedText().c_str());
+  GetCPWLComboBox()->SetEditSelection(2, 3);
+  EXPECT_STREQ(L"r", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  // Type into editable combobox text field and select new text.
+  EXPECT_TRUE(
+      GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnotUserEditable(), 'a', 0));
+  EXPECT_TRUE(
+      GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnotUserEditable(), 'b', 0));
+  EXPECT_TRUE(
+      GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnotUserEditable(), 'c', 0));
+
+  EXPECT_TRUE(GetCPWLComboBox()->GetSelectedText().IsEmpty());
+  GetCPWLComboBox()->SetEditSelection(0, 5);
+  EXPECT_STREQ(L"Baabc", GetCPWLComboBox()->GetSelectedText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest, GetSelectedTextFragmentsEditable) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(50);
+
+  GetCPWLComboBox()->SetEditSelection(0, 0);
+  EXPECT_TRUE(GetCPWLComboBox()->GetSelectedText().IsEmpty());
+
+  GetCPWLComboBox()->SetEditSelection(0, 1);
+  EXPECT_STREQ(L"A", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->SetEditSelection(0, -1);
+  EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->SetEditSelection(-8, -1);
+  EXPECT_TRUE(GetCPWLComboBox()->GetSelectedText().IsEmpty());
+
+  GetCPWLComboBox()->SetEditSelection(23, 12);
+  EXPECT_STREQ(L"MNOPQRSTUVW", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->SetEditSelection(12, 23);
+  EXPECT_STREQ(L"MNOPQRSTUVW", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->SetEditSelection(49, 50);
+  EXPECT_STREQ(L"r", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->SetEditSelection(49, 55);
+  EXPECT_STREQ(L"r", GetCPWLComboBox()->GetSelectedText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest, DeleteEntireTextSelection) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(50);
+
+  GetCPWLComboBox()->SetEditSelection(0, -1);
+  EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->ReplaceSelection(L"");
+  EXPECT_TRUE(GetCPWLComboBox()->GetText().IsEmpty());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest, DeleteTextSelectionMiddle) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(50);
+
+  GetCPWLComboBox()->SetEditSelection(12, 23);
+  EXPECT_STREQ(L"MNOPQRSTUVW", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->ReplaceSelection(L"");
+  EXPECT_STREQ(L"ABCDEFGHIJKLXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest, DeleteTextSelectionLeft) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(50);
+
+  GetCPWLComboBox()->SetEditSelection(0, 5);
+  EXPECT_STREQ(L"ABCDE", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->ReplaceSelection(L"");
+  EXPECT_STREQ(L"FGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest, DeleteTextSelectionRight) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(50);
+
+  GetCPWLComboBox()->SetEditSelection(45, 50);
+  EXPECT_STREQ(L"nopqr", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->ReplaceSelection(L"");
+  EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklm",
+               GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest, DeleteEmptyTextSelection) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(50);
+
+  GetCPWLComboBox()->ReplaceSelection(L"");
+  EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest, InsertTextInEmptyEditableComboBox) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  GetCPWLComboBox()->ReplaceSelection(L"Hello");
+  EXPECT_STREQ(L"Hello", GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest,
+       InsertTextInPopulatedEditableComboBoxLeft) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(10);
+
+  // Move cursor to beginning of user-editable combobox text field.
+  EXPECT_TRUE(GetCFFLFormFiller()->OnKeyDown(GetCPDFSDKAnnotUserEditable(),
+                                             FWL_VKEY_Home, 0));
+
+  GetCPWLComboBox()->ReplaceSelection(L"Hello");
+  EXPECT_STREQ(L"HelloABCDEFGHIJ", GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest,
+       InsertTextInPopulatedEditableComboBoxMiddle) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(10);
+
+  // Move cursor to middle of user-editable combobox text field.
+  for (int i = 0; i < 5; ++i) {
+    EXPECT_TRUE(GetCFFLFormFiller()->OnKeyDown(GetCPDFSDKAnnotUserEditable(),
+                                               FWL_VKEY_Left, 0));
+  }
+
+  GetCPWLComboBox()->ReplaceSelection(L"Hello");
+  EXPECT_STREQ(L"ABCDEHelloFGHIJ", GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest,
+       InsertTextInPopulatedEditableComboBoxRight) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(10);
+
+  GetCPWLComboBox()->ReplaceSelection(L"Hello");
+  EXPECT_STREQ(L"ABCDEFGHIJHello", GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedEditableComboBoxWhole) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(10);
+
+  GetCPWLComboBox()->SetEditSelection(0, -1);
+  EXPECT_STREQ(L"ABCDEFGHIJ", GetCPWLComboBox()->GetSelectedText().c_str());
+  GetCPWLComboBox()->ReplaceSelection(L"Hello");
+  EXPECT_STREQ(L"Hello", GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedEditableComboBoxLeft) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(10);
+
+  GetCPWLComboBox()->SetEditSelection(0, 5);
+  EXPECT_STREQ(L"ABCDE", GetCPWLComboBox()->GetSelectedText().c_str());
+  GetCPWLComboBox()->ReplaceSelection(L"Hello");
+  EXPECT_STREQ(L"HelloFGHIJ", GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedEditableComboBoxMiddle) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(10);
+
+  GetCPWLComboBox()->SetEditSelection(2, 7);
+  EXPECT_STREQ(L"CDEFG", GetCPWLComboBox()->GetSelectedText().c_str());
+  GetCPWLComboBox()->ReplaceSelection(L"Hello");
+  EXPECT_STREQ(L"ABHelloHIJ", GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedEditableComboBoxRight) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(10);
+
+  GetCPWLComboBox()->SetEditSelection(5, 10);
+  EXPECT_STREQ(L"FGHIJ", GetCPWLComboBox()->GetSelectedText().c_str());
+  GetCPWLComboBox()->ReplaceSelection(L"Hello");
+  EXPECT_STREQ(L"ABCDEHello", GetCPWLComboBox()->GetText().c_str());
+}
diff --git a/fpdfsdk/pwl/cpwl_edit.cpp b/fpdfsdk/pwl/cpwl_edit.cpp
new file mode 100644
index 0000000..6c867ca
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_edit.cpp
@@ -0,0 +1,726 @@
+// 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/pwl/cpwl_edit.h"
+
+#include <algorithm>
+#include <memory>
+#include <sstream>
+#include <vector>
+
+#include "core/fpdfapi/font/cpdf_font.h"
+#include "core/fpdfdoc/cpvt_word.h"
+#include "core/fxcrt/fx_safe_types.h"
+#include "core/fxcrt/xml/cxml_content.h"
+#include "core/fxcrt/xml/cxml_element.h"
+#include "core/fxge/cfx_graphstatedata.h"
+#include "core/fxge/cfx_pathdata.h"
+#include "core/fxge/cfx_renderdevice.h"
+#include "core/fxge/fx_font.h"
+#include "fpdfsdk/pwl/cpwl_caret.h"
+#include "fpdfsdk/pwl/cpwl_edit_ctrl.h"
+#include "fpdfsdk/pwl/cpwl_edit_impl.h"
+#include "fpdfsdk/pwl/cpwl_font_map.h"
+#include "fpdfsdk/pwl/cpwl_scroll_bar.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
+#include "public/fpdf_fwlevent.h"
+#include "third_party/base/stl_util.h"
+
+CPWL_Edit::CPWL_Edit() : m_bFocus(false) {}
+
+CPWL_Edit::~CPWL_Edit() {
+  ASSERT(!m_bFocus);
+}
+
+ByteString CPWL_Edit::GetClassName() const {
+  return PWL_CLASSNAME_EDIT;
+}
+
+void CPWL_Edit::SetText(const WideString& csText) {
+  WideString swText = csText;
+  if (!HasFlag(PES_RICH)) {
+    m_pEdit->SetText(swText);
+    return;
+  }
+
+  ByteString sValue = ByteString::FromUnicode(swText);
+  std::unique_ptr<CXML_Element> pXML(
+      CXML_Element::Parse(sValue.c_str(), sValue.GetLength()));
+  if (!pXML) {
+    m_pEdit->SetText(swText);
+    return;
+  }
+  swText.clear();
+
+  bool bFirst = true;
+  size_t nCount = pXML->CountChildren();
+  for (size_t i = 0; i < nCount; ++i) {
+    CXML_Element* pSubElement = ToElement(pXML->GetChild(i));
+    if (!pSubElement || !pSubElement->GetTagName().EqualNoCase("p"))
+      continue;
+
+    WideString swSection;
+    size_t nSubChild = pSubElement->CountChildren();
+    for (size_t j = 0; j < nSubChild; ++j) {
+      CXML_Content* pSubContent = ToContent(pSubElement->GetChild(j));
+      if (pSubContent)
+        swSection += pSubContent->m_Content;
+    }
+    if (bFirst)
+      bFirst = false;
+    else
+      swText += FWL_VKEY_Return;
+    swText += swSection;
+  }
+
+  m_pEdit->SetText(swText);
+}
+
+bool CPWL_Edit::RePosChildWnd() {
+  if (CPWL_ScrollBar* pVSB = GetVScrollBar()) {
+    CFX_FloatRect rcWindow = m_rcOldWindow;
+    CFX_FloatRect rcVScroll =
+        CFX_FloatRect(rcWindow.right, rcWindow.bottom,
+                      rcWindow.right + PWL_SCROLLBAR_WIDTH, rcWindow.top);
+
+    ObservedPtr thisObserved(this);
+
+    pVSB->Move(rcVScroll, true, false);
+    if (!thisObserved)
+      return false;
+  }
+
+  if (m_pEditCaret && !HasFlag(PES_TEXTOVERFLOW)) {
+    CFX_FloatRect rect = GetClientRect();
+    if (!rect.IsEmpty()) {
+      // +1 for caret beside border
+      rect.Inflate(1.0f, 1.0f);
+      rect.Normalize();
+    }
+    m_pEditCaret->SetClipRect(rect);
+  }
+
+  return CPWL_EditCtrl::RePosChildWnd();
+}
+
+CFX_FloatRect CPWL_Edit::GetClientRect() const {
+  float width = static_cast<float>(GetBorderWidth() + GetInnerBorderWidth());
+  CFX_FloatRect rcClient = GetWindowRect().GetDeflated(width, width);
+  if (CPWL_ScrollBar* pVSB = GetVScrollBar()) {
+    if (pVSB->IsVisible()) {
+      rcClient.right -= PWL_SCROLLBAR_WIDTH;
+    }
+  }
+
+  return rcClient;
+}
+
+void CPWL_Edit::SetAlignFormatV(PWL_EDIT_ALIGNFORMAT_V nFormat, bool bPaint) {
+  m_pEdit->SetAlignmentV((int32_t)nFormat, bPaint);
+}
+
+bool CPWL_Edit::CanSelectAll() const {
+  return GetSelectWordRange() != m_pEdit->GetWholeWordRange();
+}
+
+bool CPWL_Edit::CanCopy() const {
+  return !HasFlag(PES_PASSWORD) && !HasFlag(PES_NOREAD) &&
+         m_pEdit->IsSelected();
+}
+
+bool CPWL_Edit::CanCut() const {
+  return CanCopy() && !IsReadOnly();
+}
+void CPWL_Edit::CutText() {
+  if (!CanCut())
+    return;
+  m_pEdit->ClearSelection();
+}
+
+void CPWL_Edit::OnCreated() {
+  CPWL_EditCtrl::OnCreated();
+
+  if (CPWL_ScrollBar* pScroll = GetVScrollBar()) {
+    pScroll->RemoveFlag(PWS_AUTOTRANSPARENT);
+    pScroll->SetTransparency(255);
+  }
+
+  SetParamByFlag();
+
+  m_rcOldWindow = GetWindowRect();
+
+  m_pEdit->SetOperationNotify(this);
+}
+
+void CPWL_Edit::SetParamByFlag() {
+  if (HasFlag(PES_RIGHT)) {
+    m_pEdit->SetAlignmentH(2, false);
+  } else if (HasFlag(PES_MIDDLE)) {
+    m_pEdit->SetAlignmentH(1, false);
+  } else {
+    m_pEdit->SetAlignmentH(0, false);
+  }
+
+  if (HasFlag(PES_BOTTOM)) {
+    m_pEdit->SetAlignmentV(2, false);
+  } else if (HasFlag(PES_CENTER)) {
+    m_pEdit->SetAlignmentV(1, false);
+  } else {
+    m_pEdit->SetAlignmentV(0, false);
+  }
+
+  if (HasFlag(PES_PASSWORD)) {
+    m_pEdit->SetPasswordChar('*', false);
+  }
+
+  m_pEdit->SetMultiLine(HasFlag(PES_MULTILINE), false);
+  m_pEdit->SetAutoReturn(HasFlag(PES_AUTORETURN), false);
+  m_pEdit->SetAutoFontSize(HasFlag(PWS_AUTOFONTSIZE), false);
+  m_pEdit->SetAutoScroll(HasFlag(PES_AUTOSCROLL), false);
+  m_pEdit->EnableUndo(HasFlag(PES_UNDO));
+
+  if (HasFlag(PES_TEXTOVERFLOW)) {
+    SetClipRect(CFX_FloatRect());
+    m_pEdit->SetTextOverflow(true, false);
+  } else {
+    if (m_pEditCaret) {
+      CFX_FloatRect rect = GetClientRect();
+      if (!rect.IsEmpty()) {
+        // +1 for caret beside border
+        rect.Inflate(1.0f, 1.0f);
+        rect.Normalize();
+      }
+      m_pEditCaret->SetClipRect(rect);
+    }
+  }
+}
+
+void CPWL_Edit::DrawThisAppearance(CFX_RenderDevice* pDevice,
+                                   const CFX_Matrix& mtUser2Device) {
+  CPWL_Wnd::DrawThisAppearance(pDevice, mtUser2Device);
+
+  CFX_FloatRect rcClient = GetClientRect();
+
+  int32_t nCharArray = m_pEdit->GetCharArray();
+  FX_SAFE_INT32 nCharArraySafe = nCharArray;
+  nCharArraySafe -= 1;
+  nCharArraySafe *= 2;
+
+  if (nCharArray > 0 && nCharArraySafe.IsValid()) {
+    switch (GetBorderStyle()) {
+      case BorderStyle::SOLID: {
+        CFX_GraphStateData gsd;
+        gsd.m_LineWidth = (float)GetBorderWidth();
+
+        CFX_PathData path;
+
+        for (int32_t i = 0; i < nCharArray - 1; i++) {
+          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.GetPoints().empty()) {
+          pDevice->DrawPath(&path, &mtUser2Device, &gsd, 0,
+                            GetBorderColor().ToFXColor(255), FXFILL_ALTERNATE);
+        }
+        break;
+      }
+      case BorderStyle::DASH: {
+        CFX_GraphStateData gsd;
+        gsd.m_LineWidth = (float)GetBorderWidth();
+
+        gsd.SetDashCount(2);
+        gsd.m_DashArray[0] = (float)GetBorderDash().nDash;
+        gsd.m_DashArray[1] = (float)GetBorderDash().nGap;
+        gsd.m_DashPhase = (float)GetBorderDash().nPhase;
+
+        CFX_PathData path;
+        for (int32_t i = 0; i < nCharArray - 1; i++) {
+          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.GetPoints().empty()) {
+          pDevice->DrawPath(&path, &mtUser2Device, &gsd, 0,
+                            GetBorderColor().ToFXColor(255), FXFILL_ALTERNATE);
+        }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+
+  CFX_FloatRect rcClip;
+  CPVT_WordRange wrRange = m_pEdit->GetVisibleWordRange();
+  CPVT_WordRange* pRange = nullptr;
+  if (!HasFlag(PES_TEXTOVERFLOW)) {
+    rcClip = GetClientRect();
+    pRange = &wrRange;
+  }
+
+  CFX_SystemHandler* pSysHandler = GetSystemHandler();
+  CPWL_EditImpl::DrawEdit(pDevice, mtUser2Device, m_pEdit.get(),
+                          GetTextColor().ToFXColor(GetTransparency()), rcClip,
+                          CFX_PointF(), pRange, pSysHandler,
+                          m_pFormFiller.Get());
+}
+
+bool CPWL_Edit::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
+  CPWL_Wnd::OnLButtonDown(point, nFlag);
+
+  if (HasFlag(PES_TEXTOVERFLOW) || ClientHitTest(point)) {
+    if (m_bMouseDown && !InvalidateRect(nullptr))
+      return true;
+
+    m_bMouseDown = true;
+    SetCapture();
+
+    m_pEdit->OnMouseDown(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+  }
+
+  return true;
+}
+
+bool CPWL_Edit::OnLButtonDblClk(const CFX_PointF& point, uint32_t nFlag) {
+  CPWL_Wnd::OnLButtonDblClk(point, nFlag);
+
+  if (HasFlag(PES_TEXTOVERFLOW) || ClientHitTest(point)) {
+    m_pEdit->SelectAll();
+  }
+
+  return true;
+}
+
+bool CPWL_Edit::OnRButtonUp(const CFX_PointF& point, uint32_t nFlag) {
+  if (m_bMouseDown)
+    return false;
+
+  CPWL_Wnd::OnRButtonUp(point, nFlag);
+
+  if (!HasFlag(PES_TEXTOVERFLOW) && !ClientHitTest(point))
+    return true;
+
+  CFX_SystemHandler* pSH = GetSystemHandler();
+  if (!pSH)
+    return false;
+
+  SetFocus();
+
+  return false;
+}
+
+void CPWL_Edit::OnSetFocus() {
+  ObservedPtr observed_ptr(this);
+  SetEditCaret(true);
+  if (!observed_ptr)
+    return;
+
+  if (!IsReadOnly()) {
+    if (CPWL_Wnd::FocusHandlerIface* pFocusHandler = GetFocusHandler()) {
+      pFocusHandler->OnSetFocus(this);
+      if (!observed_ptr)
+        return;
+    }
+  }
+  m_bFocus = true;
+}
+
+void CPWL_Edit::OnKillFocus() {
+  ObservedPtr observed_ptr(this);
+
+  CPWL_ScrollBar* pScroll = GetVScrollBar();
+  if (pScroll && pScroll->IsVisible()) {
+    pScroll->SetVisible(false);
+    if (!observed_ptr)
+      return;
+
+    if (!Move(m_rcOldWindow, true, true))
+      return;
+  }
+
+  m_pEdit->SelectNone();
+  if (!observed_ptr)
+    return;
+
+  if (!SetCaret(false, CFX_PointF(), CFX_PointF()))
+    return;
+
+  SetCharSet(FX_CHARSET_ANSI);
+  m_bFocus = false;
+}
+
+void CPWL_Edit::SetCharSpace(float fCharSpace) {
+  m_pEdit->SetCharSpace(fCharSpace);
+}
+
+CPVT_WordRange CPWL_Edit::GetSelectWordRange() const {
+  if (!m_pEdit->IsSelected())
+    return CPVT_WordRange();
+
+  int32_t nStart = -1;
+  int32_t nEnd = -1;
+
+  m_pEdit->GetSelection(nStart, nEnd);
+
+  CPVT_WordPlace wpStart = m_pEdit->WordIndexToWordPlace(nStart);
+  CPVT_WordPlace wpEnd = m_pEdit->WordIndexToWordPlace(nEnd);
+
+  return CPVT_WordRange(wpStart, wpEnd);
+}
+
+CFX_PointF CPWL_Edit::GetWordRightBottomPoint(const CPVT_WordPlace& wpWord) {
+  CPWL_EditImpl_Iterator* pIterator = m_pEdit->GetIterator();
+  CPVT_WordPlace wpOld = pIterator->GetAt();
+  pIterator->SetAt(wpWord);
+
+  CFX_PointF pt;
+  CPVT_Word word;
+  if (pIterator->GetWord(word))
+    pt = CFX_PointF(word.ptWord.x + word.fWidth, word.ptWord.y + word.fDescent);
+  pIterator->SetAt(wpOld);
+  return pt;
+}
+
+bool CPWL_Edit::IsTextFull() const {
+  return m_pEdit->IsTextFull();
+}
+
+float CPWL_Edit::GetCharArrayAutoFontSize(CPDF_Font* pFont,
+                                          const CFX_FloatRect& rcPlate,
+                                          int32_t nCharArray) {
+  if (!pFont || pFont->IsStandardFont())
+    return 0.0f;
+
+  FX_RECT rcBBox;
+  pFont->GetFontBBox(rcBBox);
+
+  CFX_FloatRect rcCell = rcPlate;
+  float xdiv = rcCell.Width() / nCharArray * 1000.0f / rcBBox.Width();
+  float ydiv = -rcCell.Height() * 1000.0f / rcBBox.Height();
+
+  return xdiv < ydiv ? xdiv : ydiv;
+}
+
+void CPWL_Edit::SetCharArray(int32_t nCharArray) {
+  if (!HasFlag(PES_CHARARRAY) || nCharArray <= 0)
+    return;
+
+  m_pEdit->SetCharArray(nCharArray);
+  m_pEdit->SetTextOverflow(true, true);
+
+  if (!HasFlag(PWS_AUTOFONTSIZE))
+    return;
+
+  IPVT_FontMap* pFontMap = GetFontMap();
+  if (!pFontMap)
+    return;
+
+  float fFontSize = GetCharArrayAutoFontSize(pFontMap->GetPDFFont(0),
+                                             GetClientRect(), nCharArray);
+  if (fFontSize <= 0.0f)
+    return;
+
+  m_pEdit->SetAutoFontSize(false, true);
+  m_pEdit->SetFontSize(fFontSize);
+}
+
+void CPWL_Edit::SetLimitChar(int32_t nLimitChar) {
+  m_pEdit->SetLimitChar(nLimitChar);
+}
+
+void CPWL_Edit::ReplaceSel(const WideString& wsText) {
+  m_pEdit->ClearSelection();
+  m_pEdit->InsertText(wsText, FX_CHARSET_Default);
+}
+
+CFX_FloatRect CPWL_Edit::GetFocusRect() const {
+  return CFX_FloatRect();
+}
+
+bool CPWL_Edit::IsVScrollBarVisible() const {
+  CPWL_ScrollBar* pScroll = GetVScrollBar();
+  return pScroll && pScroll->IsVisible();
+}
+
+bool CPWL_Edit::OnKeyDown(uint16_t nChar, uint32_t nFlag) {
+  if (m_bMouseDown)
+    return true;
+
+  if (nChar == FWL_VKEY_Delete) {
+    if (m_pFillerNotify) {
+      WideString strChange;
+      WideString strChangeEx;
+
+      int nSelStart = 0;
+      int nSelEnd = 0;
+      GetSelection(nSelStart, nSelEnd);
+
+      if (nSelStart == nSelEnd)
+        nSelEnd = nSelStart + 1;
+
+      CPWL_Wnd::ObservedPtr thisObserved(this);
+
+      bool bRC;
+      bool bExit;
+      std::tie(bRC, bExit) = m_pFillerNotify->OnBeforeKeyStroke(
+          GetAttachedData(), strChange, strChangeEx, nSelStart, nSelEnd, true,
+          nFlag);
+
+      if (!thisObserved)
+        return false;
+
+      if (!bRC)
+        return false;
+      if (bExit)
+        return false;
+    }
+  }
+
+  bool bRet = CPWL_EditCtrl::OnKeyDown(nChar, nFlag);
+
+  // In case of implementation swallow the OnKeyDown event.
+  if (IsProceedtoOnChar(nChar, nFlag))
+    return true;
+
+  return bRet;
+}
+
+// static
+bool CPWL_Edit::IsProceedtoOnChar(uint16_t nKeyCode, uint32_t nFlag) {
+  bool bCtrl = IsCTRLpressed(nFlag);
+  bool bAlt = IsALTpressed(nFlag);
+  if (bCtrl && !bAlt) {
+    // hot keys for edit control.
+    switch (nKeyCode) {
+      case 'C':
+      case 'V':
+      case 'X':
+      case 'A':
+      case 'Z':
+        return true;
+      default:
+        break;
+    }
+  }
+  // control characters.
+  switch (nKeyCode) {
+    case FWL_VKEY_Escape:
+    case FWL_VKEY_Back:
+    case FWL_VKEY_Return:
+    case FWL_VKEY_Space:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool CPWL_Edit::OnChar(uint16_t nChar, uint32_t nFlag) {
+  if (m_bMouseDown)
+    return true;
+
+  bool bRC = true;
+  bool bExit = false;
+
+  if (!IsCTRLpressed(nFlag)) {
+    if (m_pFillerNotify) {
+      WideString swChange;
+
+      int nSelStart = 0;
+      int nSelEnd = 0;
+      GetSelection(nSelStart, nSelEnd);
+
+      switch (nChar) {
+        case FWL_VKEY_Back:
+          if (nSelStart == nSelEnd)
+            nSelStart = nSelEnd - 1;
+          break;
+        case FWL_VKEY_Return:
+          break;
+        default:
+          swChange += nChar;
+          break;
+      }
+
+      CPWL_Wnd::ObservedPtr thisObserved(this);
+
+      WideString strChangeEx;
+      std::tie(bRC, bExit) = m_pFillerNotify->OnBeforeKeyStroke(
+          GetAttachedData(), swChange, strChangeEx, nSelStart, nSelEnd, true,
+          nFlag);
+
+      if (!thisObserved)
+        return false;
+    }
+  }
+
+  if (!bRC)
+    return true;
+  if (bExit)
+    return false;
+
+  if (IPVT_FontMap* pFontMap = GetFontMap()) {
+    int32_t nOldCharSet = GetCharSet();
+    int32_t nNewCharSet =
+        pFontMap->CharSetFromUnicode(nChar, FX_CHARSET_Default);
+    if (nOldCharSet != nNewCharSet) {
+      SetCharSet(nNewCharSet);
+    }
+  }
+
+  return CPWL_EditCtrl::OnChar(nChar, nFlag);
+}
+
+bool CPWL_Edit::OnMouseWheel(short zDelta,
+                             const CFX_PointF& point,
+                             uint32_t nFlag) {
+  if (!HasFlag(PES_MULTILINE))
+    return false;
+
+  CFX_PointF ptScroll = GetScrollPos();
+  if (zDelta > 0)
+    ptScroll.y += GetFontSize();
+  else
+    ptScroll.y -= GetFontSize();
+  SetScrollPos(ptScroll);
+  return true;
+}
+
+void CPWL_Edit::OnInsertReturn(const CPVT_WordPlace& place,
+                               const CPVT_WordPlace& oldplace) {
+  if (HasFlag(PES_SPELLCHECK)) {
+    m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
+                                               GetLatinWordsRange(place)));
+  }
+}
+
+void CPWL_Edit::OnBackSpace(const CPVT_WordPlace& place,
+                            const CPVT_WordPlace& oldplace) {
+  if (HasFlag(PES_SPELLCHECK)) {
+    m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
+                                               GetLatinWordsRange(place)));
+  }
+}
+
+void CPWL_Edit::OnDelete(const CPVT_WordPlace& place,
+                         const CPVT_WordPlace& oldplace) {
+  if (HasFlag(PES_SPELLCHECK)) {
+    m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
+                                               GetLatinWordsRange(place)));
+  }
+}
+
+void CPWL_Edit::OnClear(const CPVT_WordPlace& place,
+                        const CPVT_WordPlace& oldplace) {
+  if (HasFlag(PES_SPELLCHECK)) {
+    m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
+                                               GetLatinWordsRange(place)));
+  }
+}
+
+void CPWL_Edit::OnInsertWord(const CPVT_WordPlace& place,
+                             const CPVT_WordPlace& oldplace) {
+  if (HasFlag(PES_SPELLCHECK)) {
+    m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
+                                               GetLatinWordsRange(place)));
+  }
+}
+
+void CPWL_Edit::OnInsertText(const CPVT_WordPlace& place,
+                             const CPVT_WordPlace& oldplace) {
+  if (HasFlag(PES_SPELLCHECK)) {
+    m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
+                                               GetLatinWordsRange(place)));
+  }
+}
+
+CPVT_WordRange CPWL_Edit::CombineWordRange(const CPVT_WordRange& wr1,
+                                           const CPVT_WordRange& wr2) {
+  return CPVT_WordRange(std::min(wr1.BeginPos, wr2.BeginPos),
+                        std::max(wr1.EndPos, wr2.EndPos));
+}
+
+CPVT_WordRange CPWL_Edit::GetLatinWordsRange(const CFX_PointF& point) const {
+  return GetSameWordsRange(m_pEdit->SearchWordPlace(point), true, false);
+}
+
+CPVT_WordRange CPWL_Edit::GetLatinWordsRange(
+    const CPVT_WordPlace& place) const {
+  return GetSameWordsRange(place, true, false);
+}
+
+#define PWL_ISARABICWORD(word) \
+  ((word >= 0x0600 && word <= 0x06FF) || (word >= 0xFB50 && word <= 0xFEFC))
+
+CPVT_WordRange CPWL_Edit::GetSameWordsRange(const CPVT_WordPlace& place,
+                                            bool bLatin,
+                                            bool bArabic) const {
+  CPVT_WordRange range;
+
+  CPWL_EditImpl_Iterator* pIterator = m_pEdit->GetIterator();
+  CPVT_Word wordinfo;
+  CPVT_WordPlace wpStart(place), wpEnd(place);
+  pIterator->SetAt(place);
+
+  if (bLatin) {
+    while (pIterator->NextWord()) {
+      if (!pIterator->GetWord(wordinfo) ||
+          !FX_EDIT_ISLATINWORD(wordinfo.Word)) {
+        break;
+      }
+
+      wpEnd = pIterator->GetAt();
+    }
+  } else if (bArabic) {
+    while (pIterator->NextWord()) {
+      if (!pIterator->GetWord(wordinfo) || !PWL_ISARABICWORD(wordinfo.Word))
+        break;
+
+      wpEnd = pIterator->GetAt();
+    }
+  }
+
+  pIterator->SetAt(place);
+
+  if (bLatin) {
+    do {
+      if (!pIterator->GetWord(wordinfo) ||
+          !FX_EDIT_ISLATINWORD(wordinfo.Word)) {
+        break;
+      }
+
+      wpStart = pIterator->GetAt();
+    } while (pIterator->PrevWord());
+  } else if (bArabic) {
+    do {
+      if (!pIterator->GetWord(wordinfo) || !PWL_ISARABICWORD(wordinfo.Word))
+        break;
+
+      wpStart = pIterator->GetAt();
+    } while (pIterator->PrevWord());
+  }
+
+  range.Set(wpStart, wpEnd);
+  return range;
+}
diff --git a/fpdfsdk/pwl/cpwl_edit.h b/fpdfsdk/pwl/cpwl_edit.h
new file mode 100644
index 0000000..3f9cd43
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_edit.h
@@ -0,0 +1,134 @@
+// 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 FPDFSDK_PWL_CPWL_EDIT_H_
+#define FPDFSDK_PWL_CPWL_EDIT_H_
+
+#include <utility>
+
+#include "core/fpdfdoc/cpvt_wordrange.h"
+#include "core/fxcrt/unowned_ptr.h"
+#include "fpdfsdk/pwl/cpwl_edit_ctrl.h"
+
+#define PWL_CLASSNAME_EDIT "CPWL_Edit"
+
+class IPWL_Filler_Notify {
+ public:
+  virtual ~IPWL_Filler_Notify() {}
+
+  // Must write to |bBottom| and |fPopupRet|.
+  virtual void QueryWherePopup(CPWL_Wnd::PrivateData* pAttached,
+                               float fPopupMin,
+                               float fPopupMax,
+                               bool* bBottom,
+                               float* fPopupRet) = 0;
+  virtual std::pair<bool, bool> OnBeforeKeyStroke(
+      CPWL_Wnd::PrivateData* pAttached,
+      WideString& strChange,
+      const WideString& strChangeEx,
+      int nSelStart,
+      int nSelEnd,
+      bool bKeyDown,
+      uint32_t nFlag) = 0;
+#ifdef PDF_ENABLE_XFA
+  virtual bool OnPopupPreOpen(CPWL_Wnd::PrivateData* pAttached,
+                              uint32_t nFlag) = 0;
+  virtual bool OnPopupPostOpen(CPWL_Wnd::PrivateData* pAttached,
+                               uint32_t nFlag) = 0;
+#endif  // PDF_ENABLE_XFA
+};
+
+class CPWL_Edit : public CPWL_EditCtrl {
+ public:
+  CPWL_Edit();
+  ~CPWL_Edit() override;
+
+  // CPWL_EditCtrl
+  ByteString GetClassName() const override;
+  void OnCreated() override;
+  bool RePosChildWnd() override;
+  CFX_FloatRect GetClientRect() const override;
+  void DrawThisAppearance(CFX_RenderDevice* pDevice,
+                          const CFX_Matrix& mtUser2Device) 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_PointF& point,
+                    uint32_t nFlag) override;
+  bool OnKeyDown(uint16_t nChar, uint32_t nFlag) override;
+  bool OnChar(uint16_t nChar, uint32_t nFlag) override;
+  CFX_FloatRect GetFocusRect() const override;
+  void OnSetFocus() override;
+  void OnKillFocus() override;
+
+  void SetAlignFormatV(PWL_EDIT_ALIGNFORMAT_V nFormat = PEAV_TOP,
+                       bool bPaint = true);  // 0:top 1:bottom 2:center
+
+  void SetCharArray(int32_t nCharArray);
+  void SetLimitChar(int32_t nLimitChar);
+
+  void SetCharSpace(float fCharSpace);
+
+  bool CanSelectAll() const;
+  bool CanCopy() const;
+  bool CanCut() const;
+
+  void CutText();
+
+  void SetText(const WideString& csText);
+  void ReplaceSel(const WideString& csText);
+
+  bool IsTextFull() const;
+
+  static float GetCharArrayAutoFontSize(CPDF_Font* pFont,
+                                        const CFX_FloatRect& rcPlate,
+                                        int32_t nCharArray);
+
+  void SetFillerNotify(IPWL_Filler_Notify* pNotify) {
+    m_pFillerNotify = pNotify;
+  }
+
+  void AttachFFLData(CFFL_FormFiller* pData) { m_pFormFiller = pData; }
+
+  void OnInsertWord(const CPVT_WordPlace& place,
+                    const CPVT_WordPlace& oldplace);
+  void OnInsertReturn(const CPVT_WordPlace& place,
+                      const CPVT_WordPlace& oldplace);
+  void OnBackSpace(const CPVT_WordPlace& place, const CPVT_WordPlace& oldplace);
+  void OnDelete(const CPVT_WordPlace& place, const CPVT_WordPlace& oldplace);
+  void OnClear(const CPVT_WordPlace& place, const CPVT_WordPlace& oldplace);
+  void OnInsertText(const CPVT_WordPlace& place,
+                    const CPVT_WordPlace& oldplace);
+
+ private:
+  // In case of implementation swallow the OnKeyDown event. If the event is
+  // swallowed, implementation may do other unexpected things, which is not the
+  // control means to do.
+  static bool IsProceedtoOnChar(uint16_t nKeyCode, uint32_t nFlag);
+
+  CPVT_WordRange GetSelectWordRange() const;
+  bool IsVScrollBarVisible() const;
+  void SetParamByFlag();
+
+  float GetCharArrayAutoFontSize(int32_t nCharArray);
+  CFX_PointF GetWordRightBottomPoint(const CPVT_WordPlace& wpWord);
+
+  CPVT_WordRange CombineWordRange(const CPVT_WordRange& wr1,
+                                  const CPVT_WordRange& wr2);
+  CPVT_WordRange GetLatinWordsRange(const CFX_PointF& point) const;
+  CPVT_WordRange GetLatinWordsRange(const CPVT_WordPlace& place) const;
+  CPVT_WordRange GetSameWordsRange(const CPVT_WordPlace& place,
+                                   bool bLatin,
+                                   bool bArabic) const;
+
+  bool m_bFocus;
+  CFX_FloatRect m_rcOldWindow;
+  UnownedPtr<IPWL_Filler_Notify> m_pFillerNotify;
+  UnownedPtr<CFFL_FormFiller> m_pFormFiller;
+};
+
+#endif  // FPDFSDK_PWL_CPWL_EDIT_H_
diff --git a/fpdfsdk/pwl/cpwl_edit_ctrl.cpp b/fpdfsdk/pwl/cpwl_edit_ctrl.cpp
new file mode 100644
index 0000000..06b5ded
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_edit_ctrl.cpp
@@ -0,0 +1,431 @@
+// 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/pwl/cpwl_edit_ctrl.h"
+
+#include "core/fpdfdoc/cpvt_word.h"
+#include "core/fxge/fx_font.h"
+#include "fpdfsdk/pwl/cpwl_caret.h"
+#include "fpdfsdk/pwl/cpwl_edit_impl.h"
+#include "fpdfsdk/pwl/cpwl_font_map.h"
+#include "fpdfsdk/pwl/cpwl_scroll_bar.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
+#include "public/fpdf_fwlevent.h"
+
+CPWL_EditCtrl::CPWL_EditCtrl()
+    : m_pEdit(new CPWL_EditImpl),
+      m_pEditCaret(nullptr),
+      m_bMouseDown(false),
+      m_nCharSet(FX_CHARSET_Default) {}
+
+CPWL_EditCtrl::~CPWL_EditCtrl() {}
+
+void CPWL_EditCtrl::OnCreate(CreateParams* pParamsToAdjust) {
+  pParamsToAdjust->eCursorType = FXCT_VBEAM;
+}
+
+void CPWL_EditCtrl::OnCreated() {
+  SetFontSize(GetCreationParams().fFontSize);
+
+  m_pEdit->SetFontMap(GetFontMap());
+  m_pEdit->SetNotify(this);
+  m_pEdit->Initialize();
+}
+
+bool CPWL_EditCtrl::IsWndHorV() {
+  CFX_Matrix mt = GetWindowMatrix();
+  return mt.Transform(CFX_PointF(1, 1)).y == mt.Transform(CFX_PointF(0, 1)).y;
+}
+
+void CPWL_EditCtrl::SetCursor() {
+  if (IsValid()) {
+    if (CFX_SystemHandler* pSH = GetSystemHandler()) {
+      if (IsWndHorV())
+        pSH->SetCursor(FXCT_VBEAM);
+      else
+        pSH->SetCursor(FXCT_HBEAM);
+    }
+  }
+}
+
+WideString CPWL_EditCtrl::GetSelectedText() {
+  if (m_pEdit)
+    return m_pEdit->GetSelectedText();
+
+  return WideString();
+}
+
+void CPWL_EditCtrl::ReplaceSelection(const WideString& text) {
+  if (!m_pEdit)
+    return;
+
+  m_pEdit->ClearSelection();
+  m_pEdit->InsertText(text, FX_CHARSET_Default);
+}
+
+bool CPWL_EditCtrl::RePosChildWnd() {
+  m_pEdit->SetPlateRect(GetClientRect());
+  return true;
+}
+
+void CPWL_EditCtrl::SetScrollInfo(const PWL_SCROLL_INFO& info) {
+  if (CPWL_Wnd* pChild = GetVScrollBar())
+    pChild->SetScrollInfo(info);
+}
+
+void CPWL_EditCtrl::SetScrollPosition(float pos) {
+  if (CPWL_Wnd* pChild = GetVScrollBar())
+    pChild->SetScrollPosition(pos);
+}
+
+void CPWL_EditCtrl::ScrollWindowVertically(float pos) {
+  m_pEdit->SetScrollPos(CFX_PointF(m_pEdit->GetScrollPos().x, pos));
+}
+
+void CPWL_EditCtrl::CreateChildWnd(const CreateParams& cp) {
+  if (!IsReadOnly())
+    CreateEditCaret(cp);
+}
+
+void CPWL_EditCtrl::CreateEditCaret(const CreateParams& cp) {
+  if (m_pEditCaret)
+    return;
+
+  m_pEditCaret = new CPWL_Caret;
+  m_pEditCaret->SetInvalidRect(GetClientRect());
+
+  CreateParams ecp = cp;
+  ecp.pParentWnd = this;
+  ecp.dwFlags = PWS_CHILD | PWS_NOREFRESHCLIP;
+  ecp.dwBorderWidth = 0;
+  ecp.nBorderStyle = BorderStyle::SOLID;
+  ecp.rcRectWnd = CFX_FloatRect();
+
+  m_pEditCaret->Create(ecp);
+}
+
+void CPWL_EditCtrl::SetFontSize(float fFontSize) {
+  m_pEdit->SetFontSize(fFontSize);
+}
+
+float CPWL_EditCtrl::GetFontSize() const {
+  return m_pEdit->GetFontSize();
+}
+
+bool CPWL_EditCtrl::OnKeyDown(uint16_t nChar, uint32_t nFlag) {
+  if (m_bMouseDown)
+    return true;
+
+  bool bRet = CPWL_Wnd::OnKeyDown(nChar, nFlag);
+
+  // FILTER
+  switch (nChar) {
+    default:
+      return false;
+    case FWL_VKEY_Delete:
+    case FWL_VKEY_Up:
+    case FWL_VKEY_Down:
+    case FWL_VKEY_Left:
+    case FWL_VKEY_Right:
+    case FWL_VKEY_Home:
+    case FWL_VKEY_End:
+    case FWL_VKEY_Insert:
+    case 'C':
+    case 'V':
+    case 'X':
+    case 'A':
+    case 'Z':
+    case 'c':
+    case 'v':
+    case 'x':
+    case 'a':
+    case 'z':
+      break;
+  }
+
+  if (nChar == FWL_VKEY_Delete && m_pEdit->IsSelected())
+    nChar = FWL_VKEY_Unknown;
+
+  switch (nChar) {
+    case FWL_VKEY_Delete:
+      Delete();
+      return true;
+    case FWL_VKEY_Insert:
+      if (IsSHIFTpressed(nFlag))
+        PasteText();
+      return true;
+    case FWL_VKEY_Up:
+      m_pEdit->OnVK_UP(IsSHIFTpressed(nFlag), false);
+      return true;
+    case FWL_VKEY_Down:
+      m_pEdit->OnVK_DOWN(IsSHIFTpressed(nFlag), false);
+      return true;
+    case FWL_VKEY_Left:
+      m_pEdit->OnVK_LEFT(IsSHIFTpressed(nFlag), false);
+      return true;
+    case FWL_VKEY_Right:
+      m_pEdit->OnVK_RIGHT(IsSHIFTpressed(nFlag), false);
+      return true;
+    case FWL_VKEY_Home:
+      m_pEdit->OnVK_HOME(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+      return true;
+    case FWL_VKEY_End:
+      m_pEdit->OnVK_END(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+      return true;
+    case FWL_VKEY_Unknown:
+      if (!IsSHIFTpressed(nFlag))
+        ClearSelection();
+      else
+        CutText();
+      return true;
+    default:
+      break;
+  }
+
+  return bRet;
+}
+
+bool CPWL_EditCtrl::OnChar(uint16_t nChar, uint32_t nFlag) {
+  if (m_bMouseDown)
+    return true;
+
+  CPWL_Wnd::OnChar(nChar, nFlag);
+
+  // FILTER
+  switch (nChar) {
+    case 0x0A:
+    case 0x1B:
+      return false;
+    default:
+      break;
+  }
+
+  bool bCtrl = IsCTRLpressed(nFlag);
+  bool bAlt = IsALTpressed(nFlag);
+  bool bShift = IsSHIFTpressed(nFlag);
+
+  uint16_t word = nChar;
+
+  if (bCtrl && !bAlt) {
+    switch (nChar) {
+      case 'C' - 'A' + 1:
+        CopyText();
+        return true;
+      case 'V' - 'A' + 1:
+        PasteText();
+        return true;
+      case 'X' - 'A' + 1:
+        CutText();
+        return true;
+      case 'A' - 'A' + 1:
+        SelectAll();
+        return true;
+      case 'Z' - 'A' + 1:
+        if (bShift)
+          Redo();
+        else
+          Undo();
+        return true;
+      default:
+        if (nChar < 32)
+          return false;
+    }
+  }
+
+  if (IsReadOnly())
+    return true;
+
+  if (m_pEdit->IsSelected() && word == FWL_VKEY_Back)
+    word = FWL_VKEY_Unknown;
+
+  ClearSelection();
+
+  switch (word) {
+    case FWL_VKEY_Back:
+      Backspace();
+      break;
+    case FWL_VKEY_Return:
+      InsertReturn();
+      break;
+    case FWL_VKEY_Unknown:
+      break;
+    default:
+      InsertWord(word, GetCharSet());
+      break;
+  }
+
+  return true;
+}
+
+bool CPWL_EditCtrl::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
+  CPWL_Wnd::OnLButtonDown(point, nFlag);
+
+  if (ClientHitTest(point)) {
+    if (m_bMouseDown && !InvalidateRect(nullptr))
+      return true;
+
+    m_bMouseDown = true;
+    SetCapture();
+
+    m_pEdit->OnMouseDown(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+  }
+
+  return true;
+}
+
+bool CPWL_EditCtrl::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
+  CPWL_Wnd::OnLButtonUp(point, nFlag);
+
+  if (m_bMouseDown) {
+    // can receive keybord message
+    if (ClientHitTest(point) && !IsFocused())
+      SetFocus();
+
+    ReleaseCapture();
+    m_bMouseDown = false;
+  }
+
+  return true;
+}
+
+bool CPWL_EditCtrl::OnMouseMove(const CFX_PointF& point, uint32_t nFlag) {
+  CPWL_Wnd::OnMouseMove(point, nFlag);
+
+  if (m_bMouseDown)
+    m_pEdit->OnMouseMove(point, false, false);
+
+  return true;
+}
+
+void CPWL_EditCtrl::SetEditCaret(bool bVisible) {
+  CFX_PointF ptHead;
+  CFX_PointF ptFoot;
+  if (bVisible)
+    GetCaretInfo(&ptHead, &ptFoot);
+
+  SetCaret(bVisible, ptHead, ptFoot);
+  // Note, |this| may no longer be viable at this point. If more work needs to
+  // be done, check the return value of SetCaret().
+}
+
+void CPWL_EditCtrl::GetCaretInfo(CFX_PointF* ptHead, CFX_PointF* ptFoot) const {
+  CPWL_EditImpl_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;
+  } 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;
+  }
+}
+
+bool CPWL_EditCtrl::SetCaret(bool bVisible,
+                             const CFX_PointF& ptHead,
+                             const CFX_PointF& ptFoot) {
+  if (!m_pEditCaret)
+    return true;
+
+  if (!IsFocused() || m_pEdit->IsSelected())
+    bVisible = false;
+
+  ObservedPtr thisObserved(this);
+  m_pEditCaret->SetCaret(bVisible, ptHead, ptFoot);
+  if (!thisObserved)
+    return false;
+
+  return true;
+}
+
+WideString CPWL_EditCtrl::GetText() const {
+  return m_pEdit->GetText();
+}
+
+void CPWL_EditCtrl::SetSelection(int32_t nStartChar, int32_t nEndChar) {
+  m_pEdit->SetSelection(nStartChar, nEndChar);
+}
+
+void CPWL_EditCtrl::GetSelection(int32_t& nStartChar, int32_t& nEndChar) const {
+  m_pEdit->GetSelection(nStartChar, nEndChar);
+}
+
+void CPWL_EditCtrl::ClearSelection() {
+  if (!IsReadOnly())
+    m_pEdit->ClearSelection();
+}
+
+void CPWL_EditCtrl::SelectAll() {
+  m_pEdit->SelectAll();
+}
+
+void CPWL_EditCtrl::SetScrollPos(const CFX_PointF& point) {
+  m_pEdit->SetScrollPos(point);
+}
+
+CFX_PointF CPWL_EditCtrl::GetScrollPos() const {
+  return m_pEdit->GetScrollPos();
+}
+
+void CPWL_EditCtrl::CopyText() {}
+
+void CPWL_EditCtrl::PasteText() {}
+
+void CPWL_EditCtrl::CutText() {}
+
+void CPWL_EditCtrl::InsertWord(uint16_t word, int32_t nCharset) {
+  if (!IsReadOnly())
+    m_pEdit->InsertWord(word, nCharset);
+}
+
+void CPWL_EditCtrl::InsertReturn() {
+  if (!IsReadOnly())
+    m_pEdit->InsertReturn();
+}
+
+void CPWL_EditCtrl::Delete() {
+  if (!IsReadOnly())
+    m_pEdit->Delete();
+}
+
+void CPWL_EditCtrl::Backspace() {
+  if (!IsReadOnly())
+    m_pEdit->Backspace();
+}
+
+bool CPWL_EditCtrl::CanUndo() const {
+  return !IsReadOnly() && m_pEdit->CanUndo();
+}
+
+bool CPWL_EditCtrl::CanRedo() const {
+  return !IsReadOnly() && m_pEdit->CanRedo();
+}
+
+void CPWL_EditCtrl::Redo() {
+  if (CanRedo())
+    m_pEdit->Redo();
+}
+
+void CPWL_EditCtrl::Undo() {
+  if (CanUndo())
+    m_pEdit->Undo();
+}
+
+int32_t CPWL_EditCtrl::GetCharSet() const {
+  return m_nCharSet < 0 ? FX_CHARSET_Default : m_nCharSet;
+}
+
+void CPWL_EditCtrl::SetReadyToInput() {
+  if (m_bMouseDown) {
+    ReleaseCapture();
+    m_bMouseDown = false;
+  }
+}
diff --git a/fpdfsdk/pwl/cpwl_edit_ctrl.h b/fpdfsdk/pwl/cpwl_edit_ctrl.h
new file mode 100644
index 0000000..31140e3
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_edit_ctrl.h
@@ -0,0 +1,96 @@
+// 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 FPDFSDK_PWL_CPWL_EDIT_CTRL_H_
+#define FPDFSDK_PWL_CPWL_EDIT_CTRL_H_
+
+#include <memory>
+
+#include "core/fxcrt/fx_string.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
+
+class CPWL_EditImpl;
+class CPWL_Caret;
+struct CPVT_WordPlace;
+
+enum PWL_EDIT_ALIGNFORMAT_H { PEAH_LEFT = 0, PEAH_MIDDLE, PEAH_RIGHT };
+
+enum PWL_EDIT_ALIGNFORMAT_V { PEAV_TOP = 0, PEAV_CENTER, PEAV_BOTTOM };
+
+class CPWL_EditCtrl : public CPWL_Wnd {
+ public:
+  CPWL_EditCtrl();
+  ~CPWL_EditCtrl() override;
+
+  WideString GetText() const;
+  void SetSelection(int32_t nStartChar, int32_t nEndChar);
+  void GetSelection(int32_t& nStartChar, int32_t& nEndChar) const;
+  void ClearSelection();
+  void SelectAll();
+
+  CFX_PointF GetScrollPos() const;
+  void SetScrollPos(const CFX_PointF& point);
+
+  void SetCharSet(uint8_t nCharSet) { m_nCharSet = nCharSet; }
+  int32_t GetCharSet() const;
+
+  bool CanUndo() const;
+  bool CanRedo() const;
+  void Redo();
+  void Undo();
+
+  void SetReadyToInput();
+
+  // CPWL_Wnd:
+  void OnCreate(CreateParams* pParamsToAdjust) override;
+  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_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 SetScrollInfo(const PWL_SCROLL_INFO& info) override;
+  void SetScrollPosition(float pos) override;
+  void ScrollWindowVertically(float pos) override;
+  void CreateChildWnd(const CreateParams& cp) override;
+  bool RePosChildWnd() override;
+  void SetFontSize(float fFontSize) override;
+  float GetFontSize() const override;
+  void SetCursor() override;
+  WideString GetSelectedText() override;
+  void ReplaceSelection(const WideString& text) override;
+
+  bool SetCaret(bool bVisible,
+                const CFX_PointF& ptHead,
+                const CFX_PointF& ptFoot);
+
+ protected:
+  void CopyText();
+  void PasteText();
+  void CutText();
+  void InsertWord(uint16_t word, int32_t nCharset);
+  void InsertReturn();
+
+  bool IsWndHorV();
+
+  void Delete();
+  void Backspace();
+
+  void GetCaretInfo(CFX_PointF* ptHead, CFX_PointF* ptFoot) const;
+
+  void SetEditCaret(bool bVisible);
+
+  std::unique_ptr<CPWL_EditImpl> m_pEdit;
+  CPWL_Caret* m_pEditCaret;
+  bool m_bMouseDown;
+
+ private:
+  void CreateEditCaret(const CreateParams& cp);
+
+  int32_t m_nCharSet;
+};
+
+#endif  // FPDFSDK_PWL_CPWL_EDIT_CTRL_H_
diff --git a/fpdfsdk/pwl/cpwl_edit_embeddertest.cpp b/fpdfsdk/pwl/cpwl_edit_embeddertest.cpp
new file mode 100644
index 0000000..b3f0d5d
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_edit_embeddertest.cpp
@@ -0,0 +1,421 @@
+// 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 "fpdfsdk/cba_annotiterator.h"
+#include "fpdfsdk/cpdfsdk_annot.h"
+#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
+#include "fpdfsdk/formfiller/cffl_formfiller.h"
+#include "fpdfsdk/formfiller/cffl_interactiveformfiller.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
+#include "testing/embedder_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class CPWLEditEmbeddertest : public EmbedderTest {
+ protected:
+  void SetUp() override {
+    EmbedderTest::SetUp();
+    CreateAndInitializeFormPDF();
+  }
+
+  void TearDown() override {
+    UnloadPage(GetPage());
+    EmbedderTest::TearDown();
+  }
+
+  void CreateAndInitializeFormPDF() {
+    EXPECT_TRUE(OpenDocument("text_form_multiple.pdf"));
+    m_page = LoadPage(0);
+    ASSERT_TRUE(m_page);
+
+    m_pFormFillEnv = static_cast<CPDFSDK_FormFillEnvironment*>(form_handle());
+    CBA_AnnotIterator iter(m_pFormFillEnv->GetPageView(0),
+                           CPDF_Annot::Subtype::WIDGET);
+    // Normal text field.
+    m_pAnnot = iter.GetFirstAnnot();
+    ASSERT_TRUE(m_pAnnot);
+    ASSERT_EQ(CPDF_Annot::Subtype::WIDGET, m_pAnnot->GetAnnotSubtype());
+
+    // Read-only text field.
+    CPDFSDK_Annot* pAnnotReadOnly = iter.GetNextAnnot(m_pAnnot);
+
+    // Pre-filled text field with char limit of 10.
+    m_pAnnotCharLimit = iter.GetNextAnnot(pAnnotReadOnly);
+    ASSERT_TRUE(m_pAnnotCharLimit);
+    ASSERT_EQ(CPDF_Annot::Subtype::WIDGET,
+              m_pAnnotCharLimit->GetAnnotSubtype());
+    CPDFSDK_Annot* pLastAnnot = iter.GetLastAnnot();
+    ASSERT_EQ(m_pAnnotCharLimit, pLastAnnot);
+  }
+
+  void FormFillerAndWindowSetup(CPDFSDK_Annot* pAnnotTextField) {
+    CFFL_InteractiveFormFiller* pInteractiveFormFiller =
+        m_pFormFillEnv->GetInteractiveFormFiller();
+    {
+      CPDFSDK_Annot::ObservedPtr pObserved(pAnnotTextField);
+      EXPECT_TRUE(pInteractiveFormFiller->OnSetFocus(&pObserved, 0));
+    }
+
+    m_pFormFiller =
+        pInteractiveFormFiller->GetFormFiller(pAnnotTextField, false);
+    ASSERT_TRUE(m_pFormFiller);
+
+    CPWL_Wnd* pWindow =
+        m_pFormFiller->GetPDFWindow(m_pFormFillEnv->GetPageView(0), false);
+    ASSERT_TRUE(pWindow);
+    ASSERT_EQ(PWL_CLASSNAME_EDIT, pWindow->GetClassName());
+
+    m_pEdit = static_cast<CPWL_Edit*>(pWindow);
+  }
+
+  void TypeTextIntoTextField(int num_chars) {
+    // Type text starting with 'A' to as many chars as specified by |num_chars|.
+    for (int i = 0; i < num_chars; ++i) {
+      EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), i + 'A', 0));
+    }
+  }
+
+  FPDF_PAGE GetPage() { return m_page; }
+  CPWL_Edit* GetCPWLEdit() { return m_pEdit; }
+  CFFL_FormFiller* GetCFFLFormFiller() { return m_pFormFiller; }
+  CPDFSDK_Annot* GetCPDFSDKAnnot() { return m_pAnnot; }
+  CPDFSDK_Annot* GetCPDFSDKAnnotCharLimit() { return m_pAnnotCharLimit; }
+
+ private:
+  FPDF_PAGE m_page;
+  CPWL_Edit* m_pEdit;
+  CFFL_FormFiller* m_pFormFiller;
+  CPDFSDK_Annot* m_pAnnot;
+  CPDFSDK_Annot* m_pAnnotCharLimit;
+  CPDFSDK_FormFillEnvironment* m_pFormFillEnv;
+};
+
+TEST_F(CPWLEditEmbeddertest, TypeText) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  EXPECT_TRUE(GetCPWLEdit()->GetText().IsEmpty());
+  EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), 'a', 0));
+  EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), 'b', 0));
+  EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), 'c', 0));
+
+  EXPECT_STREQ(L"abc", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, GetSelectedTextEmptyAndBasic) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  // Attempt to set selection before text has been typed to test that
+  // selection is identified as empty.
+  //
+  // Select from character index [0, 3) within form text field.
+  GetCPWLEdit()->SetSelection(0, 3);
+  EXPECT_TRUE(GetCPWLEdit()->GetSelectedText().IsEmpty());
+
+  EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), 'a', 0));
+  EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), 'b', 0));
+  EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), 'c', 0));
+  GetCPWLEdit()->SetSelection(0, 2);
+
+  EXPECT_STREQ(L"ab", GetCPWLEdit()->GetSelectedText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, GetSelectedTextFragments) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(50);
+
+  GetCPWLEdit()->SetSelection(0, 0);
+  EXPECT_TRUE(GetCPWLEdit()->GetSelectedText().IsEmpty());
+
+  GetCPWLEdit()->SetSelection(0, 1);
+  EXPECT_STREQ(L"A", GetCPWLEdit()->GetSelectedText().c_str());
+
+  GetCPWLEdit()->SetSelection(0, -1);
+  EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLEdit()->GetSelectedText().c_str());
+
+  GetCPWLEdit()->SetSelection(-8, -1);
+  EXPECT_TRUE(GetCPWLEdit()->GetSelectedText().IsEmpty());
+
+  GetCPWLEdit()->SetSelection(23, 12);
+  EXPECT_STREQ(L"MNOPQRSTUVW", GetCPWLEdit()->GetSelectedText().c_str());
+
+  GetCPWLEdit()->SetSelection(12, 23);
+  EXPECT_STREQ(L"MNOPQRSTUVW", GetCPWLEdit()->GetSelectedText().c_str());
+
+  GetCPWLEdit()->SetSelection(49, 50);
+  EXPECT_STREQ(L"r", GetCPWLEdit()->GetSelectedText().c_str());
+
+  GetCPWLEdit()->SetSelection(49, 55);
+  EXPECT_STREQ(L"r", GetCPWLEdit()->GetSelectedText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, DeleteEntireTextSelection) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(50);
+
+  GetCPWLEdit()->SetSelection(0, -1);
+  EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLEdit()->GetSelectedText().c_str());
+
+  GetCPWLEdit()->ReplaceSelection(L"");
+  EXPECT_TRUE(GetCPWLEdit()->GetText().IsEmpty());
+}
+
+TEST_F(CPWLEditEmbeddertest, DeleteTextSelectionMiddle) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(50);
+
+  GetCPWLEdit()->SetSelection(12, 23);
+  EXPECT_STREQ(L"MNOPQRSTUVW", GetCPWLEdit()->GetSelectedText().c_str());
+
+  GetCPWLEdit()->ReplaceSelection(L"");
+  EXPECT_STREQ(L"ABCDEFGHIJKLXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, DeleteTextSelectionLeft) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(50);
+
+  GetCPWLEdit()->SetSelection(0, 5);
+  EXPECT_STREQ(L"ABCDE", GetCPWLEdit()->GetSelectedText().c_str());
+
+  GetCPWLEdit()->ReplaceSelection(L"");
+  EXPECT_STREQ(L"FGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, DeleteTextSelectionRight) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(50);
+
+  GetCPWLEdit()->SetSelection(45, 50);
+  EXPECT_STREQ(L"nopqr", GetCPWLEdit()->GetSelectedText().c_str());
+
+  GetCPWLEdit()->ReplaceSelection(L"");
+  EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklm",
+               GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, DeleteEmptyTextSelection) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(50);
+
+  GetCPWLEdit()->ReplaceSelection(L"");
+  EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInEmptyTextField) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  GetCPWLEdit()->ReplaceSelection(L"Hello");
+  EXPECT_STREQ(L"Hello", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInPopulatedTextFieldLeft) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(10);
+
+  // Move cursor to beginning of text field.
+  EXPECT_TRUE(
+      GetCFFLFormFiller()->OnKeyDown(GetCPDFSDKAnnot(), FWL_VKEY_Home, 0));
+
+  GetCPWLEdit()->ReplaceSelection(L"Hello");
+  EXPECT_STREQ(L"HelloABCDEFGHIJ", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInPopulatedTextFieldMiddle) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(10);
+
+  // Move cursor to middle of text field.
+  for (int i = 0; i < 5; ++i) {
+    EXPECT_TRUE(
+        GetCFFLFormFiller()->OnKeyDown(GetCPDFSDKAnnot(), FWL_VKEY_Left, 0));
+  }
+
+  GetCPWLEdit()->ReplaceSelection(L"Hello");
+  EXPECT_STREQ(L"ABCDEHelloFGHIJ", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInPopulatedTextFieldRight) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(10);
+
+  GetCPWLEdit()->ReplaceSelection(L"Hello");
+  EXPECT_STREQ(L"ABCDEFGHIJHello", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedTextFieldWhole) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(10);
+
+  GetCPWLEdit()->SetSelection(0, -1);
+  EXPECT_STREQ(L"ABCDEFGHIJ", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(L"Hello");
+  EXPECT_STREQ(L"Hello", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedTextFieldLeft) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(10);
+
+  GetCPWLEdit()->SetSelection(0, 5);
+  EXPECT_STREQ(L"ABCDE", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(L"Hello");
+  EXPECT_STREQ(L"HelloFGHIJ", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedTextFieldMiddle) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(10);
+
+  GetCPWLEdit()->SetSelection(2, 7);
+  EXPECT_STREQ(L"CDEFG", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(L"Hello");
+  EXPECT_STREQ(L"ABHelloHIJ", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedTextFieldRight) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(10);
+
+  GetCPWLEdit()->SetSelection(5, 10);
+  EXPECT_STREQ(L"FGHIJ", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(L"Hello");
+  EXPECT_STREQ(L"ABCDEHello", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInEmptyCharLimitTextFieldOverflow) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  GetCPWLEdit()->SetSelection(0, -1);
+  EXPECT_STREQ(L"Elephant", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(L"");
+
+  GetCPWLEdit()->ReplaceSelection(L"Hippopotamus");
+  EXPECT_STREQ(L"Hippopotam", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInEmptyCharLimitTextFieldFit) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  GetCPWLEdit()->SetSelection(0, -1);
+  EXPECT_STREQ(L"Elephant", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(L"");
+
+  GetCPWLEdit()->ReplaceSelection(L"Zebra");
+  EXPECT_STREQ(L"Zebra", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInPopulatedCharLimitTextFieldLeft) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  GetCPWLEdit()->ReplaceSelection(L"Hippopotamus");
+  EXPECT_STREQ(L"HiElephant", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInPopulatedCharLimitTextFieldMiddle) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  // Move cursor to middle of text field.
+  for (int i = 0; i < 5; ++i) {
+    EXPECT_TRUE(GetCFFLFormFiller()->OnKeyDown(GetCPDFSDKAnnotCharLimit(),
+                                               FWL_VKEY_Right, 0));
+  }
+
+  GetCPWLEdit()->ReplaceSelection(L"Hippopotamus");
+  EXPECT_STREQ(L"ElephHiant", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInPopulatedCharLimitTextFieldRight) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  // Move cursor to end of text field.
+  EXPECT_TRUE(GetCFFLFormFiller()->OnKeyDown(GetCPDFSDKAnnotCharLimit(),
+                                             FWL_VKEY_End, 0));
+
+  GetCPWLEdit()->ReplaceSelection(L"Hippopotamus");
+  EXPECT_STREQ(L"ElephantHi", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedCharLimitTextFieldWhole) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  GetCPWLEdit()->SetSelection(0, -1);
+  EXPECT_STREQ(L"Elephant", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(L"Hippopotamus");
+  EXPECT_STREQ(L"Hippopotam", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedCharLimitTextFieldLeft) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  GetCPWLEdit()->SetSelection(0, 4);
+  EXPECT_STREQ(L"Elep", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(L"Hippopotamus");
+  EXPECT_STREQ(L"Hippophant", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedCharLimitTextFieldMiddle) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  GetCPWLEdit()->SetSelection(2, 6);
+  EXPECT_STREQ(L"epha", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(L"Hippopotamus");
+  EXPECT_STREQ(L"ElHippopnt", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedCharLimitTextFieldRight) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  GetCPWLEdit()->SetSelection(4, 8);
+  EXPECT_STREQ(L"hant", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(L"Hippopotamus");
+  EXPECT_STREQ(L"ElepHippop", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, SetTextWithEndCarriageFeed) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  GetCPWLEdit()->SetText(L"Foo\r");
+  EXPECT_STREQ(L"Foo", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, SetTextWithEndNewline) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  GetCPWLEdit()->SetText(L"Foo\n");
+  EXPECT_STREQ(L"Foo", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, SetTextWithEndCarriageFeedAndNewLine) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  GetCPWLEdit()->SetText(L"Foo\r\n");
+  EXPECT_STREQ(L"Foo", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, SetTextWithEndNewLineAndCarriageFeed) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  GetCPWLEdit()->SetText(L"Foo\n\r");
+  EXPECT_STREQ(L"Foo", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, SetTextWithBodyCarriageFeed) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  GetCPWLEdit()->SetText(L"Foo\rBar");
+  EXPECT_STREQ(L"FooBar", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, SetTextWithBodyNewline) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  GetCPWLEdit()->SetText(L"Foo\nBar");
+  EXPECT_STREQ(L"FooBar", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, SetTextWithBodyCarriageFeedAndNewLine) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  GetCPWLEdit()->SetText(L"Foo\r\nBar");
+  EXPECT_STREQ(L"FooBar", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, SetTextWithBodyNewLineAndCarriageFeed) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  GetCPWLEdit()->SetText(L"Foo\n\rBar");
+  EXPECT_STREQ(L"FooBar", GetCPWLEdit()->GetText().c_str());
+}
diff --git a/fpdfsdk/pwl/cpwl_edit_impl.cpp b/fpdfsdk/pwl/cpwl_edit_impl.cpp
new file mode 100644
index 0000000..a2a7b1d
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_edit_impl.cpp
@@ -0,0 +1,1899 @@
+// 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/pwl/cpwl_edit_impl.h"
+
+#include <algorithm>
+#include <memory>
+#include <sstream>
+#include <utility>
+
+#include "core/fpdfapi/font/cpdf_font.h"
+#include "core/fpdfapi/page/cpdf_pageobject.h"
+#include "core/fpdfapi/page/cpdf_pageobjectholder.h"
+#include "core/fpdfapi/page/cpdf_pathobject.h"
+#include "core/fpdfapi/page/cpdf_textobject.h"
+#include "core/fpdfapi/parser/fpdf_parser_decode.h"
+#include "core/fpdfapi/render/cpdf_renderoptions.h"
+#include "core/fpdfapi/render/cpdf_textrenderer.h"
+#include "core/fpdfdoc/cpvt_word.h"
+#include "core/fpdfdoc/ipvt_fontmap.h"
+#include "core/fxcrt/autorestorer.h"
+#include "core/fxcrt/fx_codepage.h"
+#include "core/fxge/cfx_graphstatedata.h"
+#include "core/fxge/cfx_pathdata.h"
+#include "core/fxge/cfx_renderdevice.h"
+#include "fpdfsdk/cfx_systemhandler.h"
+#include "fpdfsdk/pwl/cpwl_edit.h"
+#include "fpdfsdk/pwl/cpwl_edit_ctrl.h"
+#include "fpdfsdk/pwl/cpwl_scroll_bar.h"
+#include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
+
+namespace {
+
+const int kEditUndoMaxItems = 10000;
+
+void DrawTextString(CFX_RenderDevice* pDevice,
+                    const CFX_PointF& pt,
+                    CPDF_Font* pFont,
+                    float fFontSize,
+                    const CFX_Matrix& mtUser2Device,
+                    const ByteString& str,
+                    FX_ARGB crTextFill,
+                    int32_t nHorzScale) {
+  if (!pFont)
+    return;
+
+  CFX_PointF pos = mtUser2Device.Transform(pt);
+  CFX_Matrix mt;
+  if (nHorzScale == 100) {
+    mt = mtUser2Device;
+  } else {
+    mt = CFX_Matrix(nHorzScale / 100.0f, 0, 0, 1, 0, 0);
+    mt.Concat(mtUser2Device);
+  }
+
+  CPDF_RenderOptions ro;
+  ro.SetFlags(RENDER_CLEARTYPE);
+
+  ro.SetColorMode(CPDF_RenderOptions::kNormal);
+  CPDF_TextRenderer::DrawTextString(pDevice, pos.x, pos.y, pFont, fFontSize,
+                                    &mt, str, crTextFill, nullptr, &ro);
+}
+
+}  // namespace
+
+CPWL_EditImpl_Iterator::CPWL_EditImpl_Iterator(
+    CPWL_EditImpl* pEdit,
+    CPDF_VariableText::Iterator* pVTIterator)
+    : m_pEdit(pEdit), m_pVTIterator(pVTIterator) {}
+
+CPWL_EditImpl_Iterator::~CPWL_EditImpl_Iterator() {}
+
+bool CPWL_EditImpl_Iterator::NextWord() {
+  return m_pVTIterator->NextWord();
+}
+
+bool CPWL_EditImpl_Iterator::PrevWord() {
+  return m_pVTIterator->PrevWord();
+}
+
+bool CPWL_EditImpl_Iterator::GetWord(CPVT_Word& word) const {
+  ASSERT(m_pEdit);
+
+  if (m_pVTIterator->GetWord(word)) {
+    word.ptWord = m_pEdit->VTToEdit(word.ptWord);
+    return true;
+  }
+  return false;
+}
+
+bool CPWL_EditImpl_Iterator::GetLine(CPVT_Line& line) const {
+  ASSERT(m_pEdit);
+
+  if (m_pVTIterator->GetLine(line)) {
+    line.ptLine = m_pEdit->VTToEdit(line.ptLine);
+    return true;
+  }
+  return false;
+}
+
+void CPWL_EditImpl_Iterator::SetAt(int32_t nWordIndex) {
+  m_pVTIterator->SetAt(nWordIndex);
+}
+
+void CPWL_EditImpl_Iterator::SetAt(const CPVT_WordPlace& place) {
+  m_pVTIterator->SetAt(place);
+}
+
+const CPVT_WordPlace& CPWL_EditImpl_Iterator::GetAt() const {
+  return m_pVTIterator->GetWordPlace();
+}
+
+CPWL_EditImpl_Provider::CPWL_EditImpl_Provider(IPVT_FontMap* pFontMap)
+    : CPDF_VariableText::Provider(pFontMap), m_pFontMap(pFontMap) {
+  ASSERT(m_pFontMap);
+}
+
+CPWL_EditImpl_Provider::~CPWL_EditImpl_Provider() {}
+
+IPVT_FontMap* CPWL_EditImpl_Provider::GetFontMap() const {
+  return m_pFontMap;
+}
+
+int32_t CPWL_EditImpl_Provider::GetCharWidth(int32_t nFontIndex,
+                                             uint16_t word) {
+  if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) {
+    uint32_t charcode = word;
+
+    if (pPDFFont->IsUnicodeCompatible())
+      charcode = pPDFFont->CharCodeFromUnicode(word);
+    else
+      charcode = m_pFontMap->CharCodeFromUnicode(nFontIndex, word);
+
+    if (charcode != CPDF_Font::kInvalidCharCode)
+      return pPDFFont->GetCharWidthF(charcode);
+  }
+
+  return 0;
+}
+
+int32_t CPWL_EditImpl_Provider::GetTypeAscent(int32_t nFontIndex) {
+  if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex))
+    return pPDFFont->GetTypeAscent();
+
+  return 0;
+}
+
+int32_t CPWL_EditImpl_Provider::GetTypeDescent(int32_t nFontIndex) {
+  if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex))
+    return pPDFFont->GetTypeDescent();
+
+  return 0;
+}
+
+int32_t CPWL_EditImpl_Provider::GetWordFontIndex(uint16_t word,
+                                                 int32_t charset,
+                                                 int32_t nFontIndex) {
+  return m_pFontMap->GetWordFontIndex(word, charset, nFontIndex);
+}
+
+int32_t CPWL_EditImpl_Provider::GetDefaultFontIndex() {
+  return 0;
+}
+
+bool CPWL_EditImpl_Provider::IsLatinWord(uint16_t word) {
+  return FX_EDIT_ISLATINWORD(word);
+}
+
+CPWL_EditImpl_Refresh::CPWL_EditImpl_Refresh() {}
+
+CPWL_EditImpl_Refresh::~CPWL_EditImpl_Refresh() {}
+
+void CPWL_EditImpl_Refresh::BeginRefresh() {
+  m_RefreshRects.clear();
+  m_OldLineRects = std::move(m_NewLineRects);
+}
+
+void CPWL_EditImpl_Refresh::Push(const CPVT_WordRange& linerange,
+                                 const CFX_FloatRect& rect) {
+  m_NewLineRects.emplace_back(CPWL_EditImpl_LineRect(linerange, rect));
+}
+
+void CPWL_EditImpl_Refresh::NoAnalyse() {
+  for (const auto& lineRect : m_OldLineRects)
+    Add(lineRect.m_rcLine);
+
+  for (const auto& lineRect : m_NewLineRects)
+    Add(lineRect.m_rcLine);
+}
+
+std::vector<CFX_FloatRect>* CPWL_EditImpl_Refresh::GetRefreshRects() {
+  return &m_RefreshRects;
+}
+
+void CPWL_EditImpl_Refresh::EndRefresh() {
+  m_RefreshRects.clear();
+}
+
+void CPWL_EditImpl_Refresh::Add(const CFX_FloatRect& new_rect) {
+  // Check for overlapped area.
+  for (const auto& rect : m_RefreshRects) {
+    if (rect.Contains(new_rect))
+      return;
+  }
+  m_RefreshRects.emplace_back(CFX_FloatRect(new_rect));
+}
+
+CPWL_EditImpl_Undo::CPWL_EditImpl_Undo()
+    : m_nCurUndoPos(0), m_bWorking(false) {}
+
+CPWL_EditImpl_Undo::~CPWL_EditImpl_Undo() {}
+
+bool CPWL_EditImpl_Undo::CanUndo() const {
+  return m_nCurUndoPos > 0;
+}
+
+void CPWL_EditImpl_Undo::Undo() {
+  m_bWorking = true;
+  if (CanUndo()) {
+    m_UndoItemStack[m_nCurUndoPos - 1]->Undo();
+    m_nCurUndoPos--;
+  }
+  m_bWorking = false;
+}
+
+bool CPWL_EditImpl_Undo::CanRedo() const {
+  return m_nCurUndoPos < m_UndoItemStack.size();
+}
+
+void CPWL_EditImpl_Undo::Redo() {
+  m_bWorking = true;
+  if (CanRedo()) {
+    m_UndoItemStack[m_nCurUndoPos]->Redo();
+    m_nCurUndoPos++;
+  }
+  m_bWorking = false;
+}
+
+void CPWL_EditImpl_Undo::AddItem(std::unique_ptr<IFX_Edit_UndoItem> pItem) {
+  ASSERT(!m_bWorking);
+  ASSERT(pItem);
+  if (CanRedo())
+    RemoveTails();
+
+  if (m_UndoItemStack.size() >= kEditUndoMaxItems)
+    RemoveHeads();
+
+  m_UndoItemStack.push_back(std::move(pItem));
+  m_nCurUndoPos = m_UndoItemStack.size();
+}
+
+void CPWL_EditImpl_Undo::RemoveHeads() {
+  ASSERT(m_UndoItemStack.size() > 1);
+  m_UndoItemStack.pop_front();
+}
+
+void CPWL_EditImpl_Undo::RemoveTails() {
+  while (CanRedo())
+    m_UndoItemStack.pop_back();
+}
+
+CFXEU_InsertWord::CFXEU_InsertWord(CPWL_EditImpl* pEdit,
+                                   const CPVT_WordPlace& wpOldPlace,
+                                   const CPVT_WordPlace& wpNewPlace,
+                                   uint16_t word,
+                                   int32_t charset)
+    : m_pEdit(pEdit),
+      m_wpOld(wpOldPlace),
+      m_wpNew(wpNewPlace),
+      m_Word(word),
+      m_nCharset(charset) {
+  ASSERT(m_pEdit);
+}
+
+CFXEU_InsertWord::~CFXEU_InsertWord() {}
+
+void CFXEU_InsertWord::Redo() {
+  m_pEdit->SelectNone();
+  m_pEdit->SetCaret(m_wpOld);
+  m_pEdit->InsertWord(m_Word, m_nCharset, false, true);
+}
+
+void CFXEU_InsertWord::Undo() {
+  m_pEdit->SelectNone();
+  m_pEdit->SetCaret(m_wpNew);
+  m_pEdit->Backspace(false, true);
+}
+
+CFXEU_InsertReturn::CFXEU_InsertReturn(CPWL_EditImpl* pEdit,
+                                       const CPVT_WordPlace& wpOldPlace,
+                                       const CPVT_WordPlace& wpNewPlace)
+    : m_pEdit(pEdit), m_wpOld(wpOldPlace), m_wpNew(wpNewPlace) {
+  ASSERT(m_pEdit);
+}
+
+CFXEU_InsertReturn::~CFXEU_InsertReturn() {}
+
+void CFXEU_InsertReturn::Redo() {
+  m_pEdit->SelectNone();
+  m_pEdit->SetCaret(m_wpOld);
+  m_pEdit->InsertReturn(false, true);
+}
+
+void CFXEU_InsertReturn::Undo() {
+  m_pEdit->SelectNone();
+  m_pEdit->SetCaret(m_wpNew);
+  m_pEdit->Backspace(false, true);
+}
+
+CFXEU_Backspace::CFXEU_Backspace(CPWL_EditImpl* pEdit,
+                                 const CPVT_WordPlace& wpOldPlace,
+                                 const CPVT_WordPlace& wpNewPlace,
+                                 uint16_t word,
+                                 int32_t charset)
+    : m_pEdit(pEdit),
+      m_wpOld(wpOldPlace),
+      m_wpNew(wpNewPlace),
+      m_Word(word),
+      m_nCharset(charset) {
+  ASSERT(m_pEdit);
+}
+
+CFXEU_Backspace::~CFXEU_Backspace() {}
+
+void CFXEU_Backspace::Redo() {
+  m_pEdit->SelectNone();
+  m_pEdit->SetCaret(m_wpOld);
+  m_pEdit->Backspace(false, true);
+}
+
+void CFXEU_Backspace::Undo() {
+  m_pEdit->SelectNone();
+  m_pEdit->SetCaret(m_wpNew);
+  if (m_wpNew.nSecIndex != m_wpOld.nSecIndex)
+    m_pEdit->InsertReturn(false, true);
+  else
+    m_pEdit->InsertWord(m_Word, m_nCharset, false, true);
+}
+
+CFXEU_Delete::CFXEU_Delete(CPWL_EditImpl* pEdit,
+                           const CPVT_WordPlace& wpOldPlace,
+                           const CPVT_WordPlace& wpNewPlace,
+                           uint16_t word,
+                           int32_t charset,
+                           bool bSecEnd)
+    : m_pEdit(pEdit),
+      m_wpOld(wpOldPlace),
+      m_wpNew(wpNewPlace),
+      m_Word(word),
+      m_nCharset(charset),
+      m_bSecEnd(bSecEnd) {
+  ASSERT(m_pEdit);
+}
+
+CFXEU_Delete::~CFXEU_Delete() {}
+
+void CFXEU_Delete::Redo() {
+  m_pEdit->SelectNone();
+  m_pEdit->SetCaret(m_wpOld);
+  m_pEdit->Delete(false, true);
+}
+
+void CFXEU_Delete::Undo() {
+  m_pEdit->SelectNone();
+  m_pEdit->SetCaret(m_wpNew);
+  if (m_bSecEnd)
+    m_pEdit->InsertReturn(false, true);
+  else
+    m_pEdit->InsertWord(m_Word, m_nCharset, false, true);
+}
+
+CFXEU_Clear::CFXEU_Clear(CPWL_EditImpl* pEdit,
+                         const CPVT_WordRange& wrSel,
+                         const WideString& swText)
+    : m_pEdit(pEdit), m_wrSel(wrSel), m_swText(swText) {
+  ASSERT(m_pEdit);
+}
+
+CFXEU_Clear::~CFXEU_Clear() {}
+
+void CFXEU_Clear::Redo() {
+  m_pEdit->SelectNone();
+  m_pEdit->SetSelection(m_wrSel.BeginPos, m_wrSel.EndPos);
+  m_pEdit->Clear(false, true);
+}
+
+void CFXEU_Clear::Undo() {
+  m_pEdit->SelectNone();
+  m_pEdit->SetCaret(m_wrSel.BeginPos);
+  m_pEdit->InsertText(m_swText, FX_CHARSET_Default, false, true);
+  m_pEdit->SetSelection(m_wrSel.BeginPos, m_wrSel.EndPos);
+}
+
+CFXEU_InsertText::CFXEU_InsertText(CPWL_EditImpl* pEdit,
+                                   const CPVT_WordPlace& wpOldPlace,
+                                   const CPVT_WordPlace& wpNewPlace,
+                                   const WideString& swText,
+                                   int32_t charset)
+    : m_pEdit(pEdit),
+      m_wpOld(wpOldPlace),
+      m_wpNew(wpNewPlace),
+      m_swText(swText),
+      m_nCharset(charset) {
+  ASSERT(m_pEdit);
+}
+
+CFXEU_InsertText::~CFXEU_InsertText() {}
+
+void CFXEU_InsertText::Redo() {
+  m_pEdit->SelectNone();
+  m_pEdit->SetCaret(m_wpOld);
+  m_pEdit->InsertText(m_swText, m_nCharset, false, true);
+}
+
+void CFXEU_InsertText::Undo() {
+  m_pEdit->SelectNone();
+  m_pEdit->SetSelection(m_wpOld, m_wpNew);
+  m_pEdit->Clear(false, true);
+}
+
+// static
+void CPWL_EditImpl::DrawEdit(CFX_RenderDevice* pDevice,
+                             const CFX_Matrix& mtUser2Device,
+                             CPWL_EditImpl* pEdit,
+                             FX_COLORREF crTextFill,
+                             const CFX_FloatRect& rcClip,
+                             const CFX_PointF& ptOffset,
+                             const CPVT_WordRange* pRange,
+                             CFX_SystemHandler* pSystemHandler,
+                             CFFL_FormFiller* pFFLData) {
+  const bool bContinuous =
+      pEdit->GetCharArray() == 0 && pEdit->GetCharSpace() <= 0.0f;
+  uint16_t SubWord = pEdit->GetPasswordChar();
+  float fFontSize = pEdit->GetFontSize();
+  CPVT_WordRange wrSelect = pEdit->GetSelectWordRange();
+  int32_t nHorzScale = pEdit->GetHorzScale();
+
+  FX_COLORREF crCurFill = crTextFill;
+  FX_COLORREF crOldFill = crCurFill;
+
+  bool bSelect = false;
+  static const FX_COLORREF crWhite = ArgbEncode(255, 255, 255, 255);
+  static const FX_COLORREF crSelBK = ArgbEncode(255, 0, 51, 113);
+
+  std::ostringstream sTextBuf;
+  int32_t nFontIndex = -1;
+  CFX_PointF ptBT;
+  CFX_RenderDevice::StateRestorer restorer(pDevice);
+  if (!rcClip.IsEmpty())
+    pDevice->SetClip_Rect(mtUser2Device.TransformRect(rcClip).ToFxRect());
+
+  CPWL_EditImpl_Iterator* pIterator = pEdit->GetIterator();
+  IPVT_FontMap* pFontMap = pEdit->GetFontMap();
+  if (!pFontMap)
+    return;
+
+  if (pRange)
+    pIterator->SetAt(pRange->BeginPos);
+  else
+    pIterator->SetAt(0);
+
+  CPVT_WordPlace oldplace;
+  while (pIterator->NextWord()) {
+    CPVT_WordPlace place = pIterator->GetAt();
+    if (pRange && place > pRange->EndPos)
+      break;
+
+    if (!wrSelect.IsEmpty()) {
+      bSelect = place > wrSelect.BeginPos && place <= wrSelect.EndPos;
+      crCurFill = bSelect ? crWhite : crTextFill;
+    }
+    if (pSystemHandler && pSystemHandler->IsSelectionImplemented()) {
+      crCurFill = crTextFill;
+      crOldFill = crCurFill;
+    }
+    CPVT_Word word;
+    if (pIterator->GetWord(word)) {
+      if (bSelect) {
+        CPVT_Line line;
+        pIterator->GetLine(line);
+
+        if (pSystemHandler && pSystemHandler->IsSelectionImplemented()) {
+          CFX_FloatRect rc(word.ptWord.x, line.ptLine.y + line.fLineDescent,
+                           word.ptWord.x + word.fWidth,
+                           line.ptLine.y + line.fLineAscent);
+          rc.Intersect(rcClip);
+          pSystemHandler->OutputSelectedRect(pFFLData, rc);
+        } else {
+          CFX_PathData pathSelBK;
+          pathSelBK.AppendRect(word.ptWord.x, line.ptLine.y + line.fLineDescent,
+                               word.ptWord.x + word.fWidth,
+                               line.ptLine.y + line.fLineAscent);
+
+          pDevice->DrawPath(&pathSelBK, &mtUser2Device, nullptr, crSelBK, 0,
+                            FXFILL_WINDING);
+        }
+      }
+
+      if (bContinuous) {
+        if (place.LineCmp(oldplace) != 0 || word.nFontIndex != nFontIndex ||
+            crOldFill != crCurFill) {
+          if (sTextBuf.tellp() > 0) {
+            DrawTextString(
+                pDevice, CFX_PointF(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
+                pFontMap->GetPDFFont(nFontIndex), fFontSize, mtUser2Device,
+                ByteString(sTextBuf), crOldFill, nHorzScale);
+
+            sTextBuf.str("");
+          }
+          nFontIndex = word.nFontIndex;
+          ptBT = word.ptWord;
+          crOldFill = crCurFill;
+        }
+
+        sTextBuf << pEdit->GetPDFWordString(word.nFontIndex, word.Word,
+                                            SubWord);
+      } else {
+        DrawTextString(
+            pDevice,
+            CFX_PointF(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y),
+            pFontMap->GetPDFFont(word.nFontIndex), fFontSize, mtUser2Device,
+            pEdit->GetPDFWordString(word.nFontIndex, word.Word, SubWord),
+            crCurFill, nHorzScale);
+      }
+      oldplace = place;
+    }
+  }
+
+  if (sTextBuf.tellp() > 0) {
+    DrawTextString(pDevice,
+                   CFX_PointF(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
+                   pFontMap->GetPDFFont(nFontIndex), fFontSize, mtUser2Device,
+                   ByteString(sTextBuf), crOldFill, nHorzScale);
+  }
+}
+
+CPWL_EditImpl::CPWL_EditImpl()
+    : m_pVT(pdfium::MakeUnique<CPDF_VariableText>()),
+      m_bEnableScroll(false),
+      m_nAlignment(0),
+      m_bNotifyFlag(false),
+      m_bEnableOverflow(false),
+      m_bEnableRefresh(true),
+      m_bEnableUndo(true) {}
+
+CPWL_EditImpl::~CPWL_EditImpl() {}
+
+void CPWL_EditImpl::Initialize() {
+  m_pVT->Initialize();
+  SetCaret(m_pVT->GetBeginWordPlace());
+  SetCaretOrigin();
+}
+
+void CPWL_EditImpl::SetFontMap(IPVT_FontMap* pFontMap) {
+  m_pVTProvider = pdfium::MakeUnique<CPWL_EditImpl_Provider>(pFontMap);
+  m_pVT->SetProvider(m_pVTProvider.get());
+}
+
+void CPWL_EditImpl::SetNotify(CPWL_EditCtrl* pNotify) {
+  m_pNotify = pNotify;
+}
+
+void CPWL_EditImpl::SetOperationNotify(CPWL_Edit* pOperationNotify) {
+  m_pOperationNotify = pOperationNotify;
+}
+
+CPWL_EditImpl_Iterator* CPWL_EditImpl::GetIterator() {
+  if (!m_pIterator) {
+    m_pIterator =
+        pdfium::MakeUnique<CPWL_EditImpl_Iterator>(this, m_pVT->GetIterator());
+  }
+  return m_pIterator.get();
+}
+
+IPVT_FontMap* CPWL_EditImpl::GetFontMap() {
+  return m_pVTProvider ? m_pVTProvider->GetFontMap() : nullptr;
+}
+
+void CPWL_EditImpl::SetPlateRect(const CFX_FloatRect& rect) {
+  m_pVT->SetPlateRect(rect);
+  m_ptScrollPos = CFX_PointF(rect.left, rect.top);
+  Paint();
+}
+
+void CPWL_EditImpl::SetAlignmentH(int32_t nFormat, bool bPaint) {
+  m_pVT->SetAlignment(nFormat);
+  if (bPaint)
+    Paint();
+}
+
+void CPWL_EditImpl::SetAlignmentV(int32_t nFormat, bool bPaint) {
+  m_nAlignment = nFormat;
+  if (bPaint)
+    Paint();
+}
+
+void CPWL_EditImpl::SetPasswordChar(uint16_t wSubWord, bool bPaint) {
+  m_pVT->SetPasswordChar(wSubWord);
+  if (bPaint)
+    Paint();
+}
+
+void CPWL_EditImpl::SetLimitChar(int32_t nLimitChar) {
+  m_pVT->SetLimitChar(nLimitChar);
+  Paint();
+}
+
+void CPWL_EditImpl::SetCharArray(int32_t nCharArray) {
+  m_pVT->SetCharArray(nCharArray);
+  Paint();
+}
+
+void CPWL_EditImpl::SetCharSpace(float fCharSpace) {
+  m_pVT->SetCharSpace(fCharSpace);
+  Paint();
+}
+
+void CPWL_EditImpl::SetMultiLine(bool bMultiLine, bool bPaint) {
+  m_pVT->SetMultiLine(bMultiLine);
+  if (bPaint)
+    Paint();
+}
+
+void CPWL_EditImpl::SetAutoReturn(bool bAuto, bool bPaint) {
+  m_pVT->SetAutoReturn(bAuto);
+  if (bPaint)
+    Paint();
+}
+
+void CPWL_EditImpl::SetAutoFontSize(bool bAuto, bool bPaint) {
+  m_pVT->SetAutoFontSize(bAuto);
+  if (bPaint)
+    Paint();
+}
+
+void CPWL_EditImpl::SetFontSize(float fFontSize) {
+  m_pVT->SetFontSize(fFontSize);
+  Paint();
+}
+
+void CPWL_EditImpl::SetAutoScroll(bool bAuto, bool bPaint) {
+  m_bEnableScroll = bAuto;
+  if (bPaint)
+    Paint();
+}
+
+void CPWL_EditImpl::SetTextOverflow(bool bAllowed, bool bPaint) {
+  m_bEnableOverflow = bAllowed;
+  if (bPaint)
+    Paint();
+}
+
+void CPWL_EditImpl::SetSelection(int32_t nStartChar, int32_t nEndChar) {
+  if (m_pVT->IsValid()) {
+    if (nStartChar == 0 && nEndChar < 0) {
+      SelectAll();
+    } else if (nStartChar < 0) {
+      SelectNone();
+    } else {
+      if (nStartChar < nEndChar) {
+        SetSelection(m_pVT->WordIndexToWordPlace(nStartChar),
+                     m_pVT->WordIndexToWordPlace(nEndChar));
+      } else {
+        SetSelection(m_pVT->WordIndexToWordPlace(nEndChar),
+                     m_pVT->WordIndexToWordPlace(nStartChar));
+      }
+    }
+  }
+}
+
+void CPWL_EditImpl::SetSelection(const CPVT_WordPlace& begin,
+                                 const CPVT_WordPlace& end) {
+  if (!m_pVT->IsValid())
+    return;
+
+  SelectNone();
+  m_SelState.Set(begin, end);
+  SetCaret(m_SelState.EndPos);
+  ScrollToCaret();
+  if (!m_SelState.IsEmpty())
+    Refresh();
+  SetCaretInfo();
+}
+
+void CPWL_EditImpl::GetSelection(int32_t& nStartChar, int32_t& nEndChar) const {
+  nStartChar = -1;
+  nEndChar = -1;
+  if (!m_pVT->IsValid())
+    return;
+
+  if (m_SelState.IsEmpty()) {
+    nStartChar = m_pVT->WordPlaceToWordIndex(m_wpCaret);
+    nEndChar = m_pVT->WordPlaceToWordIndex(m_wpCaret);
+    return;
+  }
+  if (m_SelState.BeginPos < m_SelState.EndPos) {
+    nStartChar = m_pVT->WordPlaceToWordIndex(m_SelState.BeginPos);
+    nEndChar = m_pVT->WordPlaceToWordIndex(m_SelState.EndPos);
+    return;
+  }
+  nStartChar = m_pVT->WordPlaceToWordIndex(m_SelState.EndPos);
+  nEndChar = m_pVT->WordPlaceToWordIndex(m_SelState.BeginPos);
+}
+
+int32_t CPWL_EditImpl::GetCaret() const {
+  if (m_pVT->IsValid())
+    return m_pVT->WordPlaceToWordIndex(m_wpCaret);
+
+  return -1;
+}
+
+CPVT_WordPlace CPWL_EditImpl::GetCaretWordPlace() const {
+  return m_wpCaret;
+}
+
+WideString CPWL_EditImpl::GetText() const {
+  WideString swRet;
+  if (!m_pVT->IsValid())
+    return swRet;
+
+  CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
+  pIterator->SetAt(0);
+
+  CPVT_Word wordinfo;
+  CPVT_WordPlace oldplace = pIterator->GetWordPlace();
+  while (pIterator->NextWord()) {
+    CPVT_WordPlace place = pIterator->GetWordPlace();
+    if (pIterator->GetWord(wordinfo))
+      swRet += wordinfo.Word;
+    if (oldplace.nSecIndex != place.nSecIndex)
+      swRet += L"\r\n";
+    oldplace = place;
+  }
+  return swRet;
+}
+
+WideString CPWL_EditImpl::GetRangeText(const CPVT_WordRange& range) const {
+  WideString swRet;
+  if (!m_pVT->IsValid())
+    return swRet;
+
+  CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
+  CPVT_WordRange wrTemp = range;
+  m_pVT->UpdateWordPlace(wrTemp.BeginPos);
+  m_pVT->UpdateWordPlace(wrTemp.EndPos);
+  pIterator->SetAt(wrTemp.BeginPos);
+
+  CPVT_Word wordinfo;
+  CPVT_WordPlace oldplace = wrTemp.BeginPos;
+  while (pIterator->NextWord()) {
+    CPVT_WordPlace place = pIterator->GetWordPlace();
+    if (place > wrTemp.EndPos)
+      break;
+    if (pIterator->GetWord(wordinfo))
+      swRet += wordinfo.Word;
+    if (oldplace.nSecIndex != place.nSecIndex)
+      swRet += L"\r\n";
+    oldplace = place;
+  }
+  return swRet;
+}
+
+WideString CPWL_EditImpl::GetSelectedText() const {
+  return GetRangeText(m_SelState.ConvertToWordRange());
+}
+
+int32_t CPWL_EditImpl::GetTotalLines() const {
+  int32_t nLines = 1;
+
+  CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
+  pIterator->SetAt(0);
+  while (pIterator->NextLine())
+    ++nLines;
+
+  return nLines;
+}
+
+CPVT_WordRange CPWL_EditImpl::GetSelectWordRange() const {
+  return m_SelState.ConvertToWordRange();
+}
+
+void CPWL_EditImpl::SetText(const WideString& sText) {
+  Empty();
+  DoInsertText(CPVT_WordPlace(0, 0, -1), sText, FX_CHARSET_Default);
+  Paint();
+}
+
+bool CPWL_EditImpl::InsertWord(uint16_t word, int32_t charset) {
+  return InsertWord(word, charset, true, true);
+}
+
+bool CPWL_EditImpl::InsertReturn() {
+  return InsertReturn(true, true);
+}
+
+bool CPWL_EditImpl::Backspace() {
+  return Backspace(true, true);
+}
+
+bool CPWL_EditImpl::Delete() {
+  return Delete(true, true);
+}
+
+bool CPWL_EditImpl::ClearSelection() {
+  return Clear(true, true);
+}
+
+bool CPWL_EditImpl::InsertText(const WideString& sText, int32_t charset) {
+  return InsertText(sText, charset, true, true);
+}
+
+float CPWL_EditImpl::GetFontSize() const {
+  return m_pVT->GetFontSize();
+}
+
+uint16_t CPWL_EditImpl::GetPasswordChar() const {
+  return m_pVT->GetPasswordChar();
+}
+
+int32_t CPWL_EditImpl::GetCharArray() const {
+  return m_pVT->GetCharArray();
+}
+
+CFX_FloatRect CPWL_EditImpl::GetContentRect() const {
+  return VTToEdit(m_pVT->GetContentRect());
+}
+
+int32_t CPWL_EditImpl::GetHorzScale() const {
+  return m_pVT->GetHorzScale();
+}
+
+float CPWL_EditImpl::GetCharSpace() const {
+  return m_pVT->GetCharSpace();
+}
+
+CPVT_WordRange CPWL_EditImpl::GetWholeWordRange() const {
+  if (m_pVT->IsValid())
+    return CPVT_WordRange(m_pVT->GetBeginWordPlace(), m_pVT->GetEndWordPlace());
+
+  return CPVT_WordRange();
+}
+
+CPVT_WordRange CPWL_EditImpl::GetVisibleWordRange() const {
+  if (m_bEnableOverflow)
+    return GetWholeWordRange();
+
+  if (m_pVT->IsValid()) {
+    CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
+
+    CPVT_WordPlace place1 =
+        m_pVT->SearchWordPlace(EditToVT(CFX_PointF(rcPlate.left, rcPlate.top)));
+    CPVT_WordPlace place2 = m_pVT->SearchWordPlace(
+        EditToVT(CFX_PointF(rcPlate.right, rcPlate.bottom)));
+
+    return CPVT_WordRange(place1, place2);
+  }
+
+  return CPVT_WordRange();
+}
+
+CPVT_WordPlace CPWL_EditImpl::SearchWordPlace(const CFX_PointF& point) const {
+  if (m_pVT->IsValid()) {
+    return m_pVT->SearchWordPlace(EditToVT(point));
+  }
+
+  return CPVT_WordPlace();
+}
+
+void CPWL_EditImpl::Paint() {
+  if (m_pVT->IsValid()) {
+    RearrangeAll();
+    ScrollToCaret();
+    Refresh();
+    SetCaretOrigin();
+    SetCaretInfo();
+  }
+}
+
+void CPWL_EditImpl::RearrangeAll() {
+  if (m_pVT->IsValid()) {
+    m_pVT->UpdateWordPlace(m_wpCaret);
+    m_pVT->RearrangeAll();
+    m_pVT->UpdateWordPlace(m_wpCaret);
+    SetScrollInfo();
+    SetContentChanged();
+  }
+}
+
+void CPWL_EditImpl::RearrangePart(const CPVT_WordRange& range) {
+  if (m_pVT->IsValid()) {
+    m_pVT->UpdateWordPlace(m_wpCaret);
+    m_pVT->RearrangePart(range);
+    m_pVT->UpdateWordPlace(m_wpCaret);
+    SetScrollInfo();
+    SetContentChanged();
+  }
+}
+
+void CPWL_EditImpl::SetContentChanged() {
+  if (m_pNotify) {
+    CFX_FloatRect rcContent = m_pVT->GetContentRect();
+    if (rcContent.Width() != m_rcOldContent.Width() ||
+        rcContent.Height() != m_rcOldContent.Height()) {
+      m_rcOldContent = rcContent;
+    }
+  }
+}
+
+void CPWL_EditImpl::SelectAll() {
+  if (!m_pVT->IsValid())
+    return;
+  m_SelState = CPWL_EditImpl_Select(GetWholeWordRange());
+  SetCaret(m_SelState.EndPos);
+  ScrollToCaret();
+  Refresh();
+  SetCaretInfo();
+}
+
+void CPWL_EditImpl::SelectNone() {
+  if (!m_pVT->IsValid() || m_SelState.IsEmpty())
+    return;
+
+  m_SelState.Reset();
+  Refresh();
+}
+
+bool CPWL_EditImpl::IsSelected() const {
+  return !m_SelState.IsEmpty();
+}
+
+CFX_PointF CPWL_EditImpl::VTToEdit(const CFX_PointF& point) const {
+  CFX_FloatRect rcContent = m_pVT->GetContentRect();
+  CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
+
+  float fPadding = 0.0f;
+
+  switch (m_nAlignment) {
+    case 0:
+      fPadding = 0.0f;
+      break;
+    case 1:
+      fPadding = (rcPlate.Height() - rcContent.Height()) * 0.5f;
+      break;
+    case 2:
+      fPadding = rcPlate.Height() - rcContent.Height();
+      break;
+  }
+
+  return CFX_PointF(point.x - (m_ptScrollPos.x - rcPlate.left),
+                    point.y - (m_ptScrollPos.y + fPadding - rcPlate.top));
+}
+
+CFX_PointF CPWL_EditImpl::EditToVT(const CFX_PointF& point) const {
+  CFX_FloatRect rcContent = m_pVT->GetContentRect();
+  CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
+
+  float fPadding = 0.0f;
+
+  switch (m_nAlignment) {
+    case 0:
+      fPadding = 0.0f;
+      break;
+    case 1:
+      fPadding = (rcPlate.Height() - rcContent.Height()) * 0.5f;
+      break;
+    case 2:
+      fPadding = rcPlate.Height() - rcContent.Height();
+      break;
+  }
+
+  return CFX_PointF(point.x + (m_ptScrollPos.x - rcPlate.left),
+                    point.y + (m_ptScrollPos.y + fPadding - rcPlate.top));
+}
+
+CFX_FloatRect CPWL_EditImpl::VTToEdit(const CFX_FloatRect& rect) const {
+  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);
+}
+
+void CPWL_EditImpl::SetScrollInfo() {
+  if (!m_pNotify)
+    return;
+
+  CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
+  CFX_FloatRect rcContent = m_pVT->GetContentRect();
+  if (m_bNotifyFlag)
+    return;
+
+  AutoRestorer<bool> restorer(&m_bNotifyFlag);
+  m_bNotifyFlag = true;
+
+  PWL_SCROLL_INFO Info;
+  Info.fPlateWidth = rcPlate.top - rcPlate.bottom;
+  Info.fContentMin = rcContent.bottom;
+  Info.fContentMax = rcContent.top;
+  Info.fSmallStep = rcPlate.Height() / 3;
+  Info.fBigStep = rcPlate.Height();
+  m_pNotify->SetScrollInfo(Info);
+}
+
+void CPWL_EditImpl::SetScrollPosX(float fx) {
+  if (!m_bEnableScroll)
+    return;
+
+  if (m_pVT->IsValid()) {
+    if (!IsFloatEqual(m_ptScrollPos.x, fx)) {
+      m_ptScrollPos.x = fx;
+      Refresh();
+    }
+  }
+}
+
+void CPWL_EditImpl::SetScrollPosY(float fy) {
+  if (!m_bEnableScroll)
+    return;
+
+  if (m_pVT->IsValid()) {
+    if (!IsFloatEqual(m_ptScrollPos.y, fy)) {
+      m_ptScrollPos.y = fy;
+      Refresh();
+
+      if (m_pNotify) {
+        if (!m_bNotifyFlag) {
+          AutoRestorer<bool> restorer(&m_bNotifyFlag);
+          m_bNotifyFlag = true;
+          m_pNotify->SetScrollPosition(fy);
+        }
+      }
+    }
+  }
+}
+
+void CPWL_EditImpl::SetScrollPos(const CFX_PointF& point) {
+  SetScrollPosX(point.x);
+  SetScrollPosY(point.y);
+  SetScrollLimit();
+  SetCaretInfo();
+}
+
+CFX_PointF CPWL_EditImpl::GetScrollPos() const {
+  return m_ptScrollPos;
+}
+
+void CPWL_EditImpl::SetScrollLimit() {
+  if (m_pVT->IsValid()) {
+    CFX_FloatRect rcContent = m_pVT->GetContentRect();
+    CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
+
+    if (rcPlate.Width() > rcContent.Width()) {
+      SetScrollPosX(rcPlate.left);
+    } else {
+      if (IsFloatSmaller(m_ptScrollPos.x, rcContent.left)) {
+        SetScrollPosX(rcContent.left);
+      } else if (IsFloatBigger(m_ptScrollPos.x,
+                               rcContent.right - rcPlate.Width())) {
+        SetScrollPosX(rcContent.right - rcPlate.Width());
+      }
+    }
+
+    if (rcPlate.Height() > rcContent.Height()) {
+      SetScrollPosY(rcPlate.top);
+    } else {
+      if (IsFloatSmaller(m_ptScrollPos.y,
+                         rcContent.bottom + rcPlate.Height())) {
+        SetScrollPosY(rcContent.bottom + rcPlate.Height());
+      } else if (IsFloatBigger(m_ptScrollPos.y, rcContent.top)) {
+        SetScrollPosY(rcContent.top);
+      }
+    }
+  }
+}
+
+void CPWL_EditImpl::ScrollToCaret() {
+  SetScrollLimit();
+
+  if (!m_pVT->IsValid())
+    return;
+
+  CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
+  pIterator->SetAt(m_wpCaret);
+
+  CFX_PointF ptHead;
+  CFX_PointF ptFoot;
+  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;
+  } 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;
+  }
+
+  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) ||
+        IsFloatEqual(ptHeadEdit.x, rcPlate.left)) {
+      SetScrollPosX(ptHead.x);
+    } else if (IsFloatBigger(ptHeadEdit.x, rcPlate.right)) {
+      SetScrollPosX(ptHead.x - rcPlate.Width());
+    }
+  }
+
+  if (!IsFloatEqual(rcPlate.top, rcPlate.bottom)) {
+    if (IsFloatSmaller(ptFootEdit.y, rcPlate.bottom) ||
+        IsFloatEqual(ptFootEdit.y, rcPlate.bottom)) {
+      if (IsFloatSmaller(ptHeadEdit.y, rcPlate.top)) {
+        SetScrollPosY(ptFoot.y + rcPlate.Height());
+      }
+    } else if (IsFloatBigger(ptHeadEdit.y, rcPlate.top)) {
+      if (IsFloatBigger(ptFootEdit.y, rcPlate.bottom)) {
+        SetScrollPosY(ptHead.y);
+      }
+    }
+  }
+}
+
+void CPWL_EditImpl::Refresh() {
+  if (m_bEnableRefresh && m_pVT->IsValid()) {
+    m_Refresh.BeginRefresh();
+    RefreshPushLineRects(GetVisibleWordRange());
+
+    m_Refresh.NoAnalyse();
+    m_ptRefreshScrollPos = m_ptScrollPos;
+
+    if (m_pNotify) {
+      if (!m_bNotifyFlag) {
+        AutoRestorer<bool> restorer(&m_bNotifyFlag);
+        m_bNotifyFlag = true;
+        if (std::vector<CFX_FloatRect>* pRects = m_Refresh.GetRefreshRects()) {
+          for (auto& rect : *pRects)
+            m_pNotify->InvalidateRect(&rect);
+        }
+      }
+    }
+
+    m_Refresh.EndRefresh();
+  }
+}
+
+void CPWL_EditImpl::RefreshPushLineRects(const CPVT_WordRange& wr) {
+  if (!m_pVT->IsValid())
+    return;
+
+  CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
+  CPVT_WordPlace wpBegin = wr.BeginPos;
+  m_pVT->UpdateWordPlace(wpBegin);
+  CPVT_WordPlace wpEnd = wr.EndPos;
+  m_pVT->UpdateWordPlace(wpEnd);
+  pIterator->SetAt(wpBegin);
+
+  CPVT_Line lineinfo;
+  do {
+    if (!pIterator->GetLine(lineinfo))
+      break;
+    if (lineinfo.lineplace.LineCmp(wpEnd) > 0)
+      break;
+
+    CFX_FloatRect rcLine(lineinfo.ptLine.x,
+                         lineinfo.ptLine.y + lineinfo.fLineDescent,
+                         lineinfo.ptLine.x + lineinfo.fLineWidth,
+                         lineinfo.ptLine.y + lineinfo.fLineAscent);
+
+    m_Refresh.Push(CPVT_WordRange(lineinfo.lineplace, lineinfo.lineEnd),
+                   VTToEdit(rcLine));
+  } while (pIterator->NextLine());
+}
+
+void CPWL_EditImpl::RefreshWordRange(const CPVT_WordRange& wr) {
+  CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
+  CPVT_WordRange wrTemp = wr;
+
+  m_pVT->UpdateWordPlace(wrTemp.BeginPos);
+  m_pVT->UpdateWordPlace(wrTemp.EndPos);
+  pIterator->SetAt(wrTemp.BeginPos);
+
+  CPVT_Word wordinfo;
+  CPVT_Line lineinfo;
+  CPVT_WordPlace place;
+
+  while (pIterator->NextWord()) {
+    place = pIterator->GetWordPlace();
+    if (place > wrTemp.EndPos)
+      break;
+
+    pIterator->GetWord(wordinfo);
+    pIterator->GetLine(lineinfo);
+    if (place.LineCmp(wrTemp.BeginPos) == 0 ||
+        place.LineCmp(wrTemp.EndPos) == 0) {
+      CFX_FloatRect rcWord(wordinfo.ptWord.x,
+                           lineinfo.ptLine.y + lineinfo.fLineDescent,
+                           wordinfo.ptWord.x + wordinfo.fWidth,
+                           lineinfo.ptLine.y + lineinfo.fLineAscent);
+
+      if (m_pNotify) {
+        if (!m_bNotifyFlag) {
+          AutoRestorer<bool> restorer(&m_bNotifyFlag);
+          m_bNotifyFlag = true;
+          CFX_FloatRect rcRefresh = VTToEdit(rcWord);
+          m_pNotify->InvalidateRect(&rcRefresh);
+        }
+      }
+    } else {
+      CFX_FloatRect rcLine(lineinfo.ptLine.x,
+                           lineinfo.ptLine.y + lineinfo.fLineDescent,
+                           lineinfo.ptLine.x + lineinfo.fLineWidth,
+                           lineinfo.ptLine.y + lineinfo.fLineAscent);
+
+      if (m_pNotify) {
+        if (!m_bNotifyFlag) {
+          AutoRestorer<bool> restorer(&m_bNotifyFlag);
+          m_bNotifyFlag = true;
+          CFX_FloatRect rcRefresh = VTToEdit(rcLine);
+          m_pNotify->InvalidateRect(&rcRefresh);
+        }
+      }
+
+      pIterator->NextLine();
+    }
+  }
+}
+
+void CPWL_EditImpl::SetCaret(const CPVT_WordPlace& place) {
+  m_wpOldCaret = m_wpCaret;
+  m_wpCaret = place;
+}
+
+void CPWL_EditImpl::SetCaretInfo() {
+  if (m_pNotify) {
+    if (!m_bNotifyFlag) {
+      CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
+      pIterator->SetAt(m_wpCaret);
+
+      CFX_PointF ptHead;
+      CFX_PointF ptFoot;
+      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;
+      } 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;
+      }
+
+      AutoRestorer<bool> restorer(&m_bNotifyFlag);
+      m_bNotifyFlag = true;
+      m_pNotify->SetCaret(m_SelState.IsEmpty(), VTToEdit(ptHead),
+                          VTToEdit(ptFoot));
+    }
+  }
+}
+
+void CPWL_EditImpl::OnMouseDown(const CFX_PointF& point,
+                                bool bShift,
+                                bool bCtrl) {
+  if (!m_pVT->IsValid())
+    return;
+
+  SelectNone();
+  SetCaret(m_pVT->SearchWordPlace(EditToVT(point)));
+  m_SelState.Set(m_wpCaret, m_wpCaret);
+  ScrollToCaret();
+  SetCaretOrigin();
+  SetCaretInfo();
+}
+
+void CPWL_EditImpl::OnMouseMove(const CFX_PointF& point,
+                                bool bShift,
+                                bool bCtrl) {
+  if (!m_pVT->IsValid())
+    return;
+
+  SetCaret(m_pVT->SearchWordPlace(EditToVT(point)));
+  if (m_wpCaret == m_wpOldCaret)
+    return;
+
+  m_SelState.SetEndPos(m_wpCaret);
+  ScrollToCaret();
+  Refresh();
+  SetCaretOrigin();
+  SetCaretInfo();
+}
+
+void CPWL_EditImpl::OnVK_UP(bool bShift, bool bCtrl) {
+  if (!m_pVT->IsValid())
+    return;
+
+  SetCaret(m_pVT->GetUpWordPlace(m_wpCaret, m_ptCaret));
+  if (bShift) {
+    if (m_SelState.IsEmpty())
+      m_SelState.Set(m_wpOldCaret, m_wpCaret);
+    else
+      m_SelState.SetEndPos(m_wpCaret);
+
+    if (m_wpOldCaret != m_wpCaret) {
+      ScrollToCaret();
+      Refresh();
+      SetCaretInfo();
+    }
+  } else {
+    SelectNone();
+    ScrollToCaret();
+    SetCaretInfo();
+  }
+}
+
+void CPWL_EditImpl::OnVK_DOWN(bool bShift, bool bCtrl) {
+  if (!m_pVT->IsValid())
+    return;
+
+  SetCaret(m_pVT->GetDownWordPlace(m_wpCaret, m_ptCaret));
+  if (bShift) {
+    if (m_SelState.IsEmpty())
+      m_SelState.Set(m_wpOldCaret, m_wpCaret);
+    else
+      m_SelState.SetEndPos(m_wpCaret);
+
+    if (m_wpOldCaret != m_wpCaret) {
+      ScrollToCaret();
+      Refresh();
+      SetCaretInfo();
+    }
+  } else {
+    SelectNone();
+    ScrollToCaret();
+    SetCaretInfo();
+  }
+}
+
+void CPWL_EditImpl::OnVK_LEFT(bool bShift, bool bCtrl) {
+  if (!m_pVT->IsValid())
+    return;
+
+  if (bShift) {
+    if (m_wpCaret == m_pVT->GetLineBeginPlace(m_wpCaret) &&
+        m_wpCaret != m_pVT->GetSectionBeginPlace(m_wpCaret)) {
+      SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
+    }
+    SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
+    if (m_SelState.IsEmpty())
+      m_SelState.Set(m_wpOldCaret, m_wpCaret);
+    else
+      m_SelState.SetEndPos(m_wpCaret);
+
+    if (m_wpOldCaret != m_wpCaret) {
+      ScrollToCaret();
+      Refresh();
+      SetCaretInfo();
+    }
+  } else {
+    if (!m_SelState.IsEmpty()) {
+      if (m_SelState.BeginPos < m_SelState.EndPos)
+        SetCaret(m_SelState.BeginPos);
+      else
+        SetCaret(m_SelState.EndPos);
+
+      SelectNone();
+      ScrollToCaret();
+      SetCaretInfo();
+    } else {
+      if (m_wpCaret == m_pVT->GetLineBeginPlace(m_wpCaret) &&
+          m_wpCaret != m_pVT->GetSectionBeginPlace(m_wpCaret)) {
+        SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
+      }
+      SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
+      ScrollToCaret();
+      SetCaretOrigin();
+      SetCaretInfo();
+    }
+  }
+}
+
+void CPWL_EditImpl::OnVK_RIGHT(bool bShift, bool bCtrl) {
+  if (!m_pVT->IsValid())
+    return;
+
+  if (bShift) {
+    SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
+    if (m_wpCaret == m_pVT->GetLineEndPlace(m_wpCaret) &&
+        m_wpCaret != m_pVT->GetSectionEndPlace(m_wpCaret))
+      SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
+
+    if (m_SelState.IsEmpty())
+      m_SelState.Set(m_wpOldCaret, m_wpCaret);
+    else
+      m_SelState.SetEndPos(m_wpCaret);
+
+    if (m_wpOldCaret != m_wpCaret) {
+      ScrollToCaret();
+      Refresh();
+      SetCaretInfo();
+    }
+  } else {
+    if (!m_SelState.IsEmpty()) {
+      if (m_SelState.BeginPos > m_SelState.EndPos)
+        SetCaret(m_SelState.BeginPos);
+      else
+        SetCaret(m_SelState.EndPos);
+
+      SelectNone();
+      ScrollToCaret();
+      SetCaretInfo();
+    } else {
+      SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
+      if (m_wpCaret == m_pVT->GetLineEndPlace(m_wpCaret) &&
+          m_wpCaret != m_pVT->GetSectionEndPlace(m_wpCaret)) {
+        SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
+      }
+      ScrollToCaret();
+      SetCaretOrigin();
+      SetCaretInfo();
+    }
+  }
+}
+
+void CPWL_EditImpl::OnVK_HOME(bool bShift, bool bCtrl) {
+  if (!m_pVT->IsValid())
+    return;
+
+  if (bShift) {
+    if (bCtrl)
+      SetCaret(m_pVT->GetBeginWordPlace());
+    else
+      SetCaret(m_pVT->GetLineBeginPlace(m_wpCaret));
+
+    if (m_SelState.IsEmpty())
+      m_SelState.Set(m_wpOldCaret, m_wpCaret);
+    else
+      m_SelState.SetEndPos(m_wpCaret);
+
+    ScrollToCaret();
+    Refresh();
+    SetCaretInfo();
+  } else {
+    if (!m_SelState.IsEmpty()) {
+      SetCaret(std::min(m_SelState.BeginPos, m_SelState.EndPos));
+      SelectNone();
+      ScrollToCaret();
+      SetCaretInfo();
+    } else {
+      if (bCtrl)
+        SetCaret(m_pVT->GetBeginWordPlace());
+      else
+        SetCaret(m_pVT->GetLineBeginPlace(m_wpCaret));
+
+      ScrollToCaret();
+      SetCaretOrigin();
+      SetCaretInfo();
+    }
+  }
+}
+
+void CPWL_EditImpl::OnVK_END(bool bShift, bool bCtrl) {
+  if (!m_pVT->IsValid())
+    return;
+
+  if (bShift) {
+    if (bCtrl)
+      SetCaret(m_pVT->GetEndWordPlace());
+    else
+      SetCaret(m_pVT->GetLineEndPlace(m_wpCaret));
+
+    if (m_SelState.IsEmpty())
+      m_SelState.Set(m_wpOldCaret, m_wpCaret);
+    else
+      m_SelState.SetEndPos(m_wpCaret);
+
+    ScrollToCaret();
+    Refresh();
+    SetCaretInfo();
+  } else {
+    if (!m_SelState.IsEmpty()) {
+      SetCaret(std::max(m_SelState.BeginPos, m_SelState.EndPos));
+      SelectNone();
+      ScrollToCaret();
+      SetCaretInfo();
+    } else {
+      if (bCtrl)
+        SetCaret(m_pVT->GetEndWordPlace());
+      else
+        SetCaret(m_pVT->GetLineEndPlace(m_wpCaret));
+
+      ScrollToCaret();
+      SetCaretOrigin();
+      SetCaretInfo();
+    }
+  }
+}
+
+bool CPWL_EditImpl::InsertWord(uint16_t word,
+                               int32_t charset,
+                               bool bAddUndo,
+                               bool bPaint) {
+  if (IsTextOverflow() || !m_pVT->IsValid())
+    return false;
+
+  m_pVT->UpdateWordPlace(m_wpCaret);
+  SetCaret(
+      m_pVT->InsertWord(m_wpCaret, word, GetCharSetFromUnicode(word, charset)));
+  m_SelState.Set(m_wpCaret, m_wpCaret);
+  if (m_wpCaret == m_wpOldCaret)
+    return false;
+
+  if (bAddUndo && m_bEnableUndo) {
+    AddEditUndoItem(pdfium::MakeUnique<CFXEU_InsertWord>(
+        this, m_wpOldCaret, m_wpCaret, word, charset));
+  }
+  if (bPaint)
+    PaintInsertText(m_wpOldCaret, m_wpCaret);
+
+  if (m_pOperationNotify)
+    m_pOperationNotify->OnInsertWord(m_wpCaret, m_wpOldCaret);
+
+  return true;
+}
+
+bool CPWL_EditImpl::InsertReturn(bool bAddUndo, bool bPaint) {
+  if (IsTextOverflow() || !m_pVT->IsValid())
+    return false;
+
+  m_pVT->UpdateWordPlace(m_wpCaret);
+  SetCaret(m_pVT->InsertSection(m_wpCaret));
+  m_SelState.Set(m_wpCaret, m_wpCaret);
+  if (m_wpCaret == m_wpOldCaret)
+    return false;
+
+  if (bAddUndo && m_bEnableUndo) {
+    AddEditUndoItem(
+        pdfium::MakeUnique<CFXEU_InsertReturn>(this, m_wpOldCaret, m_wpCaret));
+  }
+  if (bPaint) {
+    RearrangePart(CPVT_WordRange(m_wpOldCaret, m_wpCaret));
+    ScrollToCaret();
+    Refresh();
+    SetCaretOrigin();
+    SetCaretInfo();
+  }
+  if (m_pOperationNotify)
+    m_pOperationNotify->OnInsertReturn(m_wpCaret, m_wpOldCaret);
+
+  return true;
+}
+
+bool CPWL_EditImpl::Backspace(bool bAddUndo, bool bPaint) {
+  if (!m_pVT->IsValid() || m_wpCaret == m_pVT->GetBeginWordPlace())
+    return false;
+
+  CPVT_Word word;
+  if (bAddUndo) {
+    CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
+    pIterator->SetAt(m_wpCaret);
+    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 && m_bEnableUndo) {
+    if (m_wpCaret.nSecIndex != m_wpOldCaret.nSecIndex) {
+      AddEditUndoItem(pdfium::MakeUnique<CFXEU_Backspace>(
+          this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset));
+    } else {
+      AddEditUndoItem(pdfium::MakeUnique<CFXEU_Backspace>(
+          this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset));
+    }
+  }
+  if (bPaint) {
+    RearrangePart(CPVT_WordRange(m_wpCaret, m_wpOldCaret));
+    ScrollToCaret();
+    Refresh();
+    SetCaretOrigin();
+    SetCaretInfo();
+  }
+  if (m_pOperationNotify)
+    m_pOperationNotify->OnBackSpace(m_wpCaret, m_wpOldCaret);
+
+  return true;
+}
+
+bool CPWL_EditImpl::Delete(bool bAddUndo, bool bPaint) {
+  if (!m_pVT->IsValid() || m_wpCaret == m_pVT->GetEndWordPlace())
+    return false;
+
+  CPVT_Word word;
+  if (bAddUndo) {
+    CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
+    pIterator->SetAt(m_pVT->GetNextWordPlace(m_wpCaret));
+    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, bSecEnd));
+    } else {
+      AddEditUndoItem(pdfium::MakeUnique<CFXEU_Delete>(
+          this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset, bSecEnd));
+    }
+  }
+  if (bPaint) {
+    RearrangePart(CPVT_WordRange(m_wpOldCaret, m_wpCaret));
+    ScrollToCaret();
+    Refresh();
+    SetCaretOrigin();
+    SetCaretInfo();
+  }
+  if (m_pOperationNotify)
+    m_pOperationNotify->OnDelete(m_wpCaret, m_wpOldCaret);
+
+  return true;
+}
+
+bool CPWL_EditImpl::Empty() {
+  if (m_pVT->IsValid()) {
+    m_pVT->DeleteWords(GetWholeWordRange());
+    SetCaret(m_pVT->GetBeginWordPlace());
+
+    return true;
+  }
+
+  return false;
+}
+
+bool CPWL_EditImpl::Clear(bool bAddUndo, bool bPaint) {
+  if (!m_pVT->IsValid() || m_SelState.IsEmpty())
+    return false;
+
+  CPVT_WordRange range = m_SelState.ConvertToWordRange();
+  if (bAddUndo && m_bEnableUndo) {
+    AddEditUndoItem(
+        pdfium::MakeUnique<CFXEU_Clear>(this, range, GetSelectedText()));
+  }
+
+  SelectNone();
+  SetCaret(m_pVT->DeleteWords(range));
+  m_SelState.Set(m_wpCaret, m_wpCaret);
+  if (bPaint) {
+    RearrangePart(range);
+    ScrollToCaret();
+    Refresh();
+    SetCaretOrigin();
+    SetCaretInfo();
+  }
+  if (m_pOperationNotify)
+    m_pOperationNotify->OnClear(m_wpCaret, m_wpOldCaret);
+
+  return true;
+}
+
+bool CPWL_EditImpl::InsertText(const WideString& sText,
+                               int32_t charset,
+                               bool bAddUndo,
+                               bool bPaint) {
+  if (IsTextOverflow())
+    return false;
+
+  m_pVT->UpdateWordPlace(m_wpCaret);
+  SetCaret(DoInsertText(m_wpCaret, sText, charset));
+  m_SelState.Set(m_wpCaret, m_wpCaret);
+  if (m_wpCaret == m_wpOldCaret)
+    return false;
+
+  if (bAddUndo && m_bEnableUndo) {
+    AddEditUndoItem(pdfium::MakeUnique<CFXEU_InsertText>(
+        this, m_wpOldCaret, m_wpCaret, sText, charset));
+  }
+  if (bPaint)
+    PaintInsertText(m_wpOldCaret, m_wpCaret);
+
+  if (m_pOperationNotify)
+    m_pOperationNotify->OnInsertText(m_wpCaret, m_wpOldCaret);
+
+  return true;
+}
+
+void CPWL_EditImpl::PaintInsertText(const CPVT_WordPlace& wpOld,
+                                    const CPVT_WordPlace& wpNew) {
+  if (m_pVT->IsValid()) {
+    RearrangePart(CPVT_WordRange(wpOld, wpNew));
+    ScrollToCaret();
+    Refresh();
+    SetCaretOrigin();
+    SetCaretInfo();
+  }
+}
+
+bool CPWL_EditImpl::Redo() {
+  if (m_bEnableUndo) {
+    if (m_Undo.CanRedo()) {
+      m_Undo.Redo();
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool CPWL_EditImpl::Undo() {
+  if (m_bEnableUndo) {
+    if (m_Undo.CanUndo()) {
+      m_Undo.Undo();
+      return true;
+    }
+  }
+
+  return false;
+}
+
+void CPWL_EditImpl::SetCaretOrigin() {
+  if (!m_pVT->IsValid())
+    return;
+
+  CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
+  pIterator->SetAt(m_wpCaret);
+  CPVT_Word word;
+  CPVT_Line line;
+  if (pIterator->GetWord(word)) {
+    m_ptCaret.x = word.ptWord.x + word.fWidth;
+    m_ptCaret.y = word.ptWord.y;
+  } else if (pIterator->GetLine(line)) {
+    m_ptCaret.x = line.ptLine.x;
+    m_ptCaret.y = line.ptLine.y;
+  }
+}
+
+CPVT_WordPlace CPWL_EditImpl::WordIndexToWordPlace(int32_t index) const {
+  if (m_pVT->IsValid())
+    return m_pVT->WordIndexToWordPlace(index);
+
+  return CPVT_WordPlace();
+}
+
+bool CPWL_EditImpl::IsTextFull() const {
+  int32_t nTotalWords = m_pVT->GetTotalWords();
+  int32_t nLimitChar = m_pVT->GetLimitChar();
+  int32_t nCharArray = m_pVT->GetCharArray();
+
+  return IsTextOverflow() || (nLimitChar > 0 && nTotalWords >= nLimitChar) ||
+         (nCharArray > 0 && nTotalWords >= nCharArray);
+}
+
+bool CPWL_EditImpl::IsTextOverflow() const {
+  if (!m_bEnableScroll && !m_bEnableOverflow) {
+    CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
+    CFX_FloatRect rcContent = m_pVT->GetContentRect();
+
+    if (m_pVT->IsMultiLine() && GetTotalLines() > 1 &&
+        IsFloatBigger(rcContent.Height(), rcPlate.Height())) {
+      return true;
+    }
+
+    if (IsFloatBigger(rcContent.Width(), rcPlate.Width()))
+      return true;
+  }
+
+  return false;
+}
+
+bool CPWL_EditImpl::CanUndo() const {
+  if (m_bEnableUndo) {
+    return m_Undo.CanUndo();
+  }
+
+  return false;
+}
+
+bool CPWL_EditImpl::CanRedo() const {
+  if (m_bEnableUndo) {
+    return m_Undo.CanRedo();
+  }
+
+  return false;
+}
+
+void CPWL_EditImpl::EnableRefresh(bool bRefresh) {
+  m_bEnableRefresh = bRefresh;
+}
+
+void CPWL_EditImpl::EnableUndo(bool bUndo) {
+  m_bEnableUndo = bUndo;
+}
+
+CPVT_WordPlace CPWL_EditImpl::DoInsertText(const CPVT_WordPlace& place,
+                                           const WideString& sText,
+                                           int32_t charset) {
+  CPVT_WordPlace wp = place;
+
+  if (m_pVT->IsValid()) {
+    for (int32_t i = 0, sz = sText.GetLength(); i < sz; i++) {
+      uint16_t word = sText[i];
+      switch (word) {
+        case 0x0D:
+          wp = m_pVT->InsertSection(wp);
+          if (i + 1 < sz && sText[i + 1] == 0x0A)
+            i++;
+          break;
+        case 0x0A:
+          wp = m_pVT->InsertSection(wp);
+          break;
+        case 0x09:
+          word = 0x20;
+        default:
+          wp =
+              m_pVT->InsertWord(wp, word, GetCharSetFromUnicode(word, charset));
+          break;
+      }
+    }
+  }
+
+  return wp;
+}
+
+int32_t CPWL_EditImpl::GetCharSetFromUnicode(uint16_t word,
+                                             int32_t nOldCharset) {
+  if (IPVT_FontMap* pFontMap = GetFontMap())
+    return pFontMap->CharSetFromUnicode(word, nOldCharset);
+  return nOldCharset;
+}
+
+void CPWL_EditImpl::AddEditUndoItem(
+    std::unique_ptr<IFX_Edit_UndoItem> pEditUndoItem) {
+  m_Undo.AddItem(std::move(pEditUndoItem));
+}
+
+ByteString CPWL_EditImpl::GetPDFWordString(int32_t nFontIndex,
+                                           uint16_t Word,
+                                           uint16_t SubWord) {
+  IPVT_FontMap* pFontMap = GetFontMap();
+  CPDF_Font* pPDFFont = pFontMap->GetPDFFont(nFontIndex);
+  if (!pPDFFont)
+    return ByteString();
+
+  ByteString sWord;
+  if (SubWord > 0) {
+    Word = SubWord;
+  } else {
+    uint32_t dwCharCode = pPDFFont->IsUnicodeCompatible()
+                              ? pPDFFont->CharCodeFromUnicode(Word)
+                              : pFontMap->CharCodeFromUnicode(nFontIndex, Word);
+    if (dwCharCode > 0) {
+      pPDFFont->AppendChar(&sWord, dwCharCode);
+      return sWord;
+    }
+  }
+  pPDFFont->AppendChar(&sWord, Word);
+  return sWord;
+}
+
+CPWL_EditImpl_Select::CPWL_EditImpl_Select() {}
+
+CPWL_EditImpl_Select::CPWL_EditImpl_Select(const CPVT_WordRange& range) {
+  Set(range.BeginPos, range.EndPos);
+}
+
+CPVT_WordRange CPWL_EditImpl_Select::ConvertToWordRange() const {
+  return CPVT_WordRange(BeginPos, EndPos);
+}
+
+void CPWL_EditImpl_Select::Reset() {
+  BeginPos.Reset();
+  EndPos.Reset();
+}
+
+void CPWL_EditImpl_Select::Set(const CPVT_WordPlace& begin,
+                               const CPVT_WordPlace& end) {
+  BeginPos = begin;
+  EndPos = end;
+}
+
+void CPWL_EditImpl_Select::SetEndPos(const CPVT_WordPlace& end) {
+  EndPos = end;
+}
+
+bool CPWL_EditImpl_Select::IsEmpty() const {
+  return BeginPos == EndPos;
+}
diff --git a/fpdfsdk/pwl/cpwl_edit_impl.h b/fpdfsdk/pwl/cpwl_edit_impl.h
new file mode 100644
index 0000000..38477db
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_edit_impl.h
@@ -0,0 +1,439 @@
+// 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 FPDFSDK_PWL_CPWL_EDIT_IMPL_H_
+#define FPDFSDK_PWL_CPWL_EDIT_IMPL_H_
+
+#include <deque>
+#include <memory>
+#include <vector>
+
+#include "core/fpdfdoc/cpdf_variabletext.h"
+#include "core/fpdfdoc/cpvt_wordrange.h"
+#include "core/fxcrt/unowned_ptr.h"
+#include "core/fxge/fx_dib.h"
+
+#define FX_EDIT_ISLATINWORD(u)                  \
+  (u == 0x2D || (u <= 0x005A && u >= 0x0041) || \
+   (u <= 0x007A && u >= 0x0061) || (u <= 0x02AF && u >= 0x00C0))
+
+class CFFL_FormFiller;
+class CPWL_EditImpl;
+class CPWL_EditImpl_Iterator;
+class CPWL_EditImpl_Provider;
+class CFX_RenderDevice;
+class CFX_SystemHandler;
+class CPWL_Edit;
+class CPWL_EditCtrl;
+class IFX_Edit_UndoItem;
+
+struct CPWL_EditImpl_LineRect {
+  CPWL_EditImpl_LineRect(const CPVT_WordRange& wrLine,
+                         const CFX_FloatRect& rcLine)
+      : m_wrLine(wrLine), m_rcLine(rcLine) {}
+
+  CPVT_WordRange m_wrLine;
+  CFX_FloatRect m_rcLine;
+};
+
+class CPWL_EditImpl_Refresh {
+ public:
+  CPWL_EditImpl_Refresh();
+  ~CPWL_EditImpl_Refresh();
+
+  void BeginRefresh();
+  void Push(const CPVT_WordRange& linerange, const CFX_FloatRect& rect);
+  void NoAnalyse();
+  std::vector<CFX_FloatRect>* GetRefreshRects();
+  void EndRefresh();
+
+ private:
+  void Add(const CFX_FloatRect& new_rect);
+
+  std::vector<CPWL_EditImpl_LineRect> m_NewLineRects;
+  std::vector<CPWL_EditImpl_LineRect> m_OldLineRects;
+  std::vector<CFX_FloatRect> m_RefreshRects;
+};
+
+class CPWL_EditImpl_Select {
+ public:
+  CPWL_EditImpl_Select();
+  explicit CPWL_EditImpl_Select(const CPVT_WordRange& range);
+
+  void Reset();
+  void Set(const CPVT_WordPlace& begin, const CPVT_WordPlace& end);
+  void SetEndPos(const CPVT_WordPlace& end);
+
+  CPVT_WordRange ConvertToWordRange() const;
+  bool IsEmpty() const;
+
+  CPVT_WordPlace BeginPos;
+  CPVT_WordPlace EndPos;
+};
+
+class CPWL_EditImpl_Undo {
+ public:
+  CPWL_EditImpl_Undo();
+  ~CPWL_EditImpl_Undo();
+
+  void AddItem(std::unique_ptr<IFX_Edit_UndoItem> pItem);
+  void Undo();
+  void Redo();
+  bool CanUndo() const;
+  bool CanRedo() const;
+
+ private:
+  void RemoveHeads();
+  void RemoveTails();
+
+  std::deque<std::unique_ptr<IFX_Edit_UndoItem>> m_UndoItemStack;
+  size_t m_nCurUndoPos;
+  bool m_bWorking;
+};
+
+class IFX_Edit_UndoItem {
+ public:
+  virtual ~IFX_Edit_UndoItem() {}
+
+  virtual void Undo() = 0;
+  virtual void Redo() = 0;
+};
+
+class CFXEU_InsertWord : public IFX_Edit_UndoItem {
+ public:
+  CFXEU_InsertWord(CPWL_EditImpl* pEdit,
+                   const CPVT_WordPlace& wpOldPlace,
+                   const CPVT_WordPlace& wpNewPlace,
+                   uint16_t word,
+                   int32_t charset);
+  ~CFXEU_InsertWord() override;
+
+  // IFX_Edit_UndoItem:
+  void Redo() override;
+  void Undo() override;
+
+ private:
+  UnownedPtr<CPWL_EditImpl> m_pEdit;
+
+  CPVT_WordPlace m_wpOld;
+  CPVT_WordPlace m_wpNew;
+  uint16_t m_Word;
+  int32_t m_nCharset;
+};
+
+class CFXEU_InsertReturn : public IFX_Edit_UndoItem {
+ public:
+  CFXEU_InsertReturn(CPWL_EditImpl* pEdit,
+                     const CPVT_WordPlace& wpOldPlace,
+                     const CPVT_WordPlace& wpNewPlace);
+  ~CFXEU_InsertReturn() override;
+
+  // IFX_Edit_UndoItem:
+  void Redo() override;
+  void Undo() override;
+
+ private:
+  UnownedPtr<CPWL_EditImpl> m_pEdit;
+
+  CPVT_WordPlace m_wpOld;
+  CPVT_WordPlace m_wpNew;
+};
+
+class CFXEU_Backspace : public IFX_Edit_UndoItem {
+ public:
+  CFXEU_Backspace(CPWL_EditImpl* pEdit,
+                  const CPVT_WordPlace& wpOldPlace,
+                  const CPVT_WordPlace& wpNewPlace,
+                  uint16_t word,
+                  int32_t charset);
+  ~CFXEU_Backspace() override;
+
+  // IFX_Edit_UndoItem:
+  void Redo() override;
+  void Undo() override;
+
+ private:
+  UnownedPtr<CPWL_EditImpl> m_pEdit;
+
+  CPVT_WordPlace m_wpOld;
+  CPVT_WordPlace m_wpNew;
+  uint16_t m_Word;
+  int32_t m_nCharset;
+};
+
+class CFXEU_Delete : public IFX_Edit_UndoItem {
+ public:
+  CFXEU_Delete(CPWL_EditImpl* pEdit,
+               const CPVT_WordPlace& wpOldPlace,
+               const CPVT_WordPlace& wpNewPlace,
+               uint16_t word,
+               int32_t charset,
+               bool bSecEnd);
+  ~CFXEU_Delete() override;
+
+  // IFX_Edit_UndoItem:
+  void Redo() override;
+  void Undo() override;
+
+ private:
+  UnownedPtr<CPWL_EditImpl> m_pEdit;
+
+  CPVT_WordPlace m_wpOld;
+  CPVT_WordPlace m_wpNew;
+  uint16_t m_Word;
+  int32_t m_nCharset;
+  bool m_bSecEnd;
+};
+
+class CFXEU_Clear : public IFX_Edit_UndoItem {
+ public:
+  CFXEU_Clear(CPWL_EditImpl* pEdit,
+              const CPVT_WordRange& wrSel,
+              const WideString& swText);
+  ~CFXEU_Clear() override;
+
+  // IFX_Edit_UndoItem:
+  void Redo() override;
+  void Undo() override;
+
+ private:
+  UnownedPtr<CPWL_EditImpl> m_pEdit;
+
+  CPVT_WordRange m_wrSel;
+  WideString m_swText;
+};
+
+class CFXEU_InsertText : public IFX_Edit_UndoItem {
+ public:
+  CFXEU_InsertText(CPWL_EditImpl* pEdit,
+                   const CPVT_WordPlace& wpOldPlace,
+                   const CPVT_WordPlace& wpNewPlace,
+                   const WideString& swText,
+                   int32_t charset);
+  ~CFXEU_InsertText() override;
+
+  // IFX_Edit_UndoItem:
+  void Redo() override;
+  void Undo() override;
+
+ private:
+  UnownedPtr<CPWL_EditImpl> m_pEdit;
+
+  CPVT_WordPlace m_wpOld;
+  CPVT_WordPlace m_wpNew;
+  WideString m_swText;
+  int32_t m_nCharset;
+};
+
+class CPWL_EditImpl {
+ public:
+  static void DrawEdit(CFX_RenderDevice* pDevice,
+                       const CFX_Matrix& mtUser2Device,
+                       CPWL_EditImpl* pEdit,
+                       FX_COLORREF crTextFill,
+                       const CFX_FloatRect& rcClip,
+                       const CFX_PointF& ptOffset,
+                       const CPVT_WordRange* pRange,
+                       CFX_SystemHandler* pSystemHandler,
+                       CFFL_FormFiller* pFFLData);
+
+  CPWL_EditImpl();
+  ~CPWL_EditImpl();
+
+  void SetFontMap(IPVT_FontMap* pFontMap);
+  void SetNotify(CPWL_EditCtrl* pNotify);
+  void SetOperationNotify(CPWL_Edit* pOperationNotify);
+
+  // Returns an iterator for the contents. Should not be released.
+  CPWL_EditImpl_Iterator* GetIterator();
+  IPVT_FontMap* GetFontMap();
+  void Initialize();
+
+  // Set the bounding box of the text area.
+  void SetPlateRect(const CFX_FloatRect& rect);
+  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);
+  // Set the vertical text alignment. (nFormat [0:left, 1:middle, 2:right])
+  void SetAlignmentV(int32_t nFormat, bool bPaint);
+
+  // Set the substitution character for hidden text.
+  void SetPasswordChar(uint16_t wSubWord, bool bPaint);
+
+  // Set the maximum number of words in the text.
+  void SetLimitChar(int32_t nLimitChar);
+  void SetCharArray(int32_t nCharArray);
+  void SetCharSpace(float fCharSpace);
+  void SetMultiLine(bool bMultiLine, bool bPaint);
+  void SetAutoReturn(bool bAuto, bool bPaint);
+  void SetAutoFontSize(bool bAuto, bool bPaint);
+  void SetAutoScroll(bool bAuto, bool bPaint);
+  void SetFontSize(float fFontSize);
+  void SetTextOverflow(bool bAllowed, bool bPaint);
+  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);
+  void OnVK_RIGHT(bool bShift, bool bCtrl);
+  void OnVK_HOME(bool bShift, bool bCtrl);
+  void OnVK_END(bool bShift, bool bCtrl);
+  void SetText(const WideString& sText);
+  bool InsertWord(uint16_t word, int32_t charset);
+  bool InsertReturn();
+  bool Backspace();
+  bool Delete();
+  bool ClearSelection();
+  bool InsertText(const WideString& sText, int32_t charset);
+  bool Redo();
+  bool Undo();
+  CPVT_WordPlace WordIndexToWordPlace(int32_t index) const;
+  CPVT_WordPlace SearchWordPlace(const CFX_PointF& point) const;
+  int32_t GetCaret() const;
+  CPVT_WordPlace GetCaretWordPlace() const;
+  WideString GetSelectedText() const;
+  WideString GetText() const;
+  float GetFontSize() const;
+  uint16_t GetPasswordChar() const;
+  CFX_PointF GetScrollPos() const;
+  int32_t GetCharArray() const;
+  CFX_FloatRect GetContentRect() const;
+  WideString GetRangeText(const CPVT_WordRange& range) const;
+  int32_t GetHorzScale() const;
+  float GetCharSpace() const;
+  void SetSelection(int32_t nStartChar, int32_t nEndChar);
+  void GetSelection(int32_t& nStartChar, int32_t& nEndChar) const;
+  void SelectAll();
+  void SelectNone();
+  bool IsSelected() const;
+  void Paint();
+  void EnableRefresh(bool bRefresh);
+  void RefreshWordRange(const CPVT_WordRange& wr);
+  CPVT_WordRange GetWholeWordRange() const;
+  CPVT_WordRange GetSelectWordRange() const;
+  void EnableUndo(bool bUndo);
+  bool IsTextFull() const;
+  bool IsTextOverflow() const;
+  bool CanUndo() const;
+  bool CanRedo() const;
+  CPVT_WordRange GetVisibleWordRange() const;
+
+  bool Empty();
+
+  CPVT_WordPlace DoInsertText(const CPVT_WordPlace& place,
+                              const WideString& sText,
+                              int32_t charset);
+  int32_t GetCharSetFromUnicode(uint16_t word, int32_t nOldCharset);
+
+  int32_t GetTotalLines() const;
+
+  ByteString GetPDFWordString(int32_t nFontIndex,
+                              uint16_t Word,
+                              uint16_t SubWord);
+
+  void SetSelection(const CPVT_WordPlace& begin, const CPVT_WordPlace& end);
+
+  bool Delete(bool bAddUndo, bool bPaint);
+  bool Clear(bool bAddUndo, bool bPaint);
+  bool InsertText(const WideString& sText,
+                  int32_t charset,
+                  bool bAddUndo,
+                  bool bPaint);
+  bool InsertWord(uint16_t word, int32_t charset, bool bAddUndo, bool bPaint);
+  bool InsertReturn(bool bAddUndo, bool bPaint);
+  bool Backspace(bool bAddUndo, bool bPaint);
+  void SetCaret(const CPVT_WordPlace& place);
+
+  CFX_PointF VTToEdit(const CFX_PointF& point) const;
+
+ private:
+  void RearrangeAll();
+  void RearrangePart(const CPVT_WordRange& range);
+  void ScrollToCaret();
+  void SetScrollInfo();
+  void SetScrollPosX(float fx);
+  void SetScrollPosY(float fy);
+  void SetScrollLimit();
+  void SetContentChanged();
+
+  void PaintInsertText(const CPVT_WordPlace& wpOld,
+                       const CPVT_WordPlace& wpNew);
+
+  CFX_PointF EditToVT(const CFX_PointF& point) const;
+  CFX_FloatRect VTToEdit(const CFX_FloatRect& rect) const;
+
+  void Refresh();
+  void RefreshPushLineRects(const CPVT_WordRange& wr);
+
+  void SetCaretInfo();
+  void SetCaretOrigin();
+
+  void AddEditUndoItem(std::unique_ptr<IFX_Edit_UndoItem> pEditUndoItem);
+
+  std::unique_ptr<CPDF_VariableText> m_pVT;
+  UnownedPtr<CPWL_EditCtrl> m_pNotify;
+  UnownedPtr<CPWL_Edit> m_pOperationNotify;
+  std::unique_ptr<CPWL_EditImpl_Provider> m_pVTProvider;
+  CPVT_WordPlace m_wpCaret;
+  CPVT_WordPlace m_wpOldCaret;
+  CPWL_EditImpl_Select m_SelState;
+  CFX_PointF m_ptScrollPos;
+  CFX_PointF m_ptRefreshScrollPos;
+  bool m_bEnableScroll;
+  std::unique_ptr<CPWL_EditImpl_Iterator> m_pIterator;
+  CPWL_EditImpl_Refresh m_Refresh;
+  CFX_PointF m_ptCaret;
+  CPWL_EditImpl_Undo m_Undo;
+  int32_t m_nAlignment;
+  bool m_bNotifyFlag;
+  bool m_bEnableOverflow;
+  bool m_bEnableRefresh;
+  CFX_FloatRect m_rcOldContent;
+  bool m_bEnableUndo;
+};
+
+class CPWL_EditImpl_Iterator {
+ public:
+  CPWL_EditImpl_Iterator(CPWL_EditImpl* pEdit,
+                         CPDF_VariableText::Iterator* pVTIterator);
+  ~CPWL_EditImpl_Iterator();
+
+  bool NextWord();
+  bool PrevWord();
+  bool GetWord(CPVT_Word& word) const;
+  bool GetLine(CPVT_Line& line) const;
+  void SetAt(int32_t nWordIndex);
+  void SetAt(const CPVT_WordPlace& place);
+  const CPVT_WordPlace& GetAt() const;
+
+ private:
+  UnownedPtr<CPWL_EditImpl> m_pEdit;
+  CPDF_VariableText::Iterator* m_pVTIterator;
+};
+
+class CPWL_EditImpl_Provider : public CPDF_VariableText::Provider {
+ public:
+  explicit CPWL_EditImpl_Provider(IPVT_FontMap* pFontMap);
+  ~CPWL_EditImpl_Provider() override;
+
+  IPVT_FontMap* GetFontMap() const;
+
+  // CPDF_VariableText::Provider:
+  int32_t GetCharWidth(int32_t nFontIndex, uint16_t word) override;
+  int32_t GetTypeAscent(int32_t nFontIndex) override;
+  int32_t GetTypeDescent(int32_t nFontIndex) override;
+  int32_t GetWordFontIndex(uint16_t word,
+                           int32_t charset,
+                           int32_t nFontIndex) override;
+  int32_t GetDefaultFontIndex() override;
+  bool IsLatinWord(uint16_t word) override;
+
+ private:
+  IPVT_FontMap* m_pFontMap;
+};
+
+#endif  // FPDFSDK_PWL_CPWL_EDIT_IMPL_H_
diff --git a/fpdfsdk/pwl/cpwl_font_map.cpp b/fpdfsdk/pwl/cpwl_font_map.cpp
new file mode 100644
index 0000000..5e5556e
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_font_map.cpp
@@ -0,0 +1,408 @@
+// 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/pwl/cpwl_font_map.h"
+
+#include <utility>
+
+#include "core/fpdfapi/cpdf_modulemgr.h"
+#include "core/fpdfapi/font/cpdf_font.h"
+#include "core/fpdfapi/font/cpdf_fontencoding.h"
+#include "core/fpdfapi/parser/cpdf_document.h"
+#include "core/fpdfapi/parser/cpdf_parser.h"
+#include "core/fpdfdoc/ipvt_fontmap.h"
+#include "core/fxcrt/fx_codepage.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
+#include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
+
+namespace {
+
+const char kDefaultFontName[] = "Helvetica";
+
+const char* const g_sDEStandardFontName[] = {"Courier",
+                                             "Courier-Bold",
+                                             "Courier-BoldOblique",
+                                             "Courier-Oblique",
+                                             "Helvetica",
+                                             "Helvetica-Bold",
+                                             "Helvetica-BoldOblique",
+                                             "Helvetica-Oblique",
+                                             "Times-Roman",
+                                             "Times-Bold",
+                                             "Times-Italic",
+                                             "Times-BoldItalic",
+                                             "Symbol",
+                                             "ZapfDingbats"};
+
+}  // namespace
+
+CPWL_FontMap::CPWL_FontMap(CFX_SystemHandler* pSystemHandler)
+    : m_pSystemHandler(pSystemHandler) {
+  ASSERT(m_pSystemHandler);
+}
+
+CPWL_FontMap::~CPWL_FontMap() {
+  Empty();
+}
+
+CPDF_Document* CPWL_FontMap::GetDocument() {
+  if (!m_pPDFDoc) {
+    if (CPDF_ModuleMgr::Get()) {
+      m_pPDFDoc = pdfium::MakeUnique<CPDF_Document>(nullptr);
+      m_pPDFDoc->CreateNewDoc();
+    }
+  }
+  return m_pPDFDoc.get();
+}
+
+CPDF_Font* CPWL_FontMap::GetPDFFont(int32_t nFontIndex) {
+  if (pdfium::IndexInBounds(m_Data, nFontIndex) && m_Data[nFontIndex])
+    return m_Data[nFontIndex]->pFont;
+
+  return nullptr;
+}
+
+ByteString CPWL_FontMap::GetPDFFontAlias(int32_t nFontIndex) {
+  if (pdfium::IndexInBounds(m_Data, nFontIndex) && m_Data[nFontIndex])
+    return m_Data[nFontIndex]->sFontName;
+
+  return ByteString();
+}
+
+bool CPWL_FontMap::KnowWord(int32_t nFontIndex, uint16_t word) {
+  return pdfium::IndexInBounds(m_Data, nFontIndex) && m_Data[nFontIndex] &&
+         CharCodeFromUnicode(nFontIndex, word) >= 0;
+}
+
+int32_t CPWL_FontMap::GetWordFontIndex(uint16_t word,
+                                       int32_t nCharset,
+                                       int32_t nFontIndex) {
+  if (nFontIndex > 0) {
+    if (KnowWord(nFontIndex, word))
+      return nFontIndex;
+  } else {
+    if (const CPWL_FontMap_Data* pData = GetFontMapData(0)) {
+      if (nCharset == FX_CHARSET_Default ||
+          pData->nCharset == FX_CHARSET_Symbol || nCharset == pData->nCharset) {
+        if (KnowWord(0, word))
+          return 0;
+      }
+    }
+  }
+
+  int32_t nNewFontIndex =
+      GetFontIndex(GetNativeFontName(nCharset), nCharset, true);
+  if (nNewFontIndex >= 0) {
+    if (KnowWord(nNewFontIndex, word))
+      return nNewFontIndex;
+  }
+  nNewFontIndex = GetFontIndex("Arial Unicode MS", FX_CHARSET_Default, false);
+  if (nNewFontIndex >= 0) {
+    if (KnowWord(nNewFontIndex, word))
+      return nNewFontIndex;
+  }
+  return -1;
+}
+
+int32_t CPWL_FontMap::CharCodeFromUnicode(int32_t nFontIndex, uint16_t word) {
+  if (!pdfium::IndexInBounds(m_Data, nFontIndex))
+    return -1;
+
+  CPWL_FontMap_Data* pData = m_Data[nFontIndex].get();
+  if (!pData || !pData->pFont)
+    return -1;
+
+  if (pData->pFont->IsUnicodeCompatible())
+    return pData->pFont->CharCodeFromUnicode(word);
+
+  return word < 0xFF ? word : -1;
+}
+
+ByteString CPWL_FontMap::GetNativeFontName(int32_t nCharset) {
+  for (const auto& pData : m_NativeFont) {
+    if (pData && pData->nCharset == nCharset)
+      return pData->sFontName;
+  }
+
+  ByteString sNew = GetNativeFont(nCharset);
+  if (sNew.IsEmpty())
+    return ByteString();
+
+  auto pNewData = pdfium::MakeUnique<CPWL_FontMap_Native>();
+  pNewData->nCharset = nCharset;
+  pNewData->sFontName = sNew;
+  m_NativeFont.push_back(std::move(pNewData));
+  return sNew;
+}
+
+void CPWL_FontMap::Empty() {
+  m_Data.clear();
+  m_NativeFont.clear();
+}
+
+void CPWL_FontMap::Initialize() {
+  GetFontIndex(kDefaultFontName, FX_CHARSET_ANSI, false);
+}
+
+bool CPWL_FontMap::IsStandardFont(const ByteString& sFontName) {
+  for (const char* name : g_sDEStandardFontName) {
+    if (sFontName == name)
+      return true;
+  }
+
+  return false;
+}
+
+int32_t CPWL_FontMap::FindFont(const ByteString& sFontName, int32_t nCharset) {
+  int32_t i = 0;
+  for (const auto& pData : m_Data) {
+    if (pData &&
+        (nCharset == FX_CHARSET_Default || nCharset == pData->nCharset) &&
+        (sFontName.IsEmpty() || pData->sFontName == sFontName)) {
+      return i;
+    }
+    ++i;
+  }
+  return -1;
+}
+
+int32_t CPWL_FontMap::GetFontIndex(const ByteString& sFontName,
+                                   int32_t nCharset,
+                                   bool bFind) {
+  int32_t nFontIndex = FindFont(EncodeFontAlias(sFontName, nCharset), nCharset);
+  if (nFontIndex >= 0)
+    return nFontIndex;
+
+  ByteString sAlias;
+  CPDF_Font* pFont = bFind ? FindFontSameCharset(&sAlias, nCharset) : nullptr;
+  if (!pFont) {
+    ByteString sTemp = sFontName;
+    pFont = AddFontToDocument(GetDocument(), sTemp, nCharset);
+    sAlias = EncodeFontAlias(sTemp, nCharset);
+  }
+  AddedFont(pFont, sAlias);
+  return AddFontData(pFont, sAlias, nCharset);
+}
+
+CPDF_Font* CPWL_FontMap::FindFontSameCharset(ByteString* sFontAlias,
+                                             int32_t nCharset) {
+  return nullptr;
+}
+
+int32_t CPWL_FontMap::AddFontData(CPDF_Font* pFont,
+                                  const ByteString& sFontAlias,
+                                  int32_t nCharset) {
+  auto pNewData = pdfium::MakeUnique<CPWL_FontMap_Data>();
+  pNewData->pFont = pFont;
+  pNewData->sFontName = sFontAlias;
+  pNewData->nCharset = nCharset;
+  m_Data.push_back(std::move(pNewData));
+  return pdfium::CollectionSize<int32_t>(m_Data) - 1;
+}
+
+void CPWL_FontMap::AddedFont(CPDF_Font* pFont, const ByteString& sFontAlias) {}
+
+ByteString CPWL_FontMap::GetNativeFont(int32_t nCharset) {
+  if (nCharset == FX_CHARSET_Default)
+    nCharset = GetNativeCharset();
+
+  ByteString sFontName = GetDefaultFontByCharset(nCharset);
+  if (!m_pSystemHandler->FindNativeTrueTypeFont(sFontName))
+    return ByteString();
+
+  return sFontName;
+}
+
+CPDF_Font* CPWL_FontMap::AddFontToDocument(CPDF_Document* pDoc,
+                                           ByteString& sFontName,
+                                           uint8_t nCharset) {
+  if (IsStandardFont(sFontName))
+    return AddStandardFont(pDoc, sFontName);
+
+  return AddSystemFont(pDoc, sFontName, nCharset);
+}
+
+CPDF_Font* CPWL_FontMap::AddStandardFont(CPDF_Document* pDoc,
+                                         ByteString& sFontName) {
+  if (!pDoc)
+    return nullptr;
+
+  CPDF_Font* pFont = nullptr;
+
+  if (sFontName == "ZapfDingbats") {
+    pFont = pDoc->AddStandardFont(sFontName.c_str(), nullptr);
+  } else {
+    CPDF_FontEncoding fe(PDFFONT_ENCODING_WINANSI);
+    pFont = pDoc->AddStandardFont(sFontName.c_str(), &fe);
+  }
+
+  return pFont;
+}
+
+CPDF_Font* CPWL_FontMap::AddSystemFont(CPDF_Document* pDoc,
+                                       ByteString& sFontName,
+                                       uint8_t nCharset) {
+  if (!pDoc)
+    return nullptr;
+
+  if (sFontName.IsEmpty())
+    sFontName = GetNativeFont(nCharset);
+  if (nCharset == FX_CHARSET_Default)
+    nCharset = GetNativeCharset();
+
+  return m_pSystemHandler->AddNativeTrueTypeFontToPDF(pDoc, sFontName,
+                                                      nCharset);
+}
+
+ByteString CPWL_FontMap::EncodeFontAlias(const ByteString& sFontName,
+                                         int32_t nCharset) {
+  return EncodeFontAlias(sFontName) + ByteString::Format("_%02X", nCharset);
+}
+
+ByteString CPWL_FontMap::EncodeFontAlias(const ByteString& sFontName) {
+  ByteString sRet = sFontName;
+  sRet.Remove(' ');
+  return sRet;
+}
+
+const CPWL_FontMap_Data* CPWL_FontMap::GetFontMapData(int32_t nIndex) const {
+  return pdfium::IndexInBounds(m_Data, nIndex) ? m_Data[nIndex].get() : nullptr;
+}
+
+int32_t CPWL_FontMap::GetNativeCharset() {
+  uint8_t nCharset = FX_CHARSET_ANSI;
+  int32_t iCodePage = FXSYS_GetACP();
+  switch (iCodePage) {
+    case FX_CODEPAGE_ShiftJIS:
+      nCharset = FX_CHARSET_ShiftJIS;
+      break;
+    case FX_CODEPAGE_ChineseSimplified:
+      nCharset = FX_CHARSET_ChineseSimplified;
+      break;
+    case FX_CODEPAGE_ChineseTraditional:
+      nCharset = FX_CHARSET_ChineseTraditional;
+      break;
+    case FX_CODEPAGE_MSWin_WesternEuropean:
+      nCharset = FX_CHARSET_ANSI;
+      break;
+    case FX_CODEPAGE_MSDOS_Thai:
+      nCharset = FX_CHARSET_Thai;
+      break;
+    case FX_CODEPAGE_Hangul:
+      nCharset = FX_CHARSET_Hangul;
+      break;
+    case FX_CODEPAGE_UTF16LE:
+      nCharset = FX_CHARSET_ANSI;
+      break;
+    case FX_CODEPAGE_MSWin_EasternEuropean:
+      nCharset = FX_CHARSET_MSWin_EasternEuropean;
+      break;
+    case FX_CODEPAGE_MSWin_Cyrillic:
+      nCharset = FX_CHARSET_MSWin_Cyrillic;
+      break;
+    case FX_CODEPAGE_MSWin_Greek:
+      nCharset = FX_CHARSET_MSWin_Greek;
+      break;
+    case FX_CODEPAGE_MSWin_Turkish:
+      nCharset = FX_CHARSET_MSWin_Turkish;
+      break;
+    case FX_CODEPAGE_MSWin_Hebrew:
+      nCharset = FX_CHARSET_MSWin_Hebrew;
+      break;
+    case FX_CODEPAGE_MSWin_Arabic:
+      nCharset = FX_CHARSET_MSWin_Arabic;
+      break;
+    case FX_CODEPAGE_MSWin_Baltic:
+      nCharset = FX_CHARSET_MSWin_Baltic;
+      break;
+    case FX_CODEPAGE_MSWin_Vietnamese:
+      nCharset = FX_CHARSET_MSWin_Vietnamese;
+      break;
+    case FX_CODEPAGE_Johab:
+      nCharset = FX_CHARSET_Johab;
+      break;
+  }
+  return nCharset;
+}
+
+const FPDF_CharsetFontMap CPWL_FontMap::defaultTTFMap[] = {
+    {FX_CHARSET_ANSI, "Helvetica"},
+    {FX_CHARSET_ChineseSimplified, "SimSun"},
+    {FX_CHARSET_ChineseTraditional, "MingLiU"},
+    {FX_CHARSET_ShiftJIS, "MS Gothic"},
+    {FX_CHARSET_Hangul, "Batang"},
+    {FX_CHARSET_MSWin_Cyrillic, "Arial"},
+#if _FX_PLATFORM_ == _FX_PLATFORM_LINUX_ || _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+    {FX_CHARSET_MSWin_EasternEuropean, "Arial"},
+#else
+    {FX_CHARSET_MSWin_EasternEuropean, "Tahoma"},
+#endif
+    {FX_CHARSET_MSWin_Arabic, "Arial"},
+    {-1, nullptr}};
+
+ByteString CPWL_FontMap::GetDefaultFontByCharset(int32_t nCharset) {
+  int i = 0;
+  while (defaultTTFMap[i].charset != -1) {
+    if (nCharset == defaultTTFMap[i].charset)
+      return defaultTTFMap[i].fontname;
+    ++i;
+  }
+  return "";
+}
+
+int32_t CPWL_FontMap::CharSetFromUnicode(uint16_t word, int32_t nOldCharset) {
+  // to avoid CJK Font to show ASCII
+  if (word < 0x7F)
+    return FX_CHARSET_ANSI;
+  // follow the old charset
+  if (nOldCharset != FX_CHARSET_Default)
+    return nOldCharset;
+
+  // find new charset
+  if ((word >= 0x4E00 && word <= 0x9FA5) ||
+      (word >= 0xE7C7 && word <= 0xE7F3) ||
+      (word >= 0x3000 && word <= 0x303F) ||
+      (word >= 0x2000 && word <= 0x206F)) {
+    return FX_CHARSET_ChineseSimplified;
+  }
+
+  if (((word >= 0x3040) && (word <= 0x309F)) ||
+      ((word >= 0x30A0) && (word <= 0x30FF)) ||
+      ((word >= 0x31F0) && (word <= 0x31FF)) ||
+      ((word >= 0xFF00) && (word <= 0xFFEF))) {
+    return FX_CHARSET_ShiftJIS;
+  }
+
+  if (((word >= 0xAC00) && (word <= 0xD7AF)) ||
+      ((word >= 0x1100) && (word <= 0x11FF)) ||
+      ((word >= 0x3130) && (word <= 0x318F))) {
+    return FX_CHARSET_Hangul;
+  }
+
+  if (word >= 0x0E00 && word <= 0x0E7F)
+    return FX_CHARSET_Thai;
+
+  if ((word >= 0x0370 && word <= 0x03FF) || (word >= 0x1F00 && word <= 0x1FFF))
+    return FX_CHARSET_MSWin_Greek;
+
+  if ((word >= 0x0600 && word <= 0x06FF) || (word >= 0xFB50 && word <= 0xFEFC))
+    return FX_CHARSET_MSWin_Arabic;
+
+  if (word >= 0x0590 && word <= 0x05FF)
+    return FX_CHARSET_MSWin_Hebrew;
+
+  if (word >= 0x0400 && word <= 0x04FF)
+    return FX_CHARSET_MSWin_Cyrillic;
+
+  if (word >= 0x0100 && word <= 0x024F)
+    return FX_CHARSET_MSWin_EasternEuropean;
+
+  if (word >= 0x1E00 && word <= 0x1EFF)
+    return FX_CHARSET_MSWin_Vietnamese;
+
+  return FX_CHARSET_ANSI;
+}
diff --git a/fpdfsdk/pwl/cpwl_font_map.h b/fpdfsdk/pwl/cpwl_font_map.h
new file mode 100644
index 0000000..592c3fa
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_font_map.h
@@ -0,0 +1,93 @@
+// 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 FPDFSDK_PWL_CPWL_FONT_MAP_H_
+#define FPDFSDK_PWL_CPWL_FONT_MAP_H_
+
+#include <memory>
+#include <vector>
+
+#include "core/fpdfdoc/ipvt_fontmap.h"
+#include "core/fxcrt/fx_codepage.h"
+#include "public/fpdf_sysfontinfo.h"
+
+class CPDF_Document;
+class CFX_SystemHandler;
+
+struct CPWL_FontMap_Data {
+  CPDF_Font* pFont;
+  int32_t nCharset;
+  ByteString sFontName;
+};
+
+struct CPWL_FontMap_Native {
+  int32_t nCharset;
+  ByteString sFontName;
+};
+
+class CPWL_FontMap : public IPVT_FontMap {
+ public:
+  explicit CPWL_FontMap(CFX_SystemHandler* pSystemHandler);
+  ~CPWL_FontMap() override;
+
+  // IPVT_FontMap
+  CPDF_Font* GetPDFFont(int32_t nFontIndex) override;
+  ByteString GetPDFFontAlias(int32_t nFontIndex) override;
+  int32_t GetWordFontIndex(uint16_t word,
+                           int32_t nCharset,
+                           int32_t nFontIndex) override;
+  int32_t CharCodeFromUnicode(int32_t nFontIndex, uint16_t word) override;
+  int32_t CharSetFromUnicode(uint16_t word, int32_t nOldCharset) override;
+
+  const CPWL_FontMap_Data* GetFontMapData(int32_t nIndex) const;
+  static int32_t GetNativeCharset();
+  ByteString GetNativeFontName(int32_t nCharset);
+
+  static ByteString GetDefaultFontByCharset(int32_t nCharset);
+  static const FPDF_CharsetFontMap defaultTTFMap[];
+
+ protected:
+  virtual void Initialize();
+  virtual CPDF_Document* GetDocument();
+  virtual CPDF_Font* FindFontSameCharset(ByteString* sFontAlias,
+                                         int32_t nCharset);
+  virtual void AddedFont(CPDF_Font* pFont, const ByteString& sFontAlias);
+
+  bool KnowWord(int32_t nFontIndex, uint16_t word);
+
+  void Empty();
+  int32_t GetFontIndex(const ByteString& sFontName,
+                       int32_t nCharset,
+                       bool bFind);
+  int32_t AddFontData(CPDF_Font* pFont,
+                      const ByteString& sFontAlias,
+                      int32_t nCharset = FX_CHARSET_Default);
+
+  ByteString EncodeFontAlias(const ByteString& sFontName, int32_t nCharset);
+  ByteString EncodeFontAlias(const ByteString& sFontName);
+
+  std::vector<std::unique_ptr<CPWL_FontMap_Data>> m_Data;
+  std::vector<std::unique_ptr<CPWL_FontMap_Native>> m_NativeFont;
+
+ private:
+  int32_t FindFont(const ByteString& sFontName,
+                   int32_t nCharset = FX_CHARSET_Default);
+
+  ByteString GetNativeFont(int32_t nCharset);
+  CPDF_Font* AddFontToDocument(CPDF_Document* pDoc,
+                               ByteString& sFontName,
+                               uint8_t nCharset);
+  bool IsStandardFont(const ByteString& sFontName);
+  CPDF_Font* AddStandardFont(CPDF_Document* pDoc, ByteString& sFontName);
+  CPDF_Font* AddSystemFont(CPDF_Document* pDoc,
+                           ByteString& sFontName,
+                           uint8_t nCharset);
+
+  std::unique_ptr<CPDF_Document> m_pPDFDoc;
+  UnownedPtr<CFX_SystemHandler> const m_pSystemHandler;
+};
+
+#endif  // FPDFSDK_PWL_CPWL_FONT_MAP_H_
diff --git a/fpdfsdk/pwl/cpwl_icon.cpp b/fpdfsdk/pwl/cpwl_icon.cpp
new file mode 100644
index 0000000..e7669b3
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_icon.cpp
@@ -0,0 +1,131 @@
+// 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/pwl/cpwl_icon.h"
+
+#include <algorithm>
+#include <sstream>
+
+#include "core/fpdfapi/parser/cpdf_array.h"
+#include "core/fpdfapi/parser/cpdf_stream.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
+
+CPWL_Icon::CPWL_Icon() : m_pPDFStream(nullptr), m_pIconFit(nullptr) {}
+
+CPWL_Icon::~CPWL_Icon() {}
+
+std::pair<float, float> CPWL_Icon::GetImageSize() {
+  if (!m_pPDFStream)
+    return {0.0f, 0.0f};
+
+  CPDF_Dictionary* pDict = m_pPDFStream->GetDict();
+  if (!pDict)
+    return {0.0f, 0.0f};
+
+  CFX_FloatRect rect = pDict->GetRectFor("BBox");
+  return {rect.right - rect.left, rect.top - rect.bottom};
+}
+
+CFX_Matrix CPWL_Icon::GetImageMatrix() {
+  if (!m_pPDFStream)
+    return CFX_Matrix();
+  if (CPDF_Dictionary* pDict = m_pPDFStream->GetDict())
+    return pDict->GetMatrixFor("Matrix");
+  return CFX_Matrix();
+}
+
+ByteString CPWL_Icon::GetImageAlias() {
+  if (!m_pPDFStream)
+    return ByteString();
+  if (CPDF_Dictionary* pDict = m_pPDFStream->GetDict())
+    return pDict->GetStringFor("Name");
+  return ByteString();
+}
+
+std::pair<float, float> CPWL_Icon::GetIconPosition() {
+  if (!m_pIconFit)
+    return {0.0f, 0.0f};
+
+  CPDF_Array* pA =
+      m_pIconFit->GetDict() ? m_pIconFit->GetDict()->GetArrayFor("A") : nullptr;
+  if (!pA)
+    return {0.0f, 0.0f};
+
+  size_t dwCount = pA->GetCount();
+  return {dwCount > 0 ? pA->GetNumberAt(0) : 0.0f,
+          dwCount > 1 ? pA->GetNumberAt(1) : 0.0f};
+}
+
+std::pair<float, float> CPWL_Icon::GetScale() {
+  float fHScale = 1.0f;
+  float fVScale = 1.0f;
+
+  if (!m_pPDFStream)
+    return {fHScale, fVScale};
+
+  CFX_FloatRect rcPlate = GetClientRect();
+  float fPlateWidth = rcPlate.right - rcPlate.left;
+  float fPlateHeight = rcPlate.top - rcPlate.bottom;
+
+  float fImageWidth;
+  float fImageHeight;
+  std::tie(fImageWidth, fImageHeight) = GetImageSize();
+
+  int32_t nScaleMethod = m_pIconFit ? m_pIconFit->GetScaleMethod() : 0;
+
+  switch (nScaleMethod) {
+    default:
+    case 0:
+      fHScale = fPlateWidth / std::max(fImageWidth, 1.0f);
+      fVScale = fPlateHeight / std::max(fImageHeight, 1.0f);
+      break;
+    case 1:
+      if (fPlateWidth < fImageWidth)
+        fHScale = fPlateWidth / std::max(fImageWidth, 1.0f);
+      if (fPlateHeight < fImageHeight)
+        fVScale = fPlateHeight / std::max(fImageHeight, 1.0f);
+      break;
+    case 2:
+      if (fPlateWidth > fImageWidth)
+        fHScale = fPlateWidth / std::max(fImageWidth, 1.0f);
+      if (fPlateHeight > fImageHeight)
+        fVScale = fPlateHeight / std::max(fImageHeight, 1.0f);
+      break;
+    case 3:
+      break;
+  }
+
+  float fMinScale;
+  if (m_pIconFit && m_pIconFit->IsProportionalScale()) {
+    fMinScale = std::min(fHScale, fVScale);
+    fHScale = fMinScale;
+    fVScale = fMinScale;
+  }
+  return {fHScale, fVScale};
+}
+
+std::pair<float, float> CPWL_Icon::GetImageOffset() {
+  float fLeft;
+  float fBottom;
+  std::tie(fLeft, fBottom) = GetIconPosition();
+
+  float fImageWidth;
+  float fImageHeight;
+  std::tie(fImageWidth, fImageHeight) = GetImageSize();
+
+  float fHScale, fVScale;
+  std::tie(fHScale, fVScale) = GetScale();
+
+  float fImageFactWidth = fImageWidth * fHScale;
+  float fImageFactHeight = fImageHeight * fVScale;
+
+  CFX_FloatRect rcPlate = GetClientRect();
+  float fPlateWidth = rcPlate.right - rcPlate.left;
+  float fPlateHeight = rcPlate.top - rcPlate.bottom;
+
+  return {(fPlateWidth - fImageFactWidth) * fLeft,
+          (fPlateHeight - fImageFactHeight) * fBottom};
+}
diff --git a/fpdfsdk/pwl/cpwl_icon.h b/fpdfsdk/pwl/cpwl_icon.h
new file mode 100644
index 0000000..df88465
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_icon.h
@@ -0,0 +1,44 @@
+// 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 FPDFSDK_PWL_CPWL_ICON_H_
+#define FPDFSDK_PWL_CPWL_ICON_H_
+
+#include <utility>
+
+#include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/unowned_ptr.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
+
+class CPWL_Icon : public CPWL_Wnd {
+ public:
+  CPWL_Icon();
+  ~CPWL_Icon() override;
+
+  void SetIconFit(CPDF_IconFit* pIconFit) { m_pIconFit = pIconFit; }
+  void SetPDFStream(CPDF_Stream* pStream) { m_pPDFStream = pStream; }
+
+  // horizontal scale, vertical scale
+  std::pair<float, float> GetScale();
+
+  // x, y
+  std::pair<float, float> GetImageOffset();
+
+  CFX_Matrix GetImageMatrix();
+  ByteString GetImageAlias();
+
+ private:
+  // left, bottom
+  std::pair<float, float> GetIconPosition();
+
+  // width, height
+  std::pair<float, float> GetImageSize();
+
+  UnownedPtr<CPDF_Stream> m_pPDFStream;
+  UnownedPtr<CPDF_IconFit> m_pIconFit;
+};
+
+#endif  // FPDFSDK_PWL_CPWL_ICON_H_
diff --git a/fpdfsdk/pwl/cpwl_list_box.cpp b/fpdfsdk/pwl/cpwl_list_box.cpp
new file mode 100644
index 0000000..a7c02e4
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_list_box.cpp
@@ -0,0 +1,385 @@
+// 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/pwl/cpwl_list_box.h"
+
+#include <sstream>
+
+#include "core/fxge/cfx_renderdevice.h"
+#include "fpdfsdk/pwl/cpwl_edit.h"
+#include "fpdfsdk/pwl/cpwl_edit_ctrl.h"
+#include "fpdfsdk/pwl/cpwl_edit_impl.h"
+#include "fpdfsdk/pwl/cpwl_list_impl.h"
+#include "fpdfsdk/pwl/cpwl_scroll_bar.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
+#include "public/fpdf_fwlevent.h"
+#include "third_party/base/ptr_util.h"
+
+CPWL_List_Notify::CPWL_List_Notify(CPWL_ListBox* pList) : m_pList(pList) {
+  ASSERT(m_pList);
+}
+
+CPWL_List_Notify::~CPWL_List_Notify() {}
+
+void CPWL_List_Notify::IOnSetScrollInfoY(float fPlateMin,
+                                         float fPlateMax,
+                                         float fContentMin,
+                                         float fContentMax,
+                                         float fSmallStep,
+                                         float fBigStep) {
+  PWL_SCROLL_INFO Info;
+  Info.fPlateWidth = fPlateMax - fPlateMin;
+  Info.fContentMin = fContentMin;
+  Info.fContentMax = fContentMax;
+  Info.fSmallStep = fSmallStep;
+  Info.fBigStep = fBigStep;
+  m_pList->SetScrollInfo(Info);
+
+  CPWL_ScrollBar* pScroll = m_pList->GetVScrollBar();
+  if (!pScroll)
+    return;
+
+  if (IsFloatBigger(Info.fPlateWidth, Info.fContentMax - Info.fContentMin) ||
+      IsFloatEqual(Info.fPlateWidth, Info.fContentMax - Info.fContentMin)) {
+    if (pScroll->IsVisible()) {
+      pScroll->SetVisible(false);
+      m_pList->RePosChildWnd();
+    }
+  } else {
+    if (!pScroll->IsVisible()) {
+      pScroll->SetVisible(true);
+      m_pList->RePosChildWnd();
+    }
+  }
+}
+
+void CPWL_List_Notify::IOnSetScrollPosY(float fy) {
+  m_pList->SetScrollPosition(fy);
+}
+
+void CPWL_List_Notify::IOnInvalidateRect(CFX_FloatRect* pRect) {
+  m_pList->InvalidateRect(pRect);
+}
+
+CPWL_ListBox::CPWL_ListBox()
+    : m_pList(new CPWL_ListCtrl),
+      m_bMouseDown(false),
+      m_bHoverSel(false),
+      m_pFillerNotify(nullptr) {}
+
+CPWL_ListBox::~CPWL_ListBox() {}
+
+ByteString CPWL_ListBox::GetClassName() const {
+  return "CPWL_ListBox";
+}
+
+void CPWL_ListBox::OnCreated() {
+  m_pList->SetFontMap(GetFontMap());
+  m_pListNotify = pdfium::MakeUnique<CPWL_List_Notify>(this);
+  m_pList->SetNotify(m_pListNotify.get());
+
+  SetHoverSel(HasFlag(PLBS_HOVERSEL));
+  m_pList->SetMultipleSel(HasFlag(PLBS_MULTIPLESEL));
+  m_pList->SetFontSize(GetCreationParams().fFontSize);
+
+  m_bHoverSel = HasFlag(PLBS_HOVERSEL);
+}
+
+void CPWL_ListBox::OnDestroy() {
+  // Make sure the notifier is removed from the list as we are about to
+  // destroy the notifier and don't want to leave a dangling pointer.
+  m_pList->SetNotify(nullptr);
+  m_pListNotify.reset();
+}
+
+void CPWL_ListBox::DrawThisAppearance(CFX_RenderDevice* pDevice,
+                                      const CFX_Matrix& mtUser2Device) {
+  CPWL_Wnd::DrawThisAppearance(pDevice, mtUser2Device);
+
+  CFX_FloatRect rcPlate = m_pList->GetPlateRect();
+  CFX_FloatRect rcList = GetListRect();
+  CFX_FloatRect rcClient = GetClientRect();
+
+  for (int32_t i = 0, sz = m_pList->GetCount(); i < sz; i++) {
+    CFX_FloatRect rcItem = m_pList->GetItemRect(i);
+    if (rcItem.bottom > rcPlate.top || rcItem.top < rcPlate.bottom)
+      continue;
+
+    CFX_PointF ptOffset(rcItem.left, (rcItem.top + rcItem.bottom) * 0.5f);
+    if (CPWL_EditImpl* pEdit = m_pList->GetItemEdit(i)) {
+      CFX_FloatRect rcContent = pEdit->GetContentRect();
+      if (rcContent.Width() > rcClient.Width())
+        rcItem.Intersect(rcList);
+      else
+        rcItem.Intersect(rcClient);
+    }
+
+    if (m_pList->IsItemSelected(i)) {
+      CFX_SystemHandler* pSysHandler = GetSystemHandler();
+      if (pSysHandler && pSysHandler->IsSelectionImplemented()) {
+        CPWL_EditImpl::DrawEdit(pDevice, mtUser2Device, m_pList->GetItemEdit(i),
+                                GetTextColor().ToFXColor(255), rcList, ptOffset,
+                                nullptr, pSysHandler, m_pFormFiller.Get());
+        pSysHandler->OutputSelectedRect(m_pFormFiller.Get(), rcItem);
+      } else {
+        pDevice->DrawFillRect(&mtUser2Device, rcItem,
+                              ArgbEncode(255, 0, 51, 113));
+        CPWL_EditImpl::DrawEdit(pDevice, mtUser2Device, m_pList->GetItemEdit(i),
+                                ArgbEncode(255, 255, 255, 255), rcList,
+                                ptOffset, nullptr, pSysHandler,
+                                m_pFormFiller.Get());
+      }
+    } else {
+      CFX_SystemHandler* pSysHandler = GetSystemHandler();
+      CPWL_EditImpl::DrawEdit(pDevice, mtUser2Device, m_pList->GetItemEdit(i),
+                              GetTextColor().ToFXColor(255), rcList, ptOffset,
+                              nullptr, pSysHandler, nullptr);
+    }
+  }
+}
+
+bool CPWL_ListBox::OnKeyDown(uint16_t nChar, uint32_t nFlag) {
+  CPWL_Wnd::OnKeyDown(nChar, nFlag);
+
+  switch (nChar) {
+    default:
+      return false;
+    case FWL_VKEY_Up:
+    case FWL_VKEY_Down:
+    case FWL_VKEY_Home:
+    case FWL_VKEY_Left:
+    case FWL_VKEY_End:
+    case FWL_VKEY_Right:
+      break;
+  }
+
+  switch (nChar) {
+    case FWL_VKEY_Up:
+      m_pList->OnVK_UP(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+      break;
+    case FWL_VKEY_Down:
+      m_pList->OnVK_DOWN(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+      break;
+    case FWL_VKEY_Home:
+      m_pList->OnVK_HOME(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+      break;
+    case FWL_VKEY_Left:
+      m_pList->OnVK_LEFT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+      break;
+    case FWL_VKEY_End:
+      m_pList->OnVK_END(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+      break;
+    case FWL_VKEY_Right:
+      m_pList->OnVK_RIGHT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+      break;
+    case FWL_VKEY_Delete:
+      break;
+  }
+  OnNotifySelectionChanged(true, nFlag);
+  return true;
+}
+
+bool CPWL_ListBox::OnChar(uint16_t nChar, uint32_t nFlag) {
+  CPWL_Wnd::OnChar(nChar, nFlag);
+
+  if (!m_pList->OnChar(nChar, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)))
+    return false;
+
+  OnNotifySelectionChanged(true, nFlag);
+  return true;
+}
+
+bool CPWL_ListBox::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
+  CPWL_Wnd::OnLButtonDown(point, nFlag);
+
+  if (ClientHitTest(point)) {
+    m_bMouseDown = true;
+    SetFocus();
+    SetCapture();
+
+    m_pList->OnMouseDown(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+  }
+
+  return true;
+}
+
+bool CPWL_ListBox::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
+  CPWL_Wnd::OnLButtonUp(point, nFlag);
+
+  if (m_bMouseDown) {
+    ReleaseCapture();
+    m_bMouseDown = false;
+  }
+  OnNotifySelectionChanged(false, nFlag);
+  return true;
+}
+
+void CPWL_ListBox::SetHoverSel(bool bHoverSel) {
+  m_bHoverSel = bHoverSel;
+}
+
+bool CPWL_ListBox::OnMouseMove(const CFX_PointF& point, uint32_t nFlag) {
+  CPWL_Wnd::OnMouseMove(point, nFlag);
+
+  if (m_bHoverSel && !IsCaptureMouse() && ClientHitTest(point))
+    m_pList->Select(m_pList->GetItemIndex(point));
+  if (m_bMouseDown)
+    m_pList->OnMouseMove(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+
+  return true;
+}
+
+void CPWL_ListBox::SetScrollInfo(const PWL_SCROLL_INFO& info) {
+  if (CPWL_Wnd* pChild = GetVScrollBar())
+    pChild->SetScrollInfo(info);
+}
+
+void CPWL_ListBox::SetScrollPosition(float pos) {
+  if (CPWL_Wnd* pChild = GetVScrollBar())
+    pChild->SetScrollPosition(pos);
+}
+
+void CPWL_ListBox::ScrollWindowVertically(float pos) {
+  m_pList->SetScrollPos(CFX_PointF(0, pos));
+}
+
+void CPWL_ListBox::KillFocus() {
+  CPWL_Wnd::KillFocus();
+}
+
+bool CPWL_ListBox::RePosChildWnd() {
+  if (!CPWL_Wnd::RePosChildWnd())
+    return false;
+
+  m_pList->SetPlateRect(GetListRect());
+  return true;
+}
+
+bool CPWL_ListBox::OnNotifySelectionChanged(bool bKeyDown, uint32_t nFlag) {
+  if (!m_pFillerNotify)
+    return false;
+
+  CPWL_Wnd::ObservedPtr thisObserved(this);
+
+  WideString swChange = GetText();
+  WideString strChangeEx;
+  int nSelStart = 0;
+  int nSelEnd = swChange.GetLength();
+  bool bRC;
+  bool bExit;
+  std::tie(bRC, bExit) = m_pFillerNotify->OnBeforeKeyStroke(
+      GetAttachedData(), swChange, strChangeEx, nSelStart, nSelEnd, bKeyDown,
+      nFlag);
+
+  if (!thisObserved)
+    return false;
+
+  return bExit;
+}
+
+CFX_FloatRect CPWL_ListBox::GetFocusRect() const {
+  if (m_pList->IsMultipleSel()) {
+    CFX_FloatRect rcCaret = m_pList->GetItemRect(m_pList->GetCaret());
+    rcCaret.Intersect(GetClientRect());
+    return rcCaret;
+  }
+
+  return CPWL_Wnd::GetFocusRect();
+}
+
+void CPWL_ListBox::AddString(const WideString& str) {
+  m_pList->AddString(str);
+}
+
+WideString CPWL_ListBox::GetText() const {
+  return m_pList->GetText();
+}
+
+void CPWL_ListBox::SetFontSize(float fFontSize) {
+  m_pList->SetFontSize(fFontSize);
+}
+
+float CPWL_ListBox::GetFontSize() const {
+  return m_pList->GetFontSize();
+}
+
+void CPWL_ListBox::Select(int32_t nItemIndex) {
+  m_pList->Select(nItemIndex);
+}
+
+void CPWL_ListBox::SetCaret(int32_t nItemIndex) {
+  m_pList->SetCaret(nItemIndex);
+}
+
+void CPWL_ListBox::SetTopVisibleIndex(int32_t nItemIndex) {
+  m_pList->SetTopItem(nItemIndex);
+}
+
+void CPWL_ListBox::ScrollToListItem(int32_t nItemIndex) {
+  m_pList->ScrollToListItem(nItemIndex);
+}
+
+void CPWL_ListBox::ResetContent() {
+  m_pList->Empty();
+}
+
+void CPWL_ListBox::Reset() {
+  m_pList->Cancel();
+}
+
+bool CPWL_ListBox::IsMultipleSel() const {
+  return m_pList->IsMultipleSel();
+}
+
+int32_t CPWL_ListBox::GetCaretIndex() const {
+  return m_pList->GetCaret();
+}
+
+int32_t CPWL_ListBox::GetCurSel() const {
+  return m_pList->GetSelect();
+}
+
+bool CPWL_ListBox::IsItemSelected(int32_t nItemIndex) const {
+  return m_pList->IsItemSelected(nItemIndex);
+}
+
+int32_t CPWL_ListBox::GetTopVisibleIndex() const {
+  m_pList->ScrollToListItem(m_pList->GetFirstSelected());
+  return m_pList->GetTopItem();
+}
+
+int32_t CPWL_ListBox::GetCount() const {
+  return m_pList->GetCount();
+}
+
+int32_t CPWL_ListBox::FindNext(int32_t nIndex, wchar_t nChar) const {
+  return m_pList->FindNext(nIndex, nChar);
+}
+
+CFX_FloatRect CPWL_ListBox::GetContentRect() const {
+  return m_pList->GetContentRect();
+}
+
+float CPWL_ListBox::GetFirstHeight() const {
+  return m_pList->GetFirstHeight();
+}
+
+CFX_FloatRect CPWL_ListBox::GetListRect() const {
+  float width = static_cast<float>(GetBorderWidth() + GetInnerBorderWidth());
+  return GetWindowRect().GetDeflated(width, width);
+}
+
+bool CPWL_ListBox::OnMouseWheel(short zDelta,
+                                const CFX_PointF& point,
+                                uint32_t nFlag) {
+  if (zDelta < 0)
+    m_pList->OnVK_DOWN(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+  else
+    m_pList->OnVK_UP(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
+
+  OnNotifySelectionChanged(false, nFlag);
+  return true;
+}
diff --git a/fpdfsdk/pwl/cpwl_list_box.h b/fpdfsdk/pwl/cpwl_list_box.h
new file mode 100644
index 0000000..9a725d1
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_list_box.h
@@ -0,0 +1,108 @@
+// 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 FPDFSDK_PWL_CPWL_LIST_BOX_H_
+#define FPDFSDK_PWL_CPWL_LIST_BOX_H_
+
+#include <memory>
+
+#include "core/fxcrt/unowned_ptr.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
+
+class CPWL_ListCtrl;
+class CPWL_List_Notify;
+class CPWL_ListBox;
+class IPWL_Filler_Notify;
+struct CPVT_WordPlace;
+
+class CPWL_List_Notify {
+ public:
+  explicit CPWL_List_Notify(CPWL_ListBox* pList);
+  ~CPWL_List_Notify();
+
+  void IOnSetScrollInfoY(float fPlateMin,
+                         float fPlateMax,
+                         float fContentMin,
+                         float fContentMax,
+                         float fSmallStep,
+                         float fBigStep);
+  void IOnSetScrollPosY(float fy);
+  void IOnInvalidateRect(CFX_FloatRect* pRect);
+
+ private:
+  UnownedPtr<CPWL_ListBox> m_pList;
+};
+
+class CPWL_ListBox : public CPWL_Wnd {
+ public:
+  CPWL_ListBox();
+  ~CPWL_ListBox() override;
+
+  // CPWL_Wnd
+  ByteString GetClassName() const override;
+  void OnCreated() override;
+  void OnDestroy() override;
+  void DrawThisAppearance(CFX_RenderDevice* pDevice,
+                          const CFX_Matrix& mtUser2Device) override;
+  bool OnKeyDown(uint16_t nChar, uint32_t nFlag) override;
+  bool OnChar(uint16_t nChar, 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_PointF& point,
+                    uint32_t nFlag) override;
+  void KillFocus() override;
+  void SetScrollInfo(const PWL_SCROLL_INFO& info) override;
+  void SetScrollPosition(float pos) override;
+  void ScrollWindowVertically(float pos) override;
+  bool RePosChildWnd() override;
+  CFX_FloatRect GetFocusRect() const override;
+  void SetFontSize(float fFontSize) override;
+  float GetFontSize() const override;
+
+  virtual WideString GetText() const;
+
+  bool OnNotifySelectionChanged(bool bKeyDown, uint32_t nFlag);
+
+  void AddString(const WideString& str);
+  void SetTopVisibleIndex(int32_t nItemIndex);
+  void ScrollToListItem(int32_t nItemIndex);
+  void ResetContent();
+  void Reset();
+  void Select(int32_t nItemIndex);
+  void SetCaret(int32_t nItemIndex);
+  void SetHoverSel(bool bHoverSel);
+
+  int32_t GetCount() const;
+  bool IsMultipleSel() const;
+  int32_t GetCaretIndex() const;
+  int32_t GetCurSel() const;
+  bool IsItemSelected(int32_t nItemIndex) const;
+  int32_t GetTopVisibleIndex() const;
+  int32_t FindNext(int32_t nIndex, wchar_t nChar) const;
+  CFX_FloatRect GetContentRect() const;
+  float GetFirstHeight() const;
+  CFX_FloatRect GetListRect() const;
+
+  void SetFillerNotify(IPWL_Filler_Notify* pNotify) {
+    m_pFillerNotify = pNotify;
+  }
+
+  void AttachFFLData(CFFL_FormFiller* pData) { m_pFormFiller = pData; }
+
+ protected:
+  std::unique_ptr<CPWL_ListCtrl> m_pList;
+  std::unique_ptr<CPWL_List_Notify> m_pListNotify;
+  bool m_bMouseDown;
+  bool m_bHoverSel;
+  UnownedPtr<IPWL_Filler_Notify> m_pFillerNotify;
+
+ private:
+  UnownedPtr<CFFL_FormFiller> m_pFormFiller;
+};
+
+#endif  // FPDFSDK_PWL_CPWL_LIST_BOX_H_
diff --git a/fpdfsdk/pwl/cpwl_list_impl.cpp b/fpdfsdk/pwl/cpwl_list_impl.cpp
new file mode 100644
index 0000000..da455d0
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_list_impl.cpp
@@ -0,0 +1,637 @@
+// 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/pwl/cpwl_list_impl.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "core/fpdfdoc/cpvt_word.h"
+#include "core/fxcrt/fx_extension.h"
+#include "fpdfsdk/pwl/cpwl_edit_impl.h"
+#include "fpdfsdk/pwl/cpwl_list_box.h"
+#include "third_party/base/stl_util.h"
+
+CPWL_ListCtrl::Item::Item()
+    : m_pEdit(new CPWL_EditImpl),
+      m_bSelected(false),
+      m_rcListItem(0.0f, 0.0f, 0.0f, 0.0f) {
+  m_pEdit->SetAlignmentV(1, true);
+  m_pEdit->Initialize();
+}
+
+CPWL_ListCtrl::Item::~Item() {}
+
+void CPWL_ListCtrl::Item::SetFontMap(IPVT_FontMap* pFontMap) {
+  m_pEdit->SetFontMap(pFontMap);
+}
+
+void CPWL_ListCtrl::Item::SetText(const WideString& text) {
+  m_pEdit->SetText(text);
+}
+
+void CPWL_ListCtrl::Item::SetFontSize(float fFontSize) {
+  m_pEdit->SetFontSize(fFontSize);
+}
+
+float CPWL_ListCtrl::Item::GetItemHeight() const {
+  return m_pEdit->GetContentRect().Height();
+}
+
+uint16_t CPWL_ListCtrl::Item::GetFirstChar() const {
+  CPVT_Word word;
+  CPWL_EditImpl_Iterator* pIterator = m_pEdit->GetIterator();
+  pIterator->SetAt(1);
+  pIterator->GetWord(word);
+  return word.Word;
+}
+
+WideString CPWL_ListCtrl::Item::GetText() const {
+  return m_pEdit->GetText();
+}
+
+CPLST_Select::CPLST_Select() {}
+
+CPLST_Select::~CPLST_Select() {}
+
+void CPLST_Select::Add(int32_t nItemIndex) {
+  m_Items[nItemIndex] = SELECTING;
+}
+
+void CPLST_Select::Add(int32_t nBeginIndex, int32_t nEndIndex) {
+  if (nBeginIndex > nEndIndex)
+    std::swap(nBeginIndex, nEndIndex);
+
+  for (int32_t i = nBeginIndex; i <= nEndIndex; ++i)
+    Add(i);
+}
+
+void CPLST_Select::Sub(int32_t nItemIndex) {
+  auto it = m_Items.find(nItemIndex);
+  if (it != m_Items.end())
+    it->second = DESELECTING;
+}
+
+void CPLST_Select::Sub(int32_t nBeginIndex, int32_t nEndIndex) {
+  if (nBeginIndex > nEndIndex)
+    std::swap(nBeginIndex, nEndIndex);
+
+  for (int32_t i = nBeginIndex; i <= nEndIndex; ++i)
+    Sub(i);
+}
+
+void CPLST_Select::DeselectAll() {
+  for (auto& item : m_Items)
+    item.second = DESELECTING;
+}
+
+void CPLST_Select::Done() {
+  auto it = m_Items.begin();
+  while (it != m_Items.end()) {
+    if (it->second == DESELECTING)
+      it = m_Items.erase(it);
+    else
+      (it++)->second = NORMAL;
+  }
+}
+
+CPWL_ListCtrl::CPWL_ListCtrl()
+    : m_pNotify(nullptr),
+      m_bNotifyFlag(false),
+      m_nSelItem(-1),
+      m_nFootIndex(-1),
+      m_bCtrlSel(false),
+      m_nCaretIndex(-1),
+      m_fFontSize(0.0f),
+      m_pFontMap(nullptr),
+      m_bMultiple(false) {}
+
+CPWL_ListCtrl::~CPWL_ListCtrl() {
+  Empty();
+}
+
+CFX_PointF CPWL_ListCtrl::InToOut(const CFX_PointF& point) const {
+  CFX_FloatRect rcPlate = m_rcPlate;
+  return CFX_PointF(point.x - (m_ptScrollPos.x - rcPlate.left),
+                    point.y - (m_ptScrollPos.y - rcPlate.top));
+}
+
+CFX_PointF CPWL_ListCtrl::OutToIn(const CFX_PointF& point) const {
+  CFX_FloatRect rcPlate = m_rcPlate;
+  return CFX_PointF(point.x + (m_ptScrollPos.x - rcPlate.left),
+                    point.y + (m_ptScrollPos.y - rcPlate.top));
+}
+
+CFX_FloatRect CPWL_ListCtrl::InToOut(const CFX_FloatRect& rect) const {
+  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 CPWL_ListCtrl::OutToIn(const CFX_FloatRect& rect) const {
+  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);
+}
+
+CFX_PointF CPWL_ListCtrl::InnerToOuter(const CFX_PointF& point) const {
+  return CFX_PointF(point.x + GetBTPoint().x, GetBTPoint().y - point.y);
+}
+
+CFX_PointF CPWL_ListCtrl::OuterToInner(const CFX_PointF& point) const {
+  return CFX_PointF(point.x - GetBTPoint().x, GetBTPoint().y - point.y);
+}
+
+CFX_FloatRect CPWL_ListCtrl::InnerToOuter(const CFX_FloatRect& rect) const {
+  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);
+}
+
+CFX_FloatRect CPWL_ListCtrl::OuterToInner(const CFX_FloatRect& rect) const {
+  CFX_PointF ptLeftTop = OuterToInner(CFX_PointF(rect.left, rect.top));
+  CFX_PointF ptRightBottom = OuterToInner(CFX_PointF(rect.right, rect.bottom));
+  return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x,
+                       ptLeftTop.y);
+}
+
+void CPWL_ListCtrl::OnMouseDown(const CFX_PointF& point,
+                                bool bShift,
+                                bool bCtrl) {
+  int32_t nHitIndex = GetItemIndex(point);
+
+  if (IsMultipleSel()) {
+    if (bCtrl) {
+      if (IsItemSelected(nHitIndex)) {
+        m_aSelItems.Sub(nHitIndex);
+        SelectItems();
+        m_bCtrlSel = false;
+      } else {
+        m_aSelItems.Add(nHitIndex);
+        SelectItems();
+        m_bCtrlSel = true;
+      }
+
+      m_nFootIndex = nHitIndex;
+    } else if (bShift) {
+      m_aSelItems.DeselectAll();
+      m_aSelItems.Add(m_nFootIndex, nHitIndex);
+      SelectItems();
+    } else {
+      m_aSelItems.DeselectAll();
+      m_aSelItems.Add(nHitIndex);
+      SelectItems();
+
+      m_nFootIndex = nHitIndex;
+    }
+
+    SetCaret(nHitIndex);
+  } else {
+    SetSingleSelect(nHitIndex);
+  }
+
+  if (!IsItemVisible(nHitIndex))
+    ScrollToListItem(nHitIndex);
+}
+
+void CPWL_ListCtrl::OnMouseMove(const CFX_PointF& point,
+                                bool bShift,
+                                bool bCtrl) {
+  int32_t nHitIndex = GetItemIndex(point);
+
+  if (IsMultipleSel()) {
+    if (bCtrl) {
+      if (m_bCtrlSel)
+        m_aSelItems.Add(m_nFootIndex, nHitIndex);
+      else
+        m_aSelItems.Sub(m_nFootIndex, nHitIndex);
+
+      SelectItems();
+    } else {
+      m_aSelItems.DeselectAll();
+      m_aSelItems.Add(m_nFootIndex, nHitIndex);
+      SelectItems();
+    }
+
+    SetCaret(nHitIndex);
+  } else {
+    SetSingleSelect(nHitIndex);
+  }
+
+  if (!IsItemVisible(nHitIndex))
+    ScrollToListItem(nHitIndex);
+}
+
+void CPWL_ListCtrl::OnVK(int32_t nItemIndex, bool bShift, bool bCtrl) {
+  if (IsMultipleSel()) {
+    if (nItemIndex >= 0 && nItemIndex < GetCount()) {
+      if (bCtrl) {
+      } else if (bShift) {
+        m_aSelItems.DeselectAll();
+        m_aSelItems.Add(m_nFootIndex, nItemIndex);
+        SelectItems();
+      } else {
+        m_aSelItems.DeselectAll();
+        m_aSelItems.Add(nItemIndex);
+        SelectItems();
+        m_nFootIndex = nItemIndex;
+      }
+
+      SetCaret(nItemIndex);
+    }
+  } else {
+    SetSingleSelect(nItemIndex);
+  }
+
+  if (!IsItemVisible(nItemIndex))
+    ScrollToListItem(nItemIndex);
+}
+
+void CPWL_ListCtrl::OnVK_UP(bool bShift, bool bCtrl) {
+  OnVK(IsMultipleSel() ? GetCaret() - 1 : GetSelect() - 1, bShift, bCtrl);
+}
+
+void CPWL_ListCtrl::OnVK_DOWN(bool bShift, bool bCtrl) {
+  OnVK(IsMultipleSel() ? GetCaret() + 1 : GetSelect() + 1, bShift, bCtrl);
+}
+
+void CPWL_ListCtrl::OnVK_LEFT(bool bShift, bool bCtrl) {
+  OnVK(0, bShift, bCtrl);
+}
+
+void CPWL_ListCtrl::OnVK_RIGHT(bool bShift, bool bCtrl) {
+  OnVK(GetCount() - 1, bShift, bCtrl);
+}
+
+void CPWL_ListCtrl::OnVK_HOME(bool bShift, bool bCtrl) {
+  OnVK(0, bShift, bCtrl);
+}
+
+void CPWL_ListCtrl::OnVK_END(bool bShift, bool bCtrl) {
+  OnVK(GetCount() - 1, bShift, bCtrl);
+}
+
+bool CPWL_ListCtrl::OnChar(uint16_t nChar, bool bShift, bool bCtrl) {
+  int32_t nIndex = GetLastSelected();
+  int32_t nFindIndex = FindNext(nIndex, nChar);
+
+  if (nFindIndex != nIndex) {
+    OnVK(nFindIndex, bShift, bCtrl);
+    return true;
+  }
+  return false;
+}
+
+void CPWL_ListCtrl::SetPlateRect(const CFX_FloatRect& rect) {
+  m_rcPlate = rect;
+  m_ptScrollPos.x = rect.left;
+  SetScrollPos(CFX_PointF(rect.left, rect.top));
+  ReArrange(0);
+  InvalidateItem(-1);
+}
+
+CFX_FloatRect CPWL_ListCtrl::GetItemRect(int32_t nIndex) const {
+  return InToOut(GetItemRectInternal(nIndex));
+}
+
+CFX_FloatRect CPWL_ListCtrl::GetItemRectInternal(int32_t nIndex) const {
+  if (!pdfium::IndexInBounds(m_ListItems, nIndex) || !m_ListItems[nIndex])
+    return CFX_FloatRect();
+
+  CFX_FloatRect rcItem = m_ListItems[nIndex]->GetRect();
+  rcItem.left = 0.0f;
+  rcItem.right = m_rcPlate.Width();
+  return InnerToOuter(rcItem);
+}
+
+void CPWL_ListCtrl::AddString(const WideString& str) {
+  AddItem(str);
+  ReArrange(GetCount() - 1);
+}
+
+void CPWL_ListCtrl::SetMultipleSelect(int32_t nItemIndex, bool bSelected) {
+  if (!IsValid(nItemIndex))
+    return;
+
+  if (bSelected != IsItemSelected(nItemIndex)) {
+    if (bSelected) {
+      SetItemSelect(nItemIndex, true);
+      InvalidateItem(nItemIndex);
+    } else {
+      SetItemSelect(nItemIndex, false);
+      InvalidateItem(nItemIndex);
+    }
+  }
+}
+
+void CPWL_ListCtrl::SetSingleSelect(int32_t nItemIndex) {
+  if (!IsValid(nItemIndex))
+    return;
+
+  if (m_nSelItem != nItemIndex) {
+    if (m_nSelItem >= 0) {
+      SetItemSelect(m_nSelItem, false);
+      InvalidateItem(m_nSelItem);
+    }
+
+    SetItemSelect(nItemIndex, true);
+    InvalidateItem(nItemIndex);
+    m_nSelItem = nItemIndex;
+  }
+}
+
+void CPWL_ListCtrl::SetCaret(int32_t nItemIndex) {
+  if (!IsValid(nItemIndex))
+    return;
+
+  if (IsMultipleSel()) {
+    int32_t nOldIndex = m_nCaretIndex;
+
+    if (nOldIndex != nItemIndex) {
+      m_nCaretIndex = nItemIndex;
+      InvalidateItem(nOldIndex);
+      InvalidateItem(nItemIndex);
+    }
+  }
+}
+
+void CPWL_ListCtrl::InvalidateItem(int32_t nItemIndex) {
+  if (m_pNotify) {
+    if (nItemIndex == -1) {
+      if (!m_bNotifyFlag) {
+        m_bNotifyFlag = true;
+        CFX_FloatRect rcRefresh = m_rcPlate;
+        m_pNotify->IOnInvalidateRect(&rcRefresh);
+        m_bNotifyFlag = false;
+      }
+    } else {
+      if (!m_bNotifyFlag) {
+        m_bNotifyFlag = true;
+        CFX_FloatRect rcRefresh = GetItemRect(nItemIndex);
+        rcRefresh.left -= 1.0f;
+        rcRefresh.right += 1.0f;
+        rcRefresh.bottom -= 1.0f;
+        rcRefresh.top += 1.0f;
+
+        m_pNotify->IOnInvalidateRect(&rcRefresh);
+        m_bNotifyFlag = false;
+      }
+    }
+  }
+}
+
+void CPWL_ListCtrl::SelectItems() {
+  for (const auto& item : m_aSelItems) {
+    if (item.second != CPLST_Select::NORMAL)
+      SetMultipleSelect(item.first, item.second == CPLST_Select::SELECTING);
+  }
+  m_aSelItems.Done();
+}
+
+void CPWL_ListCtrl::Select(int32_t nItemIndex) {
+  if (!IsValid(nItemIndex))
+    return;
+
+  if (IsMultipleSel()) {
+    m_aSelItems.Add(nItemIndex);
+    SelectItems();
+  } else {
+    SetSingleSelect(nItemIndex);
+  }
+}
+
+bool CPWL_ListCtrl::IsItemVisible(int32_t nItemIndex) const {
+  CFX_FloatRect rcPlate = m_rcPlate;
+  CFX_FloatRect rcItem = GetItemRect(nItemIndex);
+
+  return rcItem.bottom >= rcPlate.bottom && rcItem.top <= rcPlate.top;
+}
+
+void CPWL_ListCtrl::ScrollToListItem(int32_t nItemIndex) {
+  if (!IsValid(nItemIndex))
+    return;
+
+  CFX_FloatRect rcPlate = m_rcPlate;
+  CFX_FloatRect rcItem = GetItemRectInternal(nItemIndex);
+  CFX_FloatRect rcItemCtrl = GetItemRect(nItemIndex);
+
+  if (IsFloatSmaller(rcItemCtrl.bottom, rcPlate.bottom)) {
+    if (IsFloatSmaller(rcItemCtrl.top, rcPlate.top)) {
+      SetScrollPosY(rcItem.bottom + rcPlate.Height());
+    }
+  } else if (IsFloatBigger(rcItemCtrl.top, rcPlate.top)) {
+    if (IsFloatBigger(rcItemCtrl.bottom, rcPlate.bottom)) {
+      SetScrollPosY(rcItem.top);
+    }
+  }
+}
+
+void CPWL_ListCtrl::SetScrollInfo() {
+  if (m_pNotify) {
+    CFX_FloatRect rcPlate = m_rcPlate;
+    CFX_FloatRect rcContent = GetContentRectInternal();
+
+    if (!m_bNotifyFlag) {
+      m_bNotifyFlag = true;
+      m_pNotify->IOnSetScrollInfoY(rcPlate.bottom, rcPlate.top,
+                                   rcContent.bottom, rcContent.top,
+                                   GetFirstHeight(), rcPlate.Height());
+      m_bNotifyFlag = false;
+    }
+  }
+}
+
+void CPWL_ListCtrl::SetScrollPos(const CFX_PointF& point) {
+  SetScrollPosY(point.y);
+}
+
+void CPWL_ListCtrl::SetScrollPosY(float fy) {
+  if (!IsFloatEqual(m_ptScrollPos.y, fy)) {
+    CFX_FloatRect rcPlate = m_rcPlate;
+    CFX_FloatRect rcContent = GetContentRectInternal();
+
+    if (rcPlate.Height() > rcContent.Height()) {
+      fy = rcPlate.top;
+    } else {
+      if (IsFloatSmaller(fy - rcPlate.Height(), rcContent.bottom)) {
+        fy = rcContent.bottom + rcPlate.Height();
+      } else if (IsFloatBigger(fy, rcContent.top)) {
+        fy = rcContent.top;
+      }
+    }
+
+    m_ptScrollPos.y = fy;
+    InvalidateItem(-1);
+
+    if (m_pNotify) {
+      if (!m_bNotifyFlag) {
+        m_bNotifyFlag = true;
+        m_pNotify->IOnSetScrollPosY(fy);
+        m_bNotifyFlag = false;
+      }
+    }
+  }
+}
+
+CFX_FloatRect CPWL_ListCtrl::GetContentRectInternal() const {
+  return InnerToOuter(m_rcContent);
+}
+
+CFX_FloatRect CPWL_ListCtrl::GetContentRect() const {
+  return InToOut(GetContentRectInternal());
+}
+
+void CPWL_ListCtrl::ReArrange(int32_t nItemIndex) {
+  float fPosY = 0.0f;
+  if (pdfium::IndexInBounds(m_ListItems, nItemIndex - 1) &&
+      m_ListItems[nItemIndex - 1]) {
+    fPosY = m_ListItems[nItemIndex - 1]->GetRect().bottom;
+  }
+  for (const auto& pListItem : m_ListItems) {
+    if (pListItem) {
+      float fListItemHeight = pListItem->GetItemHeight();
+      pListItem->SetRect(
+          CFX_FloatRect(0.0f, fPosY + fListItemHeight, 0.0f, fPosY));
+      fPosY += fListItemHeight;
+    }
+  }
+  SetContentRect(CFX_FloatRect(0.0f, fPosY, 0.0f, 0.0f));
+  SetScrollInfo();
+}
+
+void CPWL_ListCtrl::SetTopItem(int32_t nIndex) {
+  if (IsValid(nIndex)) {
+    CFX_FloatRect rcItem = GetItemRectInternal(nIndex);
+    SetScrollPosY(rcItem.top);
+  }
+}
+
+int32_t CPWL_ListCtrl::GetTopItem() const {
+  int32_t nItemIndex = GetItemIndex(GetBTPoint());
+  if (!IsItemVisible(nItemIndex) && IsItemVisible(nItemIndex + 1))
+    nItemIndex += 1;
+
+  return nItemIndex;
+}
+
+void CPWL_ListCtrl::Empty() {
+  m_ListItems.clear();
+  InvalidateItem(-1);
+}
+
+void CPWL_ListCtrl::Cancel() {
+  m_aSelItems.DeselectAll();
+}
+
+int32_t CPWL_ListCtrl::GetItemIndex(const CFX_PointF& point) const {
+  CFX_PointF pt = OuterToInner(OutToIn(point));
+  bool bFirst = true;
+  bool bLast = true;
+  for (const auto& pListItem : m_ListItems) {
+    if (!pListItem)
+      continue;
+    CFX_FloatRect rcListItem = pListItem->GetRect();
+    if (IsFloatBigger(pt.y, rcListItem.top))
+      bFirst = false;
+    if (IsFloatSmaller(pt.y, rcListItem.bottom))
+      bLast = false;
+    if (pt.y >= rcListItem.top && pt.y < rcListItem.bottom)
+      return &pListItem - &m_ListItems.front();
+  }
+  if (bFirst)
+    return 0;
+  if (bLast)
+    return pdfium::CollectionSize<int32_t>(m_ListItems) - 1;
+  return -1;
+}
+
+WideString CPWL_ListCtrl::GetText() const {
+  if (IsMultipleSel())
+    return GetItemText(m_nCaretIndex);
+  return GetItemText(m_nSelItem);
+}
+
+void CPWL_ListCtrl::AddItem(const WideString& str) {
+  auto pListItem = pdfium::MakeUnique<Item>();
+  pListItem->SetFontMap(m_pFontMap.Get());
+  pListItem->SetFontSize(m_fFontSize);
+  pListItem->SetText(str);
+  m_ListItems.push_back(std::move(pListItem));
+}
+
+CPWL_EditImpl* CPWL_ListCtrl::GetItemEdit(int32_t nIndex) const {
+  if (!pdfium::IndexInBounds(m_ListItems, nIndex) || !m_ListItems[nIndex])
+    return nullptr;
+  return m_ListItems[nIndex]->GetEdit();
+}
+
+int32_t CPWL_ListCtrl::GetCount() const {
+  return pdfium::CollectionSize<int32_t>(m_ListItems);
+}
+
+float CPWL_ListCtrl::GetFirstHeight() const {
+  if (m_ListItems.empty() || !m_ListItems.front())
+    return 1.0f;
+  return m_ListItems.front()->GetItemHeight();
+}
+
+int32_t CPWL_ListCtrl::GetFirstSelected() const {
+  int32_t i = 0;
+  for (const auto& pListItem : m_ListItems) {
+    if (pListItem && pListItem->IsSelected())
+      return i;
+    ++i;
+  }
+  return -1;
+}
+
+int32_t CPWL_ListCtrl::GetLastSelected() const {
+  for (auto iter = m_ListItems.rbegin(); iter != m_ListItems.rend(); ++iter) {
+    if (*iter && (*iter)->IsSelected())
+      return &*iter - &m_ListItems.front();
+  }
+  return -1;
+}
+
+int32_t CPWL_ListCtrl::FindNext(int32_t nIndex, wchar_t nChar) const {
+  int32_t nCircleIndex = nIndex;
+  int32_t sz = pdfium::CollectionSize<int32_t>(m_ListItems);
+  for (int32_t i = 0; i < sz; i++) {
+    nCircleIndex++;
+    if (nCircleIndex >= sz)
+      nCircleIndex = 0;
+
+    if (Item* pListItem = m_ListItems[nCircleIndex].get()) {
+      if (FXSYS_toupper(pListItem->GetFirstChar()) == FXSYS_toupper(nChar))
+        return nCircleIndex;
+    }
+  }
+
+  return nCircleIndex;
+}
+
+bool CPWL_ListCtrl::IsItemSelected(int32_t nIndex) const {
+  return pdfium::IndexInBounds(m_ListItems, nIndex) && m_ListItems[nIndex] &&
+         m_ListItems[nIndex]->IsSelected();
+}
+
+void CPWL_ListCtrl::SetItemSelect(int32_t nIndex, bool bSelected) {
+  if (pdfium::IndexInBounds(m_ListItems, nIndex) && m_ListItems[nIndex])
+    m_ListItems[nIndex]->SetSelect(bSelected);
+}
+
+bool CPWL_ListCtrl::IsValid(int32_t nItemIndex) const {
+  return pdfium::IndexInBounds(m_ListItems, nItemIndex);
+}
+
+WideString CPWL_ListCtrl::GetItemText(int32_t nIndex) const {
+  if (pdfium::IndexInBounds(m_ListItems, nIndex) && m_ListItems[nIndex])
+    return m_ListItems[nIndex]->GetText();
+  return L"";
+}
diff --git a/fpdfsdk/pwl/cpwl_list_impl.h b/fpdfsdk/pwl/cpwl_list_impl.h
new file mode 100644
index 0000000..e39a9c8
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_list_impl.h
@@ -0,0 +1,169 @@
+// 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 FPDFSDK_PWL_CPWL_LIST_IMPL_H_
+#define FPDFSDK_PWL_CPWL_LIST_IMPL_H_
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "core/fxcrt/fx_coordinates.h"
+#include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/unowned_ptr.h"
+
+class CPWL_EditImpl;
+class CPWL_EditImpl_Iterator;
+class CPWL_List_Notify;
+class IPVT_FontMap;
+
+class CPLST_Select {
+ public:
+  enum State { DESELECTING = -1, NORMAL = 0, SELECTING = 1 };
+  using const_iterator = std::map<int32_t, State>::const_iterator;
+
+  CPLST_Select();
+  virtual ~CPLST_Select();
+
+  void Add(int32_t nItemIndex);
+  void Add(int32_t nBeginIndex, int32_t nEndIndex);
+  void Sub(int32_t nItemIndex);
+  void Sub(int32_t nBeginIndex, int32_t nEndIndex);
+  void DeselectAll();
+  void Done();
+
+  const_iterator begin() const { return m_Items.begin(); }
+  const_iterator end() const { return m_Items.end(); }
+
+ private:
+  std::map<int32_t, State> m_Items;
+};
+
+class CPWL_ListCtrl {
+ public:
+  CPWL_ListCtrl();
+  ~CPWL_ListCtrl();
+
+  void SetNotify(CPWL_List_Notify* pNotify) { m_pNotify = pNotify; }
+  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);
+  void OnVK_RIGHT(bool bShift, bool bCtrl);
+  void OnVK_HOME(bool bShift, bool bCtrl);
+  void OnVK_END(bool bShift, bool bCtrl);
+  bool OnChar(uint16_t nChar, bool bShift, bool bCtrl);
+
+  void SetScrollPos(const CFX_PointF& point);
+  void ScrollToListItem(int32_t nItemIndex);
+  CFX_FloatRect GetItemRect(int32_t nIndex) const;
+  int32_t GetCaret() const { return m_nCaretIndex; }
+  int32_t GetSelect() const { return m_nSelItem; }
+  int32_t GetTopItem() const;
+  void SetContentRect(const CFX_FloatRect& rect) { m_rcContent = rect; }
+  CFX_FloatRect GetContentRect() const;
+
+  int32_t GetItemIndex(const CFX_PointF& point) const;
+  void AddString(const WideString& str);
+  void SetTopItem(int32_t nIndex);
+  void Select(int32_t nItemIndex);
+  void SetCaret(int32_t nItemIndex);
+  void Empty();
+  void Cancel();
+  WideString GetText() const;
+
+  void SetFontMap(IPVT_FontMap* pFontMap) { m_pFontMap = pFontMap; }
+  void SetFontSize(float fFontSize) { m_fFontSize = fFontSize; }
+  CFX_FloatRect GetPlateRect() const { return m_rcPlate; }
+  void SetPlateRect(const CFX_FloatRect& rect);
+
+  float GetFontSize() const { return m_fFontSize; }
+  CPWL_EditImpl* GetItemEdit(int32_t nIndex) const;
+  int32_t GetCount() const;
+  bool IsItemSelected(int32_t nIndex) const;
+  float GetFirstHeight() const;
+  void SetMultipleSel(bool bMultiple) { m_bMultiple = bMultiple; }
+  bool IsMultipleSel() const { return m_bMultiple; }
+  int32_t FindNext(int32_t nIndex, wchar_t nChar) const;
+  int32_t GetFirstSelected() const;
+
+ private:
+  class Item {
+   public:
+    Item();
+    ~Item();
+
+    void SetFontMap(IPVT_FontMap* pFontMap);
+    CPWL_EditImpl* GetEdit() const { return m_pEdit.get(); }
+
+    void SetRect(const CFX_FloatRect& rect) { m_rcListItem = rect; }
+    void SetSelect(bool bSelected) { m_bSelected = bSelected; }
+    void SetText(const WideString& text);
+    void SetFontSize(float fFontSize);
+    WideString GetText() const;
+
+    CFX_FloatRect GetRect() const { return m_rcListItem; }
+    bool IsSelected() const { return m_bSelected; }
+    float GetItemHeight() const;
+    uint16_t GetFirstChar() const;
+
+   private:
+    CPWL_EditImpl_Iterator* GetIterator() const;
+
+    std::unique_ptr<CPWL_EditImpl> m_pEdit;
+    bool m_bSelected;
+    CFX_FloatRect m_rcListItem;
+  };
+
+  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;
+
+  CFX_PointF InnerToOuter(const CFX_PointF& point) const;
+  CFX_PointF OuterToInner(const CFX_PointF& point) const;
+  CFX_FloatRect InnerToOuter(const CFX_FloatRect& rect) const;
+  CFX_FloatRect OuterToInner(const CFX_FloatRect& rect) const;
+
+  void OnVK(int32_t nItemIndex, bool bShift, bool bCtrl);
+  bool IsValid(int32_t nItemIndex) const;
+
+  void ReArrange(int32_t nItemIndex);
+  CFX_FloatRect GetItemRectInternal(int32_t nIndex) const;
+  CFX_FloatRect GetContentRectInternal() const;
+  void SetMultipleSelect(int32_t nItemIndex, bool bSelected);
+  void SetSingleSelect(int32_t nItemIndex);
+  void InvalidateItem(int32_t nItemIndex);
+  void SelectItems();
+  bool IsItemVisible(int32_t nItemIndex) const;
+  void SetScrollInfo();
+  void SetScrollPosY(float fy);
+  void AddItem(const WideString& str);
+  WideString GetItemText(int32_t nIndex) const;
+  void SetItemSelect(int32_t nItemIndex, bool bSelected);
+  int32_t GetLastSelected() const;
+  CFX_PointF GetBTPoint() const {
+    return CFX_PointF(m_rcPlate.left, m_rcPlate.top);
+  }
+
+  CFX_FloatRect m_rcPlate;
+  CFX_FloatRect m_rcContent;
+  UnownedPtr<CPWL_List_Notify> m_pNotify;
+  bool m_bNotifyFlag;
+  CFX_PointF m_ptScrollPos;
+  CPLST_Select m_aSelItems;  // for multiple
+  int32_t m_nSelItem;        // for single
+  int32_t m_nFootIndex;      // for multiple
+  bool m_bCtrlSel;           // for multiple
+  int32_t m_nCaretIndex;     // for multiple
+  std::vector<std::unique_ptr<Item>> m_ListItems;
+  float m_fFontSize;
+  UnownedPtr<IPVT_FontMap> m_pFontMap;
+  bool m_bMultiple;
+};
+
+#endif  // FPDFSDK_PWL_CPWL_LIST_IMPL_H_
diff --git a/fpdfsdk/pwl/cpwl_scroll_bar.cpp b/fpdfsdk/pwl/cpwl_scroll_bar.cpp
new file mode 100644
index 0000000..65a51e3
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_scroll_bar.cpp
@@ -0,0 +1,930 @@
+// 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/pwl/cpwl_scroll_bar.h"
+
+#include <algorithm>
+#include <sstream>
+#include <vector>
+
+#include "core/fxge/cfx_pathdata.h"
+#include "core/fxge/cfx_renderdevice.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
+
+namespace {
+
+constexpr float kButtonWidth = 9.0f;
+constexpr float kPosButtonMinWidth = 2.0f;
+constexpr float kScrollBarTriangleHalfLength = 2.0f;
+
+}  // namespace
+
+#define PWL_DEFAULT_HEAVYGRAYCOLOR CFX_Color(CFX_Color::kGray, 0.50)
+
+PWL_FLOATRANGE::PWL_FLOATRANGE() {
+  Default();
+}
+
+PWL_FLOATRANGE::PWL_FLOATRANGE(float min, float max) {
+  Set(min, max);
+}
+
+void PWL_FLOATRANGE::Default() {
+  fMin = 0;
+  fMax = 0;
+}
+
+void PWL_FLOATRANGE::Set(float min, float max) {
+  if (min > max) {
+    fMin = max;
+    fMax = min;
+  } else {
+    fMin = min;
+    fMax = max;
+  }
+}
+
+bool PWL_FLOATRANGE::In(float x) const {
+  return (IsFloatBigger(x, fMin) || IsFloatEqual(x, fMin)) &&
+         (IsFloatSmaller(x, fMax) || IsFloatEqual(x, fMax));
+}
+
+float PWL_FLOATRANGE::GetWidth() const {
+  return fMax - fMin;
+}
+
+PWL_SCROLL_PRIVATEDATA::PWL_SCROLL_PRIVATEDATA() {
+  Default();
+}
+
+void PWL_SCROLL_PRIVATEDATA::Default() {
+  ScrollRange.Default();
+  fScrollPos = ScrollRange.fMin;
+  fClientWidth = 0;
+  fBigStep = 10;
+  fSmallStep = 1;
+}
+
+void PWL_SCROLL_PRIVATEDATA::SetScrollRange(float min, float max) {
+  ScrollRange.Set(min, max);
+
+  if (IsFloatSmaller(fScrollPos, ScrollRange.fMin))
+    fScrollPos = ScrollRange.fMin;
+  if (IsFloatBigger(fScrollPos, ScrollRange.fMax))
+    fScrollPos = ScrollRange.fMax;
+}
+
+void PWL_SCROLL_PRIVATEDATA::SetClientWidth(float width) {
+  fClientWidth = width;
+}
+
+void PWL_SCROLL_PRIVATEDATA::SetSmallStep(float step) {
+  fSmallStep = step;
+}
+
+void PWL_SCROLL_PRIVATEDATA::SetBigStep(float step) {
+  fBigStep = step;
+}
+
+bool PWL_SCROLL_PRIVATEDATA::SetPos(float pos) {
+  if (ScrollRange.In(pos)) {
+    fScrollPos = pos;
+    return true;
+  }
+  return false;
+}
+
+void PWL_SCROLL_PRIVATEDATA::AddSmall() {
+  if (!SetPos(fScrollPos + fSmallStep))
+    SetPos(ScrollRange.fMax);
+}
+
+void PWL_SCROLL_PRIVATEDATA::SubSmall() {
+  if (!SetPos(fScrollPos - fSmallStep))
+    SetPos(ScrollRange.fMin);
+}
+
+void PWL_SCROLL_PRIVATEDATA::AddBig() {
+  if (!SetPos(fScrollPos + fBigStep))
+    SetPos(ScrollRange.fMax);
+}
+
+void PWL_SCROLL_PRIVATEDATA::SubBig() {
+  if (!SetPos(fScrollPos - fBigStep))
+    SetPos(ScrollRange.fMin);
+}
+
+CPWL_SBButton::CPWL_SBButton(PWL_SCROLLBAR_TYPE eScrollBarType,
+                             PWL_SBBUTTON_TYPE eButtonType) {
+  m_eScrollBarType = eScrollBarType;
+  m_eSBButtonType = eButtonType;
+
+  m_bMouseDown = false;
+}
+
+CPWL_SBButton::~CPWL_SBButton() {}
+
+ByteString CPWL_SBButton::GetClassName() const {
+  return "CPWL_SBButton";
+}
+
+void CPWL_SBButton::OnCreate(CreateParams* pParamsToAdjust) {
+  pParamsToAdjust->eCursorType = FXCT_ARROW;
+}
+
+void CPWL_SBButton::DrawThisAppearance(CFX_RenderDevice* pDevice,
+                                       const CFX_Matrix& mtUser2Device) {
+  if (!IsVisible())
+    return;
+
+  CFX_FloatRect rectWnd = GetWindowRect();
+  if (rectWnd.IsEmpty())
+    return;
+
+  CFX_PointF ptCenter = GetCenterPoint();
+  int32_t nTransparency = GetTransparency();
+
+  if (m_eScrollBarType == SBT_HSCROLL) {
+    CPWL_Wnd::DrawThisAppearance(pDevice, mtUser2Device);
+
+    CFX_PointF pt1;
+    CFX_PointF pt2;
+    CFX_PointF pt3;
+    static constexpr float kScrollBarTriangleQuarterLength =
+        kScrollBarTriangleHalfLength * 0.5;
+    if (m_eSBButtonType == PSBT_MIN) {
+      pt1 =
+          CFX_PointF(ptCenter.x - kScrollBarTriangleQuarterLength, ptCenter.y);
+      pt2 = CFX_PointF(ptCenter.x + kScrollBarTriangleQuarterLength,
+                       ptCenter.y + kScrollBarTriangleHalfLength);
+      pt3 = CFX_PointF(ptCenter.x + kScrollBarTriangleQuarterLength,
+                       ptCenter.y - kScrollBarTriangleHalfLength);
+    } else if (m_eSBButtonType == PSBT_MAX) {
+      pt1 =
+          CFX_PointF(ptCenter.x + kScrollBarTriangleQuarterLength, ptCenter.y);
+      pt2 = CFX_PointF(ptCenter.x - kScrollBarTriangleQuarterLength,
+                       ptCenter.y + kScrollBarTriangleHalfLength);
+      pt3 = CFX_PointF(ptCenter.x - kScrollBarTriangleQuarterLength,
+                       ptCenter.y - kScrollBarTriangleHalfLength);
+    }
+
+    if (rectWnd.right - rectWnd.left > kScrollBarTriangleHalfLength * 2 &&
+        rectWnd.top - rectWnd.bottom > kScrollBarTriangleHalfLength) {
+      CFX_PathData path;
+      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, &mtUser2Device, nullptr,
+                        PWL_DEFAULT_BLACKCOLOR.ToFXColor(nTransparency), 0,
+                        FXFILL_ALTERNATE);
+    }
+    return;
+  }
+
+  // draw border
+  pDevice->DrawStrokeRect(&mtUser2Device, rectWnd,
+                          ArgbEncode(nTransparency, 100, 100, 100), 0.0f);
+  pDevice->DrawStrokeRect(&mtUser2Device, rectWnd.GetDeflated(0.5f, 0.5f),
+                          ArgbEncode(nTransparency, 255, 255, 255), 1.0f);
+
+  if (m_eSBButtonType != PSBT_POS) {
+    // draw background
+    if (IsEnabled()) {
+      pDevice->DrawShadow(&mtUser2Device, true, false,
+                          rectWnd.GetDeflated(1.0f, 1.0f), nTransparency, 80,
+                          220);
+    } else {
+      pDevice->DrawFillRect(&mtUser2Device, rectWnd.GetDeflated(1.0f, 1.0f),
+                            ArgbEncode(255, 255, 255, 255));
+    }
+
+    // draw arrow
+    if (rectWnd.top - rectWnd.bottom > 6.0f) {
+      float fX = rectWnd.left + 1.5f;
+      float fY = rectWnd.bottom;
+      std::vector<CFX_PointF> pts;
+      if (m_eSBButtonType == PSBT_MIN) {
+        pts.push_back(CFX_PointF(fX + 2.5f, fY + 4.0f));
+        pts.push_back(CFX_PointF(fX + 2.5f, fY + 3.0f));
+        pts.push_back(CFX_PointF(fX + 4.5f, fY + 5.0f));
+        pts.push_back(CFX_PointF(fX + 6.5f, fY + 3.0f));
+        pts.push_back(CFX_PointF(fX + 6.5f, fY + 4.0f));
+        pts.push_back(CFX_PointF(fX + 4.5f, fY + 6.0f));
+        pts.push_back(CFX_PointF(fX + 2.5f, fY + 4.0f));
+      } else {
+        pts.push_back(CFX_PointF(fX + 2.5f, fY + 5.0f));
+        pts.push_back(CFX_PointF(fX + 2.5f, fY + 6.0f));
+        pts.push_back(CFX_PointF(fX + 4.5f, fY + 4.0f));
+        pts.push_back(CFX_PointF(fX + 6.5f, fY + 6.0f));
+        pts.push_back(CFX_PointF(fX + 6.5f, fY + 5.0f));
+        pts.push_back(CFX_PointF(fX + 4.5f, fY + 3.0f));
+        pts.push_back(CFX_PointF(fX + 2.5f, fY + 5.0f));
+      }
+      pDevice->DrawFillArea(&mtUser2Device, pts.data(), 7,
+                            IsEnabled()
+                                ? ArgbEncode(nTransparency, 255, 255, 255)
+                                : PWL_DEFAULT_HEAVYGRAYCOLOR.ToFXColor(255));
+    }
+    return;
+  }
+
+  if (IsEnabled()) {
+    // draw shadow effect
+    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;
+
+    const FX_COLORREF refs[] = {ArgbEncode(nTransparency, 210, 210, 210),
+                                ArgbEncode(nTransparency, 220, 220, 220),
+                                ArgbEncode(nTransparency, 240, 240, 240),
+                                ArgbEncode(nTransparency, 240, 240, 240),
+                                ArgbEncode(nTransparency, 210, 210, 210),
+                                ArgbEncode(nTransparency, 180, 180, 180),
+                                ArgbEncode(nTransparency, 150, 150, 150),
+                                ArgbEncode(nTransparency, 150, 150, 150),
+                                ArgbEncode(nTransparency, 180, 180, 180),
+                                ArgbEncode(nTransparency, 210, 210, 210)};
+    for (FX_COLORREF ref : refs) {
+      pDevice->DrawStrokeLine(&mtUser2Device, ptTop, ptBottom, ref, 1.0f);
+
+      ptTop.x += 1.0f;
+      ptBottom.x += 1.0f;
+    }
+  } else {
+    pDevice->DrawFillRect(&mtUser2Device, rectWnd.GetDeflated(0.5f, 0.5f),
+                          ArgbEncode(255, 255, 255, 255));
+  }
+
+  // draw friction
+  if (rectWnd.Height() <= 8.0f)
+    return;
+
+  FX_COLORREF crStroke = ArgbEncode(nTransparency, 120, 120, 120);
+  if (!IsEnabled())
+    crStroke = PWL_DEFAULT_HEAVYGRAYCOLOR.ToFXColor(255);
+
+  float nFrictionWidth = 5.0f;
+  float nFrictionHeight = 5.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);
+
+  for (size_t i = 0; i < 3; ++i) {
+    pDevice->DrawStrokeLine(&mtUser2Device, ptLeft, ptRight, crStroke, 1.0f);
+    ptLeft.y += 2.0f;
+    ptRight.y += 2.0f;
+  }
+}
+
+bool CPWL_SBButton::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
+  CPWL_Wnd::OnLButtonDown(point, nFlag);
+
+  if (CPWL_Wnd* pParent = GetParentWindow())
+    pParent->NotifyLButtonDown(this, point);
+
+  m_bMouseDown = true;
+  SetCapture();
+
+  return true;
+}
+
+bool CPWL_SBButton::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
+  CPWL_Wnd::OnLButtonUp(point, nFlag);
+
+  if (CPWL_Wnd* pParent = GetParentWindow())
+    pParent->NotifyLButtonUp(this, point);
+
+  m_bMouseDown = false;
+  ReleaseCapture();
+
+  return true;
+}
+
+bool CPWL_SBButton::OnMouseMove(const CFX_PointF& point, uint32_t nFlag) {
+  CPWL_Wnd::OnMouseMove(point, nFlag);
+
+  if (CPWL_Wnd* pParent = GetParentWindow())
+    pParent->NotifyMouseMove(this, point);
+
+  return true;
+}
+
+CPWL_ScrollBar::CPWL_ScrollBar(PWL_SCROLLBAR_TYPE sbType)
+    : m_sbType(sbType),
+      m_pMinButton(nullptr),
+      m_pMaxButton(nullptr),
+      m_pPosButton(nullptr),
+      m_bMouseDown(false),
+      m_bMinOrMax(false),
+      m_bNotifyForever(true) {}
+
+CPWL_ScrollBar::~CPWL_ScrollBar() {}
+
+ByteString CPWL_ScrollBar::GetClassName() const {
+  return "CPWL_ScrollBar";
+}
+
+void CPWL_ScrollBar::OnCreate(CreateParams* pParamsToAdjust) {
+  pParamsToAdjust->eCursorType = FXCT_ARROW;
+}
+
+void CPWL_ScrollBar::OnDestroy() {
+  // Until cleanup takes place in the virtual destructor for CPWL_Wnd
+  // subclasses, implement the virtual OnDestroy method that does the
+  // cleanup first, then invokes the superclass OnDestroy ... gee,
+  // like a dtor would.
+  m_pMinButton.Release();
+  m_pMaxButton.Release();
+  m_pPosButton.Release();
+  CPWL_Wnd::OnDestroy();
+}
+
+bool CPWL_ScrollBar::RePosChildWnd() {
+  CFX_FloatRect rcClient = GetClientRect();
+  CFX_FloatRect rcMinButton, rcMaxButton;
+  float fBWidth = 0;
+
+  switch (m_sbType) {
+    case SBT_HSCROLL:
+      if (rcClient.right - rcClient.left >
+          kButtonWidth * 2 + kPosButtonMinWidth + 2) {
+        rcMinButton = CFX_FloatRect(rcClient.left, rcClient.bottom,
+                                    rcClient.left + kButtonWidth, rcClient.top);
+        rcMaxButton =
+            CFX_FloatRect(rcClient.right - kButtonWidth, rcClient.bottom,
+                          rcClient.right, rcClient.top);
+      } else {
+        fBWidth = (rcClient.right - rcClient.left - kPosButtonMinWidth - 2) / 2;
+
+        if (fBWidth > 0) {
+          rcMinButton = CFX_FloatRect(rcClient.left, rcClient.bottom,
+                                      rcClient.left + fBWidth, rcClient.top);
+          rcMaxButton = CFX_FloatRect(rcClient.right - fBWidth, rcClient.bottom,
+                                      rcClient.right, rcClient.top);
+        } else {
+          if (!SetVisible(false))
+            return false;
+        }
+      }
+      break;
+    case SBT_VSCROLL:
+      if (IsFloatBigger(rcClient.top - rcClient.bottom,
+                        kButtonWidth * 2 + kPosButtonMinWidth + 2)) {
+        rcMinButton = CFX_FloatRect(rcClient.left, rcClient.top - kButtonWidth,
+                                    rcClient.right, rcClient.top);
+        rcMaxButton =
+            CFX_FloatRect(rcClient.left, rcClient.bottom, rcClient.right,
+                          rcClient.bottom + kButtonWidth);
+      } else {
+        fBWidth = (rcClient.top - rcClient.bottom - kPosButtonMinWidth - 2) / 2;
+
+        if (IsFloatBigger(fBWidth, 0)) {
+          rcMinButton = CFX_FloatRect(rcClient.left, rcClient.top - fBWidth,
+                                      rcClient.right, rcClient.top);
+          rcMaxButton =
+              CFX_FloatRect(rcClient.left, rcClient.bottom, rcClient.right,
+                            rcClient.bottom + fBWidth);
+        } else {
+          if (!SetVisible(false))
+            return false;
+        }
+      }
+      break;
+  }
+
+  ObservedPtr thisObserved(this);
+
+  if (m_pMinButton) {
+    m_pMinButton->Move(rcMinButton, true, false);
+    if (!thisObserved)
+      return false;
+  }
+
+  if (m_pMaxButton) {
+    m_pMaxButton->Move(rcMaxButton, true, false);
+    if (!thisObserved)
+      return false;
+  }
+
+  if (!MovePosButton(false))
+    return false;
+
+  return true;
+}
+
+void CPWL_ScrollBar::DrawThisAppearance(CFX_RenderDevice* pDevice,
+                                        const CFX_Matrix& mtUser2Device) {
+  CFX_FloatRect rectWnd = GetWindowRect();
+
+  if (IsVisible() && !rectWnd.IsEmpty()) {
+    pDevice->DrawFillRect(&mtUser2Device, rectWnd, GetBackgroundColor(),
+                          GetTransparency());
+
+    pDevice->DrawStrokeLine(
+        &mtUser2Device, 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);
+
+    pDevice->DrawStrokeLine(
+        &mtUser2Device, 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_PointF& point, uint32_t nFlag) {
+  CPWL_Wnd::OnLButtonDown(point, nFlag);
+
+  if (HasFlag(PWS_AUTOTRANSPARENT)) {
+    if (GetTransparency() != 255) {
+      SetTransparency(255);
+      if (!InvalidateRect(nullptr))
+        return true;
+    }
+  }
+
+  CFX_FloatRect rcMinArea, rcMaxArea;
+
+  if (m_pPosButton && m_pPosButton->IsVisible()) {
+    CFX_FloatRect rcClient = GetClientRect();
+    CFX_FloatRect rcPosButton = m_pPosButton->GetWindowRect();
+
+    switch (m_sbType) {
+      case SBT_HSCROLL:
+        rcMinArea = CFX_FloatRect(rcClient.left + kButtonWidth, rcClient.bottom,
+                                  rcPosButton.left, rcClient.top);
+        rcMaxArea = CFX_FloatRect(rcPosButton.right, rcClient.bottom,
+                                  rcClient.right - kButtonWidth, rcClient.top);
+
+        break;
+      case SBT_VSCROLL:
+        rcMinArea = CFX_FloatRect(rcClient.left, rcPosButton.top,
+                                  rcClient.right, rcClient.top - kButtonWidth);
+        rcMaxArea = CFX_FloatRect(rcClient.left, rcClient.bottom + kButtonWidth,
+                                  rcClient.right, rcPosButton.bottom);
+        break;
+    }
+
+    rcMinArea.Normalize();
+    rcMaxArea.Normalize();
+
+    if (rcMinArea.Contains(point)) {
+      m_sData.SubBig();
+      if (!MovePosButton(true))
+        return true;
+      NotifyScrollWindow();
+    }
+
+    if (rcMaxArea.Contains(point)) {
+      m_sData.AddBig();
+      if (!MovePosButton(true))
+        return true;
+      NotifyScrollWindow();
+    }
+  }
+
+  return true;
+}
+
+bool CPWL_ScrollBar::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
+  CPWL_Wnd::OnLButtonUp(point, nFlag);
+
+  if (HasFlag(PWS_AUTOTRANSPARENT)) {
+    if (GetTransparency() != PWL_SCROLLBAR_TRANSPARENCY) {
+      SetTransparency(PWL_SCROLLBAR_TRANSPARENCY);
+      if (!InvalidateRect(nullptr))
+        return true;
+    }
+  }
+
+  EndTimer();
+  m_bMouseDown = false;
+
+  return true;
+}
+
+void CPWL_ScrollBar::SetScrollInfo(const PWL_SCROLL_INFO& info) {
+  if (info == m_OriginInfo)
+    return;
+
+  m_OriginInfo = info;
+  float fMax =
+      std::max(0.0f, info.fContentMax - info.fContentMin - info.fPlateWidth);
+  SetScrollRange(0, fMax, info.fPlateWidth);
+  SetScrollStep(info.fBigStep, info.fSmallStep);
+}
+
+void CPWL_ScrollBar::SetScrollPosition(float pos) {
+  switch (m_sbType) {
+    case SBT_HSCROLL:
+      pos = pos - m_OriginInfo.fContentMin;
+      break;
+    case SBT_VSCROLL:
+      pos = m_OriginInfo.fContentMax - pos;
+      break;
+  }
+  SetScrollPos(pos);
+}
+
+void CPWL_ScrollBar::NotifyLButtonDown(CPWL_Wnd* child, const CFX_PointF& pos) {
+  if (child == m_pMinButton)
+    OnMinButtonLBDown(pos);
+  else if (child == m_pMaxButton)
+    OnMaxButtonLBDown(pos);
+  else if (child == m_pPosButton)
+    OnPosButtonLBDown(pos);
+}
+
+void CPWL_ScrollBar::NotifyLButtonUp(CPWL_Wnd* child, const CFX_PointF& pos) {
+  if (child == m_pMinButton)
+    OnMinButtonLBUp(pos);
+  else if (child == m_pMaxButton)
+    OnMaxButtonLBUp(pos);
+  else if (child == m_pPosButton)
+    OnPosButtonLBUp(pos);
+}
+
+void CPWL_ScrollBar::NotifyMouseMove(CPWL_Wnd* child, const CFX_PointF& pos) {
+  if (child == m_pMinButton)
+    OnMinButtonMouseMove(pos);
+  else if (child == m_pMaxButton)
+    OnMaxButtonMouseMove(pos);
+  else if (child == m_pPosButton)
+    OnPosButtonMouseMove(pos);
+}
+
+void CPWL_ScrollBar::CreateButtons(const CreateParams& cp) {
+  CreateParams scp = cp;
+  scp.pParentWnd = this;
+  scp.dwBorderWidth = 2;
+  scp.nBorderStyle = BorderStyle::BEVELED;
+
+  scp.dwFlags =
+      PWS_VISIBLE | PWS_CHILD | PWS_BORDER | PWS_BACKGROUND | PWS_NOREFRESHCLIP;
+
+  if (!m_pMinButton) {
+    m_pMinButton = new CPWL_SBButton(m_sbType, PSBT_MIN);
+    m_pMinButton->Create(scp);
+  }
+
+  if (!m_pMaxButton) {
+    m_pMaxButton = new CPWL_SBButton(m_sbType, PSBT_MAX);
+    m_pMaxButton->Create(scp);
+  }
+
+  if (!m_pPosButton) {
+    m_pPosButton = new CPWL_SBButton(m_sbType, PSBT_POS);
+
+    ObservedPtr thisObserved(this);
+    if (!m_pPosButton->SetVisible(false) || !thisObserved)
+      return;
+    m_pPosButton->Create(scp);
+  }
+}
+
+float CPWL_ScrollBar::GetScrollBarWidth() const {
+  if (!IsVisible())
+    return 0;
+
+  return PWL_SCROLLBAR_WIDTH;
+}
+
+void CPWL_ScrollBar::SetScrollRange(float fMin,
+                                    float fMax,
+                                    float fClientWidth) {
+  if (!m_pPosButton)
+    return;
+
+  m_sData.SetScrollRange(fMin, fMax);
+  m_sData.SetClientWidth(fClientWidth);
+
+  ObservedPtr thisObserved(this);
+
+  if (IsFloatSmaller(m_sData.ScrollRange.GetWidth(), 0.0f)) {
+    m_pPosButton->SetVisible(false);
+    // Note, |this| may no longer be viable at this point. If more work needs
+    // to be done, check thisObserved.
+    return;
+  }
+
+  if (!m_pPosButton->SetVisible(true) || !thisObserved)
+    return;
+
+  MovePosButton(true);
+  // Note, |this| may no longer be viable at this point. If more work needs
+  // to be done, check the return value of MovePosButton().
+}
+
+void CPWL_ScrollBar::SetScrollPos(float fPos) {
+  float fOldPos = m_sData.fScrollPos;
+  m_sData.SetPos(fPos);
+  if (!IsFloatEqual(m_sData.fScrollPos, fOldPos)) {
+    MovePosButton(true);
+    // Note, |this| may no longer be viable at this point. If more work needs
+    // to be done, check the return value of MovePosButton().
+  }
+}
+
+void CPWL_ScrollBar::SetScrollStep(float fBigStep, float fSmallStep) {
+  m_sData.SetBigStep(fBigStep);
+  m_sData.SetSmallStep(fSmallStep);
+}
+
+bool CPWL_ScrollBar::MovePosButton(bool bRefresh) {
+  ASSERT(m_pMinButton);
+  ASSERT(m_pMaxButton);
+
+  if (m_pPosButton->IsVisible()) {
+    CFX_FloatRect rcClient;
+    CFX_FloatRect rcPosArea, rcPosButton;
+
+    rcClient = GetClientRect();
+    rcPosArea = GetScrollArea();
+
+    float fLeft, fRight, fTop, fBottom;
+
+    switch (m_sbType) {
+      case SBT_HSCROLL:
+        fLeft = TrueToFace(m_sData.fScrollPos);
+        fRight = TrueToFace(m_sData.fScrollPos + m_sData.fClientWidth);
+
+        if (fRight - fLeft < kPosButtonMinWidth)
+          fRight = fLeft + kPosButtonMinWidth;
+
+        if (fRight > rcPosArea.right) {
+          fRight = rcPosArea.right;
+          fLeft = fRight - kPosButtonMinWidth;
+        }
+
+        rcPosButton =
+            CFX_FloatRect(fLeft, rcPosArea.bottom, fRight, rcPosArea.top);
+
+        break;
+      case SBT_VSCROLL:
+        fBottom = TrueToFace(m_sData.fScrollPos + m_sData.fClientWidth);
+        fTop = TrueToFace(m_sData.fScrollPos);
+
+        if (IsFloatSmaller(fTop - fBottom, kPosButtonMinWidth))
+          fBottom = fTop - kPosButtonMinWidth;
+
+        if (IsFloatSmaller(fBottom, rcPosArea.bottom)) {
+          fBottom = rcPosArea.bottom;
+          fTop = fBottom + kPosButtonMinWidth;
+        }
+
+        rcPosButton =
+            CFX_FloatRect(rcPosArea.left, fBottom, rcPosArea.right, fTop);
+
+        break;
+    }
+
+    ObservedPtr thisObserved(this);
+
+    m_pPosButton->Move(rcPosButton, true, bRefresh);
+    if (!thisObserved)
+      return false;
+  }
+
+  return true;
+}
+
+void CPWL_ScrollBar::OnMinButtonLBDown(const CFX_PointF& point) {
+  m_sData.SubSmall();
+  if (!MovePosButton(true))
+    return;
+  NotifyScrollWindow();
+
+  m_bMinOrMax = true;
+
+  EndTimer();
+  BeginTimer(100);
+}
+
+void CPWL_ScrollBar::OnMinButtonLBUp(const CFX_PointF& point) {}
+
+void CPWL_ScrollBar::OnMinButtonMouseMove(const CFX_PointF& point) {}
+
+void CPWL_ScrollBar::OnMaxButtonLBDown(const CFX_PointF& point) {
+  m_sData.AddSmall();
+  if (!MovePosButton(true))
+    return;
+  NotifyScrollWindow();
+
+  m_bMinOrMax = false;
+
+  EndTimer();
+  BeginTimer(100);
+}
+
+void CPWL_ScrollBar::OnMaxButtonLBUp(const CFX_PointF& point) {}
+
+void CPWL_ScrollBar::OnMaxButtonMouseMove(const CFX_PointF& point) {}
+
+void CPWL_ScrollBar::OnPosButtonLBDown(const CFX_PointF& point) {
+  m_bMouseDown = true;
+
+  if (m_pPosButton) {
+    CFX_FloatRect rcPosButton = m_pPosButton->GetWindowRect();
+
+    switch (m_sbType) {
+      case SBT_HSCROLL:
+        m_nOldPos = point.x;
+        m_fOldPosButton = rcPosButton.left;
+        break;
+      case SBT_VSCROLL:
+        m_nOldPos = point.y;
+        m_fOldPosButton = rcPosButton.top;
+        break;
+    }
+  }
+}
+
+void CPWL_ScrollBar::OnPosButtonLBUp(const CFX_PointF& point) {
+  if (m_bMouseDown) {
+    if (!m_bNotifyForever)
+      NotifyScrollWindow();
+  }
+  m_bMouseDown = false;
+}
+
+void CPWL_ScrollBar::OnPosButtonMouseMove(const CFX_PointF& point) {
+  float fOldScrollPos = m_sData.fScrollPos;
+
+  float fNewPos = 0;
+
+  switch (m_sbType) {
+    case SBT_HSCROLL:
+      if (fabs(point.x - m_nOldPos) < 1)
+        return;
+      fNewPos = FaceToTrue(m_fOldPosButton + point.x - m_nOldPos);
+      break;
+    case SBT_VSCROLL:
+      if (fabs(point.y - m_nOldPos) < 1)
+        return;
+      fNewPos = FaceToTrue(m_fOldPosButton + point.y - m_nOldPos);
+      break;
+  }
+
+  if (m_bMouseDown) {
+    switch (m_sbType) {
+      case SBT_HSCROLL:
+
+        if (IsFloatSmaller(fNewPos, m_sData.ScrollRange.fMin)) {
+          fNewPos = m_sData.ScrollRange.fMin;
+        }
+
+        if (IsFloatBigger(fNewPos, m_sData.ScrollRange.fMax)) {
+          fNewPos = m_sData.ScrollRange.fMax;
+        }
+
+        m_sData.SetPos(fNewPos);
+
+        break;
+      case SBT_VSCROLL:
+
+        if (IsFloatSmaller(fNewPos, m_sData.ScrollRange.fMin)) {
+          fNewPos = m_sData.ScrollRange.fMin;
+        }
+
+        if (IsFloatBigger(fNewPos, m_sData.ScrollRange.fMax)) {
+          fNewPos = m_sData.ScrollRange.fMax;
+        }
+
+        m_sData.SetPos(fNewPos);
+
+        break;
+    }
+
+    if (!IsFloatEqual(fOldScrollPos, m_sData.fScrollPos)) {
+      if (!MovePosButton(true))
+        return;
+
+      if (m_bNotifyForever)
+        NotifyScrollWindow();
+    }
+  }
+}
+
+void CPWL_ScrollBar::NotifyScrollWindow() {
+  CPWL_Wnd* pParent = GetParentWindow();
+  if (!pParent || m_sbType != SBT_VSCROLL)
+    return;
+
+  pParent->ScrollWindowVertically(m_OriginInfo.fContentMax -
+                                  m_sData.fScrollPos);
+}
+
+CFX_FloatRect CPWL_ScrollBar::GetScrollArea() const {
+  CFX_FloatRect rcClient = GetClientRect();
+  CFX_FloatRect rcArea;
+
+  if (!m_pMinButton || !m_pMaxButton)
+    return rcClient;
+
+  CFX_FloatRect rcMin = m_pMinButton->GetWindowRect();
+  CFX_FloatRect rcMax = m_pMaxButton->GetWindowRect();
+
+  float fMinWidth = rcMin.right - rcMin.left;
+  float fMinHeight = rcMin.top - rcMin.bottom;
+  float fMaxWidth = rcMax.right - rcMax.left;
+  float fMaxHeight = rcMax.top - rcMax.bottom;
+
+  switch (m_sbType) {
+    case SBT_HSCROLL:
+      if (rcClient.right - rcClient.left > fMinWidth + fMaxWidth + 2) {
+        rcArea = CFX_FloatRect(rcClient.left + fMinWidth + 1, rcClient.bottom,
+                               rcClient.right - fMaxWidth - 1, rcClient.top);
+      } else {
+        rcArea = CFX_FloatRect(rcClient.left + fMinWidth + 1, rcClient.bottom,
+                               rcClient.left + fMinWidth + 1, rcClient.top);
+      }
+      break;
+    case SBT_VSCROLL:
+      if (rcClient.top - rcClient.bottom > fMinHeight + fMaxHeight + 2) {
+        rcArea = CFX_FloatRect(rcClient.left, rcClient.bottom + fMinHeight + 1,
+                               rcClient.right, rcClient.top - fMaxHeight - 1);
+      } else {
+        rcArea =
+            CFX_FloatRect(rcClient.left, rcClient.bottom + fMinHeight + 1,
+                          rcClient.right, rcClient.bottom + fMinHeight + 1);
+      }
+      break;
+  }
+
+  rcArea.Normalize();
+
+  return rcArea;
+}
+
+float CPWL_ScrollBar::TrueToFace(float fTrue) {
+  CFX_FloatRect rcPosArea;
+  rcPosArea = GetScrollArea();
+
+  float fFactWidth = m_sData.ScrollRange.GetWidth() + m_sData.fClientWidth;
+  fFactWidth = fFactWidth == 0 ? 1 : fFactWidth;
+
+  float fFace = 0;
+
+  switch (m_sbType) {
+    case SBT_HSCROLL:
+      fFace = rcPosArea.left +
+              fTrue * (rcPosArea.right - rcPosArea.left) / fFactWidth;
+      break;
+    case SBT_VSCROLL:
+      fFace = rcPosArea.top -
+              fTrue * (rcPosArea.top - rcPosArea.bottom) / fFactWidth;
+      break;
+  }
+
+  return fFace;
+}
+
+float CPWL_ScrollBar::FaceToTrue(float fFace) {
+  CFX_FloatRect rcPosArea;
+  rcPosArea = GetScrollArea();
+
+  float fFactWidth = m_sData.ScrollRange.GetWidth() + m_sData.fClientWidth;
+  fFactWidth = fFactWidth == 0 ? 1 : fFactWidth;
+
+  float fTrue = 0;
+
+  switch (m_sbType) {
+    case SBT_HSCROLL:
+      fTrue = (fFace - rcPosArea.left) * fFactWidth /
+              (rcPosArea.right - rcPosArea.left);
+      break;
+    case SBT_VSCROLL:
+      fTrue = (rcPosArea.top - fFace) * fFactWidth /
+              (rcPosArea.top - rcPosArea.bottom);
+      break;
+  }
+
+  return fTrue;
+}
+
+void CPWL_ScrollBar::CreateChildWnd(const CreateParams& cp) {
+  CreateButtons(cp);
+}
+
+void CPWL_ScrollBar::TimerProc() {
+  PWL_SCROLL_PRIVATEDATA sTemp = m_sData;
+  if (m_bMinOrMax)
+    m_sData.SubSmall();
+  else
+    m_sData.AddSmall();
+
+  if (sTemp != m_sData) {
+    if (!MovePosButton(true))
+      return;
+    NotifyScrollWindow();
+  }
+}
diff --git a/fpdfsdk/pdfwindow/PWL_ScrollBar.h b/fpdfsdk/pwl/cpwl_scroll_bar.h
similarity index 63%
rename from fpdfsdk/pdfwindow/PWL_ScrollBar.h
rename to fpdfsdk/pwl/cpwl_scroll_bar.h
index 9546a9e..6921732 100644
--- a/fpdfsdk/pdfwindow/PWL_ScrollBar.h
+++ b/fpdfsdk/pwl/cpwl_scroll_bar.h
@@ -4,10 +4,11 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
-#ifndef FPDFSDK_PDFWINDOW_PWL_SCROLLBAR_H_
-#define FPDFSDK_PDFWINDOW_PWL_SCROLLBAR_H_
+#ifndef FPDFSDK_PWL_CPWL_SCROLL_BAR_H_
+#define FPDFSDK_PWL_CPWL_SCROLL_BAR_H_
 
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
+#include "core/fxcrt/unowned_ptr.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
 
 class CPWL_SBButton;
 class CPWL_ScrollBar;
@@ -30,11 +31,11 @@
     return !(*this == that);
   }
 
-  FX_FLOAT fContentMin;
-  FX_FLOAT fContentMax;
-  FX_FLOAT fPlateWidth;
-  FX_FLOAT fBigStep;
-  FX_FLOAT fSmallStep;
+  float fContentMin;
+  float fContentMax;
+  float fPlateWidth;
+  float fBigStep;
+  float fSmallStep;
 };
 
 enum PWL_SCROLLBAR_TYPE { SBT_HSCROLL, SBT_VSCROLL };
@@ -48,11 +49,10 @@
   ~CPWL_SBButton() override;
 
   // CPWL_Wnd
-  CFX_ByteString GetClassName() const override;
-  void OnCreate(PWL_CREATEPARAM& cp) override;
-  void GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) override;
+  ByteString GetClassName() const override;
+  void OnCreate(CreateParams* pParamsToAdjust) override;
   void DrawThisAppearance(CFX_RenderDevice* pDevice,
-                          CFX_Matrix* pUser2Device) override;
+                          const CFX_Matrix& mtUser2Device) 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;
@@ -67,7 +67,7 @@
 struct PWL_FLOATRANGE {
  public:
   PWL_FLOATRANGE();
-  PWL_FLOATRANGE(FX_FLOAT min, FX_FLOAT max);
+  PWL_FLOATRANGE(float min, float max);
 
   bool operator==(const PWL_FLOATRANGE& that) const {
     return fMin == that.fMin && fMax == that.fMax;
@@ -75,12 +75,12 @@
   bool operator!=(const PWL_FLOATRANGE& that) const { return !(*this == that); }
 
   void Default();
-  void Set(FX_FLOAT min, FX_FLOAT max);
-  bool In(FX_FLOAT x) const;
-  FX_FLOAT GetWidth() const;
+  void Set(float min, float max);
+  bool In(float x) const;
+  float GetWidth() const;
 
-  FX_FLOAT fMin;
-  FX_FLOAT fMax;
+  float fMin;
+  float fMax;
 };
 
 struct PWL_SCROLL_PRIVATEDATA {
@@ -97,11 +97,11 @@
   }
 
   void Default();
-  void SetScrollRange(FX_FLOAT min, FX_FLOAT max);
-  void SetClientWidth(FX_FLOAT width);
-  void SetSmallStep(FX_FLOAT step);
-  void SetBigStep(FX_FLOAT step);
-  bool SetPos(FX_FLOAT pos);
+  void SetScrollRange(float min, float max);
+  void SetClientWidth(float width);
+  void SetSmallStep(float step);
+  void SetBigStep(float step);
+  bool SetPos(float pos);
 
   void AddSmall();
   void SubSmall();
@@ -109,10 +109,10 @@
   void SubBig();
 
   PWL_FLOATRANGE ScrollRange;
-  FX_FLOAT fClientWidth;
-  FX_FLOAT fScrollPos;
-  FX_FLOAT fBigStep;
-  FX_FLOAT fSmallStep;
+  float fClientWidth;
+  float fScrollPos;
+  float fBigStep;
+  float fSmallStep;
 };
 
 class CPWL_ScrollBar : public CPWL_Wnd {
@@ -120,37 +120,40 @@
   explicit CPWL_ScrollBar(PWL_SCROLLBAR_TYPE sbType = SBT_HSCROLL);
   ~CPWL_ScrollBar() override;
 
-  // CPWL_Wnd
-  CFX_ByteString GetClassName() const override;
-  void OnCreate(PWL_CREATEPARAM& cp) override;
-  void RePosChildWnd() override;
-  void GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) override;
+  // CPWL_Wnd:
+  ByteString GetClassName() const override;
+  void OnCreate(CreateParams* pParamsToAdjust) override;
+  void OnDestroy() override;
+  bool RePosChildWnd() override;
   void DrawThisAppearance(CFX_RenderDevice* pDevice,
-                          CFX_Matrix* pUser2Device) override;
+                          const CFX_Matrix& mtUser2Device) 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,
-                intptr_t lParam = 0) override;
-  void CreateChildWnd(const PWL_CREATEPARAM& cp) override;
+  void SetScrollInfo(const PWL_SCROLL_INFO& info) override;
+  void SetScrollPosition(float pos) override;
+  void NotifyLButtonDown(CPWL_Wnd* child, const CFX_PointF& pos) override;
+  void NotifyLButtonUp(CPWL_Wnd* child, const CFX_PointF& pos) override;
+  void NotifyMouseMove(CPWL_Wnd* child, const CFX_PointF& pos) override;
+  void CreateChildWnd(const CreateParams& cp) override;
   void TimerProc() override;
 
-  FX_FLOAT GetScrollBarWidth() const;
+  float GetScrollBarWidth() const;
   PWL_SCROLLBAR_TYPE GetScrollBarType() const { return m_sbType; }
 
   void SetNotifyForever(bool bForever) { m_bNotifyForever = bForever; }
 
  protected:
-  void SetScrollRange(FX_FLOAT fMin, FX_FLOAT fMax, FX_FLOAT fClientWidth);
-  void SetScrollPos(FX_FLOAT fPos);
-  void MovePosButton(bool bRefresh);
-  void SetScrollStep(FX_FLOAT fBigStep, FX_FLOAT fSmallStep);
+  void SetScrollRange(float fMin, float fMax, float fClientWidth);
+  void SetScrollPos(float fPos);
+
+  // Returns |true| iff this instance is still allocated.
+  bool MovePosButton(bool bRefresh);
+  void SetScrollStep(float fBigStep, float fSmallStep);
   void NotifyScrollWindow();
   CFX_FloatRect GetScrollArea() const;
 
  private:
-  void CreateButtons(const PWL_CREATEPARAM& cp);
+  void CreateButtons(const CreateParams& cp);
 
   void OnMinButtonLBDown(const CFX_PointF& point);
   void OnMinButtonLBUp(const CFX_PointF& point);
@@ -164,20 +167,20 @@
   void OnPosButtonLBUp(const CFX_PointF& point);
   void OnPosButtonMouseMove(const CFX_PointF& point);
 
-  FX_FLOAT TrueToFace(FX_FLOAT);
-  FX_FLOAT FaceToTrue(FX_FLOAT);
+  float TrueToFace(float);
+  float FaceToTrue(float);
 
   PWL_SCROLLBAR_TYPE m_sbType;
   PWL_SCROLL_INFO m_OriginInfo;
-  CPWL_SBButton* m_pMinButton;
-  CPWL_SBButton* m_pMaxButton;
-  CPWL_SBButton* m_pPosButton;
+  UnownedPtr<CPWL_SBButton> m_pMinButton;
+  UnownedPtr<CPWL_SBButton> m_pMaxButton;
+  UnownedPtr<CPWL_SBButton> m_pPosButton;
   PWL_SCROLL_PRIVATEDATA m_sData;
   bool m_bMouseDown;
   bool m_bMinOrMax;
   bool m_bNotifyForever;
-  FX_FLOAT m_nOldPos;
-  FX_FLOAT m_fOldPosButton;
+  float m_nOldPos;
+  float m_fOldPosButton;
 };
 
-#endif  // FPDFSDK_PDFWINDOW_PWL_SCROLLBAR_H_
+#endif  // FPDFSDK_PWL_CPWL_SCROLL_BAR_H_
diff --git a/fpdfsdk/pdfwindow/PWL_SpecialButton.cpp b/fpdfsdk/pwl/cpwl_special_button.cpp
similarity index 77%
rename from fpdfsdk/pdfwindow/PWL_SpecialButton.cpp
rename to fpdfsdk/pwl/cpwl_special_button.cpp
index 1c46c37..ddca67e 100644
--- a/fpdfsdk/pdfwindow/PWL_SpecialButton.cpp
+++ b/fpdfsdk/pwl/cpwl_special_button.cpp
@@ -4,28 +4,28 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
-#include "fpdfsdk/pdfwindow/PWL_Button.h"
-#include "fpdfsdk/pdfwindow/PWL_SpecialButton.h"
-#include "fpdfsdk/pdfwindow/PWL_Utils.h"
-#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
+#include "fpdfsdk/pwl/cpwl_special_button.h"
+#include "fpdfsdk/pwl/cpwl_button.h"
+#include "fpdfsdk/pwl/cpwl_wnd.h"
 
 CPWL_PushButton::CPWL_PushButton() {}
 
 CPWL_PushButton::~CPWL_PushButton() {}
 
-CFX_ByteString CPWL_PushButton::GetClassName() const {
+ByteString CPWL_PushButton::GetClassName() const {
   return "CPWL_PushButton";
 }
 
 CFX_FloatRect CPWL_PushButton::GetFocusRect() const {
-  return CPWL_Utils::DeflateRect(GetWindowRect(), (FX_FLOAT)GetBorderWidth());
+  return GetWindowRect().GetDeflated(static_cast<float>(GetBorderWidth()),
+                                     static_cast<float>(GetBorderWidth()));
 }
 
 CPWL_CheckBox::CPWL_CheckBox() : m_bChecked(false) {}
 
 CPWL_CheckBox::~CPWL_CheckBox() {}
 
-CFX_ByteString CPWL_CheckBox::GetClassName() const {
+ByteString CPWL_CheckBox::GetClassName() const {
   return "CPWL_CheckBox";
 }
 
@@ -54,7 +54,7 @@
 
 CPWL_RadioButton::~CPWL_RadioButton() {}
 
-CFX_ByteString CPWL_RadioButton::GetClassName() const {
+ByteString CPWL_RadioButton::GetClassName() const {
   return "CPWL_RadioButton";
 }
 
diff --git a/fpdfsdk/pdfwindow/PWL_SpecialButton.h b/fpdfsdk/pwl/cpwl_special_button.h
similarity index 76%
rename from fpdfsdk/pdfwindow/PWL_SpecialButton.h
rename to fpdfsdk/pwl/cpwl_special_button.h
index 93f611b..076b529 100644
--- a/fpdfsdk/pdfwindow/PWL_SpecialButton.h
+++ b/fpdfsdk/pwl/cpwl_special_button.h
@@ -4,10 +4,10 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
-#ifndef FPDFSDK_PDFWINDOW_PWL_SPECIALBUTTON_H_
-#define FPDFSDK_PDFWINDOW_PWL_SPECIALBUTTON_H_
+#ifndef FPDFSDK_PWL_CPWL_SPECIAL_BUTTON_H_
+#define FPDFSDK_PWL_CPWL_SPECIAL_BUTTON_H_
 
-#include "fpdfsdk/pdfwindow/PWL_Button.h"
+#include "fpdfsdk/pwl/cpwl_button.h"
 
 class CPWL_PushButton : public CPWL_Button {
  public:
@@ -15,7 +15,7 @@
   ~CPWL_PushButton() override;
 
   // CPWL_Button
-  CFX_ByteString GetClassName() const override;
+  ByteString GetClassName() const override;
   CFX_FloatRect GetFocusRect() const override;
 };
 
@@ -25,7 +25,7 @@
   ~CPWL_CheckBox() override;
 
   // CPWL_Button
-  CFX_ByteString GetClassName() const override;
+  ByteString GetClassName() const override;
   bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) override;
   bool OnChar(uint16_t nChar, uint32_t nFlag) override;
 
@@ -42,7 +42,7 @@
   ~CPWL_RadioButton() override;
 
   // CPWL_Button
-  CFX_ByteString GetClassName() const override;
+  ByteString GetClassName() const override;
   bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) override;
   bool OnChar(uint16_t nChar, uint32_t nFlag) override;
 
@@ -53,4 +53,4 @@
   bool m_bChecked;
 };
 
-#endif  // FPDFSDK_PDFWINDOW_PWL_SPECIALBUTTON_H_
+#endif  // FPDFSDK_PWL_CPWL_SPECIAL_BUTTON_H_
diff --git a/fpdfsdk/pwl/cpwl_timer.cpp b/fpdfsdk/pwl/cpwl_timer.cpp
new file mode 100644
index 0000000..34f81fc
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_timer.cpp
@@ -0,0 +1,62 @@
+// 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/pwl/cpwl_timer.h"
+
+#include <map>
+
+#include "fpdfsdk/cfx_systemhandler.h"
+#include "fpdfsdk/pwl/cpwl_timer_handler.h"
+
+namespace {
+
+std::map<int32_t, CPWL_Timer*>& GetPWLTimeMap() {
+  // Leak the object at shutdown.
+  static auto* timeMap = new std::map<int32_t, CPWL_Timer*>;
+  return *timeMap;
+}
+
+}  // namespace
+
+CPWL_Timer::CPWL_Timer(CPWL_TimerHandler* pAttached,
+                       CFX_SystemHandler* pSystemHandler)
+    : m_nTimerID(0), m_pAttached(pAttached), m_pSystemHandler(pSystemHandler) {
+  ASSERT(m_pAttached);
+  ASSERT(m_pSystemHandler);
+}
+
+CPWL_Timer::~CPWL_Timer() {
+  KillPWLTimer();
+}
+
+int32_t CPWL_Timer::SetPWLTimer(int32_t nElapse) {
+  if (m_nTimerID != 0)
+    KillPWLTimer();
+  m_nTimerID = m_pSystemHandler->SetTimer(nElapse, TimerProc);
+
+  GetPWLTimeMap()[m_nTimerID] = this;
+  return m_nTimerID;
+}
+
+void CPWL_Timer::KillPWLTimer() {
+  if (m_nTimerID == 0)
+    return;
+
+  m_pSystemHandler->KillTimer(m_nTimerID);
+  GetPWLTimeMap().erase(m_nTimerID);
+  m_nTimerID = 0;
+}
+
+// static
+void CPWL_Timer::TimerProc(int32_t idEvent) {
+  auto it = GetPWLTimeMap().find(idEvent);
+  if (it == GetPWLTimeMap().end())
+    return;
+
+  CPWL_Timer* pTimer = it->second;
+  if (pTimer->m_pAttached)
+    pTimer->m_pAttached->TimerProc();
+}
diff --git a/fpdfsdk/pwl/cpwl_timer.h b/fpdfsdk/pwl/cpwl_timer.h
new file mode 100644
index 0000000..6e082ab
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_timer.h
@@ -0,0 +1,31 @@
+// Copyright 2017 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FPDFSDK_PWL_CPWL_TIMER_H_
+#define FPDFSDK_PWL_CPWL_TIMER_H_
+
+#include "core/fxcrt/unowned_ptr.h"
+
+class CFX_SystemHandler;
+class CPWL_TimerHandler;
+
+class CPWL_Timer {
+ public:
+  CPWL_Timer(CPWL_TimerHandler* pAttached, CFX_SystemHandler* pSystemHandler);
+  virtual ~CPWL_Timer();
+
+  static void TimerProc(int32_t idEvent);
+
+  int32_t SetPWLTimer(int32_t nElapse);
+  void KillPWLTimer();
+
+ private:
+  int32_t m_nTimerID;
+  UnownedPtr<CPWL_TimerHandler> m_pAttached;
+  UnownedPtr<CFX_SystemHandler> m_pSystemHandler;
+};
+
+#endif  // FPDFSDK_PWL_CPWL_TIMER_H_
diff --git a/fpdfsdk/pwl/cpwl_timer_handler.cpp b/fpdfsdk/pwl/cpwl_timer_handler.cpp
new file mode 100644
index 0000000..33af306
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_timer_handler.cpp
@@ -0,0 +1,27 @@
+// 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/pwl/cpwl_timer_handler.h"
+
+#include "fpdfsdk/pwl/cpwl_timer.h"
+#include "third_party/base/ptr_util.h"
+
+CPWL_TimerHandler::CPWL_TimerHandler() {}
+
+CPWL_TimerHandler::~CPWL_TimerHandler() {}
+
+void CPWL_TimerHandler::BeginTimer(int32_t nElapse) {
+  if (!m_pTimer)
+    m_pTimer = pdfium::MakeUnique<CPWL_Timer>(this, GetSystemHandler());
+  m_pTimer->SetPWLTimer(nElapse);
+}
+
+void CPWL_TimerHandler::EndTimer() {
+  if (m_pTimer)
+    m_pTimer->KillPWLTimer();
+}
+
+void CPWL_TimerHandler::TimerProc() {}
diff --git a/fpdfsdk/pwl/cpwl_timer_handler.h b/fpdfsdk/pwl/cpwl_timer_handler.h
new file mode 100644
index 0000000..f208e1c
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_timer_handler.h
@@ -0,0 +1,30 @@
+// Copyright 2017 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FPDFSDK_PWL_CPWL_TIMER_HANDLER_H_
+#define FPDFSDK_PWL_CPWL_TIMER_HANDLER_H_
+
+#include <memory>
+
+class CFX_SystemHandler;
+class CPWL_Timer;
+
+class CPWL_TimerHandler {
+ public:
+  CPWL_TimerHandler();
+  virtual ~CPWL_TimerHandler();
+
+  virtual void TimerProc();
+  virtual CFX_SystemHandler* GetSystemHandler() const = 0;
+
+  void BeginTimer(int32_t nElapse);
+  void EndTimer();
+
+ private:
+  std::unique_ptr<CPWL_Timer> m_pTimer;
+};
+
+#endif  // FPDFSDK_PWL_CPWL_TIMER_HANDLER_H_
diff --git a/fpdfsdk/pwl/cpwl_wnd.cpp b/fpdfsdk/pwl/cpwl_wnd.cpp
new file mode 100644
index 0000000..368db74
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_wnd.cpp
@@ -0,0 +1,801 @@
+// 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/pwl/cpwl_wnd.h"
+
+#include <map>
+#include <sstream>
+#include <vector>
+
+#include "core/fxge/cfx_renderdevice.h"
+#include "fpdfsdk/pwl/cpwl_scroll_bar.h"
+#include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
+
+namespace {
+
+constexpr float kDefaultFontSize = 9.0f;
+
+}  // namespace
+
+CPWL_Wnd::CreateParams::CreateParams()
+    : rcRectWnd(0, 0, 0, 0),
+      pSystemHandler(nullptr),
+      pFontMap(nullptr),
+      pProvider(nullptr),
+      pFocusHandler(nullptr),
+      dwFlags(0),
+      sBackgroundColor(),
+      pAttachedWidget(nullptr),
+      nBorderStyle(BorderStyle::SOLID),
+      dwBorderWidth(1),
+      sBorderColor(),
+      sTextColor(),
+      nTransparency(255),
+      fFontSize(kDefaultFontSize),
+      sDash(3, 0, 0),
+      pAttachedData(nullptr),
+      pParentWnd(nullptr),
+      pMsgControl(nullptr),
+      eCursorType(FXCT_ARROW) {}
+
+CPWL_Wnd::CreateParams::CreateParams(const CreateParams& other) = default;
+
+CPWL_Wnd::CreateParams::~CreateParams() = default;
+
+class CPWL_MsgControl : public Observable<CPWL_MsgControl> {
+ public:
+  explicit CPWL_MsgControl(CPWL_Wnd* pWnd) : m_pCreatedWnd(pWnd) {}
+  ~CPWL_MsgControl() {}
+
+  bool IsWndCreated(const CPWL_Wnd* pWnd) const {
+    return m_pCreatedWnd == pWnd;
+  }
+
+  bool IsWndCaptureMouse(const CPWL_Wnd* pWnd) const {
+    return pWnd && pdfium::ContainsValue(m_aMousePath, pWnd);
+  }
+
+  bool IsMainCaptureKeyboard(const CPWL_Wnd* pWnd) const {
+    return pWnd == m_pMainKeyboardWnd;
+  }
+
+  bool IsWndCaptureKeyboard(const CPWL_Wnd* pWnd) const {
+    return pWnd && pdfium::ContainsValue(m_aKeyboardPath, pWnd);
+  }
+
+  void SetFocus(CPWL_Wnd* pWnd) {
+    m_aKeyboardPath.clear();
+    if (!pWnd)
+      return;
+
+    m_pMainKeyboardWnd = pWnd;
+    CPWL_Wnd* pParent = pWnd;
+    while (pParent) {
+      m_aKeyboardPath.push_back(pParent);
+      pParent = pParent->GetParentWindow();
+    }
+    // Note, pWnd may get destroyed in the OnSetFocus call.
+    pWnd->OnSetFocus();
+  }
+
+  void KillFocus() {
+    ObservedPtr observed_ptr(this);
+    if (!m_aKeyboardPath.empty())
+      if (CPWL_Wnd* pWnd = m_aKeyboardPath[0])
+        pWnd->OnKillFocus();
+    if (!observed_ptr)
+      return;
+
+    m_pMainKeyboardWnd = nullptr;
+    m_aKeyboardPath.clear();
+  }
+
+  void SetCapture(CPWL_Wnd* pWnd) {
+    m_aMousePath.clear();
+    if (pWnd) {
+      CPWL_Wnd* pParent = pWnd;
+      while (pParent) {
+        m_aMousePath.push_back(pParent);
+        pParent = pParent->GetParentWindow();
+      }
+    }
+  }
+
+  void ReleaseCapture() {
+    m_aMousePath.clear();
+  }
+
+  CPWL_Wnd* GetFocusedWindow() const { return m_pMainKeyboardWnd.Get(); }
+
+ private:
+  std::vector<CPWL_Wnd*> m_aMousePath;
+  std::vector<CPWL_Wnd*> m_aKeyboardPath;
+  UnownedPtr<CPWL_Wnd> m_pCreatedWnd;
+  UnownedPtr<CPWL_Wnd> m_pMainKeyboardWnd;
+};
+
+CPWL_Wnd::CPWL_Wnd()
+    : m_rcWindow(),
+      m_rcClip(),
+      m_bCreated(false),
+      m_bVisible(false),
+      m_bNotifying(false),
+      m_bEnabled(true) {}
+
+CPWL_Wnd::~CPWL_Wnd() {
+  ASSERT(!m_bCreated);
+}
+
+ByteString CPWL_Wnd::GetClassName() const {
+  return "CPWL_Wnd";
+}
+
+void CPWL_Wnd::Create(const CreateParams& cp) {
+  if (IsValid())
+    return;
+
+  m_CreationParams = cp;
+  OnCreate(&m_CreationParams);
+  m_CreationParams.rcRectWnd.Normalize();
+  m_rcWindow = m_CreationParams.rcRectWnd;
+  m_rcClip = m_rcWindow;
+  if (!m_rcClip.IsEmpty()) {
+    m_rcClip.Inflate(1.0f, 1.0f);
+    m_rcClip.Normalize();
+  }
+  CreateMsgControl();
+  if (m_CreationParams.pParentWnd)
+    m_CreationParams.pParentWnd->AddChild(this);
+
+  CreateParams ccp = m_CreationParams;
+  ccp.dwFlags &= 0xFFFF0000L;  // remove sub styles
+  CreateScrollBar(ccp);
+  CreateChildWnd(ccp);
+  m_bVisible = HasFlag(PWS_VISIBLE);
+  OnCreated();
+  if (!RePosChildWnd())
+    return;
+
+  m_bCreated = true;
+}
+
+void CPWL_Wnd::OnCreate(CreateParams* pParamsToAdjust) {}
+
+void CPWL_Wnd::OnCreated() {}
+
+void CPWL_Wnd::OnDestroy() {}
+
+void CPWL_Wnd::InvalidateFocusHandler(FocusHandlerIface* handler) {
+  if (m_CreationParams.pFocusHandler == handler)
+    m_CreationParams.pFocusHandler = nullptr;
+}
+
+void CPWL_Wnd::InvalidateProvider(ProviderIface* provider) {
+  if (m_CreationParams.pProvider.Get() == provider)
+    m_CreationParams.pProvider.Reset();
+}
+
+void CPWL_Wnd::Destroy() {
+  KillFocus();
+  OnDestroy();
+  if (m_bCreated) {
+    m_pVScrollBar = nullptr;
+    for (auto it = m_Children.rbegin(); it != m_Children.rend(); ++it) {
+      CPWL_Wnd* pChild = *it;
+      if (pChild) {
+        *it = nullptr;
+        pChild->Destroy();
+        delete pChild;
+      }
+    }
+    if (m_CreationParams.pParentWnd)
+      m_CreationParams.pParentWnd->RemoveChild(this);
+
+    m_bCreated = false;
+  }
+  DestroyMsgControl();
+  m_Children.clear();
+}
+
+bool CPWL_Wnd::Move(const CFX_FloatRect& rcNew, bool bReset, bool bRefresh) {
+  if (!IsValid())
+    return true;
+
+  CFX_FloatRect rcOld = GetWindowRect();
+  m_rcWindow = rcNew;
+  m_rcWindow.Normalize();
+
+  if (bReset) {
+    if (rcOld.left != rcNew.left || rcOld.right != rcNew.right ||
+        rcOld.top != rcNew.top || rcOld.bottom != rcNew.bottom) {
+      if (!RePosChildWnd())
+        return false;
+    }
+  }
+  if (bRefresh && !InvalidateRectMove(rcOld, rcNew))
+    return false;
+
+  m_CreationParams.rcRectWnd = m_rcWindow;
+  return true;
+}
+
+bool CPWL_Wnd::InvalidateRectMove(const CFX_FloatRect& rcOld,
+                                  const CFX_FloatRect& rcNew) {
+  CFX_FloatRect rcUnion = rcOld;
+  rcUnion.Union(rcNew);
+
+  return InvalidateRect(&rcUnion);
+}
+
+void CPWL_Wnd::DrawAppearance(CFX_RenderDevice* pDevice,
+                              const CFX_Matrix& mtUser2Device) {
+  if (IsValid() && IsVisible()) {
+    DrawThisAppearance(pDevice, mtUser2Device);
+    DrawChildAppearance(pDevice, mtUser2Device);
+  }
+}
+
+void CPWL_Wnd::DrawThisAppearance(CFX_RenderDevice* pDevice,
+                                  const CFX_Matrix& mtUser2Device) {
+  CFX_FloatRect rectWnd = GetWindowRect();
+  if (rectWnd.IsEmpty())
+    return;
+
+  if (HasFlag(PWS_BACKGROUND)) {
+    float width = static_cast<float>(GetBorderWidth() + GetInnerBorderWidth());
+    pDevice->DrawFillRect(&mtUser2Device, rectWnd.GetDeflated(width, width),
+                          GetBackgroundColor(), GetTransparency());
+  }
+
+  if (HasFlag(PWS_BORDER)) {
+    pDevice->DrawBorder(&mtUser2Device, rectWnd,
+                        static_cast<float>(GetBorderWidth()), GetBorderColor(),
+                        GetBorderLeftTopColor(GetBorderStyle()),
+                        GetBorderRightBottomColor(GetBorderStyle()),
+                        GetBorderStyle(), GetTransparency());
+  }
+}
+
+void CPWL_Wnd::DrawChildAppearance(CFX_RenderDevice* pDevice,
+                                   const CFX_Matrix& mtUser2Device) {
+  for (CPWL_Wnd* pChild : m_Children) {
+    if (!pChild)
+      continue;
+
+    CFX_Matrix mt = pChild->GetChildMatrix();
+    if (mt.IsIdentity()) {
+      pChild->DrawAppearance(pDevice, mtUser2Device);
+    } else {
+      mt.Concat(mtUser2Device);
+      pChild->DrawAppearance(pDevice, mt);
+    }
+  }
+}
+
+bool CPWL_Wnd::InvalidateRect(CFX_FloatRect* pRect) {
+  ObservedPtr thisObserved(this);
+  if (!IsValid())
+    return true;
+
+  CFX_FloatRect rcRefresh = pRect ? *pRect : GetWindowRect();
+
+  if (!HasFlag(PWS_NOREFRESHCLIP)) {
+    CFX_FloatRect rcClip = GetClipRect();
+    if (!rcClip.IsEmpty()) {
+      rcRefresh.Intersect(rcClip);
+    }
+  }
+
+  CFX_FloatRect rcWin = PWLtoWnd(rcRefresh);
+  rcWin.Inflate(1, 1);
+  rcWin.Normalize();
+
+  if (CFX_SystemHandler* pSH = GetSystemHandler()) {
+    if (CPDFSDK_Widget* widget = static_cast<CPDFSDK_Widget*>(
+            m_CreationParams.pAttachedWidget.Get())) {
+      pSH->InvalidateRect(widget, rcWin);
+      if (!thisObserved)
+        return false;
+    }
+  }
+
+  return true;
+}
+
+#define PWL_IMPLEMENT_KEY_METHOD(key_method_name)                  \
+  bool CPWL_Wnd::key_method_name(uint16_t nChar, uint32_t nFlag) { \
+    if (!IsValid() || !IsVisible() || !IsEnabled())                \
+      return false;                                                \
+    if (!IsWndCaptureKeyboard(this))                               \
+      return false;                                                \
+    for (auto* pChild : m_Children) {                              \
+      if (pChild && IsWndCaptureKeyboard(pChild))                  \
+        return pChild->key_method_name(nChar, nFlag);              \
+    }                                                              \
+    return false;                                                  \
+  }
+
+PWL_IMPLEMENT_KEY_METHOD(OnKeyDown)
+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_PointF& point, uint32_t nFlag) {  \
+    if (!IsValid() || !IsVisible() || !IsEnabled())                            \
+      return false;                                                            \
+    if (IsWndCaptureMouse(this)) {                                             \
+      for (auto* pChild : m_Children) {                                        \
+        if (pChild && IsWndCaptureMouse(pChild)) {                             \
+          return pChild->mouse_method_name(pChild->ParentToChild(point),       \
+                                           nFlag);                             \
+        }                                                                      \
+      }                                                                        \
+      SetCursor();                                                             \
+      return false;                                                            \
+    }                                                                          \
+    for (auto* pChild : m_Children) {                                          \
+      if (pChild && pChild->WndHitTest(pChild->ParentToChild(point))) {        \
+        return pChild->mouse_method_name(pChild->ParentToChild(point), nFlag); \
+      }                                                                        \
+    }                                                                          \
+    if (WndHitTest(point))                                                     \
+      SetCursor();                                                             \
+    return false;                                                              \
+  }
+
+PWL_IMPLEMENT_MOUSE_METHOD(OnLButtonDblClk)
+PWL_IMPLEMENT_MOUSE_METHOD(OnLButtonDown)
+PWL_IMPLEMENT_MOUSE_METHOD(OnLButtonUp)
+PWL_IMPLEMENT_MOUSE_METHOD(OnRButtonDown)
+PWL_IMPLEMENT_MOUSE_METHOD(OnRButtonUp)
+PWL_IMPLEMENT_MOUSE_METHOD(OnMouseMove)
+#undef PWL_IMPLEMENT_MOUSE_METHOD
+
+WideString CPWL_Wnd::GetSelectedText() {
+  return WideString();
+}
+
+void CPWL_Wnd::ReplaceSelection(const WideString& text) {}
+
+bool CPWL_Wnd::OnMouseWheel(short zDelta,
+                            const CFX_PointF& point,
+                            uint32_t nFlag) {
+  if (!IsValid() || !IsVisible() || !IsEnabled())
+    return false;
+
+  SetCursor();
+  if (!IsWndCaptureKeyboard(this))
+    return false;
+
+  for (auto* pChild : m_Children) {
+    if (pChild && IsWndCaptureKeyboard(pChild))
+      return pChild->OnMouseWheel(zDelta, pChild->ParentToChild(point), nFlag);
+  }
+  return false;
+}
+
+void CPWL_Wnd::AddChild(CPWL_Wnd* pWnd) {
+  m_Children.push_back(pWnd);
+}
+
+void CPWL_Wnd::RemoveChild(CPWL_Wnd* pWnd) {
+  for (auto it = m_Children.rbegin(); it != m_Children.rend(); ++it) {
+    if (*it && *it == pWnd) {
+      m_Children.erase(std::next(it).base());
+      break;
+    }
+  }
+}
+
+void CPWL_Wnd::SetScrollInfo(const PWL_SCROLL_INFO& info) {}
+
+void CPWL_Wnd::SetScrollPosition(float pos) {}
+
+void CPWL_Wnd::ScrollWindowVertically(float pos) {}
+
+void CPWL_Wnd::NotifyLButtonDown(CPWL_Wnd* child, const CFX_PointF& pos) {}
+
+void CPWL_Wnd::NotifyLButtonUp(CPWL_Wnd* child, const CFX_PointF& pos) {}
+
+void CPWL_Wnd::NotifyMouseMove(CPWL_Wnd* child, const CFX_PointF& pos) {}
+
+CPWL_Wnd* CPWL_Wnd::GetParentWindow() const {
+  return m_CreationParams.pParentWnd;
+}
+
+CFX_FloatRect CPWL_Wnd::GetWindowRect() const {
+  return m_rcWindow;
+}
+
+CFX_FloatRect CPWL_Wnd::GetClientRect() const {
+  CFX_FloatRect rcWindow = GetWindowRect();
+
+  float width = static_cast<float>(GetBorderWidth() + GetInnerBorderWidth());
+  CFX_FloatRect rcClient = rcWindow.GetDeflated(width, width);
+  if (CPWL_ScrollBar* pVSB = GetVScrollBar())
+    rcClient.right -= pVSB->GetScrollBarWidth();
+
+  rcClient.Normalize();
+  return rcWindow.Contains(rcClient) ? rcClient : CFX_FloatRect();
+}
+
+CFX_PointF CPWL_Wnd::GetCenterPoint() const {
+  CFX_FloatRect rcClient = GetClientRect();
+  return CFX_PointF((rcClient.left + rcClient.right) * 0.5f,
+                    (rcClient.top + rcClient.bottom) * 0.5f);
+}
+
+bool CPWL_Wnd::HasFlag(uint32_t dwFlags) const {
+  return (m_CreationParams.dwFlags & dwFlags) != 0;
+}
+
+void CPWL_Wnd::RemoveFlag(uint32_t dwFlags) {
+  m_CreationParams.dwFlags &= ~dwFlags;
+}
+
+void CPWL_Wnd::AddFlag(uint32_t dwFlags) {
+  m_CreationParams.dwFlags |= dwFlags;
+}
+
+CFX_Color CPWL_Wnd::GetBackgroundColor() const {
+  return m_CreationParams.sBackgroundColor;
+}
+
+void CPWL_Wnd::SetBackgroundColor(const CFX_Color& color) {
+  m_CreationParams.sBackgroundColor = color;
+}
+
+CFX_Color CPWL_Wnd::GetTextColor() const {
+  return m_CreationParams.sTextColor;
+}
+
+BorderStyle CPWL_Wnd::GetBorderStyle() const {
+  return m_CreationParams.nBorderStyle;
+}
+
+void CPWL_Wnd::SetBorderStyle(BorderStyle nBorderStyle) {
+  if (HasFlag(PWS_BORDER))
+    m_CreationParams.nBorderStyle = nBorderStyle;
+}
+
+int32_t CPWL_Wnd::GetBorderWidth() const {
+  return HasFlag(PWS_BORDER) ? m_CreationParams.dwBorderWidth : 0;
+}
+
+int32_t CPWL_Wnd::GetInnerBorderWidth() const {
+  return 0;
+}
+
+CFX_Color CPWL_Wnd::GetBorderColor() const {
+  return HasFlag(PWS_BORDER) ? m_CreationParams.sBorderColor : CFX_Color();
+}
+
+const CPWL_Dash& CPWL_Wnd::GetBorderDash() const {
+  return m_CreationParams.sDash;
+}
+
+CPWL_Wnd::PrivateData* CPWL_Wnd::GetAttachedData() const {
+  return m_CreationParams.pAttachedData.Get();
+}
+
+CPWL_ScrollBar* CPWL_Wnd::GetVScrollBar() const {
+  return HasFlag(PWS_VSCROLL) ? m_pVScrollBar.Get() : nullptr;
+}
+
+void CPWL_Wnd::CreateScrollBar(const CreateParams& cp) {
+  CreateVScrollBar(cp);
+}
+
+void CPWL_Wnd::CreateVScrollBar(const CreateParams& cp) {
+  if (m_pVScrollBar || !HasFlag(PWS_VSCROLL))
+    return;
+
+  CreateParams scp = cp;
+
+  // flags
+  scp.dwFlags =
+      PWS_CHILD | PWS_BACKGROUND | PWS_AUTOTRANSPARENT | PWS_NOREFRESHCLIP;
+
+  scp.pParentWnd = this;
+  scp.sBackgroundColor = PWL_DEFAULT_WHITECOLOR;
+  scp.eCursorType = FXCT_ARROW;
+  scp.nTransparency = PWL_SCROLLBAR_TRANSPARENCY;
+
+  m_pVScrollBar = new CPWL_ScrollBar(SBT_VSCROLL);
+  m_pVScrollBar->Create(scp);
+}
+
+void CPWL_Wnd::SetCapture() {
+  if (CPWL_MsgControl* pMsgCtrl = GetMsgControl())
+    pMsgCtrl->SetCapture(this);
+}
+
+void CPWL_Wnd::ReleaseCapture() {
+  for (auto* pChild : m_Children) {
+    if (pChild)
+      pChild->ReleaseCapture();
+  }
+  if (CPWL_MsgControl* pMsgCtrl = GetMsgControl())
+    pMsgCtrl->ReleaseCapture();
+}
+
+void CPWL_Wnd::SetFocus() {
+  if (CPWL_MsgControl* pMsgCtrl = GetMsgControl()) {
+    if (!pMsgCtrl->IsMainCaptureKeyboard(this))
+      pMsgCtrl->KillFocus();
+    pMsgCtrl->SetFocus(this);
+  }
+}
+
+void CPWL_Wnd::KillFocus() {
+  if (CPWL_MsgControl* pMsgCtrl = GetMsgControl()) {
+    if (pMsgCtrl->IsWndCaptureKeyboard(this))
+      pMsgCtrl->KillFocus();
+  }
+}
+
+void CPWL_Wnd::OnSetFocus() {}
+
+void CPWL_Wnd::OnKillFocus() {}
+
+bool CPWL_Wnd::WndHitTest(const CFX_PointF& point) const {
+  return IsValid() && IsVisible() && GetWindowRect().Contains(point);
+}
+
+bool CPWL_Wnd::ClientHitTest(const CFX_PointF& point) const {
+  return IsValid() && IsVisible() && GetClientRect().Contains(point);
+}
+
+const CPWL_Wnd* CPWL_Wnd::GetRootWnd() const {
+  auto* pParent = m_CreationParams.pParentWnd;
+  return pParent ? pParent->GetRootWnd() : this;
+}
+
+bool CPWL_Wnd::SetVisible(bool bVisible) {
+  if (!IsValid())
+    return true;
+
+  ObservedPtr thisObserved(this);
+
+  for (auto* pChild : m_Children) {
+    if (pChild) {
+      pChild->SetVisible(bVisible);
+      if (!thisObserved)
+        return false;
+    }
+  }
+
+  if (bVisible != m_bVisible) {
+    m_bVisible = bVisible;
+    if (!RePosChildWnd())
+      return false;
+
+    if (!InvalidateRect(nullptr))
+      return false;
+  }
+  return true;
+}
+
+void CPWL_Wnd::SetClipRect(const CFX_FloatRect& rect) {
+  m_rcClip = rect;
+  m_rcClip.Normalize();
+}
+
+const CFX_FloatRect& CPWL_Wnd::GetClipRect() const {
+  return m_rcClip;
+}
+
+bool CPWL_Wnd::IsReadOnly() const {
+  return HasFlag(PWS_READONLY);
+}
+
+bool CPWL_Wnd::RePosChildWnd() {
+  CPWL_ScrollBar* pVSB = GetVScrollBar();
+  if (!pVSB)
+    return true;
+
+  CFX_FloatRect rcContent = GetWindowRect();
+  if (!rcContent.IsEmpty()) {
+    float width = static_cast<float>(GetBorderWidth() + GetInnerBorderWidth());
+    rcContent.Deflate(width, width);
+    rcContent.Normalize();
+  }
+  CFX_FloatRect rcVScroll =
+      CFX_FloatRect(rcContent.right - PWL_SCROLLBAR_WIDTH, rcContent.bottom,
+                    rcContent.right - 1.0f, rcContent.top);
+
+  ObservedPtr thisObserved(this);
+
+  pVSB->Move(rcVScroll, true, false);
+  if (!thisObserved)
+    return false;
+
+  return true;
+}
+
+void CPWL_Wnd::CreateChildWnd(const CreateParams& cp) {}
+
+void CPWL_Wnd::SetCursor() {
+  if (IsValid()) {
+    if (CFX_SystemHandler* pSH = GetSystemHandler()) {
+      int32_t nCursorType = GetCreationParams().eCursorType;
+      pSH->SetCursor(nCursorType);
+    }
+  }
+}
+
+void CPWL_Wnd::CreateMsgControl() {
+  if (!m_CreationParams.pMsgControl)
+    m_CreationParams.pMsgControl = new CPWL_MsgControl(this);
+}
+
+void CPWL_Wnd::DestroyMsgControl() {
+  CPWL_MsgControl* pMsgControl = GetMsgControl();
+  if (pMsgControl && pMsgControl->IsWndCreated(this))
+    delete pMsgControl;
+}
+
+CPWL_MsgControl* CPWL_Wnd::GetMsgControl() const {
+  return m_CreationParams.pMsgControl;
+}
+
+bool CPWL_Wnd::IsCaptureMouse() const {
+  return IsWndCaptureMouse(this);
+}
+
+bool CPWL_Wnd::IsWndCaptureMouse(const CPWL_Wnd* pWnd) const {
+  CPWL_MsgControl* pCtrl = GetMsgControl();
+  return pCtrl ? pCtrl->IsWndCaptureMouse(pWnd) : false;
+}
+
+bool CPWL_Wnd::IsWndCaptureKeyboard(const CPWL_Wnd* pWnd) const {
+  CPWL_MsgControl* pCtrl = GetMsgControl();
+  return pCtrl ? pCtrl->IsWndCaptureKeyboard(pWnd) : false;
+}
+
+bool CPWL_Wnd::IsFocused() const {
+  CPWL_MsgControl* pCtrl = GetMsgControl();
+  return pCtrl ? pCtrl->IsMainCaptureKeyboard(this) : false;
+}
+
+CFX_FloatRect CPWL_Wnd::GetFocusRect() const {
+  CFX_FloatRect rect = GetWindowRect();
+  if (!rect.IsEmpty()) {
+    rect.Inflate(1.0f, 1.0f);
+    rect.Normalize();
+  }
+  return rect;
+}
+
+float CPWL_Wnd::GetFontSize() const {
+  return m_CreationParams.fFontSize;
+}
+
+void CPWL_Wnd::SetFontSize(float fFontSize) {
+  m_CreationParams.fFontSize = fFontSize;
+}
+
+CFX_SystemHandler* CPWL_Wnd::GetSystemHandler() const {
+  return m_CreationParams.pSystemHandler;
+}
+
+CPWL_Wnd::FocusHandlerIface* CPWL_Wnd::GetFocusHandler() const {
+  return m_CreationParams.pFocusHandler.Get();
+}
+
+CPWL_Wnd::ProviderIface* CPWL_Wnd::GetProvider() const {
+  return m_CreationParams.pProvider.Get();
+}
+
+IPVT_FontMap* CPWL_Wnd::GetFontMap() const {
+  return m_CreationParams.pFontMap;
+}
+
+CFX_Color CPWL_Wnd::GetBorderLeftTopColor(BorderStyle nBorderStyle) const {
+  switch (nBorderStyle) {
+    case BorderStyle::BEVELED:
+      return CFX_Color(CFX_Color::kGray, 1);
+    case BorderStyle::INSET:
+      return CFX_Color(CFX_Color::kGray, 0.5f);
+    default:
+      return CFX_Color();
+  }
+}
+
+CFX_Color CPWL_Wnd::GetBorderRightBottomColor(BorderStyle nBorderStyle) const {
+  switch (nBorderStyle) {
+    case BorderStyle::BEVELED:
+      return GetBackgroundColor() / 2.0f;
+    case BorderStyle::INSET:
+      return CFX_Color(CFX_Color::kGray, 0.75f);
+    default:
+      return CFX_Color();
+  }
+}
+
+int32_t CPWL_Wnd::GetTransparency() {
+  return m_CreationParams.nTransparency;
+}
+
+void CPWL_Wnd::SetTransparency(int32_t nTransparency) {
+  for (auto* pChild : m_Children) {
+    if (pChild)
+      pChild->SetTransparency(nTransparency);
+  }
+  m_CreationParams.nTransparency = nTransparency;
+}
+
+CFX_Matrix CPWL_Wnd::GetWindowMatrix() const {
+  CFX_Matrix mt = GetChildToRoot();
+  if (ProviderIface* pProvider = GetProvider())
+    mt.Concat(pProvider->GetWindowMatrix(GetAttachedData()));
+  return mt;
+}
+
+CFX_FloatRect CPWL_Wnd::PWLtoWnd(const CFX_FloatRect& rect) const {
+  CFX_Matrix mt = GetWindowMatrix();
+  return mt.TransformRect(rect);
+}
+
+CFX_PointF CPWL_Wnd::ParentToChild(const CFX_PointF& point) const {
+  CFX_Matrix mt = GetChildMatrix();
+  if (mt.IsIdentity())
+    return point;
+
+  CFX_Matrix inverse = mt.GetInverse();
+  if (!inverse.IsIdentity())
+    mt = inverse;
+  return mt.Transform(point);
+}
+
+CFX_FloatRect CPWL_Wnd::ParentToChild(const CFX_FloatRect& rect) const {
+  CFX_Matrix mt = GetChildMatrix();
+  if (mt.IsIdentity())
+    return rect;
+
+  CFX_Matrix inverse = mt.GetInverse();
+  if (!inverse.IsIdentity())
+    mt = inverse;
+
+  return mt.TransformRect(rect);
+}
+
+CFX_Matrix CPWL_Wnd::GetChildToRoot() const {
+  CFX_Matrix mt;
+  if (HasFlag(PWS_CHILD)) {
+    const CPWL_Wnd* pParent = this;
+    while (pParent) {
+      mt.Concat(pParent->GetChildMatrix());
+      pParent = pParent->GetParentWindow();
+    }
+  }
+  return mt;
+}
+
+CFX_Matrix CPWL_Wnd::GetChildMatrix() const {
+  return HasFlag(PWS_CHILD) ? m_CreationParams.mtChild : CFX_Matrix();
+}
+
+void CPWL_Wnd::SetChildMatrix(const CFX_Matrix& mt) {
+  m_CreationParams.mtChild = mt;
+}
+
+const CPWL_Wnd* CPWL_Wnd::GetFocused() const {
+  CPWL_MsgControl* pMsgCtrl = GetMsgControl();
+  return pMsgCtrl ? pMsgCtrl->GetFocusedWindow() : nullptr;
+}
+
+void CPWL_Wnd::EnableWindow(bool bEnable) {
+  if (m_bEnabled == bEnable)
+    return;
+
+  for (auto* pChild : m_Children) {
+    if (pChild)
+      pChild->EnableWindow(bEnable);
+  }
+  m_bEnabled = bEnable;
+}
diff --git a/fpdfsdk/pwl/cpwl_wnd.h b/fpdfsdk/pwl/cpwl_wnd.h
new file mode 100644
index 0000000..ba52420
--- /dev/null
+++ b/fpdfsdk/pwl/cpwl_wnd.h
@@ -0,0 +1,326 @@
+// 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 FPDFSDK_PWL_CPWL_WND_H_
+#define FPDFSDK_PWL_CPWL_WND_H_
+
+#include <memory>
+#include <vector>
+
+#include "core/fpdfdoc/cpdf_formcontrol.h"
+#include "core/fxcrt/observable.h"
+#include "core/fxcrt/unowned_ptr.h"
+#include "core/fxge/cfx_color.h"
+#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
+#include "fpdfsdk/cpdfsdk_widget.h"
+#include "fpdfsdk/pwl/cpwl_timer.h"
+#include "fpdfsdk/pwl/cpwl_timer_handler.h"
+
+class CPWL_Edit;
+class CPWL_MsgControl;
+class CPWL_ScrollBar;
+class CFX_SystemHandler;
+class IPVT_FontMap;
+struct PWL_SCROLL_INFO;
+
+// window styles
+#define PWS_CHILD 0x80000000L
+#define PWS_BORDER 0x40000000L
+#define PWS_BACKGROUND 0x20000000L
+#define PWS_HSCROLL 0x10000000L
+#define PWS_VSCROLL 0x08000000L
+#define PWS_VISIBLE 0x04000000L
+#define PWS_READONLY 0x01000000L
+#define PWS_AUTOFONTSIZE 0x00800000L
+#define PWS_AUTOTRANSPARENT 0x00400000L
+#define PWS_NOREFRESHCLIP 0x00200000L
+
+// edit and label styles
+#define PES_MULTILINE 0x0001L
+#define PES_PASSWORD 0x0002L
+#define PES_LEFT 0x0004L
+#define PES_RIGHT 0x0008L
+#define PES_MIDDLE 0x0010L
+#define PES_TOP 0x0020L
+#define PES_BOTTOM 0x0040L
+#define PES_CENTER 0x0080L
+#define PES_CHARARRAY 0x0100L
+#define PES_AUTOSCROLL 0x0200L
+#define PES_AUTORETURN 0x0400L
+#define PES_UNDO 0x0800L
+#define PES_RICH 0x1000L
+#define PES_SPELLCHECK 0x2000L
+#define PES_TEXTOVERFLOW 0x4000L
+#define PES_NOREAD 0x8000L
+
+// listbox styles
+#define PLBS_MULTIPLESEL 0x0001L
+#define PLBS_HOVERSEL 0x0008L
+
+// combobox styles
+#define PCBS_ALLOWCUSTOMTEXT 0x0001L
+
+struct CPWL_Dash {
+  CPWL_Dash() : nDash(0), nGap(0), nPhase(0) {}
+  CPWL_Dash(int32_t dash, int32_t gap, int32_t phase)
+      : nDash(dash), nGap(gap), nPhase(phase) {}
+
+  void Reset() {
+    nDash = 0;
+    nGap = 0;
+    nPhase = 0;
+  }
+
+  int32_t nDash;
+  int32_t nGap;
+  int32_t nPhase;
+};
+
+inline bool operator==(const CFX_Color& c1, const CFX_Color& c2) {
+  return c1.nColorType == c2.nColorType && c1.fColor1 - c2.fColor1 < 0.0001 &&
+         c1.fColor1 - c2.fColor1 > -0.0001 &&
+         c1.fColor2 - c2.fColor2 < 0.0001 &&
+         c1.fColor2 - c2.fColor2 > -0.0001 &&
+         c1.fColor3 - c2.fColor3 < 0.0001 &&
+         c1.fColor3 - c2.fColor3 > -0.0001 &&
+         c1.fColor4 - c2.fColor4 < 0.0001 && c1.fColor4 - c2.fColor4 > -0.0001;
+}
+
+inline bool operator!=(const CFX_Color& c1, const CFX_Color& c2) {
+  return !(c1 == c2);
+}
+
+#define PWL_SCROLLBAR_WIDTH 12.0f
+#define PWL_SCROLLBAR_TRANSPARENCY 150
+#define PWL_DEFAULT_BLACKCOLOR CFX_Color(CFX_Color::kGray, 0)
+#define PWL_DEFAULT_WHITECOLOR CFX_Color(CFX_Color::kGray, 1)
+
+class CPWL_Wnd : public CPWL_TimerHandler, public Observable<CPWL_Wnd> {
+ public:
+  class PrivateData {
+   protected:
+    ~PrivateData() {}
+  };
+
+  class ProviderIface : public Observable<ProviderIface> {
+   public:
+    virtual ~ProviderIface() {}
+
+    // get a matrix which map user space to CWnd client space
+    virtual CFX_Matrix GetWindowMatrix(PrivateData* pAttached) = 0;
+  };
+
+  class FocusHandlerIface {
+   public:
+    virtual ~FocusHandlerIface() {}
+    virtual void OnSetFocus(CPWL_Edit* pEdit) = 0;
+  };
+
+  class CreateParams {
+   public:
+    CreateParams();
+    CreateParams(const CreateParams& other);
+    ~CreateParams();
+
+    CFX_FloatRect rcRectWnd;                          // required
+    CFX_SystemHandler* pSystemHandler;                // required
+    IPVT_FontMap* pFontMap;                           // required
+    ProviderIface::ObservedPtr pProvider;             // required
+    UnownedPtr<FocusHandlerIface> pFocusHandler;      // optional
+    uint32_t dwFlags;                                 // optional
+    CFX_Color sBackgroundColor;                       // optional
+    CPDFSDK_Widget::ObservedPtr pAttachedWidget;      // required
+    BorderStyle nBorderStyle;                         // optional
+    int32_t dwBorderWidth;                            // optional
+    CFX_Color sBorderColor;                           // optional
+    CFX_Color sTextColor;                             // optional
+    int32_t nTransparency;                            // optional
+    float fFontSize;                                  // optional
+    CPWL_Dash sDash;                                  // optional
+    UnownedPtr<PrivateData> pAttachedData;            // optional
+    CPWL_Wnd* pParentWnd;                             // ignore
+    CPWL_MsgControl* pMsgControl;                     // ignore
+    int32_t eCursorType;                              // ignore
+    CFX_Matrix mtChild;                               // ignore
+  };
+
+  CPWL_Wnd();
+  ~CPWL_Wnd() override;
+
+  virtual ByteString GetClassName() const;
+
+  // Returns |true| iff this instance is still allocated.
+  virtual bool InvalidateRect(CFX_FloatRect* pRect);
+
+  virtual bool OnKeyDown(uint16_t nChar, uint32_t nFlag);
+  virtual bool OnChar(uint16_t nChar, 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_PointF& point,
+                            uint32_t nFlag);
+  virtual void SetScrollInfo(const PWL_SCROLL_INFO& info);
+  virtual void SetScrollPosition(float pos);
+  virtual void ScrollWindowVertically(float pos);
+  virtual void NotifyLButtonDown(CPWL_Wnd* child, const CFX_PointF& pos);
+  virtual void NotifyLButtonUp(CPWL_Wnd* child, const CFX_PointF& pos);
+  virtual void NotifyMouseMove(CPWL_Wnd* child, const CFX_PointF& pos);
+  virtual void SetFocus();
+  virtual void KillFocus();
+  virtual void SetCursor();
+
+  // Returns |true| iff this instance is still allocated.
+  virtual bool SetVisible(bool bVisible);
+  virtual void SetFontSize(float fFontSize);
+  virtual float GetFontSize() const;
+
+  virtual WideString GetSelectedText();
+  virtual void ReplaceSelection(const WideString& text);
+  virtual CFX_FloatRect GetFocusRect() const;
+  virtual CFX_FloatRect GetClientRect() const;
+
+  void InvalidateFocusHandler(FocusHandlerIface* handler);
+  void InvalidateProvider(ProviderIface* provider);
+  void Create(const CreateParams& cp);
+  void Destroy();
+  bool Move(const CFX_FloatRect& rcNew, bool bReset, bool bRefresh);
+
+  void SetCapture();
+  void ReleaseCapture();
+
+  void DrawAppearance(CFX_RenderDevice* pDevice,
+                      const CFX_Matrix& mtUser2Device);
+
+  CFX_Color GetBackgroundColor() const;
+  void SetBackgroundColor(const CFX_Color& color);
+  CFX_Color GetBorderColor() const;
+  CFX_Color GetTextColor() const;
+  void SetTextColor(const CFX_Color& color);
+  CFX_Color GetBorderLeftTopColor(BorderStyle nBorderStyle) const;
+  CFX_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;
+  PrivateData* GetAttachedData() 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;
+  CPWL_ScrollBar* GetVScrollBar() const;
+
+  IPVT_FontMap* GetFontMap() const;
+  ProviderIface* GetProvider() const;
+  FocusHandlerIface* GetFocusHandler() const;
+
+  int32_t GetTransparency();
+  void SetTransparency(int32_t nTransparency);
+
+  CFX_Matrix GetChildToRoot() const;
+  CFX_Matrix GetChildMatrix() const;
+  void SetChildMatrix(const CFX_Matrix& mt);
+  CFX_Matrix GetWindowMatrix() const;
+
+  virtual void OnSetFocus();
+  virtual void OnKillFocus();
+
+ protected:
+  // CPWL_TimerHandler
+  CFX_SystemHandler* GetSystemHandler() const override;
+
+  virtual void CreateChildWnd(const CreateParams& cp);
+
+  // Returns |true| iff this instance is still allocated.
+  virtual bool RePosChildWnd();
+
+  virtual void DrawThisAppearance(CFX_RenderDevice* pDevice,
+                                  const CFX_Matrix& mtUser2Device);
+
+  virtual void OnCreate(CreateParams* pParamsToAdjust);
+  virtual void OnCreated();
+  virtual void OnDestroy();
+
+  void SetNotifyFlag(bool bNotifying = true) { m_bNotifying = bNotifying; }
+  bool IsNotifying() const { return m_bNotifying; }
+  bool IsValid() const { return m_bCreated; }
+  const CreateParams& GetCreationParams() const { return m_CreationParams; }
+
+  // Returns |true| iff this instance is still allocated.
+  bool InvalidateRectMove(const CFX_FloatRect& rcOld,
+                          const CFX_FloatRect& rcNew);
+
+  bool IsWndCaptureMouse(const CPWL_Wnd* pWnd) const;
+  bool IsWndCaptureKeyboard(const CPWL_Wnd* pWnd) const;
+  const CPWL_Wnd* GetRootWnd() const;
+
+  static bool IsCTRLpressed(uint32_t nFlag) {
+    return CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
+  }
+  static bool IsSHIFTpressed(uint32_t nFlag) {
+    return CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
+  }
+  static bool IsALTpressed(uint32_t nFlag) {
+    return CPDFSDK_FormFillEnvironment::IsALTKeyDown(nFlag);
+  }
+
+ private:
+  CFX_PointF ParentToChild(const CFX_PointF& point) const;
+  CFX_FloatRect ParentToChild(const CFX_FloatRect& rect) const;
+
+  void DrawChildAppearance(CFX_RenderDevice* pDevice,
+                           const CFX_Matrix& mtUser2Device);
+
+  CFX_FloatRect PWLtoWnd(const CFX_FloatRect& rect) const;
+
+  void AddChild(CPWL_Wnd* pWnd);
+  void RemoveChild(CPWL_Wnd* pWnd);
+
+  void CreateScrollBar(const CreateParams& cp);
+  void CreateVScrollBar(const CreateParams& cp);
+
+  void AdjustStyle();
+  void CreateMsgControl();
+  void DestroyMsgControl();
+
+  CPWL_MsgControl* GetMsgControl() const;
+
+  CreateParams m_CreationParams;
+  std::vector<CPWL_Wnd*> m_Children;
+  UnownedPtr<CPWL_ScrollBar> m_pVScrollBar;
+  CFX_FloatRect m_rcWindow;
+  CFX_FloatRect m_rcClip;
+  bool m_bCreated;
+  bool m_bVisible;
+  bool m_bNotifying;
+  bool m_bEnabled;
+};
+
+#endif  // FPDFSDK_PWL_CPWL_WND_H_