Revert "Make CPDF_Color saner."

This reverts commit 73bd37c824051aac631abaf567bab7dcd02093df.

Reason for revert: Made ClusterFuzz unhappy.

Original change's description:
> Make CPDF_Color saner.
> 
> Stop casting a vector of floats to a PatternValue object type. Stop
> performing cleanup for said PatternValue outside of the class itself.
> Use std::vector in place of mallocs.
> 
> In turn, this requires making CPDF_Pattern and its subclasses
> retainable, so that the cleanups happen automatically, which is
> more straightforward than trying to move the old cleanup logic
> into the PatternValue dtor.
> 
> In turn, make the doc page data weakly cache the CPDF_Patterns by
> using the Observable pattern.
> 
> Change-Id: Idd1095cee3bd497392ea1f120bd452f3f34ce104
> Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/56750
> Commit-Queue: Tom Sepez <tsepez@chromium.org>
> Reviewed-by: Lei Zhang <thestig@chromium.org>

TBR=thestig@chromium.org,tsepez@chromium.org

Change-Id: Ia25d36b47dc283469e7756e8573849ec69892189
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: chromium:981256,chromium:981288,chromium:981347,chromium:981412
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/57330
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_color.cpp b/core/fpdfapi/page/cpdf_color.cpp
index cfa6422..96804dc 100644
--- a/core/fpdfapi/page/cpdf_color.cpp
+++ b/core/fpdfapi/page/cpdf_color.cpp
@@ -18,53 +18,122 @@
   *this = that;
 }
 
-CPDF_Color::~CPDF_Color() = default;
+CPDF_Color::~CPDF_Color() {
+  ReleaseBuffer();
+}
 
 bool CPDF_Color::IsPattern() const {
   return m_pCS && IsPatternInternal();
 }
 
+void CPDF_Color::ReleaseBuffer() {
+  if (!m_pBuffer)
+    return;
+
+  if (IsPatternInternal()) {
+    PatternValue* pvalue = reinterpret_cast<PatternValue*>(m_pBuffer);
+    CPDF_Pattern* pPattern =
+        pvalue->m_pCountedPattern ? pvalue->m_pCountedPattern->get() : nullptr;
+    if (pPattern) {
+      auto* pPageData = CPDF_DocPageData::FromDocument(pPattern->document());
+      if (pPageData)
+        pPageData->ReleasePattern(pPattern->pattern_obj());
+    }
+  }
+  FX_Free(m_pBuffer);
+  m_pBuffer = nullptr;
+}
+
 bool CPDF_Color::IsPatternInternal() const {
   return m_pCS->GetFamily() == PDFCS_PATTERN;
 }
 
 void CPDF_Color::SetColorSpace(const RetainPtr<CPDF_ColorSpace>& pCS) {
-  m_pCS = pCS;
-  if (IsPatternInternal()) {
-    m_Buffer.clear();
-    m_pValue = pdfium::MakeUnique<PatternValue>();
-  } else {
-    m_Buffer = pCS->CreateBufAndSetDefaultColor();
-    m_pValue.reset();
+  ASSERT(pCS);
+  if (m_pCS == pCS) {
+    if (!m_pBuffer)
+      m_pBuffer = pCS->CreateBuf();
+    m_pCS = pCS;
+    return;
   }
+  ReleaseBuffer();
+  m_pCS = pCS;
+  if (IsPatternInternal())
+    m_pBuffer = pCS->CreateBuf();
+  else
+    m_pBuffer = pCS->CreateBufAndSetDefaultColor();
 }
 
 void CPDF_Color::SetValueForNonPattern(const std::vector<float>& values) {
+  ASSERT(m_pBuffer);
   ASSERT(!IsPatternInternal());
   ASSERT(m_pCS->CountComponents() <= values.size());
-  m_Buffer = values;
+  memcpy(m_pBuffer, values.data(), m_pCS->CountComponents() * sizeof(float));
 }
 
-void CPDF_Color::SetValueForPattern(const RetainPtr<CPDF_Pattern>& pPattern,
+void CPDF_Color::SetValueForPattern(CPDF_Pattern* pPattern,
                                     const std::vector<float>& values) {
   if (values.size() > kMaxPatternColorComps)
     return;
 
-  if (!IsPattern())
-    SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN));
+  if (!IsPattern()) {
+    FX_Free(m_pBuffer);
+    m_pCS = CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
+    m_pBuffer = m_pCS->CreateBuf();
+  }
 
-  m_pValue->SetPattern(pPattern);
-  m_pValue->SetComps(values);
+  CPDF_DocPageData* pDocPageData = nullptr;
+  PatternValue* pvalue = reinterpret_cast<PatternValue*>(m_pBuffer);
+  if (pvalue->m_pPattern) {
+    pDocPageData =
+        CPDF_DocPageData::FromDocument(pvalue->m_pPattern->document());
+    pDocPageData->ReleasePattern(pvalue->m_pPattern->pattern_obj());
+  }
+  pvalue->m_nComps = values.size();
+  pvalue->m_pPattern = pPattern;
+  if (!values.empty())
+    memcpy(pvalue->m_Comps, values.data(), values.size() * sizeof(float));
+
+  pvalue->m_pCountedPattern = nullptr;
+  if (pPattern) {
+    if (!pDocPageData)
+      pDocPageData = CPDF_DocPageData::FromDocument(pPattern->document());
+
+    pvalue->m_pCountedPattern =
+        pDocPageData->FindPatternPtr(pPattern->pattern_obj());
+  }
 }
 
 CPDF_Color& CPDF_Color::operator=(const CPDF_Color& that) {
   if (this == &that)
     return *this;
 
-  m_Buffer = that.m_Buffer;
-  m_pValue = that.m_pValue ? pdfium::MakeUnique<PatternValue>(*that.m_pValue)
-                           : nullptr;
+  ReleaseBuffer();
   m_pCS = that.m_pCS;
+  if (!m_pCS)
+    return *this;
+
+  CPDF_Document* pDoc = m_pCS->GetDocument();
+  const CPDF_Array* pArray = m_pCS->GetArray();
+  if (pDoc && pArray) {
+    m_pCS = CPDF_DocPageData::FromDocument(pDoc)->GetCopiedColorSpace(pArray);
+    if (!m_pCS)
+      return *this;
+  }
+  m_pBuffer = m_pCS->CreateBuf();
+  memcpy(m_pBuffer, that.m_pBuffer, m_pCS->GetBufSize());
+  if (!IsPatternInternal())
+    return *this;
+
+  PatternValue* pValue = reinterpret_cast<PatternValue*>(m_pBuffer);
+  CPDF_Pattern* pPattern = pValue->m_pPattern;
+  if (!pPattern)
+    return *this;
+
+  pValue->m_pPattern = CPDF_DocPageData::FromDocument(pPattern->document())
+                           ->GetPattern(pPattern->pattern_obj(), false,
+                                        pPattern->parent_matrix());
+
   return *this;
 }
 
