Reduce some ref-churn when using CPDF_References.

Also avoid virtual function call to GetMutableDirect(), which
make sense when the subclass isn't known, but when already
in CPDF_Reference code, just go obtain the referred-to object
from the indirect object holder.

Change-Id: Ieadbf0e03143684c5c8123c98ea920014fd0ef1a
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/97974
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp b/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp
index 539aae5..59d54b9 100644
--- a/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp
+++ b/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp
@@ -16,7 +16,7 @@
 
 namespace {
 
-RetainPtr<CPDF_Object> FilterInvalidObjNum(RetainPtr<CPDF_Object> obj) {
+const CPDF_Object* FilterInvalidObjNum(const CPDF_Object* obj) {
   return obj && obj->GetObjNum() != CPDF_Object::kInvalidObjNum ? obj : nullptr;
 }
 
@@ -31,29 +31,40 @@
 
 RetainPtr<const CPDF_Object> CPDF_IndirectObjectHolder::GetIndirectObject(
     uint32_t objnum) const {
-  return const_cast<CPDF_IndirectObjectHolder*>(this)->GetMutableIndirectObject(
-      objnum);
+  return pdfium::WrapRetain(GetIndirectObjectInternal(objnum));
 }
 
 RetainPtr<CPDF_Object> CPDF_IndirectObjectHolder::GetMutableIndirectObject(
     uint32_t objnum) {
+  return pdfium::WrapRetain(
+      const_cast<CPDF_Object*>(GetIndirectObjectInternal(objnum)));
+}
+
+const CPDF_Object* CPDF_IndirectObjectHolder::GetIndirectObjectInternal(
+    uint32_t objnum) const {
   auto it = m_IndirectObjs.find(objnum);
   if (it == m_IndirectObjs.end())
     return nullptr;
 
-  return FilterInvalidObjNum(it->second);
+  return FilterInvalidObjNum(it->second.Get());
 }
 
 RetainPtr<CPDF_Object> CPDF_IndirectObjectHolder::GetOrParseIndirectObject(
     uint32_t objnum) {
+  return pdfium::WrapRetain(GetOrParseIndirectObjectInternal(objnum));
+}
+
+CPDF_Object* CPDF_IndirectObjectHolder::GetOrParseIndirectObjectInternal(
+    uint32_t objnum) {
   if (objnum == 0 || objnum == CPDF_Object::kInvalidObjNum)
     return nullptr;
 
   // Add item anyway to prevent recursively parsing of same object.
   auto insert_result = m_IndirectObjs.insert(std::make_pair(objnum, nullptr));
-  if (!insert_result.second)
-    return FilterInvalidObjNum(insert_result.first->second);
-
+  if (!insert_result.second) {
+    return const_cast<CPDF_Object*>(
+        FilterInvalidObjNum(insert_result.first->second.Get()));
+  }
   RetainPtr<CPDF_Object> pNewObj = ParseIndirectObject(objnum);
   if (!pNewObj) {
     m_IndirectObjs.erase(insert_result.first);
@@ -62,8 +73,10 @@
 
   pNewObj->SetObjNum(objnum);
   m_LastObjNum = std::max(m_LastObjNum, objnum);
-  insert_result.first->second = pNewObj;
-  return pNewObj;
+
+  CPDF_Object* result = pNewObj.Get();
+  insert_result.first->second = std::move(pNewObj);
+  return result;
 }
 
 RetainPtr<CPDF_Object> CPDF_IndirectObjectHolder::ParseIndirectObject(
@@ -89,7 +102,7 @@
     return false;
 
   auto& obj_holder = m_IndirectObjs[objnum];
-  RetainPtr<const CPDF_Object> old_object = FilterInvalidObjNum(obj_holder);
+  const CPDF_Object* old_object = FilterInvalidObjNum(obj_holder.Get());
   if (old_object && pObj->GetGenNum() <= old_object->GetGenNum())
     return false;
 
@@ -101,7 +114,7 @@
 
 void CPDF_IndirectObjectHolder::DeleteIndirectObject(uint32_t objnum) {
   auto it = m_IndirectObjs.find(objnum);
-  if (it == m_IndirectObjs.end() || !FilterInvalidObjNum(it->second))
+  if (it == m_IndirectObjs.end() || !FilterInvalidObjNum(it->second.Get()))
     return;
 
   m_IndirectObjs.erase(it);
diff --git a/core/fpdfapi/parser/cpdf_indirect_object_holder.h b/core/fpdfapi/parser/cpdf_indirect_object_holder.h
index 3906754..544e012 100644
--- a/core/fpdfapi/parser/cpdf_indirect_object_holder.h
+++ b/core/fpdfapi/parser/cpdf_indirect_object_holder.h
@@ -77,6 +77,11 @@
   virtual RetainPtr<CPDF_Object> ParseIndirectObject(uint32_t objnum);
 
  private:
+  friend class CPDF_Reference;
+
+  const CPDF_Object* GetIndirectObjectInternal(uint32_t objnum) const;
+  CPDF_Object* GetOrParseIndirectObjectInternal(uint32_t objnum);
+
   uint32_t m_LastObjNum = 0;
   std::map<uint32_t, RetainPtr<CPDF_Object>> m_IndirectObjs;
   WeakPtr<ByteStringPool> m_pByteStringPool;
diff --git a/core/fpdfapi/parser/cpdf_reference.cpp b/core/fpdfapi/parser/cpdf_reference.cpp
index e784524..9e22174 100644
--- a/core/fpdfapi/parser/cpdf_reference.cpp
+++ b/core/fpdfapi/parser/cpdf_reference.cpp
@@ -22,22 +22,22 @@
 }
 
 ByteString CPDF_Reference::GetString() const {
-  RetainPtr<const CPDF_Object> obj = SafeGetDirect();
+  const CPDF_Object* obj = FastGetDirect();
   return obj ? obj->GetString() : ByteString();
 }
 
 float CPDF_Reference::GetNumber() const {
-  RetainPtr<const CPDF_Object> obj = SafeGetDirect();
+  const CPDF_Object* obj = FastGetDirect();
   return obj ? obj->GetNumber() : 0;
 }
 
 int CPDF_Reference::GetInteger() const {
-  RetainPtr<const CPDF_Object> obj = SafeGetDirect();
+  const CPDF_Object* obj = FastGetDirect();
   return obj ? obj->GetInteger() : 0;
 }
 
 RetainPtr<const CPDF_Dictionary> CPDF_Reference::GetDict() const {
-  RetainPtr<const CPDF_Object> obj = SafeGetDirect();
+  const CPDF_Object* obj = FastGetDirect();
   return obj ? obj->GetDict() : nullptr;
 }
 
@@ -62,8 +62,11 @@
              : nullptr;
 }
 
-RetainPtr<const CPDF_Object> CPDF_Reference::SafeGetDirect() const {
-  RetainPtr<const CPDF_Object> obj = GetDirect();
+const CPDF_Object* CPDF_Reference::FastGetDirect() const {
+  if (!m_pObjList)
+    return nullptr;
+  const CPDF_Object* obj =
+      m_pObjList->GetOrParseIndirectObjectInternal(m_RefObjNum);
   return (obj && !obj->IsReference()) ? obj : nullptr;
 }
 
diff --git a/core/fpdfapi/parser/cpdf_reference.h b/core/fpdfapi/parser/cpdf_reference.h
index 68eca1d..efa4a72 100644
--- a/core/fpdfapi/parser/cpdf_reference.h
+++ b/core/fpdfapi/parser/cpdf_reference.h
@@ -43,7 +43,8 @@
   RetainPtr<CPDF_Object> CloneNonCyclic(
       bool bDirect,
       std::set<const CPDF_Object*>* pVisited) const override;
-  RetainPtr<const CPDF_Object> SafeGetDirect() const;
+
+  const CPDF_Object* FastGetDirect() const;
 
   UnownedPtr<CPDF_IndirectObjectHolder> m_pObjList;
   uint32_t m_RefObjNum;