Consolidate colorspace code into intermediate CPDF_BasedCS class

Provide a common member name and eliminate N duplicate implementations
of EnableStdConversion().

-- add initializer in one place.
-- rename one confusing local variable.

Change-Id: I54241e6ff86d88b120469693ece0c3638d25d38d
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/84712
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/page/BUILD.gn b/core/fpdfapi/page/BUILD.gn
index 9f39824..1a9607b 100644
--- a/core/fpdfapi/page/BUILD.gn
+++ b/core/fpdfapi/page/BUILD.gn
@@ -11,6 +11,8 @@
     "cpdf_allstates.h",
     "cpdf_annotcontext.cpp",
     "cpdf_annotcontext.h",
+    "cpdf_basedcs.cpp",
+    "cpdf_basedcs.h",
     "cpdf_clippath.cpp",
     "cpdf_clippath.h",
     "cpdf_color.cpp",
diff --git a/core/fpdfapi/page/cpdf_basedcs.cpp b/core/fpdfapi/page/cpdf_basedcs.cpp
new file mode 100644
index 0000000..71dea0a
--- /dev/null
+++ b/core/fpdfapi/page/cpdf_basedcs.cpp
@@ -0,0 +1,17 @@
+// Copyright 2021 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "core/fpdfapi/page/cpdf_basedcs.h"
+
+CPDF_BasedCS::CPDF_BasedCS(Family family) : CPDF_ColorSpace(family) {}
+
+CPDF_BasedCS::~CPDF_BasedCS() = default;
+
+void CPDF_BasedCS::EnableStdConversion(bool bEnabled) {
+  CPDF_ColorSpace::EnableStdConversion(bEnabled);
+  if (m_pBaseCS)
+    m_pBaseCS->EnableStdConversion(bEnabled);
+}
diff --git a/core/fpdfapi/page/cpdf_basedcs.h b/core/fpdfapi/page/cpdf_basedcs.h
new file mode 100644
index 0000000..0dcfcd8
--- /dev/null
+++ b/core/fpdfapi/page/cpdf_basedcs.h
@@ -0,0 +1,29 @@
+// Copyright 2021 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef CORE_FPDFAPI_PAGE_CPDF_BASEDCS_H_
+#define CORE_FPDFAPI_PAGE_CPDF_BASEDCS_H_
+
+#include "core/fpdfapi/page/cpdf_colorspace.h"
+#include "core/fxcrt/retain_ptr.h"
+
+// Represents a color space that is based on another color space. This includes
+// all the special color spaces in ISO 32000, table 62, as well as the ICCBased
+// color space.
+class CPDF_BasedCS : public CPDF_ColorSpace {
+ public:
+  CONSTRUCT_VIA_MAKE_RETAIN;
+  ~CPDF_BasedCS() override;
+
+  void EnableStdConversion(bool bEnabled) final;
+
+ protected:
+  explicit CPDF_BasedCS(Family family);
+
+  RetainPtr<CPDF_ColorSpace> m_pBaseCS;  // May be fallback CS in some cases.
+};
+
+#endif  // CORE_FPDFAPI_PAGE_CPDF_BASEDCS_H_
diff --git a/core/fpdfapi/page/cpdf_colorspace.cpp b/core/fpdfapi/page/cpdf_colorspace.cpp
index 18c6ce7..3f62209 100644
--- a/core/fpdfapi/page/cpdf_colorspace.cpp
+++ b/core/fpdfapi/page/cpdf_colorspace.cpp
@@ -211,7 +211,7 @@
   float m_Ranges[kRangesCount];
 };
 
