Add CPDF_PatternCS::GetPatternRGB(const PatternValue& value).

Currently, one gets data from CPDF_PatternCS via its parent class's
GetRGB(const float* pBuf) method. To squeeze through this interface, the
caller has to pass in a float*, and CPDF_PatternCS::GetRGB() has to cast
it to PatternValue*.

Instead of doing casting, add a specialized GetPatternRGB() method to
CPDF_PatternCS. In its parent class, CPDF_ColorSpace, add AsPatternCS()
so callers can get a CPDF_PatternCS* from a CPDF_ColorSpace*. Change
existing callers to use these new methods.

Change-Id: Id476c9ece7ce8d3499a718acc682bc25036a5407
Reviewed-on: https://pdfium-review.googlesource.com/31030
Reviewed-by: Henrique Nakashima <hnakashima@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 dfee9d9..b3dd141 100644
--- a/core/fpdfapi/page/cpdf_color.cpp
+++ b/core/fpdfapi/page/cpdf_color.cpp
@@ -7,6 +7,7 @@
 #include "core/fpdfapi/page/cpdf_color.h"
 
 #include "core/fpdfapi/page/cpdf_docpagedata.h"
+#include "core/fpdfapi/page/cpdf_patterncs.h"
 #include "core/fpdfapi/parser/cpdf_array.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fxcrt/fx_system.h"
@@ -155,13 +156,21 @@
 }
 
 bool CPDF_Color::GetRGB(int* R, int* G, int* B) const {
-  if (!m_pCS || !m_pBuffer)
+  if (!m_pBuffer)
     return false;
 
   float r = 0.0f;
   float g = 0.0f;
   float b = 0.0f;
-  if (!m_pCS->GetRGB(m_pBuffer, &r, &g, &b))
+  bool result;
+  if (IsPatternInternal()) {
+    const CPDF_PatternCS* pPatternCS = m_pCS->AsPatternCS();
+    const auto* pValue = reinterpret_cast<const PatternValue*>(m_pBuffer);
+    result = pPatternCS->GetPatternRGB(*pValue, &r, &g, &b);
+  } else {
+    result = m_pCS->GetRGB(m_pBuffer, &r, &g, &b);
+  }
+  if (!result)
     return false;
 
   *R = static_cast<int32_t>(r * 255 + 0.5f);
diff --git a/core/fpdfapi/page/cpdf_colorspace.cpp b/core/fpdfapi/page/cpdf_colorspace.cpp
index 8ba2d8b..3cdc96a 100644
--- a/core/fpdfapi/page/cpdf_colorspace.cpp
+++ b/core/fpdfapi/page/cpdf_colorspace.cpp
@@ -597,6 +597,24 @@
     m_dwStdConversion--;
 }
 
+CPDF_PatternCS* CPDF_ColorSpace::AsPatternCS() {
+  NOTREACHED();
+  return nullptr;
+}
+
+const CPDF_PatternCS* CPDF_ColorSpace::AsPatternCS() const {
+  NOTREACHED();
+  return nullptr;
+}
+
+bool CPDF_ColorSpace::GetPatternRGB(const PatternValue& value,
+                                    float* R,
+                                    float* G,
+                                    float* B) const {
+  NOTREACHED();
+  return false;
+}
+
 CPDF_ColorSpace::CPDF_ColorSpace(CPDF_Document* pDoc, int family)
     : m_pDocument(pDoc), m_Family(family) {}
 
diff --git a/core/fpdfapi/page/cpdf_colorspace.h b/core/fpdfapi/page/cpdf_colorspace.h
index b9879d1..7172222 100644
--- a/core/fpdfapi/page/cpdf_colorspace.h
+++ b/core/fpdfapi/page/cpdf_colorspace.h
@@ -30,6 +30,7 @@
 class CPDF_Array;
 class CPDF_Document;
 class CPDF_Object;
+class CPDF_PatternCS;
 
 constexpr size_t kMaxPatternColorComps = 16;
 
@@ -84,6 +85,18 @@
                                   bool bTransMask) const;
   virtual void EnableStdConversion(bool bEnabled);
 
+  // Only call these 3 methods below if GetFamily() returns |PDFCS_PATTERN|.
+
+  // Returns |this| as a CPDF_PatternCS* if |this| is a pattern.
+  virtual CPDF_PatternCS* AsPatternCS();
+  virtual const CPDF_PatternCS* AsPatternCS() const;
+
+  // Use instead of GetRGB() for patterns.
+  virtual bool GetPatternRGB(const PatternValue& value,
+                             float* R,
+                             float* G,
+                             float* B) const;
+
   CPDF_Array* GetArray() const { return m_pArray.Get(); }
   CPDF_Document* GetDocument() const { return m_pDocument.Get(); }
 
diff --git a/core/fpdfapi/page/cpdf_patterncs.cpp b/core/fpdfapi/page/cpdf_patterncs.cpp
index 5da1769..37e91aa 100644
--- a/core/fpdfapi/page/cpdf_patterncs.cpp
+++ b/core/fpdfapi/page/cpdf_patterncs.cpp
@@ -54,12 +54,25 @@
                             float* R,
                             float* G,
                             float* B) const {
-  if (m_pBaseCS) {
-    ASSERT(m_pBaseCS->GetFamily() != PDFCS_PATTERN);
-    const auto* pvalue = reinterpret_cast<const PatternValue*>(pBuf);
-    if (m_pBaseCS->GetRGB(pvalue->m_Comps, R, G, B))
-      return true;
-  }
+  NOTREACHED();
+  return false;
+}
+
+CPDF_PatternCS* CPDF_PatternCS::AsPatternCS() {
+  return this;
+}
+
+const CPDF_PatternCS* CPDF_PatternCS::AsPatternCS() const {
+  return this;
+}
+
+bool CPDF_PatternCS::GetPatternRGB(const PatternValue& value,
+                                   float* R,
+                                   float* G,
+                                   float* B) const {
+  if (m_pBaseCS && m_pBaseCS->GetRGB(value.m_Comps, R, G, B))
+    return true;
+
   *R = 0.75f;
   *G = 0.75f;
   *B = 0.75f;
diff --git a/core/fpdfapi/page/cpdf_patterncs.h b/core/fpdfapi/page/cpdf_patterncs.h
index 488c83d..45365cc 100644
--- a/core/fpdfapi/page/cpdf_patterncs.h
+++ b/core/fpdfapi/page/cpdf_patterncs.h
@@ -27,6 +27,12 @@
                   CPDF_Array* pArray,
                   std::set<CPDF_Object*>* pVisited) override;
   bool GetRGB(const float* pBuf, float* R, float* G, float* B) const override;
+  CPDF_PatternCS* AsPatternCS() override;
+  const CPDF_PatternCS* AsPatternCS() const override;
+  bool GetPatternRGB(const PatternValue& value,
+                     float* R,
+                     float* G,
+                     float* B) const override;
 
  private:
   CPDF_ColorSpace* m_pBaseCS;