Validate the BitsPerFlag entry in shading dictionaries.

BUG=616248

Review-Url: https://codereview.chromium.org/2020183004
diff --git a/core/fpdfapi/fpdf_page/cpdf_meshstream.cpp b/core/fpdfapi/fpdf_page/cpdf_meshstream.cpp
index de35541..d3649a1 100644
--- a/core/fpdfapi/fpdf_page/cpdf_meshstream.cpp
+++ b/core/fpdfapi/fpdf_page/cpdf_meshstream.cpp
@@ -44,17 +44,46 @@
   }
 }
 
+// See PDF Reference 1.7, page 315, table 4.32. (Also table 4.34)
+bool ShouldCheckBitsPerFlag(ShadingType type) {
+  switch (type) {
+    case kFreeFormGouraudTriangleMeshShading:
+    case kCoonsPatchMeshShading:
+    case kTensorProductPatchMeshShading:
+      return true;
+    default:
+      return false;
+  }
+}
+
+// Same references as ShouldCheckBitsPerFlag() above.
+bool IsValidBitsPerFlag(uint32_t x) {
+  switch (x) {
+    case 2:
+    case 4:
+    case 8:
+      return true;
+    default:
+      return false;
+  }
+}
+
 }  // namespace
 
 CPDF_MeshStream::CPDF_MeshStream(
+    ShadingType type,
     const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
+    CPDF_Stream* pShadingStream,
     CPDF_ColorSpace* pCS)
-    : m_funcs(funcs), m_pCS(pCS) {}
+    : m_type(type),
+      m_funcs(funcs),
+      m_pShadingStream(pShadingStream),
+      m_pCS(pCS) {}
 
