Rework "Make common page base class."

Re-landing of https://pdfium-review.googlesource.com/c/pdfium/+/32892

This time, however, we do not build on the previous CL which cached
pages. This CL by itself should be OK but was reverted only because
it was blocking earlier reverts.

Change-Id: I067d5f07373eeac6cced5d0c113ea40e5f8dcd15
Reviewed-on: https://pdfium-review.googlesource.com/34910
Commit-Queue: dsinclair <dsinclair@chromium.org>
Reviewed-by: dsinclair <dsinclair@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index c6d7a05..008ac77 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -594,6 +594,7 @@
     "core/fpdfapi/page/cpdf_textstate.h",
     "core/fpdfapi/page/cpdf_tilingpattern.cpp",
     "core/fpdfapi/page/cpdf_tilingpattern.h",
+    "core/fpdfapi/page/ipdf_page.h",
     "core/fpdfapi/parser/cfdf_document.cpp",
     "core/fpdfapi/parser/cfdf_document.h",
     "core/fpdfapi/parser/cpdf_array.cpp",
diff --git a/core/fpdfapi/page/cpdf_page.cpp b/core/fpdfapi/page/cpdf_page.cpp
index e730aee..4cd58dd 100644
--- a/core/fpdfapi/page/cpdf_page.cpp
+++ b/core/fpdfapi/page/cpdf_page.cpp
@@ -75,6 +75,26 @@
 
 CPDF_Page::~CPDF_Page() {}
 
+CPDF_Page* CPDF_Page::AsPDFPage() {
+  return this;
+}
+
+CPDFXFA_Page* CPDF_Page::AsXFAPage() {
+  return nullptr;
+}
+
+CPDF_Document* CPDF_Page::GetDocument() const {
+  return GetPDFDocument();
+}
+
+float CPDF_Page::GetPageWidth() const {
+  return m_PageSize.width;
+}
+
+float CPDF_Page::GetPageHeight() const {
+  return m_PageSize.height;
+}
+
 bool CPDF_Page::IsPage() const {
   return true;
 }
diff --git a/core/fpdfapi/page/cpdf_page.h b/core/fpdfapi/page/cpdf_page.h
index 1d01861..44bb6d8 100644
--- a/core/fpdfapi/page/cpdf_page.h
+++ b/core/fpdfapi/page/cpdf_page.h
@@ -10,6 +10,7 @@
 #include <memory>
 
 #include "core/fpdfapi/page/cpdf_pageobjectholder.h"
+#include "core/fpdfapi/page/ipdf_page.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_system.h"
 #include "core/fxcrt/retain_ptr.h"
@@ -22,45 +23,43 @@
 class CPDF_PageRenderCache;
 class CPDF_PageRenderContext;
 