-class CPDF_ICCBasedCS final : public CPDF_ColorSpace {
+class CPDF_ICCBasedCS final : public CPDF_BasedCS {
  public:
   CONSTRUCT_VIA_MAKE_RETAIN;
   ~CPDF_ICCBasedCS() override;
@@ -221,7 +221,6 @@
               float* R,
               float* G,
               float* B) const override;
-  void EnableStdConversion(bool bEnabled) override;
   void TranslateImageLine(uint8_t* pDestBuf,
                           const uint8_t* pSrcBuf,
                           int pixels,
@@ -246,13 +245,12 @@
   static std::vector<float> GetRanges(const CPDF_Dictionary* pDict,
                                       uint32_t nComponents);
 
-  RetainPtr<CPDF_ColorSpace> m_pAlterCS;
   RetainPtr<CPDF_IccProfile> m_pProfile;
   mutable std::vector<uint8_t, FxAllocAllocator<uint8_t>> m_pCache;
   std::vector<float> m_pRanges;
 };
 
-class CPDF_IndexedCS final : public CPDF_ColorSpace {
+class CPDF_IndexedCS final : public CPDF_BasedCS {
  public:
   CONSTRUCT_VIA_MAKE_RETAIN;
   ~CPDF_IndexedCS() override;
@@ -262,7 +260,6 @@
               float* R,
               float* G,
               float* B) const override;
-  void EnableStdConversion(bool bEnabled) override;
   uint32_t v_Load(CPDF_Document* pDoc,
                   const CPDF_Array* pArray,
                   std::set<const CPDF_Object*>* pVisited) override;
@@ -270,14 +267,13 @@
  private:
   CPDF_IndexedCS();
 
-  RetainPtr<CPDF_ColorSpace> m_pBaseCS;
   uint32_t m_nBaseComponents = 0;
   int m_MaxIndex = 0;
   ByteString m_Table;
   std::vector<float> m_pCompMinMax;
 };
 
-class CPDF_SeparationCS final : public CPDF_ColorSpace {
+class CPDF_SeparationCS final : public CPDF_BasedCS {
  public:
   CONSTRUCT_VIA_MAKE_RETAIN;
   ~CPDF_SeparationCS() override;
@@ -291,7 +287,6 @@
                        float* value,
                        float* min,
                        float* max) const override;
-  void EnableStdConversion(bool bEnabled) override;
   uint32_t v_Load(CPDF_Document* pDoc,
                   const CPDF_Array* pArray,
                   std::set<const CPDF_Object*>* pVisited) override;
@@ -299,12 +294,11 @@
  private:
   CPDF_SeparationCS();
 
-  bool m_IsNoneType;
-  RetainPtr<CPDF_ColorSpace> m_pAltCS;
+  bool m_IsNoneType = false;
   std::unique_ptr<const CPDF_Function> m_pFunc;
 };
 
-class CPDF_DeviceNCS final : public CPDF_ColorSpace {
+class CPDF_DeviceNCS final : public CPDF_BasedCS {
  public:
   CONSTRUCT_VIA_MAKE_RETAIN;
   ~CPDF_DeviceNCS() override;
@@ -318,7 +312,6 @@
                        float* value,
                        float* min,
                        float* max) const override;
-  void EnableStdConversion(bool bEnabled) override;
   uint32_t v_Load(CPDF_Document* pDoc,
                   const CPDF_Array* pArray,
                   std::set<const CPDF_Object*>* pVisited) override;
@@ -326,7 +319,6 @@
  private:
   CPDF_DeviceNCS();
 
-  RetainPtr<CPDF_ColorSpace> m_pAltCS;
   std::unique_ptr<const CPDF_Function> m_pFunc;
 };
 
@@ -909,7 +901,7 @@
   }
 }
 
-CPDF_ICCBasedCS::CPDF_ICCBasedCS() : CPDF_ColorSpace(Family::kICCBased) {}
+CPDF_ICCBasedCS::CPDF_ICCBasedCS() : CPDF_BasedCS(Family::kICCBased) {}
 
 CPDF_ICCBasedCS::~CPDF_ICCBasedCS() = default;
 
@@ -947,8 +939,8 @@
       !FindAlternateProfile(pDoc, pDict, pVisited, nComponents)) {
     // If there is no alternate profile, use a stock profile as mentioned in
     // the PDF 1.7 spec in table 4.16 in the "Alternate" key description.
-    DCHECK(!m_pAlterCS);
-    m_pAlterCS = GetStockAlternateProfile(nComponents);
+    DCHECK(!m_pBaseCS);
+    m_pBaseCS = GetStockAlternateProfile(nComponents);
   }
 
   m_pRanges = GetRanges(pDict, nComponents);
@@ -974,8 +966,8 @@
     *B = rgb[2];
     return true;
   }
-  if (m_pAlterCS)
-    return m_pAlterCS->GetRGB(pBuf, R, G, B);
+  if (m_pBaseCS)
+    return m_pBaseCS->GetRGB(pBuf, R, G, B);
 
   *R = 0.0f;
   *G = 0.0f;
@@ -983,12 +975,6 @@
   return true;
 }
 