-bool CPDF_MeshStream::Load(CPDF_Stream* pShadingStream) {
-  m_Stream.LoadAllData(pShadingStream);
+bool CPDF_MeshStream::Load() {
+  m_Stream.LoadAllData(m_pShadingStream);
   m_BitStream.Init(m_Stream.GetData(), m_Stream.GetSize());
-  CPDF_Dictionary* pDict = pShadingStream->GetDict();
+  CPDF_Dictionary* pDict = m_pShadingStream->GetDict();
   m_nCoordBits = pDict->GetIntegerBy("BitsPerCoordinate");
   if (!IsValidBitsPerCoordinate(m_nCoordBits))
     return false;
@@ -64,6 +93,9 @@
     return false;
 
   m_nFlagBits = pDict->GetIntegerBy("BitsPerFlag");
+  if (ShouldCheckBitsPerFlag(m_type) && !IsValidBitsPerFlag(m_nFlagBits))
+    return false;
+
   uint32_t nComps = m_pCS->CountComponents();
   if (nComps > 8)
     return false;
@@ -87,6 +119,7 @@
 }
 
 uint32_t CPDF_MeshStream::GetFlag() {
+  ASSERT(ShouldCheckBitsPerFlag(m_type));
   return m_BitStream.GetBits(m_nFlagBits) & 0x03;
 }
 
@@ -105,7 +138,6 @@
 }
 
 void CPDF_MeshStream::GetColor(FX_FLOAT& r, FX_FLOAT& g, FX_FLOAT& b) {
-  static const int kMaxResults = 8;
   FX_FLOAT color_value[kMaxResults];
   for (uint32_t i = 0; i < m_nComps; ++i) {
     color_value[i] = m_ColorMin[i] +
diff --git a/core/fpdfapi/fpdf_page/cpdf_meshstream.h b/core/fpdfapi/fpdf_page/cpdf_meshstream.h
index e5d37fe..8f47265 100644
--- a/core/fpdfapi/fpdf_page/cpdf_meshstream.h
+++ b/core/fpdfapi/fpdf_page/cpdf_meshstream.h
@@ -10,6 +10,7 @@
 #include <memory>
 #include <vector>
 
+#include "core/fpdfapi/fpdf_page/cpdf_shadingpattern.h"
 #include "core/fpdfapi/fpdf_parser/include/cpdf_stream_acc.h"
 #include "core/fxcrt/include/fx_basic.h"
 #include "core/fxcrt/include/fx_system.h"
@@ -29,12 +30,14 @@
 
 class CPDF_MeshStream {
  public:
-  CPDF_MeshStream(const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
+  CPDF_MeshStream(ShadingType type,
+                  const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
+                  CPDF_Stream* pShadingStream,
                   CPDF_ColorSpace* pCS);
 
-  bool Load(CPDF_Stream* pShadingStream);
-  uint32_t GetFlag();
+  bool Load();
 
+  uint32_t GetFlag();
   void GetCoords(FX_FLOAT& x, FX_FLOAT& y);
   void GetColor(FX_FLOAT& r, FX_FLOAT& g, FX_FLOAT& b);
 
@@ -44,13 +47,15 @@
                        CFX_Matrix* pObject2Bitmap);
 
   CFX_BitStream* BitStream() { return &m_BitStream; }
-  uint32_t CoordBits() const { return m_nCoordBits; }
   uint32_t CompBits() const { return m_nCompBits; }
-  uint32_t FlagBits() const { return m_nFlagBits; }
   uint32_t comps() const { return m_nComps; }
 
  private:
+  static const uint32_t kMaxResults = 8;
+
+  const ShadingType m_type;
   const std::vector<std::unique_ptr<CPDF_Function>>& m_funcs;
+  CPDF_Stream* const m_pShadingStream;
   CPDF_ColorSpace* const m_pCS;
   uint32_t m_nCoordBits;
   uint32_t m_nCompBits;
@@ -62,8 +67,8 @@
   FX_FLOAT m_xmax;
   FX_FLOAT m_ymin;
   FX_FLOAT m_ymax;
-  FX_FLOAT m_ColorMin[8];
-  FX_FLOAT m_ColorMax[8];
+  FX_FLOAT m_ColorMin[kMaxResults];
+  FX_FLOAT m_ColorMax[kMaxResults];
   CPDF_StreamAcc m_Stream;
   CFX_BitStream m_BitStream;
 };
diff --git a/core/fpdfapi/fpdf_page/fpdf_page_parser.cpp b/core/fpdfapi/fpdf_page/fpdf_page_parser.cpp
index ddea2e6..0592c97 100644
--- a/core/fpdfapi/fpdf_page/fpdf_page_parser.cpp
+++ b/core/fpdfapi/fpdf_page/fpdf_page_parser.cpp
@@ -106,8 +106,8 @@
   if (!pStream || !pCS)
     return CFX_FloatRect(0, 0, 0, 0);
 
-  CPDF_MeshStream stream(pShading->GetFuncs(), pCS);
-  if (!stream.Load(pStream))
+  CPDF_MeshStream stream(type, pShading->GetFuncs(), pStream, pCS);
+  if (!stream.Load())
     return CFX_FloatRect(0, 0, 0, 0);
 
   CFX_FloatRect rect;
diff --git a/core/fpdfapi/fpdf_render/fpdf_render_pattern.cpp b/core/fpdfapi/fpdf_render/fpdf_render_pattern.cpp
index 754394d..7896f83 100644
--- a/core/fpdfapi/fpdf_render/fpdf_render_pattern.cpp
+++ b/core/fpdfapi/fpdf_render/fpdf_render_pattern.cpp
@@ -411,8 +411,9 @@
     int alpha) {
   ASSERT(pBitmap->GetFormat() == FXDIB_Argb);
 
-  CPDF_MeshStream stream(funcs, pCS);
-  if (!stream.Load(pShadingStream))
+  CPDF_MeshStream stream(kFreeFormGouraudTriangleMeshShading, funcs,
+                         pShadingStream, pCS);
+  if (!stream.Load())
     return;
 
   CPDF_MeshVertex triangle[3];
@@ -450,8 +451,9 @@
   if (row_verts < 2)
     return;
 
-  CPDF_MeshStream stream(funcs, pCS);
-  if (!stream.Load(pShadingStream))
+  CPDF_MeshStream stream(kLatticeFormGouraudTriangleMeshShading, funcs,
+                         pShadingStream, pCS);
+  if (!stream.Load())
     return;
 
   std::unique_ptr<CPDF_MeshVertex, FxFreeDeleter> vertex(
@@ -724,24 +726,8 @@
   }
 };
 
-bool CheckCoonTensorPara(const CPDF_MeshStream& stream) {
-  uint32_t coord = stream.CoordBits();
-  bool bCoordBitsValid =
-      (coord == 1 || coord == 2 || coord == 4 || coord == 8 || coord == 12 ||
-       coord == 16 || coord == 24 || coord == 32);
-
-  uint32_t comp = stream.CompBits();
-  bool bCompBitsValid = (comp == 1 || comp == 2 || comp == 4 || comp == 8 ||
-                         comp == 12 || comp == 16);
-
-  uint32_t flag = stream.FlagBits();
-  bool bFlagBitsValid = (flag == 2 || flag == 4 || flag == 8);
-
-  return bCoordBitsValid && bCompBitsValid && bFlagBitsValid;
-}
-
 void DrawCoonPatchMeshes(
-    FX_BOOL bTensor,
+    ShadingType type,
     CFX_DIBitmap* pBitmap,
     CFX_Matrix* pObject2Bitmap,
     CPDF_Stream* pShadingStream,
@@ -750,13 +736,13 @@
     int fill_mode,
     int alpha) {
   ASSERT(pBitmap->GetFormat() == FXDIB_Argb);
+  ASSERT(type == kCoonsPatchMeshShading ||
+         type == kTensorProductPatchMeshShading);
 
   CFX_FxgeDevice device;
   device.Attach(pBitmap, false, nullptr, false);
-  CPDF_MeshStream stream(funcs, pCS);
-  if (!stream.Load(pShadingStream))
-    return;
-  if (!CheckCoonTensorPara(stream))
+  CPDF_MeshStream stream(type, funcs, pShadingStream, pCS);
+  if (!stream.Load())
     return;
 
   CPDF_PatchDrawer patch;
@@ -766,11 +752,10 @@
   patch.path.SetPointCount(13);
   FX_PATHPOINT* pPoints = patch.path.GetPoints();
   pPoints[0].m_Flag = FXPT_MOVETO;
-  for (int i = 1; i < 13; i++) {
+  for (int i = 1; i < 13; i++)
     pPoints[i].m_Flag = FXPT_BEZIERTO;
-  }
   CFX_PointF coords[16];
-  int point_count = bTensor ? 16 : 12;
+  int point_count = type == kTensorProductPatchMeshShading ? 16 : 12;
   while (!stream.BitStream()->IsEOF()) {
     uint32_t flag = stream.GetFlag();
     int iStartPoint = 0, iStartColor = 0, i = 0;
@@ -934,10 +919,8 @@
       // The shading object can be a stream or a dictionary. We do not handle
       // the case of dictionary at the moment.
       if (CPDF_Stream* pStream = ToStream(pPattern->GetShadingObject())) {
-        DrawCoonPatchMeshes(
-            pPattern->GetShadingType() == kTensorProductPatchMeshShading,
-            pBitmap, &FinalMatrix, pStream, funcs, pColorSpace, fill_mode,
-            alpha);
+        DrawCoonPatchMeshes(pPattern->GetShadingType(), pBitmap, &FinalMatrix,
+                            pStream, funcs, pColorSpace, fill_mode, alpha);
       }
     } break;
   }