[Merge M64] Add parameter validation to CPDF_ShadingPattern.

Check if the ColorSpace and the Function params are valid for the
shading type.

TBR=dsinclair@chromium.org
Bug: chromium:794990
Change-Id: I022e976e5489a6b325d95ad16eab056235a8944d
Reviewed-on: https://pdfium-review.googlesource.com/21450
Commit-Queue: Henrique Nakashima <hnakashima@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
(cherry picked from commit 30ef542b6f631f0ffbcd4110857e7c1a304a8a23)
Reviewed-on: https://pdfium-review.googlesource.com/22030
Reviewed-by: Henrique Nakashima <hnakashima@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_shadingpattern.cpp b/core/fpdfapi/page/cpdf_shadingpattern.cpp
index ef40f54..c5972b7 100644
--- a/core/fpdfapi/page/cpdf_shadingpattern.cpp
+++ b/core/fpdfapi/page/cpdf_shadingpattern.cpp
@@ -100,9 +100,98 @@
 
   m_ShadingType = ToShadingType(pShadingDict->GetIntegerFor("ShadingType"));
 
+  return Validate();
+}
+
+bool CPDF_ShadingPattern::Validate() const {
+  if (m_ShadingType == kInvalidShading)
+    return false;
+
   // We expect to have a stream if our shading type is a mesh.
   if (IsMeshShading() && !ToStream(m_pShadingObj.Get()))
     return false;
 
+  // Validate color space
+  switch (m_ShadingType) {
+    case kFunctionBasedShading:
+    case kAxialShading:
+    case kRadialShading: {
+      if (m_pCS->GetFamily() == PDFCS_INDEXED)
+        return false;
+      break;
+    }
+    case kFreeFormGouraudTriangleMeshShading:
+    case kLatticeFormGouraudTriangleMeshShading:
+    case kCoonsPatchMeshShading:
+    case kTensorProductPatchMeshShading: {
+      if (!m_pFunctions.empty() && m_pCS->GetFamily() == PDFCS_INDEXED)
+        return false;
+      break;
+    }
+    default: {
+      NOTREACHED();
+      return false;
+    }
+  }
+
+  uint32_t nNumColorSpaceComponents = m_pCS->CountComponents();
+  switch (m_ShadingType) {
+    case kFunctionBasedShading: {
+      // Either one 2-to-N function or N 2-to-1 functions.
+      if (!ValidateFunctions(1, 2, nNumColorSpaceComponents) &&
+          !ValidateFunctions(nNumColorSpaceComponents, 2, 1)) {
+        return false;
+      }
+      break;
+    }
+    case kAxialShading:
+    case kRadialShading: {
+      // Either one 1-to-N function or N 1-to-1 functions.
+      if (!ValidateFunctions(1, 1, nNumColorSpaceComponents) &&
+          !ValidateFunctions(nNumColorSpaceComponents, 1, 1)) {
+        return false;
+      }
+      break;
+    }
+    case kFreeFormGouraudTriangleMeshShading:
+    case kLatticeFormGouraudTriangleMeshShading:
+    case kCoonsPatchMeshShading:
+    case kTensorProductPatchMeshShading: {
+      // Either no function, one 1-to-N function, or N 1-to-1 functions.
+      if (!m_pFunctions.empty() &&
+          !ValidateFunctions(1, 1, nNumColorSpaceComponents) &&
+          !ValidateFunctions(nNumColorSpaceComponents, 1, 1)) {
+        return false;
+      }
+      break;
+    }
+    default: {
+      NOTREACHED();
+      return false;
+    }
+  }
   return true;
 }
+
+bool CPDF_ShadingPattern::ValidateFunctions(
+    uint32_t nExpectedNumFunctions,
+    uint32_t nExpectedNumInputs,
+    uint32_t nExpectedNumOutputs) const {
+  if (m_pFunctions.size() != nExpectedNumFunctions)
+    return false;
+
+  pdfium::base::CheckedNumeric<uint32_t> nTotalOutputs = 0;
+  for (const auto& function : m_pFunctions) {
+    if (!function)
+      return false;
+
+    if (function->CountInputs() != nExpectedNumInputs ||
+        function->CountOutputs() != nExpectedNumOutputs) {
+      return false;
+    }
+
+    nTotalOutputs += function->CountOutputs();
+  }
+
+  return nTotalOutputs.IsValid();
+}
diff --git a/core/fpdfapi/page/cpdf_shadingpattern.h b/core/fpdfapi/page/cpdf_shadingpattern.h
index d0fafef..17b6e4b 100644
--- a/core/fpdfapi/page/cpdf_shadingpattern.h
+++ b/core/fpdfapi/page/cpdf_shadingpattern.h
@@ -61,6 +61,12 @@
   }
 
  private:
+  // Constraints in PDF 1.7 spec, 4.6.3 Shading Patterns, pages 308-331.
+  bool Validate() const;
+  bool ValidateFunctions(uint32_t nExpectedNumFunctions,
+                         uint32_t nExpectedNumInputs,
+                         uint32_t nExpectedNumOutputs) const;
+
   ShadingType m_ShadingType;
   bool m_bShadingObj;
   UnownedPtr<CPDF_Object> m_pShadingObj;