-class CPDF_Page : public Retainable, public CPDF_PageObjectHolder {
+class CPDF_Page : public IPDF_Page, public CPDF_PageObjectHolder {
  public:
   class View {};  // Caller implements as desired, empty here due to layering.
-  class Extension : public Retainable {};  // XFA page parent class, layering.
 
   template <typename T, typename... Args>
   friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
 
+  // IPDF_Page:
+  CPDF_Page* AsPDFPage() override;
+  CPDFXFA_Page* AsXFAPage() override;
+  CPDF_Document* GetDocument() const override;
+  float GetPageWidth() const override;
+  float GetPageHeight() const override;
+  CFX_Matrix GetDisplayMatrix(const FX_RECT& rect, int iRotate) const override;
+  Optional<CFX_PointF> DeviceToPage(
+      const FX_RECT& rect,
+      int rotate,
+      const CFX_PointF& device_point) const override;
+  Optional<CFX_PointF> PageToDevice(
+      const FX_RECT& rect,
+      int rotate,
+      const CFX_PointF& page_point) const override;
+
   // CPDF_PageObjectHolder:
   bool IsPage() const override;
 
   void ParseContent();
-
-  Optional<CFX_PointF> DeviceToPage(const FX_RECT& rect,
-                                    int rotate,
-                                    const CFX_PointF& device_point) const;
-  Optional<CFX_PointF> PageToDevice(const FX_RECT& rect,
-                                    int rotate,
-                                    const CFX_PointF& page_point) const;
-
-  CFX_Matrix GetDisplayMatrix(const FX_RECT& rect, int iRotate) const;
-
-  float GetPageWidth() const { return m_PageSize.width; }
-  float GetPageHeight() const { return m_PageSize.height; }
   const CFX_SizeF& GetPageSize() const { return m_PageSize; }
-
   int GetPageRotation() const;
   CPDF_PageRenderCache* GetRenderCache() const { return m_pPageRender.get(); }
-
   CPDF_PageRenderContext* GetRenderContext() const {
     return m_pRenderContext.get();
   }
   void SetRenderContext(std::unique_ptr<CPDF_PageRenderContext> pContext);
-
   CPDF_Document* GetPDFDocument() const { return m_pPDFDocument.Get(); }
   View* GetView() const { return m_pView.Get(); }
   void SetView(View* pView) { m_pView = pView; }
-  Extension* GetPageExtension() const { return m_pPageExtension.Get(); }
-  void SetPageExtension(Extension* pExt) { m_pPageExtension = pExt; }
 
  private:
   CPDF_Page(CPDF_Document* pDocument,
@@ -74,7 +73,6 @@
   CFX_SizeF m_PageSize;
   CFX_Matrix m_PageMatrix;
   UnownedPtr<CPDF_Document> m_pPDFDocument;
-  UnownedPtr<Extension> m_pPageExtension;
   std::unique_ptr<CPDF_PageRenderCache> m_pPageRender;
   std::unique_ptr<CPDF_PageRenderContext> m_pRenderContext;
   UnownedPtr<View> m_pView;
diff --git a/core/fpdfapi/page/ipdf_page.h b/core/fpdfapi/page/ipdf_page.h
new file mode 100644
index 0000000..7c9fce7
--- /dev/null
+++ b/core/fpdfapi/page/ipdf_page.h
@@ -0,0 +1,52 @@
+// Copyright 2018 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef CORE_FPDFAPI_PAGE_IPDF_PAGE_H_
+#define CORE_FPDFAPI_PAGE_IPDF_PAGE_H_
+
+#include "core/fxcrt/fx_coordinates.h"
+#include "core/fxcrt/retain_ptr.h"
+#include "third_party/base/optional.h"
+
+class CPDF_Document;
+class CPDF_Page;
+
+// Small layering violation, incomplete type and always null if non-XFA.
+class CPDFXFA_Page;
+
+// Interface implemented by both page types (CPDF_Page and CPDFXFA_Page).
+class IPDF_Page : public Retainable {
+ public:
+  virtual CPDF_Page* AsPDFPage() = 0;
+  virtual CPDFXFA_Page* AsXFAPage() = 0;
+
+  virtual CPDF_Document* GetDocument() const = 0;
+
+  virtual float GetPageWidth() const = 0;
+  virtual float GetPageHeight() const = 0;
+  virtual CFX_Matrix GetDisplayMatrix(const FX_RECT& rect,
+                                      int iRotate) const = 0;
+
+  virtual Optional<CFX_PointF> DeviceToPage(
+      const FX_RECT& rect,
+      int rotate,
+      const CFX_PointF& device_point) const = 0;
+
+  virtual Optional<CFX_PointF> PageToDevice(
+      const FX_RECT& rect,
+      int rotate,
+      const CFX_PointF& page_point) const = 0;
+};
+
+inline CPDF_Page* ToPDFPage(IPDF_Page* pBase) {
+  return pBase ? pBase->AsPDFPage() : nullptr;
+}
+
+inline CPDFXFA_Page* ToXFAPage(IPDF_Page* pBase) {
+  return pBase ? pBase->AsXFAPage() : nullptr;
+}
+
+#endif  // CORE_FPDFAPI_PAGE_IPDF_PAGE_H_
diff --git a/fpdfsdk/cfx_systemhandler.cpp b/fpdfsdk/cfx_systemhandler.cpp
index 8281f56..99aff8c 100644
--- a/fpdfsdk/cfx_systemhandler.cpp
+++ b/fpdfsdk/cfx_systemhandler.cpp
@@ -28,7 +28,7 @@
 void CFX_SystemHandler::InvalidateRect(CPDFSDK_Widget* widget,
                                        const CFX_FloatRect& rect) {
   CPDFSDK_PageView* pPageView = widget->GetPageView();
-  UnderlyingPageType* pPage = widget->GetUnderlyingPage();
+  IPDF_Page* pPage = widget->GetPage();
   if (!pPage || !pPageView)
     return;
 
@@ -55,7 +55,7 @@
   CFX_PointF ptB = pFormFiller->PWLtoFFL(CFX_PointF(rect.right, rect.top));
 
   CPDFSDK_Annot* pAnnot = pFormFiller->GetSDKAnnot();
-  UnderlyingPageType* pPage = pAnnot->GetUnderlyingPage();
+  IPDF_Page* pPage = pAnnot->GetPage();
   ASSERT(pPage);
 
   m_pFormFillEnv->OutputSelectedRect(pPage,
diff --git a/fpdfsdk/cpdfsdk_annot.cpp b/fpdfsdk/cpdfsdk_annot.cpp
index e105ed9..6c17628 100644
--- a/fpdfsdk/cpdfsdk_annot.cpp
+++ b/fpdfsdk/cpdfsdk_annot.cpp
@@ -73,7 +73,7 @@
   return CFX_FloatRect();
 }
 
-UnderlyingPageType* CPDFSDK_Annot::GetUnderlyingPage() {
+IPDF_Page* CPDFSDK_Annot::GetPage() {
 #ifdef PDF_ENABLE_XFA
   return GetPDFXFAPage();
 #else   // PDF_ENABLE_XFA
diff --git a/fpdfsdk/cpdfsdk_annot.h b/fpdfsdk/cpdfsdk_annot.h
index bf6e2cc..2d97f08 100644
--- a/fpdfsdk/cpdfsdk_annot.h
+++ b/fpdfsdk/cpdfsdk_annot.h
@@ -45,7 +45,7 @@
   virtual CFX_FloatRect GetRect() const;
   virtual void SetRect(const CFX_FloatRect& rect);
 
-  UnderlyingPageType* GetUnderlyingPage();
+  IPDF_Page* GetPage();
   CPDF_Page* GetPDFPage();
 #ifdef PDF_ENABLE_XFA
   CPDFXFA_Page* GetPDFXFAPage();
diff --git a/fpdfsdk/cpdfsdk_annothandlermgr.cpp b/fpdfsdk/cpdfsdk_annothandlermgr.cpp
index 37d5274..117bf93 100644
--- a/fpdfsdk/cpdfsdk_annothandlermgr.cpp
+++ b/fpdfsdk/cpdfsdk_annothandlermgr.cpp
@@ -311,7 +311,7 @@
   CPDFXFA_Page* pPage = pPageView->GetPDFXFAPage();
   if (!pPage)
     return nullptr;
-  if (pPage->GetPDFPage()) {  // for pdf annots.
+  if (pPage->AsPDFPage()) {  // for pdf annots.
     CPDFSDK_AnnotIterator ai(pSDKAnnot->GetPageView(),
                              pSDKAnnot->GetAnnotSubtype());
     CPDFSDK_Annot* pNext =
diff --git a/fpdfsdk/cpdfsdk_formfillenvironment.cpp b/fpdfsdk/cpdfsdk_formfillenvironment.cpp
index a0859a2..44807fd 100644
--- a/fpdfsdk/cpdfsdk_formfillenvironment.cpp
+++ b/fpdfsdk/cpdfsdk_formfillenvironment.cpp
@@ -231,19 +231,19 @@
   return m_pFormFiller.get();
 }
 
-void CPDFSDK_FormFillEnvironment::Invalidate(UnderlyingPageType* page,
+void CPDFSDK_FormFillEnvironment::Invalidate(IPDF_Page* page,
                                              const FX_RECT& rect) {
   if (m_pInfo && m_pInfo->FFI_Invalidate) {
-    m_pInfo->FFI_Invalidate(m_pInfo, FPDFPageFromUnderlying(page), rect.left,
+    m_pInfo->FFI_Invalidate(m_pInfo, FPDFPageFromIPDFPage(page), rect.left,
                             rect.top, rect.right, rect.bottom);
   }
 }
 
 void CPDFSDK_FormFillEnvironment::OutputSelectedRect(
-    UnderlyingPageType* page,
+    IPDF_Page* page,
     const CFX_FloatRect& rect) {
   if (m_pInfo && m_pInfo->FFI_OutputSelectedRect) {
-    m_pInfo->FFI_OutputSelectedRect(m_pInfo, FPDFPageFromUnderlying(page),
+    m_pInfo->FFI_OutputSelectedRect(m_pInfo, FPDFPageFromIPDFPage(page),
                                     rect.left, rect.top, rect.right,
                                     rect.bottom);
   }
@@ -332,7 +332,7 @@
                                                double right,
                                                double bottom) {
   if (m_pInfo && m_pInfo->FFI_DisplayCaret) {
-    m_pInfo->FFI_DisplayCaret(m_pInfo, FPDFPageFromUnderlying(page), bVisible,
+    m_pInfo->FFI_DisplayCaret(m_pInfo, FPDFPageFromIPDFPage(page), bVisible,
                               left, top, right, bottom);
   }
 }
@@ -387,8 +387,8 @@
   double top;
   double right;
   double bottom;
-  m_pInfo->FFI_GetPageViewRect(m_pInfo, FPDFPageFromUnderlying(page), &left,
-                               &top, &right, &bottom);
+  m_pInfo->FFI_GetPageViewRect(m_pInfo, FPDFPageFromIPDFPage(page), &left, &top,
+                               &right, &bottom);
 
   dstRect.left = static_cast<float>(left);
   dstRect.top = static_cast<float>(top);
@@ -401,7 +401,7 @@
                                             int menuFlag,
                                             CFX_PointF pt) {
   return m_pInfo && m_pInfo->FFI_PopupMenu &&
-         m_pInfo->FFI_PopupMenu(m_pInfo, FPDFPageFromUnderlying(page), hWidget,
+         m_pInfo->FFI_PopupMenu(m_pInfo, FPDFPageFromIPDFPage(page), hWidget,
                                 menuFlag, pt.x, pt.y);
 }
 
@@ -531,7 +531,7 @@
 }
 
 CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetPageView(
-    UnderlyingPageType* pUnderlyingPage,
+    IPDF_Page* pUnderlyingPage,
     bool renew) {
   auto it = m_PageMap.find(pUnderlyingPage);
   if (it != m_PageMap.end())
@@ -550,12 +550,12 @@
 }
 
 CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetCurrentView() {
-  UnderlyingPageType* pPage = UnderlyingFromFPDFPage(GetCurrentPage());
+  IPDF_Page* pPage = IPDFPageFromFPDFPage(GetCurrentPage());
   return pPage ? GetPageView(pPage, true) : nullptr;
 }
 
 CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetPageView(int nIndex) {
-  UnderlyingPageType* pTempPage = GetPage(nIndex);
+  IPDF_Page* pTempPage = GetPage(nIndex);
   if (!pTempPage)
     return nullptr;
 
@@ -599,8 +599,7 @@
   return true;
 }
 
-void CPDFSDK_FormFillEnvironment::RemovePageView(
-    UnderlyingPageType* pUnderlyingPage) {
+void CPDFSDK_FormFillEnvironment::RemovePageView(IPDF_Page* pUnderlyingPage) {
   auto it = m_PageMap.find(pUnderlyingPage);
   if (it == m_PageMap.end())
     return;
@@ -626,10 +625,10 @@
   m_PageMap.erase(it);
 }
 
-UnderlyingPageType* CPDFSDK_FormFillEnvironment::GetPage(int nIndex) {
+IPDF_Page* CPDFSDK_FormFillEnvironment::GetPage(int nIndex) {
   if (!m_pInfo || !m_pInfo->FFI_GetPage)
     return nullptr;
-  return UnderlyingFromFPDFPage(m_pInfo->FFI_GetPage(
+  return IPDFPageFromFPDFPage(m_pInfo->FFI_GetPage(
       m_pInfo, FPDFDocumentFromCPDFDocument(m_pCPDFDoc.Get()), nIndex));
 }
 
diff --git a/fpdfsdk/cpdfsdk_formfillenvironment.h b/fpdfsdk/cpdfsdk_formfillenvironment.h
index 8baa584..9818259 100644
--- a/fpdfsdk/cpdfsdk_formfillenvironment.h
+++ b/fpdfsdk/cpdfsdk_formfillenvironment.h
@@ -60,10 +60,10 @@
     return !!(nFlag & FWL_EVENTFLAG_AltKey);
   }
 
-  CPDFSDK_PageView* GetPageView(UnderlyingPageType* pPage, bool renew);
+  CPDFSDK_PageView* GetPageView(IPDF_Page* pPage, bool renew);
   CPDFSDK_PageView* GetPageView(int nIndex);
   CPDFSDK_PageView* GetCurrentView();
-  void RemovePageView(UnderlyingPageType* pPage);
+  void RemovePageView(IPDF_Page* pPage);
   void UpdateAllViews(CPDFSDK_PageView* pSender, CPDFSDK_Annot* pAnnot);
 
   CPDFSDK_Annot* GetFocusAnnot() { return m_pFocusAnnot.Get(); }
@@ -90,8 +90,8 @@
   void ProcJavascriptFun();
   bool ProcOpenAction();
 
-  void Invalidate(UnderlyingPageType* page, const FX_RECT& rect);
-  void OutputSelectedRect(UnderlyingPageType* page, const CFX_FloatRect& rect);
+  void Invalidate(IPDF_Page* page, const FX_RECT& rect);
+  void OutputSelectedRect(IPDF_Page* page, const CFX_FloatRect& rect);
 
   void SetCursor(int nCursorType);
   int SetTimer(int uElapse, TimerCallback lpTimerFunc);
@@ -210,13 +210,13 @@
   CPDFSDK_InterForm* GetInterForm();              // Creates if not present.
 
  private:
-  UnderlyingPageType* GetPage(int nIndex);
+  IPDF_Page* 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_pIJSRuntime;
-  std::map<UnderlyingPageType*, std::unique_ptr<CPDFSDK_PageView>> m_PageMap;
+  std::map<IPDF_Page*, std::unique_ptr<CPDFSDK_PageView>> m_PageMap;
   std::unique_ptr<CPDFSDK_InterForm> m_pInterForm;
   CPDFSDK_Annot::ObservedPtr m_pFocusAnnot;
   UnownedPtr<CPDF_Document> const m_pCPDFDoc;
diff --git a/fpdfsdk/cpdfsdk_helpers.cpp b/fpdfsdk/cpdfsdk_helpers.cpp
index 1ceecfe..2f42f14 100644
--- a/fpdfsdk/cpdfsdk_helpers.cpp
+++ b/fpdfsdk/cpdfsdk_helpers.cpp
@@ -144,11 +144,11 @@
 
 }  // namespace
 
-UnderlyingPageType* UnderlyingFromFPDFPage(FPDF_PAGE page) {
-  return reinterpret_cast<UnderlyingPageType*>(page);
+IPDF_Page* IPDFPageFromFPDFPage(FPDF_PAGE page) {
+  return reinterpret_cast<IPDF_Page*>(page);
 }
 
-FPDF_PAGE FPDFPageFromUnderlying(UnderlyingPageType* page) {
+FPDF_PAGE FPDFPageFromIPDFPage(IPDF_Page* page) {
   return reinterpret_cast<FPDF_PAGE>(page);
 }
 
@@ -161,11 +161,7 @@
 }
 
 CPDF_Page* CPDFPageFromFPDFPage(FPDF_PAGE page) {
-#ifdef PDF_ENABLE_XFA
-  return page ? UnderlyingFromFPDFPage(page)->GetPDFPage() : nullptr;
-#else   // PDF_ENABLE_XFA
-  return UnderlyingFromFPDFPage(page);
-#endif  // PDF_ENABLE_XFA
+  return page ? IPDFPageFromFPDFPage(page)->AsPDFPage() : nullptr;
 }
 
 ByteString CFXByteStringFromFPDFWideString(FPDF_WIDESTRING wide_string) {
diff --git a/fpdfsdk/cpdfsdk_helpers.h b/fpdfsdk/cpdfsdk_helpers.h
index fae7ef0..98d7e45 100644
--- a/fpdfsdk/cpdfsdk_helpers.h
+++ b/fpdfsdk/cpdfsdk_helpers.h
@@ -7,6 +7,7 @@
 #ifndef FPDFSDK_CPDFSDK_HELPERS_H_
 #define FPDFSDK_CPDFSDK_HELPERS_H_
 
+#include "core/fpdfapi/page/cpdf_page.h"
 #include "core/fpdfapi/parser/cpdf_parser.h"
 #include "core/fxge/dib/cfx_dibitmap.h"
 #include "core/fxge/fx_dib.h"
@@ -29,7 +30,6 @@
 class CPDF_Object;
 class CPDF_Font;
 class CPDF_LinkExtract;
-class CPDF_Page;
 class CPDF_PageObject;
 class CPDF_PageRenderContext;
 class CPDF_PathObject;
@@ -47,18 +47,9 @@
 class CXFA_FFWidget;
 #endif  // PDF_ENABLE_XFA
 
-// Object types for public FPDF_ types; these correspond to next layer down
-// from fpdfsdk. For master, these are CPDF_ types, but for XFA, these are
-// CPDFXFA_ types.
-#ifdef PDF_ENABLE_XFA
-using UnderlyingPageType = CPDFXFA_Page;
-#else   // PDF_ENABLE_XFA
-using UnderlyingPageType = CPDF_Page;
-#endif  // PDF_ENABLE_XFA
-
 // Conversions to/from underlying types.
-UnderlyingPageType* UnderlyingFromFPDFPage(FPDF_PAGE page);
-FPDF_PAGE FPDFPageFromUnderlying(UnderlyingPageType* page);
+IPDF_Page* IPDFPageFromFPDFPage(FPDF_PAGE page);
+FPDF_PAGE FPDFPageFromIPDFPage(IPDF_Page* page);
 CPDF_Page* CPDFPageFromFPDFPage(FPDF_PAGE page);
 FPDF_DOCUMENT FPDFDocumentFromCPDFDocument(CPDF_Document* doc);
 CPDF_Document* CPDFDocumentFromFPDFDocument(FPDF_DOCUMENT doc);
diff --git a/fpdfsdk/cpdfsdk_interform.cpp b/fpdfsdk/cpdfsdk_interform.cpp
index 1d8002a..1e24746 100644
--- a/fpdfsdk/cpdfsdk_interform.cpp
+++ b/fpdfsdk/cpdfsdk_interform.cpp
@@ -358,7 +358,7 @@
     if (!pWidget)
       continue;
 
-    UnderlyingPageType* pPage = pWidget->GetUnderlyingPage();
+    IPDF_Page* pPage = pWidget->GetPage();
     FX_RECT rect = formfiller->GetViewBBox(
         m_pFormFillEnv->GetPageView(pPage, false), pWidget);
     m_pFormFillEnv->Invalidate(pPage, rect);
diff --git a/fpdfsdk/cpdfsdk_pageview.cpp b/fpdfsdk/cpdfsdk_pageview.cpp
index 74802a8..d2736b1 100644
--- a/fpdfsdk/cpdfsdk_pageview.cpp
+++ b/fpdfsdk/cpdfsdk_pageview.cpp
@@ -31,17 +31,17 @@
 #endif  // PDF_ENABLE_XFA
 
 CPDFSDK_PageView::CPDFSDK_PageView(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                                   UnderlyingPageType* page)
+                                   IPDF_Page* page)
     : m_page(page), m_pFormFillEnv(pFormFillEnv) {
-  CPDFSDK_InterForm* pInterForm = pFormFillEnv->GetInterForm();
-  CPDF_InterForm* pPDFInterForm = pInterForm->GetInterForm();
-#ifdef PDF_ENABLE_XFA
-  if (page->GetPDFPage())
-    pPDFInterForm->FixPageFields(page->GetPDFPage());
-#else   // PDF_ENABLE_XFA
-  pPDFInterForm->FixPageFields(page);
-  m_page->SetView(this);
+  CPDF_Page* pPDFPage = ToPDFPage(page);
+  if (pPDFPage) {
+    CPDFSDK_InterForm* pInterForm = pFormFillEnv->GetInterForm();
+    CPDF_InterForm* pPDFInterForm = pInterForm->GetInterForm();
+    pPDFInterForm->FixPageFields(pPDFPage);
+#ifndef PDF_ENABLE_XFA
+    pPDFPage->SetView(this);
 #endif  // PDF_ENABLE_XFA
+  }
 }
 
 CPDFSDK_PageView::~CPDFSDK_PageView() {
@@ -49,7 +49,7 @@
   // The call to |ReleaseAnnot| can cause the page pointed to by |m_page| to
   // be freed, which will cause issues if we try to cleanup the pageview pointer
   // in |m_page|. So, reset the pageview pointer before doing anything else.
-  m_page->SetView(nullptr);
+  m_page->AsPDFPage()->SetView(nullptr);
 #endif  // PDF_ENABLE_XFA
 
   CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
@@ -190,22 +190,11 @@
 #endif  // PDF_ENABLE_XFA
 
 CPDF_Document* CPDFSDK_PageView::GetPDFDocument() {
-  if (m_page) {
-#ifdef PDF_ENABLE_XFA
-    return m_page->GetDocumentExtension()->GetPDFDoc();
-#else   // PDF_ENABLE_XFA
-    return m_page->GetDocument();
-#endif  // PDF_ENABLE_XFA
-  }
-  return nullptr;
+  return m_page ? m_page->GetDocument() : nullptr;
 }
 
 CPDF_Page* CPDFSDK_PageView::GetPDFPage() const {
-#ifdef PDF_ENABLE_XFA
-  return m_page ? m_page->GetPDFPage() : nullptr;
-#else   // PDF_ENABLE_XFA
-  return m_page;
-#endif  // PDF_ENABLE_XFA
+  return ToPDFPage(m_page);
 }
 
 CPDFSDK_Annot* CPDFSDK_PageView::GetAnnotByDict(CPDF_Dictionary* pDict) {
@@ -460,9 +449,9 @@
   m_bLocked = true;
 
 #ifdef PDF_ENABLE_XFA
-  RetainPtr<CPDFXFA_Page> protector(m_page);
+  RetainPtr<CPDFXFA_Page> protector(ToXFAPage(m_page));
   if (m_pFormFillEnv->GetXFAContext()->GetFormType() == FormType::kXFAFull) {
-    CXFA_FFPageView* pageView = m_page->GetXFAPageView();
+    CXFA_FFPageView* pageView = protector->GetXFAPageView();
     std::unique_ptr<IXFA_WidgetIterator> pWidgetHandler(
         pageView->CreateWidgetIterator(
             XFA_TRAVERSEWAY_Form,
@@ -518,11 +507,11 @@
     return -1;
 
 #ifdef PDF_ENABLE_XFA
-  auto* pContext =
-      static_cast<CPDFXFA_Context*>(m_page->GetDocumentExtension());
+  auto* pContext = static_cast<CPDFXFA_Context*>(
+      m_page->AsXFAPage()->GetDocumentExtension());
   switch (pContext->GetFormType()) {
     case FormType::kXFAFull: {
-      CXFA_FFPageView* pPageView = m_page->GetXFAPageView();
+      CXFA_FFPageView* pPageView = m_page->AsXFAPage()->GetXFAPageView();
       return pPageView ? pPageView->GetPageIndex() : -1;
     }
     case FormType::kNone:
diff --git a/fpdfsdk/cpdfsdk_pageview.h b/fpdfsdk/cpdfsdk_pageview.h
index bfb6450..38ff288 100644
--- a/fpdfsdk/cpdfsdk_pageview.h
+++ b/fpdfsdk/cpdfsdk_pageview.h
@@ -22,8 +22,7 @@
 
 class CPDFSDK_PageView final : public CPDF_Page::View {
  public:
-  CPDFSDK_PageView(CPDFSDK_FormFillEnvironment* pFormFillEnv,
-                   UnderlyingPageType* page);
+  CPDFSDK_PageView(CPDFSDK_FormFillEnvironment* pFormFillEnv, IPDF_Page* page);
   ~CPDFSDK_PageView();
 
   void PageView_OnDraw(CFX_RenderDevice* pDevice,
@@ -46,7 +45,7 @@
   CPDFSDK_Annot* AddAnnot(CXFA_FFWidget* pPDFAnnot);
   CPDFSDK_Annot* GetAnnotByXFAWidget(CXFA_FFWidget* hWidget);
 
-  CPDFXFA_Page* GetPDFXFAPage() { return m_page; }
+  CPDFXFA_Page* GetPDFXFAPage() { return ToXFAPage(m_page); }
 #endif  // PDF_ENABLE_XFA
 
   CPDF_Page* GetPDFPage() const;
@@ -96,7 +95,7 @@
   bool IsBeingDestroyed() const { return m_bBeingDestroyed; }
 
 #ifndef PDF_ENABLE_XFA
-  void TakePageOwnership() { m_pOwnsPage.Reset(m_page); }
+  void TakePageOwnership() { m_pOwnsPage.Reset(ToPDFPage(m_page)); }
 #endif  // PDF_ENABLE_XFA
 
  private:
@@ -113,7 +112,7 @@
                   uint32_t nFlag);
 
   CFX_Matrix m_curMatrix;
-  UnderlyingPageType* const m_page;
+  IPDF_Page* const m_page;
   std::unique_ptr<CPDF_AnnotList> m_pAnnotList;
   std::vector<CPDFSDK_Annot*> m_SDKAnnotArray;
   UnownedPtr<CPDFSDK_FormFillEnvironment> const m_pFormFillEnv;
diff --git a/fpdfsdk/formfiller/cffl_formfiller.cpp b/fpdfsdk/formfiller/cffl_formfiller.cpp
index 4438df0..6174dde 100644
--- a/fpdfsdk/formfiller/cffl_formfiller.cpp
+++ b/fpdfsdk/formfiller/cffl_formfiller.cpp
@@ -302,7 +302,7 @@
 
 void CFFL_FormFiller::SetFocusForAnnot(CPDFSDK_Annot* pAnnot, uint32_t nFlag) {
   auto* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot);
-  UnderlyingPageType* pPage = pWidget->GetUnderlyingPage();
+  IPDF_Page* pPage = pWidget->GetPage();
   CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetPageView(pPage, true);
   if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, true))
     pWnd->SetFocus();
@@ -479,7 +479,7 @@
 }
 
 CPDFSDK_PageView* CFFL_FormFiller::GetCurPageView(bool renew) {
-  UnderlyingPageType* pPage = m_pWidget->GetUnderlyingPage();
+  IPDF_Page* pPage = m_pWidget->GetPage();
   return m_pFormFillEnv->GetPageView(pPage, renew);
 }
 
@@ -617,5 +617,5 @@
 }
 
 void CFFL_FormFiller::InvalidateRect(const FX_RECT& rect) {
-  m_pFormFillEnv->Invalidate(m_pWidget->GetUnderlyingPage(), rect);
+  m_pFormFillEnv->Invalidate(m_pWidget->GetPage(), rect);
 }
diff --git a/fpdfsdk/formfiller/cffl_textfield.cpp b/fpdfsdk/formfiller/cffl_textfield.cpp
index eeed266..da011e4 100644
--- a/fpdfsdk/formfiller/cffl_textfield.cpp
+++ b/fpdfsdk/formfiller/cffl_textfield.cpp
@@ -100,7 +100,7 @@
       CPDFSDK_PageView* pPageView = GetCurPageView(true);
       ASSERT(pPageView);
       m_bValid = !m_bValid;
-      m_pFormFillEnv->Invalidate(pAnnot->GetUnderlyingPage(),
+      m_pFormFillEnv->Invalidate(pAnnot->GetPage(),
                                  pAnnot->GetRect().GetOuterRect());
 
       if (m_bValid) {
diff --git a/fpdfsdk/fpdf_editpage.cpp b/fpdfsdk/fpdf_editpage.cpp
index d8b39b4..9dcd470 100644
--- a/fpdfsdk/fpdf_editpage.cpp
+++ b/fpdfsdk/fpdf_editpage.cpp
@@ -197,14 +197,14 @@
   if (pContext) {
     auto pXFAPage = pdfium::MakeRetain<CPDFXFA_Page>(pContext, page_index);
     pXFAPage->LoadPDFPage(pPageDict);
-    return FPDFPageFromUnderlying(pXFAPage.Leak());  // Caller takes ownership.
+    return FPDFPageFromIPDFPage(pXFAPage.Leak());  // Caller takes ownership.
   }
   // Eventually, fallthru into non-XFA case once page type is consistent.
   return nullptr;
 #else  // PDF_ENABLE_XFA
   auto pPage = pdfium::MakeRetain<CPDF_Page>(pDoc, pPageDict, true);
   pPage->ParseContent();
-  return FPDFPageFromUnderlying(pPage.Leak());  // Caller takes ownership.
+  return FPDFPageFromIPDFPage(pPage.Leak());  // Caller takes ownership.
 #endif  // PDF_ENABLE_XFA
 }
 
diff --git a/fpdfsdk/fpdf_formfill.cpp b/fpdfsdk/fpdf_formfill.cpp
index ec26ef0..cd4a8c5 100644
--- a/fpdfsdk/fpdf_formfill.cpp
+++ b/fpdfsdk/fpdf_formfill.cpp
@@ -111,7 +111,7 @@
 
 CPDFSDK_PageView* FormHandleToPageView(FPDF_FORMHANDLE hHandle,
                                        FPDF_PAGE page) {
-  UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
+  IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
   if (!pPage)
     return nullptr;
 
@@ -133,12 +133,13 @@
   if (!hHandle)
     return;
 
-  UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
+  IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
   if (!pPage)
     return;
 
 #ifdef PDF_ENABLE_XFA
-  CPDF_Document::Extension* pExtension = pPage->GetDocumentExtension();
+  CPDF_Document::Extension* pExtension =
+      pPage->AsXFAPage()->GetDocumentExtension();
   if (!pExtension)
     return;
   CPDF_Document* pPDFDoc = pExtension->GetPDFDoc();
@@ -185,7 +186,7 @@
     CPDFSDK_PageView* pPageView = pFormFillEnv->GetPageView(pPage, true);
 #else   // PDF_ENABLE_XFA
     CPDFSDK_PageView* pPageView =
-        FormHandleToPageView(hHandle, FPDFPageFromUnderlying(pPage));
+        FormHandleToPageView(hHandle, FPDFPageFromIPDFPage(pPage));
 #endif  // PDF_ENABLE_XFA
 
     if (pPageView)
@@ -220,7 +221,7 @@
   }
 
 #ifdef PDF_ENABLE_XFA
-  CPDFXFA_Page* pXFAPage = UnderlyingFromFPDFPage(page);
+  CPDFXFA_Page* pXFAPage = ToXFAPage(IPDFPageFromFPDFPage(page));
   if (!pXFAPage)
     return -1;
 
@@ -598,7 +599,7 @@
   if (!pFormFillEnv)
     return;
 
-  UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
+  IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
   if (!pPage)
     return;
 
@@ -656,7 +657,7 @@
   if (!pFormFillEnv)
     return;
 
-  UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
+  IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
   CPDF_Page* pPDFPage = CPDFPageFromFPDFPage(page);
   if (!pPDFPage)
     return;
diff --git a/fpdfsdk/fpdf_view.cpp b/fpdfsdk/fpdf_view.cpp
index 96de5d5..535f1e5 100644
--- a/fpdfsdk/fpdf_view.cpp
+++ b/fpdfsdk/fpdf_view.cpp
@@ -351,7 +351,7 @@
 #ifdef PDF_ENABLE_XFA
   auto* pContext = static_cast<CPDFXFA_Context*>(pDoc->GetExtension());
   if (pContext)
-    return FPDFPageFromUnderlying(pContext->GetXFAPage(page_index).Leak());
+    return FPDFPageFromIPDFPage(pContext->GetXFAPage(page_index).Leak());
 
   // Eventually, fallthrough into non-xfa case once page type made consistent.
   return nullptr;
@@ -362,17 +362,17 @@
 
   auto pPage = pdfium::MakeRetain<CPDF_Page>(pDoc, pDict, true);
   pPage->ParseContent();
-  return FPDFPageFromUnderlying(pPage.Leak());
+  return FPDFPageFromIPDFPage(pPage.Leak());
 #endif  // PDF_ENABLE_XFA
 }
 
 FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page) {
-  UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
+  IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
   return pPage ? pPage->GetPageWidth() : 0.0;
 }
 
 FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page) {
-  UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
+  IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
   return pPage ? pPage->GetPageHeight() : 0.0;
 }
 
@@ -732,12 +732,12 @@
     return;
 
   // Take it back across the API and hold for duration of this function.
-  RetainPtr<UnderlyingPageType> pPage;
-  pPage.Unleak(UnderlyingFromFPDFPage(page));
+  RetainPtr<IPDF_Page> pPage;
+  pPage.Unleak(IPDFPageFromFPDFPage(page));
 
 #ifndef PDF_ENABLE_XFA
   CPDFSDK_PageView* pPageView =
-      static_cast<CPDFSDK_PageView*>(pPage->GetView());
+      static_cast<CPDFSDK_PageView*>(pPage->AsPDFPage()->GetView());
   if (!pPageView || pPageView->IsBeingDestroyed())
     return;
 
@@ -775,7 +775,7 @@
   if (!page || !page_x || !page_y)
     return false;
 
-  UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
+  IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
   const FX_RECT rect(start_x, start_y, start_x + size_x, start_y + size_y);
   Optional<CFX_PointF> pos =
       pPage->DeviceToPage(rect, rotate, CFX_PointF(device_x, device_y));
@@ -800,7 +800,7 @@
   if (!page || !device_x || !device_y)
     return false;
 
-  UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
+  IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
   const FX_RECT rect(start_x, start_y, start_x + size_x, start_y + size_y);
   CFX_PointF page_point(static_cast<float>(page_x), static_cast<float>(page_y));
   Optional<CFX_PointF> pos = pPage->PageToDevice(rect, rotate, page_point);
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_page.cpp b/fpdfsdk/fpdfxfa/cpdfxfa_page.cpp
index 7e2deda..e4618e3 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_page.cpp
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_page.cpp
@@ -22,6 +22,18 @@
 
 CPDFXFA_Page::~CPDFXFA_Page() {}
 
+CPDF_Page* CPDFXFA_Page::AsPDFPage() {
+  return m_pPDFPage.Get();
+}
+
+CPDFXFA_Page* CPDFXFA_Page::AsXFAPage() {
+  return this;
+}
+
+CPDF_Document* CPDFXFA_Page::GetDocument() const {
+  return GetDocumentExtension()->GetPDFDoc();
+}
+
 bool CPDFXFA_Page::LoadPDFPage() {
   if (!m_pContext)
     return false;
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_page.h b/fpdfsdk/fpdfxfa/cpdfxfa_page.h
index 2573b9c..b660869 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_page.h
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_page.h
@@ -10,6 +10,7 @@
 #include <memory>
 
 #include "core/fpdfapi/page/cpdf_page.h"
+#include "core/fpdfapi/page/ipdf_page.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_system.h"
@@ -21,36 +22,36 @@
 class CPDFXFA_Context;
 class CXFA_FFPageView;
 
-class CPDFXFA_Page : public CPDF_Page::Extension {
+class CPDFXFA_Page : public IPDF_Page {
  public:
   template <typename T, typename... Args>
   friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
 
+  // IPDF_Page:
+  CPDF_Page* AsPDFPage() override;
+  CPDFXFA_Page* AsXFAPage() override;
+  CPDF_Document* GetDocument() const override;
+  float GetPageWidth() const override;
+  float GetPageHeight() const override;
+  CFX_Matrix GetDisplayMatrix(const FX_RECT& rect, int iRotate) const override;
+  Optional<CFX_PointF> DeviceToPage(
+      const FX_RECT& rect,
+      int rotate,
+      const CFX_PointF& device_point) const override;
+  Optional<CFX_PointF> PageToDevice(
+      const FX_RECT& rect,
+      int rotate,
+      const CFX_PointF& page_point) const override;
+
   bool LoadPage();
   bool LoadPDFPage(CPDF_Dictionary* pageDict);
-
   CPDF_Document::Extension* GetDocumentExtension() const;
-
   int GetPageIndex() const { return m_iPageIndex; }
-  CPDF_Page* GetPDFPage() const { return m_pPDFPage.Get(); }
   CXFA_FFPageView* GetXFAPageView() const { return m_pXFAPageView; }
-
   void SetXFAPageView(CXFA_FFPageView* pPageView) {
     m_pXFAPageView = pPageView;
   }
 
-  float GetPageWidth() const;
-  float GetPageHeight() const;
-
-  Optional<CFX_PointF> DeviceToPage(const FX_RECT& rect,
-                                    int rotate,
-                                    const CFX_PointF& device_point) const;
-  Optional<CFX_PointF> PageToDevice(const FX_RECT& rect,
-                                    int rotate,
-                                    const CFX_PointF& page_point) const;
-
-  CFX_Matrix GetDisplayMatrix(const FX_RECT& rect, int iRotate) const;
-
  protected:
   // Refcounted class.
   CPDFXFA_Page(CPDFXFA_Context* pContext, int page_index);
diff --git a/fxjs/cjs_document.cpp b/fxjs/cjs_document.cpp
index f562991..74304bb 100644
--- a/fxjs/cjs_document.cpp
+++ b/fxjs/cjs_document.cpp
@@ -437,7 +437,7 @@
     ++rcAnnot.top;
 
     std::vector<CFX_FloatRect> aRefresh(1, rcAnnot);
-    UnderlyingPageType* pPage = pWidget->GetUnderlyingPage();
+    IPDF_Page* pPage = pWidget->GetPage();
     ASSERT(pPage);
 
     // If there is currently no pageview associated with the page being used
diff --git a/fxjs/cjs_field.cpp b/fxjs/cjs_field.cpp
index 2ed88ef..e9aa777 100644
--- a/fxjs/cjs_field.cpp
+++ b/fxjs/cjs_field.cpp
@@ -2583,8 +2583,7 @@
   if (nCount == 1) {
     pWidget = pInterForm->GetWidget(pFormField->GetControl(0));
   } else {
-    UnderlyingPageType* pPage =
-        UnderlyingFromFPDFPage(m_pFormFillEnv->GetCurrentPage());
+    IPDF_Page* pPage = IPDFPageFromFPDFPage(m_pFormFillEnv->GetCurrentPage());
     if (!pPage)
       return CJS_Return(JSMessage::kBadObjectError);
     if (CPDFSDK_PageView* pCurPageView =