Add CPDF_Dest::Create().

Consolidate nearly identical CPDF_Dest creation code.

Change-Id: I652186bb709cde969a5dfc6f6bd41aa72e091fbc
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/68270
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfdoc/cpdf_action.cpp b/core/fpdfdoc/cpdf_action.cpp
index 5133c1b..0b1b96e 100644
--- a/core/fpdfdoc/cpdf_action.cpp
+++ b/core/fpdfdoc/cpdf_action.cpp
@@ -12,7 +12,6 @@
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fpdfapi/parser/cpdf_name.h"
 #include "core/fpdfdoc/cpdf_filespec.h"
-#include "core/fpdfdoc/cpdf_nametree.h"
 
 namespace {
 
@@ -57,18 +56,7 @@
   ActionType type = GetType();
   if (type != GoTo && type != GoToR)
     return CPDF_Dest();
-
-  const CPDF_Object* pDest = m_pDict->GetDirectObjectFor("D");
-  if (!pDest)
-    return CPDF_Dest();
-  if (pDest->IsString() || pDest->IsName()) {
-    CPDF_NameTree name_tree(pDoc, "Dests");
-    return CPDF_Dest(name_tree.LookupNamedDest(pDoc, pDest->GetUnicodeText()));
-  }
-  if (const CPDF_Array* pArray = pDest->AsArray())
-    return CPDF_Dest(pArray);
-
-  return CPDF_Dest();
+  return CPDF_Dest::Create(pDoc, m_pDict->GetDirectObjectFor("D"));
 }
 
 WideString CPDF_Action::GetFilePath() const {
diff --git a/core/fpdfdoc/cpdf_bookmark.cpp b/core/fpdfdoc/cpdf_bookmark.cpp
index b08fba5..2f8d5c3 100644
--- a/core/fpdfdoc/cpdf_bookmark.cpp
+++ b/core/fpdfdoc/cpdf_bookmark.cpp
@@ -9,10 +9,8 @@
 #include <memory>
 #include <vector>
 
-#include "core/fpdfapi/parser/cpdf_array.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_string.h"
-#include "core/fpdfdoc/cpdf_nametree.h"
 #include "core/fxcrt/fx_memory_wrappers.h"
 #include "core/fxge/fx_dib.h"
 
@@ -48,18 +46,7 @@
 CPDF_Dest CPDF_Bookmark::GetDest(CPDF_Document* pDocument) const {
   if (!m_pDict)
     return CPDF_Dest();
-
-  const CPDF_Object* pDest = m_pDict->GetDirectObjectFor("Dest");
-  if (!pDest)
-    return CPDF_Dest();
-  if (pDest->IsString() || pDest->IsName()) {
-    CPDF_NameTree name_tree(pDocument, "Dests");
-    return CPDF_Dest(
-        name_tree.LookupNamedDest(pDocument, pDest->GetUnicodeText()));
-  }
-  if (const CPDF_Array* pArray = pDest->AsArray())
-    return CPDF_Dest(pArray);
-  return CPDF_Dest();
+  return CPDF_Dest::Create(pDocument, m_pDict->GetDirectObjectFor("Dest"));
 }
 
 CPDF_Action CPDF_Bookmark::GetAction() const {
diff --git a/core/fpdfdoc/cpdf_dest.cpp b/core/fpdfdoc/cpdf_dest.cpp
index 1a07acf..45279e5 100644
--- a/core/fpdfdoc/cpdf_dest.cpp
+++ b/core/fpdfdoc/cpdf_dest.cpp
@@ -12,6 +12,7 @@
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fpdfapi/parser/cpdf_name.h"
 #include "core/fpdfapi/parser/cpdf_number.h"
+#include "core/fpdfdoc/cpdf_nametree.h"
 
 namespace {
 
@@ -36,7 +37,23 @@
 
 CPDF_Dest::CPDF_Dest(const CPDF_Dest& that) = default;
 
-CPDF_Dest::~CPDF_Dest() {}
+CPDF_Dest::~CPDF_Dest() = default;
+
+// static
+CPDF_Dest CPDF_Dest::Create(CPDF_Document* pDoc, const CPDF_Object* pDest) {
+  if (!pDest)
+    return CPDF_Dest();
+
+  if (pDest->IsString() || pDest->IsName()) {
+    CPDF_NameTree name_tree(pDoc, "Dests");
+    return CPDF_Dest(name_tree.LookupNamedDest(pDoc, pDest->GetUnicodeText()));
+  }
+
+  const CPDF_Array* pArray = pDest->AsArray();
+  if (!pArray)
+    return CPDF_Dest();
+  return CPDF_Dest(pArray);
+}
 
 int CPDF_Dest::GetDestPageIndex(CPDF_Document* pDoc) const {
   if (!m_pArray)
diff --git a/core/fpdfdoc/cpdf_dest.h b/core/fpdfdoc/cpdf_dest.h
index c215634..0734182 100644
--- a/core/fpdfdoc/cpdf_dest.h
+++ b/core/fpdfdoc/cpdf_dest.h
@@ -7,12 +7,12 @@
 #ifndef CORE_FPDFDOC_CPDF_DEST_H_
 #define CORE_FPDFDOC_CPDF_DEST_H_
 
-#include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
 #include "core/fxcrt/retain_ptr.h"
 
-class CPDF_Document;
 class CPDF_Array;
+class CPDF_Document;
+class CPDF_Object;
 
 class CPDF_Dest {
  public:
@@ -21,6 +21,9 @@
   CPDF_Dest(const CPDF_Dest& that);
   ~CPDF_Dest();
 
+  // Use when |pDest| is an object of an unknown type. Can pass in nullptr.
+  static CPDF_Dest Create(CPDF_Document* pDoc, const CPDF_Object* pDest);
+
   const CPDF_Array* GetArray() const { return m_pArray.Get(); }
   int GetDestPageIndex(CPDF_Document* pDoc) const;
 
diff --git a/core/fpdfdoc/cpdf_link.cpp b/core/fpdfdoc/cpdf_link.cpp
index d5f24b1..24d1a5d 100644
--- a/core/fpdfdoc/cpdf_link.cpp
+++ b/core/fpdfdoc/cpdf_link.cpp
@@ -6,9 +6,7 @@
 
 #include "core/fpdfdoc/cpdf_link.h"
 
-#include "core/fpdfapi/parser/cpdf_array.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
-#include "core/fpdfdoc/cpdf_nametree.h"
 
 CPDF_Link::CPDF_Link() = default;
 
@@ -23,17 +21,7 @@
 }
 
 CPDF_Dest CPDF_Link::GetDest(CPDF_Document* pDoc) {
-  CPDF_Object* pDest = m_pDict->GetDirectObjectFor("Dest");
-  if (!pDest)
-    return CPDF_Dest();
-
-  if (pDest->IsString() || pDest->IsName()) {
-    CPDF_NameTree name_tree(pDoc, "Dests");
-    return CPDF_Dest(name_tree.LookupNamedDest(pDoc, pDest->GetUnicodeText()));
-  }
-  if (CPDF_Array* pArray = pDest->AsArray())
-    return CPDF_Dest(pArray);
-  return CPDF_Dest();
+  return CPDF_Dest::Create(pDoc, m_pDict->GetDirectObjectFor("Dest"));
 }
 
 CPDF_Action CPDF_Link::GetAction() {