Weakly cache CPDF_IccProfile in CPDF_DocPageData

Change-Id: I591c8a91bcb0d338281d22adbaf0255b7b76a21a
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/58231
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_colorspace.cpp b/core/fpdfapi/page/cpdf_colorspace.cpp
index 40cadc5..1365f8a 100644
--- a/core/fpdfapi/page/cpdf_colorspace.cpp
+++ b/core/fpdfapi/page/cpdf_colorspace.cpp
@@ -902,15 +902,7 @@
 CPDF_ICCBasedCS::CPDF_ICCBasedCS(CPDF_Document* pDoc)
     : CPDF_ColorSpace(pDoc, PDFCS_ICCBASED) {}
 
-CPDF_ICCBasedCS::~CPDF_ICCBasedCS() {
-  if (m_pProfile && m_pDocument) {
-    const CPDF_Stream* pStream = m_pProfile->GetStream();
-    m_pProfile.Reset();  // Give up our reference first.
-    auto* pPageData = CPDF_DocPageData::FromDocument(m_pDocument.Get());
-    if (pPageData)
-      pPageData->MaybePurgeIccProfile(pStream);
-  }
-}
+CPDF_ICCBasedCS::~CPDF_ICCBasedCS() = default;
 
 uint32_t CPDF_ICCBasedCS::v_Load(CPDF_Document* pDoc,
                                  const CPDF_Array* pArray,
diff --git a/core/fpdfapi/page/cpdf_docpagedata.cpp b/core/fpdfapi/page/cpdf_docpagedata.cpp
index 978de5c..08cbd31 100644
--- a/core/fpdfapi/page/cpdf_docpagedata.cpp
+++ b/core/fpdfapi/page/cpdf_docpagedata.cpp
@@ -165,15 +165,16 @@
 CPDF_DocPageData::CPDF_DocPageData() = default;
 
 CPDF_DocPageData::~CPDF_DocPageData() {
+  m_PatternMap.clear();
+
   Clear(false);
   Clear(true);
 
-  m_PatternMap.clear();
-
   for (auto& it : m_FontMap)
     delete it.second;
 
   m_FontMap.clear();
+  m_ImageMap.clear();
 }
 
 void CPDF_DocPageData::ClearStockFont() {
@@ -183,8 +184,6 @@
 void CPDF_DocPageData::Clear(bool bForceRelease) {
   m_bForceClear = bForceRelease;
 
-  m_PatternMap.clear();
-
   for (auto& it : m_FontMap) {
     CPDF_CountedFont* fontData = it.second;
     if (!fontData->get())
@@ -196,27 +195,11 @@
 
   m_ColorSpaceMap.clear();
 
-  for (auto it = m_IccProfileMap.begin(); it != m_IccProfileMap.end();) {
-    auto curr_it = it++;
-    if (bForceRelease || curr_it->second->HasOneRef()) {
-      for (auto hash_it = m_HashProfileMap.begin();
-           hash_it != m_HashProfileMap.end(); ++hash_it) {
-        if (curr_it->first == hash_it->second) {
-          m_HashProfileMap.erase(hash_it);
-          break;
-        }
-      }
-      m_IccProfileMap.erase(curr_it);
-    }
-  }
-
   for (auto it = m_FontFileMap.begin(); it != m_FontFileMap.end();) {
     auto curr_it = it++;
     if (bForceRelease || curr_it->second->HasOneRef())
       m_FontFileMap.erase(curr_it);
   }
-
-  m_ImageMap.clear();
 }
 
 CPDF_Font* CPDF_DocPageData::GetFont(CPDF_Dictionary* pFontDict) {
@@ -458,8 +441,8 @@
     return nullptr;
 
   auto it = m_IccProfileMap.find(pProfileStream);
-  if (it != m_IccProfileMap.end())
-    return it->second;
+  if (it != m_IccProfileMap.end() && it->second)
+    return pdfium::WrapRetain(it->second.Get());
 
   auto pAccessor = pdfium::MakeRetain<CPDF_StreamAcc>(pProfileStream);
   pAccessor->LoadAllDataFiltered();
@@ -470,24 +453,17 @@
   ByteString bsDigest(digest, 20);
   auto hash_it = m_HashProfileMap.find(bsDigest);
   if (hash_it != m_HashProfileMap.end()) {
-    auto it_copied_stream = m_IccProfileMap.find(hash_it->second);
-    if (it_copied_stream != m_IccProfileMap.end())
-      return it_copied_stream->second;
+    auto it_copied_stream = m_IccProfileMap.find(hash_it->second.Get());
+    if (it_copied_stream != m_IccProfileMap.end() && it_copied_stream->second)
+      return pdfium::WrapRetain(it_copied_stream->second.Get());
   }
   auto pProfile =
       pdfium::MakeRetain<CPDF_IccProfile>(pProfileStream, pAccessor->GetSpan());
-  m_IccProfileMap[pProfileStream] = pProfile;
-  m_HashProfileMap[bsDigest] = pProfileStream;
+  m_IccProfileMap[pProfileStream].Reset(pProfile.Get());
+  m_HashProfileMap[bsDigest].Reset(pProfileStream);
   return pProfile;
 }
 
-void CPDF_DocPageData::MaybePurgeIccProfile(const CPDF_Stream* pProfileStream) {
-  ASSERT(pProfileStream);
-  auto it = m_IccProfileMap.find(pProfileStream);
-  if (it != m_IccProfileMap.end() && it->second->HasOneRef())
-    m_IccProfileMap.erase(it);
-}
-
 RetainPtr<CPDF_StreamAcc> CPDF_DocPageData::GetFontFileStreamAcc(
     const CPDF_Stream* pFontStream) {
   ASSERT(pFontStream);
diff --git a/core/fpdfapi/page/cpdf_docpagedata.h b/core/fpdfapi/page/cpdf_docpagedata.h
index 89d8264..9fda806 100644
--- a/core/fpdfapi/page/cpdf_docpagedata.h
+++ b/core/fpdfapi/page/cpdf_docpagedata.h
@@ -84,7 +84,6 @@
   void MaybePurgeImage(uint32_t dwStreamObjNum);
 
   RetainPtr<CPDF_IccProfile> GetIccProfile(const CPDF_Stream* pProfileStream);
-  void MaybePurgeIccProfile(const CPDF_Stream* pProfileStream);
 
  private:
   using CPDF_CountedFont = CPDF_CountedObject<CPDF_Font>;
@@ -109,11 +108,11 @@
   void Clear(bool bForceRelease);
 
   bool m_bForceClear = false;
-  std::map<ByteString, const CPDF_Stream*> m_HashProfileMap;
+  std::map<ByteString, RetainPtr<const CPDF_Stream>> m_HashProfileMap;
   std::map<const CPDF_Object*, ObservedPtr<CPDF_ColorSpace>> m_ColorSpaceMap;
   std::map<const CPDF_Stream*, RetainPtr<CPDF_StreamAcc>> m_FontFileMap;
   std::map<const CPDF_Dictionary*, CPDF_CountedFont*> m_FontMap;
-  std::map<const CPDF_Stream*, RetainPtr<CPDF_IccProfile>> m_IccProfileMap;
+  std::map<const CPDF_Stream*, ObservedPtr<CPDF_IccProfile>> m_IccProfileMap;
   std::map<uint32_t, RetainPtr<CPDF_Image>> m_ImageMap;
   std::map<const CPDF_Object*, ObservedPtr<CPDF_Pattern>> m_PatternMap;
 };
diff --git a/core/fpdfapi/page/cpdf_iccprofile.h b/core/fpdfapi/page/cpdf_iccprofile.h
index 2ee1b07..070f884 100644
--- a/core/fpdfapi/page/cpdf_iccprofile.h
+++ b/core/fpdfapi/page/cpdf_iccprofile.h
@@ -9,6 +9,7 @@
 
 #include <memory>
 
+#include "core/fxcrt/observed_ptr.h"
 #include "core/fxcrt/retain_ptr.h"
 #include "third_party/base/span.h"
 
@@ -18,7 +19,7 @@
 class CLcmsCmm;
 }  // namespace fxcodec
 
-class CPDF_IccProfile final : public Retainable {
+class CPDF_IccProfile final : public Retainable, public Observable {
  public:
   template <typename T, typename... Args>
   friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);