@@ -77,18 +146,19 @@
 }
 
 bool CPDF_Color::GetRGB(int* R, int* G, int* B) const {
+  if (!m_pBuffer)
+    return false;
+
   float r = 0.0f;
   float g = 0.0f;
   float b = 0.0f;
-  bool result = false;
+  bool result;
   if (IsPatternInternal()) {
-    if (m_pValue) {
-      const CPDF_PatternCS* pPatternCS = m_pCS->AsPatternCS();
-      result = pPatternCS->GetPatternRGB(*m_pValue, &r, &g, &b);
-    }
+    const CPDF_PatternCS* pPatternCS = m_pCS->AsPatternCS();
+    const auto* pValue = reinterpret_cast<const PatternValue*>(m_pBuffer);
+    result = pPatternCS->GetPatternRGB(*pValue, &r, &g, &b);
   } else {
-    if (!m_Buffer.empty())
-      result = m_pCS->GetRGB(m_Buffer.data(), &r, &g, &b);
+    result = m_pCS->GetRGB(m_pBuffer, &r, &g, &b);
   }
   if (!result)
     return false;
@@ -101,5 +171,10 @@
 
 CPDF_Pattern* CPDF_Color::GetPattern() const {
   ASSERT(IsPattern());
-  return m_pValue ? m_pValue->GetPattern() : nullptr;
+
+  if (!m_pBuffer)
+    return nullptr;
+
+  PatternValue* pvalue = reinterpret_cast<PatternValue*>(m_pBuffer);
+  return pvalue->m_pPattern;
 }
diff --git a/core/fpdfapi/page/cpdf_color.h b/core/fpdfapi/page/cpdf_color.h
index b533d08..d3cfc94 100644
--- a/core/fpdfapi/page/cpdf_color.h
+++ b/core/fpdfapi/page/cpdf_color.h
@@ -7,7 +7,6 @@
 #ifndef CORE_FPDFAPI_PAGE_CPDF_COLOR_H_
 #define CORE_FPDFAPI_PAGE_CPDF_COLOR_H_
 
-#include <memory>
 #include <vector>
 
 #include "core/fxcrt/fx_system.h"
@@ -15,7 +14,6 @@
 
 class CPDF_ColorSpace;
 class CPDF_Pattern;
-class PatternValue;
 
 class CPDF_Color {
  public:
@@ -26,11 +24,11 @@
 
   CPDF_Color& operator=(const CPDF_Color& that);
 
-  bool IsNull() const { return m_Buffer.empty() && !m_pValue; }
+  bool IsNull() const { return !m_pBuffer; }
   bool IsPattern() const;
   void SetColorSpace(const RetainPtr<CPDF_ColorSpace>& pCS);
   void SetValueForNonPattern(const std::vector<float>& values);
-  void SetValueForPattern(const RetainPtr<CPDF_Pattern>& pPattern,
+  void SetValueForPattern(CPDF_Pattern* pPattern,
                           const std::vector<float>& values);
   uint32_t CountComponents() const;
   bool IsColorSpaceRGB() const;
@@ -40,10 +38,13 @@
   CPDF_Pattern* GetPattern() const;
 
  protected:
+  void ReleaseBuffer();
   bool IsPatternInternal() const;
 
-  std::vector<float> m_Buffer;             // Used for non-pattern colorspaces.
-  std::unique_ptr<PatternValue> m_pValue;  // Used for pattern colorspaces.
+  // TODO(thestig): Convert this to a smart pointer or vector.
+  // |m_pBuffer| is created by |m_pCS|, so if it is non-null, then so is
+  // |m_pCS|, since SetColorSpace() prohibits setting to null.
+  float* m_pBuffer = nullptr;
   RetainPtr<CPDF_ColorSpace> m_pCS;
 };
 
diff --git a/core/fpdfapi/page/cpdf_colorspace.cpp b/core/fpdfapi/page/cpdf_colorspace.cpp
index 95af192..338025f 100644
--- a/core/fpdfapi/page/cpdf_colorspace.cpp
+++ b/core/fpdfapi/page/cpdf_colorspace.cpp
@@ -442,12 +442,6 @@
 
 }  // namespace
 
-PatternValue::PatternValue() = default;
-
-PatternValue::PatternValue(const PatternValue& that) = default;
-
-PatternValue::~PatternValue() = default;
-
 // static
 RetainPtr<CPDF_ColorSpace> CPDF_ColorSpace::ColorspaceFromName(
     const ByteString& name) {
@@ -573,15 +567,24 @@
   }
 }
 
