Make common page base class for XFA and non-XFA.

Now that both are ref-counted, we can replace ifdef's with some
polymorphism.

Bug: pdfium:760

Change-Id: Ie22ea259c9af56fa569f0af268b8e7065789a3f2
Reviewed-on: https://pdfium-review.googlesource.com/32892
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: dsinclair <dsinclair@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index d23d8bd..0a84db8 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -589,6 +589,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 c5c8563..918c55e 100644
--- a/core/fpdfapi/page/cpdf_page.cpp
+++ b/core/fpdfapi/page/cpdf_page.cpp
@@ -74,6 +74,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 b94326e..f1d6f21 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/observable.h"
@@ -20,41 +21,50 @@
 class CPDF_Dictionary;
 class CPDF_Document;
 class CPDF_Object;
+class CPDF_Page;
 class CPDF_PageRenderCache;
 class CPDF_PageRenderContext;
 
-class CPDF_Page : public Retainable,
+// Small layering violation, incomplete type and always null if non-XFA.
+class CPDFXFA_Page;
+
+class CPDF_Page : public IPDF_Page,
                   public Observable<CPDF_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; }
-
   const CFX_FloatRect& GetPageBBox() const { return m_BBox; }
   int GetPageRotation() const;
-  CPDF_PageRenderCache* GetRenderCache() const { return m_pPageRender.get(); }
 
+  CPDF_PageRenderCache* GetRenderCache() const { return m_pPageRender.get(); }
   CPDF_PageRenderContext* GetRenderContext() const {
     return m_pRenderContext.get();
   }
@@ -63,8 +73,6 @@
   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,
@@ -80,7 +88,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..929cba7
--- /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 implented 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 bbb0293..28170d2 100644
--- a/fpdfsdk/cfx_systemhandler.cpp
+++ b/fpdfsdk/cfx_systemhandler.cpp
@@ -44,7 +44,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;
 
@@ -71,7 +71,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 76e5449..c6861bc 100644
--- a/fpdfsdk/cpdfsdk_helpers.cpp
+++ b/fpdfsdk/cpdfsdk_helpers.cpp
@@ -143,11 +143,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);
 }
 
@@ -164,11 +164,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 638b4df..3b92723 100644
--- a/fpdfsdk/cpdfsdk_interform.cpp
+++ b/fpdfsdk/cpdfsdk_interform.cpp
@@ -361,7 +361,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 43f8ee0..5cb5f2c 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..cf2d9bf 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,
@@ -45,8 +44,7 @@
   bool DeleteAnnot(CPDFSDK_Annot* pAnnot);
   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 +94,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 +111,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 261cb65..44e91d3 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);
 }
 
@@ -618,5 +618,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 9fb6c1f..9a4d5c7 100644
--- a/fpdfsdk/fpdf_editpage.cpp
+++ b/fpdfsdk/fpdf_editpage.cpp
@@ -191,13 +191,13 @@
   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
   RetainPtr<CPDF_Page> pPage = pDoc->GetOrCreatePDFPage(pPageDict);
-  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 62d2c00..c03b55b 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;
 
@@ -582,7 +583,7 @@
   if (!pFormFillEnv)
     return;
 
-  UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
+  IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
   if (!pPage)
     return;
 
@@ -640,7 +641,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 9af0ca4..806b9d2 100644
--- a/fpdfsdk/fpdf_view.cpp
+++ b/fpdfsdk/fpdf_view.cpp
@@ -345,7 +345,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;
@@ -355,17 +355,17 @@
     return nullptr;
 
   RetainPtr<CPDF_Page> pPage = pDoc->GetOrCreatePDFPage(pDict);
-  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;
 }
 
@@ -725,12 +725,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;
 
@@ -777,7 +777,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));
@@ -802,7 +802,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 f412089..ad06155 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..76c425f 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,35 +22,39 @@
 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.
diff --git a/fxjs/cjs_document.cpp b/fxjs/cjs_document.cpp
index 3a4ca27..24be12d 100644
--- a/fxjs/cjs_document.cpp
+++ b/fxjs/cjs_document.cpp
@@ -442,7 +442,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 1e9e389..263585c 100644
--- a/fxjs/cjs_field.cpp
+++ b/fxjs/cjs_field.cpp
@@ -2530,8 +2530,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(false);
     if (CPDFSDK_PageView* pCurPageView =