-void CPDF_ICCBasedCS::EnableStdConversion(bool bEnabled) {
-  CPDF_ColorSpace::EnableStdConversion(bEnabled);
-  if (m_pAlterCS)
-    m_pAlterCS->EnableStdConversion(bEnabled);
-}
-
 void CPDF_ICCBasedCS::TranslateImageLine(uint8_t* pDestBuf,
                                          const uint8_t* pSrcBuf,
                                          int pixels,
@@ -1000,9 +986,9 @@
     return;
   }
   if (!m_pProfile->transform()) {
-    if (m_pAlterCS) {
-      m_pAlterCS->TranslateImageLine(pDestBuf, pSrcBuf, pixels, image_width,
-                                     image_height, false);
+    if (m_pBaseCS) {
+      m_pBaseCS->TranslateImageLine(pDestBuf, pSrcBuf, pixels, image_width,
+                                    image_height, false);
     }
     return;
   }
@@ -1063,8 +1049,8 @@
     return true;
   if (m_pProfile->transform())
     return m_pProfile->transform()->IsNormal();
-  if (m_pAlterCS)
-    return m_pAlterCS->IsNormal();
+  if (m_pBaseCS)
+    return m_pBaseCS->IsNormal();
   return false;
 }
 
@@ -1087,7 +1073,7 @@
   if (pAlterCS->CountComponents() != nExpectedComponents)
     return false;
 
-  m_pAlterCS = std::move(pAlterCS);
+  m_pBaseCS = std::move(pAlterCS);
   return true;
 }
 
@@ -1123,7 +1109,7 @@
   return ranges;
 }
 
-CPDF_IndexedCS::CPDF_IndexedCS() : CPDF_ColorSpace(Family::kIndexed) {}
+CPDF_IndexedCS::CPDF_IndexedCS() : CPDF_BasedCS(Family::kIndexed) {}
 
 CPDF_IndexedCS::~CPDF_IndexedCS() = default;
 
@@ -1202,13 +1188,7 @@
   return m_pBaseCS->GetRGB(comps, R, G, B);
 }
 
-void CPDF_IndexedCS::EnableStdConversion(bool bEnabled) {
-  CPDF_ColorSpace::EnableStdConversion(bEnabled);
-  if (m_pBaseCS)
-    m_pBaseCS->EnableStdConversion(bEnabled);
-}
-
-CPDF_SeparationCS::CPDF_SeparationCS() : CPDF_ColorSpace(Family::kSeparation) {}
+CPDF_SeparationCS::CPDF_SeparationCS() : CPDF_BasedCS(Family::kSeparation) {}
 
 CPDF_SeparationCS::~CPDF_SeparationCS() = default;
 
@@ -1228,21 +1208,21 @@
   if (m_IsNoneType)
     return 1;
 
-  const CPDF_Object* pAltCS = pArray->GetDirectObjectAt(2);
-  if (pAltCS == m_pArray)
+  const CPDF_Object* pAltArray = pArray->GetDirectObjectAt(2);
+  if (pAltArray == m_pArray)
     return 0;
 
-  m_pAltCS = Load(pDoc, pAltCS, pVisited);
-  if (!m_pAltCS)
+  m_pBaseCS = Load(pDoc, pAltArray, pVisited);
+  if (!m_pBaseCS)
     return 0;
 
-  if (m_pAltCS->IsSpecial())
+  if (m_pBaseCS->IsSpecial())
     return 0;
 
   const CPDF_Object* pFuncObj = pArray->GetDirectObjectAt(3);
   if (pFuncObj && !pFuncObj->IsName()) {
     auto pFunc = CPDF_Function::Load(pFuncObj);
-    if (pFunc && pFunc->CountOutputs() >= m_pAltCS->CountComponents())
+    if (pFunc && pFunc->CountOutputs() >= m_pBaseCS->CountComponents())
       m_pFunc = std::move(pFunc);
   }
   return 1;
@@ -1256,14 +1236,14 @@
     return false;
 
   if (!m_pFunc) {
-    if (!m_pAltCS)
+    if (!m_pBaseCS)
       return false;
 
-    int nComps = m_pAltCS->CountComponents();
+    int nComps = m_pBaseCS->CountComponents();
     std::vector<float> results(nComps);
     for (int i = 0; i < nComps; i++)
       results[i] = pBuf[0];
-    return m_pAltCS->GetRGB(results, R, G, B);
+    return m_pBaseCS->GetRGB(results, R, G, B);
   }
 
   // Using at least 16 elements due to the call m_pAltCS->GetRGB() below.
