Avoid circular includes between CPDF_Document and CPDF_LinkList

Introduce a trivial pure virtual interface to resolve the issue.
Ideally, we'd find some other object to own the links, but this
cleans it up in the mean time.

Change-Id: I15e2792da328ac9de16c021dfa2521357b5a886d
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/54991
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_document.h b/core/fpdfapi/parser/cpdf_document.h
index 6684eb8..172e991 100644
--- a/core/fpdfapi/parser/cpdf_document.h
+++ b/core/fpdfapi/parser/cpdf_document.h
@@ -18,7 +18,6 @@
 #include "core/fpdfapi/page/cpdf_page.h"
 #include "core/fpdfapi/parser/cpdf_object.h"
 #include "core/fpdfapi/parser/cpdf_parser.h"
-#include "core/fpdfdoc/cpdf_linklist.h"
 #include "core/fxcrt/observable.h"
 #include "core/fxcrt/retain_ptr.h"
 
@@ -56,6 +55,12 @@
     virtual uint32_t GetUserPermissions() const = 0;
   };
 
+  class LinkListIface {
+   public:
+    // CPDF_Document merely helps manage the lifetime.
+    virtual ~LinkListIface() = default;
+  };
+
   static const int kPageMaxNum = 0xFFFFF;
 
   CPDF_Document();
@@ -85,7 +90,10 @@
   std::unique_ptr<JBig2_DocumentContext>* CodecContext() {
     return &m_pCodecContext;
   }
-  std::unique_ptr<CPDF_LinkList>* LinksContext() { return &m_pLinksContext; }
+  LinkListIface* GetLinksContext() const { return m_pLinksContext.get(); }
+  void SetLinksContext(std::unique_ptr<LinkListIface> pContext) {
+    m_pLinksContext = std::move(pContext);
+  }
 
   CPDF_DocRenderData* GetRenderData() const { return m_pDocRender.get(); }
 
@@ -192,7 +200,7 @@
   std::unique_ptr<CPDF_DocPageData> m_pDocPage;
 
   std::unique_ptr<JBig2_DocumentContext> m_pCodecContext;
-  std::unique_ptr<CPDF_LinkList> m_pLinksContext;
+  std::unique_ptr<LinkListIface> m_pLinksContext;
   std::vector<uint32_t> m_PageList;  // Page number to page's dict objnum.
 
   // Must be second to last.
diff --git a/core/fpdfdoc/BUILD.gn b/core/fpdfdoc/BUILD.gn
index ada4382..82289f3 100644
--- a/core/fpdfdoc/BUILD.gn
+++ b/core/fpdfdoc/BUILD.gn
@@ -95,10 +95,7 @@
     "../fxcrt",
     "../fxge",
   ]
-  allow_circular_includes_from = [
-    "../fpdfapi/parser",
-    "../fpdfapi/render",
-  ]
+  allow_circular_includes_from = [ "../fpdfapi/render" ]
   visibility = [ "../../*" ]
 }
 
diff --git a/core/fpdfdoc/cpdf_linklist.h b/core/fpdfdoc/cpdf_linklist.h
index 129790f..442f66c 100644
--- a/core/fpdfdoc/cpdf_linklist.h
+++ b/core/fpdfdoc/cpdf_linklist.h
@@ -10,16 +10,17 @@
 #include <map>
 #include <vector>
 
+#include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fpdfdoc/cpdf_link.h"
 #include "core/fxcrt/fx_system.h"
 
 class CPDF_Page;
 class CPDF_Dictionary;
 
-class CPDF_LinkList {
+class CPDF_LinkList : public CPDF_Document::LinkListIface {
  public:
   CPDF_LinkList();
-  ~CPDF_LinkList();
+  ~CPDF_LinkList() override;
 
   CPDF_Link GetLinkAtPoint(CPDF_Page* pPage,
                            const CFX_PointF& point,
diff --git a/fpdfsdk/fpdf_doc.cpp b/fpdfsdk/fpdf_doc.cpp
index e523321..58e2b5d 100644
--- a/fpdfsdk/fpdf_doc.cpp
+++ b/fpdfsdk/fpdf_doc.cpp
@@ -8,6 +8,7 @@
 
 #include <memory>
 #include <set>
+#include <utility>
 
 #include "core/fpdfapi/page/cpdf_page.h"
 #include "core/fpdfapi/parser/cpdf_array.h"
@@ -17,6 +18,7 @@
 #include "core/fpdfdoc/cpdf_bookmark.h"
 #include "core/fpdfdoc/cpdf_bookmarktree.h"
 #include "core/fpdfdoc/cpdf_dest.h"
+#include "core/fpdfdoc/cpdf_linklist.h"
 #include "core/fpdfdoc/cpdf_pagelabel.h"
 #include "fpdfsdk/cpdfsdk_helpers.h"
 #include "third_party/base/ptr_util.h"
@@ -53,10 +55,14 @@
 
 CPDF_LinkList* GetLinkList(CPDF_Page* page) {
   CPDF_Document* pDoc = page->GetDocument();
-  std::unique_ptr<CPDF_LinkList>* pHolder = pDoc->LinksContext();
-  if (!pHolder->get())
-    *pHolder = pdfium::MakeUnique<CPDF_LinkList>();
-  return pHolder->get();
+  auto* pList = static_cast<CPDF_LinkList*>(pDoc->GetLinksContext());
+  if (pList)
+    return pList;
+
+  auto pNewList = pdfium::MakeUnique<CPDF_LinkList>();
+  pList = pNewList.get();
+  pDoc->SetLinksContext(std::move(pNewList));
+  return pList;
 }
 
 }  // namespace