-std::vector<float> CPDF_ColorSpace::CreateBufAndSetDefaultColor() const {
+size_t CPDF_ColorSpace::GetBufSize() const {
+  if (m_Family == PDFCS_PATTERN)
+    return sizeof(PatternValue);
+  return m_nComponents * sizeof(float);
+}
+
+float* CPDF_ColorSpace::CreateBuf() const {
+  return reinterpret_cast<float*>(FX_Alloc(uint8_t, GetBufSize()));
+}
+
+float* CPDF_ColorSpace::CreateBufAndSetDefaultColor() const {
   ASSERT(m_Family != PDFCS_PATTERN);
 
+  float* buf = CreateBuf();
   float min;
   float max;
-  std::vector<float> buf(m_nComponents);
   for (uint32_t i = 0; i < m_nComponents; i++)
     GetDefaultValue(i, &buf[i], &min, &max);
-
   return buf;
 }
 
diff --git a/core/fpdfapi/page/cpdf_colorspace.h b/core/fpdfapi/page/cpdf_colorspace.h
index d86747b..d3057fc 100644
--- a/core/fpdfapi/page/cpdf_colorspace.h
+++ b/core/fpdfapi/page/cpdf_colorspace.h
@@ -9,7 +9,6 @@
 
 #include <memory>
 #include <set>
-#include <vector>
 
 #include "core/fpdfapi/page/cpdf_pattern.h"
 #include "core/fxcrt/fx_string.h"
@@ -17,7 +16,6 @@
 #include "core/fxcrt/observed_ptr.h"
 #include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/unowned_ptr.h"
-#include "third_party/base/span.h"
 
 #define PDFCS_DEVICEGRAY 1
 #define PDFCS_DEVICERGB 2
@@ -38,23 +36,11 @@
 
 constexpr size_t kMaxPatternColorComps = 16;
 
-class PatternValue {
- public:
-  PatternValue();
-  PatternValue(const PatternValue& that);
-  ~PatternValue();
-
-  pdfium::span<const float> GetComps() const { return m_Comps; }
-  void SetComps(const std::vector<float>& comps) { m_Comps = comps; }
-
-  CPDF_Pattern* GetPattern() const { return m_pRetainedPattern.Get(); }
-  void SetPattern(const RetainPtr<CPDF_Pattern>& pPattern) {
-    m_pRetainedPattern = pPattern;
-  }
-
- private:
-  std::vector<float> m_Comps;
-  RetainPtr<CPDF_Pattern> m_pRetainedPattern;
+struct PatternValue {
+  CPDF_Pattern* m_pPattern;
+  CPDF_CountedPattern* m_pCountedPattern;
+  int m_nComps;
+  float m_Comps[kMaxPatternColorComps];
 };
 
 class CPDF_ColorSpace : public Retainable, public Observable {
@@ -71,9 +57,11 @@
 
   const CPDF_Array* GetArray() const { return m_pArray.Get(); }
   CPDF_Document* GetDocument() const { return m_pDocument.Get(); }
+  size_t GetBufSize() const;
+  float* CreateBuf() const;
 
   // Should only be called if this colorspace is not a pattern.
-  std::vector<float> CreateBufAndSetDefaultColor() const;
+  float* CreateBufAndSetDefaultColor() const;
 
   uint32_t CountComponents() const;
   int GetFamily() const { return m_Family; }
diff --git a/core/fpdfapi/page/cpdf_colorstate.cpp b/core/fpdfapi/page/cpdf_colorstate.cpp
index 50dbb71..706e5c9 100644
--- a/core/fpdfapi/page/cpdf_colorstate.cpp
+++ b/core/fpdfapi/page/cpdf_colorstate.cpp
@@ -82,13 +82,13 @@
   SetColor(pCS, values, &pData->m_StrokeColor, &pData->m_StrokeColorRef);
 }
 
-void CPDF_ColorState::SetFillPattern(const RetainPtr<CPDF_Pattern>& pPattern,
+void CPDF_ColorState::SetFillPattern(CPDF_Pattern* pPattern,
                                      const std::vector<float>& values) {
   ColorData* pData = m_Ref.GetPrivateCopy();
   SetPattern(pPattern, values, &pData->m_FillColor, &pData->m_FillColorRef);
 }
 
-void CPDF_ColorState::SetStrokePattern(const RetainPtr<CPDF_Pattern>& pPattern,
+void CPDF_ColorState::SetStrokePattern(CPDF_Pattern* pPattern,
                                        const std::vector<float>& values) {
   ColorData* pData = m_Ref.GetPrivateCopy();
   SetPattern(pPattern, values, &pData->m_StrokeColor, &pData->m_StrokeColorRef);
@@ -117,7 +117,7 @@
   *colorref = color->GetRGB(&R, &G, &B) ? FXSYS_BGR(B, G, R) : 0xFFFFFFFF;
 }
 
-void CPDF_ColorState::SetPattern(const RetainPtr<CPDF_Pattern>& pPattern,
+void CPDF_ColorState::SetPattern(CPDF_Pattern* pPattern,
                                  const std::vector<float>& values,
                                  CPDF_Color* color,
                                  FX_COLORREF* colorref) {
diff --git a/core/fpdfapi/page/cpdf_colorstate.h b/core/fpdfapi/page/cpdf_colorstate.h
index f0f6ebd..43244cc 100644
--- a/core/fpdfapi/page/cpdf_colorstate.h
+++ b/core/fpdfapi/page/cpdf_colorstate.h
@@ -46,9 +46,8 @@
                     const std::vector<float>& values);
   void SetStrokeColor(const RetainPtr<CPDF_ColorSpace>& pCS,
                       const std::vector<float>& values);
-  void SetFillPattern(const RetainPtr<CPDF_Pattern>& pattern,
-                      const std::vector<float>& values);
-  void SetStrokePattern(const RetainPtr<CPDF_Pattern>& pattern,
+  void SetFillPattern(CPDF_Pattern* pattern, const std::vector<float>& values);
+  void SetStrokePattern(CPDF_Pattern* pattern,
                         const std::vector<float>& values);
 
   bool HasRef() const { return !!m_Ref; }
@@ -78,7 +77,7 @@
                 const std::vector<float>& values,
                 CPDF_Color* color,
                 FX_COLORREF* colorref);
-  void SetPattern(const RetainPtr<CPDF_Pattern>& pPattern,
+  void SetPattern(CPDF_Pattern* pPattern,
                   const std::vector<float>& values,
                   CPDF_Color* color,
                   FX_COLORREF* colorref);
diff --git a/core/fpdfapi/page/cpdf_docpagedata.cpp b/core/fpdfapi/page/cpdf_docpagedata.cpp
index bbd9ab3..a2ed1b9 100644
--- a/core/fpdfapi/page/cpdf_docpagedata.cpp
+++ b/core/fpdfapi/page/cpdf_docpagedata.cpp
@@ -167,11 +167,12 @@
   Clear(false);
   Clear(true);
 
+  for (auto& it : m_PatternMap)
+    delete it.second;
   m_PatternMap.clear();
 
   for (auto& it : m_FontMap)
     delete it.second;
-
   m_FontMap.clear();
 }
 
@@ -182,7 +183,29 @@
 void CPDF_DocPageData::Clear(bool bForceRelease) {
   m_bForceClear = bForceRelease;
 
-  m_PatternMap.clear();
+  // This is needed because if |bForceRelease| is true we will destroy any
+  // pattern we see regardless of the ref-count. The tiling pattern owns a
+  // Form object which owns a ShadingObject. The ShadingObject has an unowned
+  // pointer to a ShadingPattern. The ShadingPattern is owned by the
+  // DocPageData. So, we loop through and clear any tiling patterns before we
+  // do the same for any shading patterns, otherwise we may free the
+  // ShadingPattern before the ShadingObject and trigger an unowned pointer
+  // probe warning.
+  for (auto& it : m_PatternMap) {
+    CPDF_CountedPattern* ptData = it.second;
+    if (!ptData->get() || !ptData->get()->AsTilingPattern())
+      continue;
+    if (bForceRelease || ptData->use_count() < 2)
+      ptData->clear();
+  }
+
+  for (auto& it : m_PatternMap) {
+    CPDF_CountedPattern* ptData = it.second;
+    if (!ptData->get())
+      continue;
+    if (bForceRelease || ptData->use_count() < 2)
+      ptData->clear();
+  }
 
   for (auto& it : m_FontMap) {
     CPDF_CountedFont* fontData = it.second;
@@ -408,19 +431,23 @@
   return pdfium::WrapRetain(it->second.Get());
 }
 
-RetainPtr<CPDF_Pattern> CPDF_DocPageData::GetPattern(CPDF_Object* pPatternObj,
-                                                     bool bShading,
-                                                     const CFX_Matrix& matrix) {
+CPDF_Pattern* CPDF_DocPageData::GetPattern(CPDF_Object* pPatternObj,
+                                           bool bShading,
+                                           const CFX_Matrix& matrix) {
   if (!pPatternObj)
     return nullptr;
 
+  CPDF_CountedPattern* ptData = nullptr;
   auto it = m_PatternMap.find(pPatternObj);
-  if (it != m_PatternMap.end() && it->second)
-    return pdfium::WrapRetain(it->second.Get());
-
-  RetainPtr<CPDF_Pattern> pPattern;
+  if (it != m_PatternMap.end()) {
+    ptData = it->second;
+    if (ptData->get()) {
+      return ptData->AddRef();
+    }
+  }
+  std::unique_ptr<CPDF_Pattern> pPattern;
   if (bShading) {
-    pPattern = pdfium::MakeRetain<CPDF_ShadingPattern>(
+    pPattern = pdfium::MakeUnique<CPDF_ShadingPattern>(
         GetDocument(), pPatternObj, true, matrix);
   } else {
     CPDF_Dictionary* pDict = pPatternObj->GetDict();
@@ -429,18 +456,43 @@
 
     int type = pDict->GetIntegerFor("PatternType");
     if (type == CPDF_Pattern::kTiling) {
-      pPattern = pdfium::MakeRetain<CPDF_TilingPattern>(GetDocument(),
+      pPattern = pdfium::MakeUnique<CPDF_TilingPattern>(GetDocument(),
                                                         pPatternObj, matrix);
     } else if (type == CPDF_Pattern::kShading) {
-      pPattern = pdfium::MakeRetain<CPDF_ShadingPattern>(
+      pPattern = pdfium::MakeUnique<CPDF_ShadingPattern>(
           GetDocument(), pPatternObj, false, matrix);
     } else {
       return nullptr;
     }
   }
 
-  m_PatternMap[pPatternObj].Reset(pPattern.Get());
-  return pPattern;
+  if (ptData) {
+    ptData->reset(std::move(pPattern));
+  } else {
+    ptData = new CPDF_CountedPattern(std::move(pPattern));
+    m_PatternMap[pPatternObj] = ptData;
+  }
+  return ptData->AddRef();
+}
+
+void CPDF_DocPageData::ReleasePattern(const CPDF_Object* pPatternObj) {
+  if (!pPatternObj)
+    return;
+
+  auto it = m_PatternMap.find(pPatternObj);
+  if (it == m_PatternMap.end())
+    return;
+
+  CPDF_CountedPattern* pPattern = it->second;
+  if (!pPattern->get())
+    return;
+
+  pPattern->RemoveRef();
+  if (pPattern->use_count() > 1)
+    return;
+
+  // We have item only in m_PatternMap cache. Clean it.
+  pPattern->clear();
 }
 
 RetainPtr<CPDF_Image> CPDF_DocPageData::GetImage(uint32_t dwStreamObjNum) {
@@ -544,6 +596,15 @@
   return pdfium::WrapRetain(it->second.Get());
 }
 
+CPDF_CountedPattern* CPDF_DocPageData::FindPatternPtr(
+    const CPDF_Object* pPatternObj) const {
+  if (!pPatternObj)
+    return nullptr;
+
+  auto it = m_PatternMap.find(pPatternObj);
+  return it != m_PatternMap.end() ? it->second : nullptr;
+}
+
 CPDF_Font* CPDF_DocPageData::AddStandardFont(
     const char* font,
     const CPDF_FontEncoding* pEncoding) {
diff --git a/core/fpdfapi/page/cpdf_docpagedata.h b/core/fpdfapi/page/cpdf_docpagedata.h
index d25fcdc..9140372 100644
--- a/core/fpdfapi/page/cpdf_docpagedata.h
+++ b/core/fpdfapi/page/cpdf_docpagedata.h
@@ -11,7 +11,6 @@
 #include <set>
 
 #include "core/fpdfapi/page/cpdf_colorspace.h"
-#include "core/fpdfapi/page/cpdf_countedobject.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_string.h"
@@ -71,9 +70,10 @@
 
   RetainPtr<CPDF_ColorSpace> GetCopiedColorSpace(const CPDF_Object* pCSObj);
 
-  RetainPtr<CPDF_Pattern> GetPattern(CPDF_Object* pPatternObj,
-                                     bool bShading,
-                                     const CFX_Matrix& matrix);
+  CPDF_Pattern* GetPattern(CPDF_Object* pPatternObj,
+                           bool bShading,
+                           const CFX_Matrix& matrix);
+  void ReleasePattern(const CPDF_Object* pPatternObj);
 
   RetainPtr<CPDF_Image> GetImage(uint32_t dwStreamObjNum);
   void MaybePurgeImage(uint32_t dwStreamObjNum);
@@ -82,6 +82,7 @@
   void MaybePurgeIccProfile(const CPDF_Stream* pProfileStream);
 
   RetainPtr<CPDF_ColorSpace> FindColorSpacePtr(const CPDF_Object* pCSObj) const;
+  CPDF_CountedPattern* FindPatternPtr(const CPDF_Object* pPatternObj) const;
 
  private:
   using CPDF_CountedFont = CPDF_CountedObject<CPDF_Font>;
@@ -111,7 +112,7 @@
   std::map<const CPDF_Dictionary*, CPDF_CountedFont*> m_FontMap;
   std::map<const CPDF_Stream*, RetainPtr<CPDF_IccProfile>> m_IccProfileMap;
   std::map<uint32_t, RetainPtr<CPDF_Image>> m_ImageMap;
-  std::map<const CPDF_Object*, ObservedPtr<CPDF_Pattern>> m_PatternMap;
+  std::map<const CPDF_Object*, CPDF_CountedPattern*> m_PatternMap;
 };
 
 #endif  // CORE_FPDFAPI_PAGE_CPDF_DOCPAGEDATA_H_
diff --git a/core/fpdfapi/page/cpdf_pattern.cpp b/core/fpdfapi/page/cpdf_pattern.cpp
index 36ecc98..84e641a 100644
--- a/core/fpdfapi/page/cpdf_pattern.cpp
+++ b/core/fpdfapi/page/cpdf_pattern.cpp
@@ -18,14 +18,6 @@
 
 CPDF_Pattern::~CPDF_Pattern() = default;
 
-CPDF_TilingPattern* CPDF_Pattern::AsTilingPattern() {
-  return nullptr;
-}
-
-CPDF_ShadingPattern* CPDF_Pattern::AsShadingPattern() {
-  return nullptr;
-}
-
 void CPDF_Pattern::SetPatternToFormMatrix() {
   const CPDF_Dictionary* pDict = pattern_obj()->GetDict();
   m_Pattern2Form = pDict->GetMatrixFor("Matrix") * m_ParentMatrix;
diff --git a/core/fpdfapi/page/cpdf_pattern.h b/core/fpdfapi/page/cpdf_pattern.h
index 7e3eb7b..3882b81 100644
--- a/core/fpdfapi/page/cpdf_pattern.h
+++ b/core/fpdfapi/page/cpdf_pattern.h
@@ -7,9 +7,9 @@
 #ifndef CORE_FPDFAPI_PAGE_CPDF_PATTERN_H_
 #define CORE_FPDFAPI_PAGE_CPDF_PATTERN_H_
 
+#include "core/fpdfapi/page/cpdf_countedobject.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_system.h"
-#include "core/fxcrt/observed_ptr.h"
 #include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/unowned_ptr.h"
 
@@ -18,15 +18,15 @@
 class CPDF_ShadingPattern;
 class CPDF_TilingPattern;
 
-class CPDF_Pattern : public Retainable, public Observable {
+class CPDF_Pattern {
  public:
   // Values used in PDFs. Do not change.
   enum PatternType { kTiling = 1, kShading = 2 };
 
-  ~CPDF_Pattern() override;
+  virtual ~CPDF_Pattern();
 
-  virtual CPDF_TilingPattern* AsTilingPattern();
-  virtual CPDF_ShadingPattern* AsShadingPattern();
+  virtual CPDF_TilingPattern* AsTilingPattern() = 0;
+  virtual CPDF_ShadingPattern* AsShadingPattern() = 0;
 
   // All the getters that return pointers return non-NULL pointers.
   CPDF_Document* document() const { return m_pDocument.Get(); }
@@ -47,5 +47,6 @@
   CFX_Matrix m_Pattern2Form;
   const CFX_Matrix m_ParentMatrix;
 };
+using CPDF_CountedPattern = CPDF_CountedObject<CPDF_Pattern>;
 
 #endif  // CORE_FPDFAPI_PAGE_CPDF_PATTERN_H_
diff --git a/core/fpdfapi/page/cpdf_patterncs.cpp b/core/fpdfapi/page/cpdf_patterncs.cpp
index 1c5dc6c..cd8a921 100644
--- a/core/fpdfapi/page/cpdf_patterncs.cpp
+++ b/core/fpdfapi/page/cpdf_patterncs.cpp
@@ -60,7 +60,7 @@
                                    float* R,
                                    float* G,
                                    float* B) const {
-  if (m_pBaseCS && m_pBaseCS->GetRGB(value.GetComps().data(), R, G, B))
+  if (m_pBaseCS && m_pBaseCS->GetRGB(value.m_Comps, R, G, B))
     return true;
 
   *R = 0.75f;
diff --git a/core/fpdfapi/page/cpdf_shadingobject.h b/core/fpdfapi/page/cpdf_shadingobject.h
index 072a025..c246870 100644
--- a/core/fpdfapi/page/cpdf_shadingobject.h
+++ b/core/fpdfapi/page/cpdf_shadingobject.h
@@ -9,7 +9,7 @@
 
 #include "core/fpdfapi/page/cpdf_pageobject.h"
 #include "core/fxcrt/fx_coordinates.h"
-#include "core/fxcrt/retain_ptr.h"
+#include "core/fxcrt/unowned_ptr.h"
 
 class CPDF_ShadingPattern;
 
@@ -33,7 +33,7 @@
   const CFX_Matrix& matrix() const { return m_Matrix; }
 
  private:
-  RetainPtr<CPDF_ShadingPattern> m_pShading;
+  UnownedPtr<const CPDF_ShadingPattern> m_pShading;
   CFX_Matrix m_Matrix;
 };
 
diff --git a/core/fpdfapi/page/cpdf_shadingpattern.cpp b/core/fpdfapi/page/cpdf_shadingpattern.cpp
index 86f5106..f3da1ac 100644
--- a/core/fpdfapi/page/cpdf_shadingpattern.cpp
+++ b/core/fpdfapi/page/cpdf_shadingpattern.cpp
@@ -38,6 +38,10 @@
 
 CPDF_ShadingPattern::~CPDF_ShadingPattern() = default;
 
+CPDF_TilingPattern* CPDF_ShadingPattern::AsTilingPattern() {
+  return nullptr;
+}
+
 CPDF_ShadingPattern* CPDF_ShadingPattern::AsShadingPattern() {
   return this;
 }
diff --git a/core/fpdfapi/page/cpdf_shadingpattern.h b/core/fpdfapi/page/cpdf_shadingpattern.h
index 392aa27..2d8fc8e 100644
--- a/core/fpdfapi/page/cpdf_shadingpattern.h
+++ b/core/fpdfapi/page/cpdf_shadingpattern.h
@@ -38,12 +38,13 @@
 
 class CPDF_ShadingPattern final : public CPDF_Pattern {
  public:
-  template <typename T, typename... Args>
-  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
-
+  CPDF_ShadingPattern(CPDF_Document* pDoc,
+                      CPDF_Object* pPatternObj,
+                      bool bShading,
+                      const CFX_Matrix& parentMatrix);
   ~CPDF_ShadingPattern() override;
 
-  // CPDF_Pattern:
+  CPDF_TilingPattern* AsTilingPattern() override;
   CPDF_ShadingPattern* AsShadingPattern() override;
 
   bool IsMeshShading() const {
@@ -63,13 +64,6 @@
   }
 
  private:
-  CPDF_ShadingPattern(CPDF_Document* pDoc,
-                      CPDF_Object* pPatternObj,
-                      bool bShading,
-                      const CFX_Matrix& parentMatrix);
-  CPDF_ShadingPattern(const CPDF_ShadingPattern&) = delete;
-  CPDF_ShadingPattern& operator=(const CPDF_ShadingPattern&) = delete;
-
   // Constraints in PDF 1.7 spec, 4.6.3 Shading Patterns, pages 308-331.
   bool Validate() const;
   bool ValidateFunctions(uint32_t nExpectedNumFunctions,
diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.cpp b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
index 6eba6dd..b72b2bc 100644
--- a/core/fpdfapi/page/cpdf_streamcontentparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
@@ -1063,7 +1063,7 @@
 
   // A valid |pLastParam| implies |m_ParamCount| > 0, so GetNamedColors() call
   // below is safe.
-  RetainPtr<CPDF_Pattern> pPattern = FindPattern(GetString(0), false);
+  CPDF_Pattern* pPattern = FindPattern(GetString(0), false);
   if (pPattern)
     m_pCurStates->m_ColorState.SetFillPattern(pPattern, GetNamedColors());
 }
@@ -1080,13 +1080,13 @@
 
   // A valid |pLastParam| implies |m_ParamCount| > 0, so GetNamedColors() call
   // below is safe.
-  RetainPtr<CPDF_Pattern> pPattern = FindPattern(GetString(0), false);
+  CPDF_Pattern* pPattern = FindPattern(GetString(0), false);
   if (pPattern)
     m_pCurStates->m_ColorState.SetStrokePattern(pPattern, GetNamedColors());
 }
 
 void CPDF_StreamContentParser::Handle_ShadeFill() {
-  RetainPtr<CPDF_Pattern> pPattern = FindPattern(GetString(0), true);
+  CPDF_Pattern* pPattern = FindPattern(GetString(0), true);
   if (!pPattern)
     return;
 
@@ -1202,9 +1202,8 @@
       ->GetColorSpace(pCSObj, nullptr);
 }
 
-RetainPtr<CPDF_Pattern> CPDF_StreamContentParser::FindPattern(
-    const ByteString& name,
-    bool bShading) {
+CPDF_Pattern* CPDF_StreamContentParser::FindPattern(const ByteString& name,
+                                                    bool bShading) {
   CPDF_Object* pPattern =
       FindResourceObj(bShading ? "Shading" : "Pattern", name);
   if (!pPattern || (!pPattern->IsDictionary() && !pPattern->IsStream())) {
diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.h b/core/fpdfapi/page/cpdf_streamcontentparser.h
index 6e4b46f..45cf0ba 100644
--- a/core/fpdfapi/page/cpdf_streamcontentparser.h
+++ b/core/fpdfapi/page/cpdf_streamcontentparser.h
@@ -118,7 +118,7 @@
                         bool bText,
                         bool bGraph);
   RetainPtr<CPDF_ColorSpace> FindColorSpace(const ByteString& name);
-  RetainPtr<CPDF_Pattern> FindPattern(const ByteString& name, bool bShading);
+  CPDF_Pattern* FindPattern(const ByteString& name, bool bShading);
   CPDF_Dictionary* FindResourceHolder(const ByteString& type);
   CPDF_Object* FindResourceObj(const ByteString& type, const ByteString& name);
 
diff --git a/core/fpdfapi/page/cpdf_tilingpattern.cpp b/core/fpdfapi/page/cpdf_tilingpattern.cpp
index eca6478d..9bf9a86 100644
--- a/core/fpdfapi/page/cpdf_tilingpattern.cpp
+++ b/core/fpdfapi/page/cpdf_tilingpattern.cpp
@@ -29,6 +29,10 @@
   return this;
 }
 
+CPDF_ShadingPattern* CPDF_TilingPattern::AsShadingPattern() {
+  return nullptr;
+}
+
 std::unique_ptr<CPDF_Form> CPDF_TilingPattern::Load(CPDF_PageObject* pPageObj) {
   const CPDF_Dictionary* pDict = pattern_obj()->GetDict();
   m_bColored = pDict->GetIntegerFor("PaintType") == 1;
diff --git a/core/fpdfapi/page/cpdf_tilingpattern.h b/core/fpdfapi/page/cpdf_tilingpattern.h
index 134da8e..35dd9e0 100644
--- a/core/fpdfapi/page/cpdf_tilingpattern.h
+++ b/core/fpdfapi/page/cpdf_tilingpattern.h
@@ -20,13 +20,13 @@
 
 class CPDF_TilingPattern final : public CPDF_Pattern {
  public:
-  template <typename T, typename... Args>
-  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
-
+  CPDF_TilingPattern(CPDF_Document* pDoc,
+                     CPDF_Object* pPatternObj,
+                     const CFX_Matrix& parentMatrix);
   ~CPDF_TilingPattern() override;
 
-  // CPDF_Pattern:
   CPDF_TilingPattern* AsTilingPattern() override;
+  CPDF_ShadingPattern* AsShadingPattern() override;
 
   std::unique_ptr<CPDF_Form> Load(CPDF_PageObject* pPageObj);
 
@@ -36,12 +36,6 @@
   float y_step() const { return m_YStep; }
 
  private:
-  CPDF_TilingPattern(CPDF_Document* pDoc,
-                     CPDF_Object* pPatternObj,
-                     const CFX_Matrix& parentMatrix);
-  CPDF_TilingPattern(const CPDF_TilingPattern&) = delete;
-  CPDF_TilingPattern& operator=(const CPDF_TilingPattern&) = delete;
-
   bool m_bColored;
   CFX_FloatRect m_BBox;
   float m_XStep;
diff --git a/core/fpdfapi/render/cpdf_imagerenderer.cpp b/core/fpdfapi/render/cpdf_imagerenderer.cpp
index ee88794..865f72a 100644
--- a/core/fpdfapi/render/cpdf_imagerenderer.cpp
+++ b/core/fpdfapi/render/cpdf_imagerenderer.cpp
@@ -96,7 +96,7 @@
   if (m_pDIBBase->IsAlphaMask()) {
     const CPDF_Color* pColor = m_pImageObject->m_ColorState.GetFillColor();
     if (pColor && pColor->IsPattern()) {
-      m_pPattern.Reset(pColor->GetPattern());
+      m_pPattern = pColor->GetPattern();
       if (m_pPattern)
         m_bPatternColor = true;
     }
diff --git a/core/fpdfapi/render/cpdf_imagerenderer.h b/core/fpdfapi/render/cpdf_imagerenderer.h
index d7c7bf0..bfedfc1 100644
--- a/core/fpdfapi/render/cpdf_imagerenderer.h
+++ b/core/fpdfapi/render/cpdf_imagerenderer.h
@@ -85,7 +85,7 @@
 
   UnownedPtr<CPDF_RenderStatus> m_pRenderStatus;
   UnownedPtr<CPDF_ImageObject> m_pImageObject;
-  RetainPtr<CPDF_Pattern> m_pPattern;
+  UnownedPtr<CPDF_Pattern> m_pPattern;
   RetainPtr<CFX_DIBBase> m_pDIBBase;
   CFX_Matrix m_mtObj2Device;
   CFX_Matrix m_ImageMatrix;