@@ -1272,8 +1252,8 @@
   if (nresults == 0)
     return false;
 
-  if (m_pAltCS)
-    return m_pAltCS->GetRGB(results, R, G, B);
+  if (m_pBaseCS)
+    return m_pBaseCS->GetRGB(results, R, G, B);
 
   R = 0;
   G = 0;
@@ -1281,13 +1261,7 @@
   return false;
 }
 
-void CPDF_SeparationCS::EnableStdConversion(bool bEnabled) {
-  CPDF_ColorSpace::EnableStdConversion(bEnabled);
-  if (m_pAltCS)
-    m_pAltCS->EnableStdConversion(bEnabled);
-}
-
-CPDF_DeviceNCS::CPDF_DeviceNCS() : CPDF_ColorSpace(Family::kDeviceN) {}
+CPDF_DeviceNCS::CPDF_DeviceNCS() : CPDF_BasedCS(Family::kDeviceN) {}
 
 CPDF_DeviceNCS::~CPDF_DeviceNCS() = default;
 
@@ -1311,15 +1285,15 @@
   if (!pAltCS || pAltCS == m_pArray)
     return 0;
 
-  m_pAltCS = Load(pDoc, pAltCS, pVisited);
+  m_pBaseCS = Load(pDoc, pAltCS, pVisited);
   m_pFunc = CPDF_Function::Load(pArray->GetDirectObjectAt(3));
-  if (!m_pAltCS || !m_pFunc)
+  if (!m_pBaseCS || !m_pFunc)
     return 0;
 
-  if (m_pAltCS->IsSpecial())
+  if (m_pBaseCS->IsSpecial())
     return 0;
 
-  if (m_pFunc->CountOutputs() < m_pAltCS->CountComponents())
+  if (m_pFunc->CountOutputs() < m_pBaseCS->CountComponents())
     return 0;
 
   return pObj->size();
@@ -1341,12 +1315,5 @@
   if (nresults == 0)
     return false;
 
-  return m_pAltCS->GetRGB(results, R, G, B);
-}
-
-void CPDF_DeviceNCS::EnableStdConversion(bool bEnabled) {
-  CPDF_ColorSpace::EnableStdConversion(bEnabled);
-  if (m_pAltCS) {
-    m_pAltCS->EnableStdConversion(bEnabled);
-  }
+  return m_pBaseCS->GetRGB(results, R, G, B);
 }
diff --git a/core/fpdfapi/page/cpdf_patterncs.cpp b/core/fpdfapi/page/cpdf_patterncs.cpp
index adb15c8..f66a41c 100644
--- a/core/fpdfapi/page/cpdf_patterncs.cpp
+++ b/core/fpdfapi/page/cpdf_patterncs.cpp
@@ -11,7 +11,7 @@
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "third_party/base/notreached.h"
 
-CPDF_PatternCS::CPDF_PatternCS() : CPDF_ColorSpace(Family::kPattern) {}
+CPDF_PatternCS::CPDF_PatternCS() : CPDF_BasedCS(Family::kPattern) {}
 
 CPDF_PatternCS::~CPDF_PatternCS() = default;
 
diff --git a/core/fpdfapi/page/cpdf_patterncs.h b/core/fpdfapi/page/cpdf_patterncs.h
index 7b14e04..dda1d28 100644
--- a/core/fpdfapi/page/cpdf_patterncs.h
+++ b/core/fpdfapi/page/cpdf_patterncs.h
@@ -9,12 +9,12 @@
 
 #include <set>
 
-#include "core/fpdfapi/page/cpdf_colorspace.h"
+#include "core/fpdfapi/page/cpdf_basedcs.h"
 #include "core/fxcrt/retain_ptr.h"
 
 class CPDF_Document;
 
-class CPDF_PatternCS final : public CPDF_ColorSpace {
+class CPDF_PatternCS final : public CPDF_BasedCS {
  public:
   CONSTRUCT_VIA_MAKE_RETAIN;
   ~CPDF_PatternCS() override;
@@ -41,8 +41,6 @@
 
  private:
   CPDF_PatternCS();
-
-  RetainPtr<CPDF_ColorSpace> m_pBaseCS;
 };
 
 #endif  // CORE_FPDFAPI_PAGE_CPDF_PATTERNCS_H_