1 // Copyright 2016 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "core/fpdfapi/page/cpdf_meshstream.h"
8 
9 #include "core/fpdfapi/page/cpdf_colorspace.h"
10 #include "core/fpdfapi/page/cpdf_function.h"
11 #include "core/fpdfapi/parser/cpdf_array.h"
12 
13 namespace {
14 
15 // See PDF Reference 1.7, page 315, table 4.32. (Also table 4.33 and 4.34)
ShouldCheckBPC(ShadingType type)16 bool ShouldCheckBPC(ShadingType type) {
17   switch (type) {
18     case kFreeFormGouraudTriangleMeshShading:
19     case kLatticeFormGouraudTriangleMeshShading:
20     case kCoonsPatchMeshShading:
21     case kTensorProductPatchMeshShading:
22       return true;
23     default:
24       return false;
25   }
26 }
27 
28 // Same references as ShouldCheckBPC() above.
IsValidBitsPerComponent(uint32_t x)29 bool IsValidBitsPerComponent(uint32_t x) {
30   switch (x) {
31     case 1:
32     case 2:
33     case 4:
34     case 8:
35     case 12:
36     case 16:
37       return true;
38     default:
39       return false;
40   }
41 }
42 
43 // Same references as ShouldCheckBPC() above.
IsValidBitsPerCoordinate(uint32_t x)44 bool IsValidBitsPerCoordinate(uint32_t x) {
45   switch (x) {
46     case 1:
47     case 2:
48     case 4:
49     case 8:
50     case 12:
51     case 16:
52     case 24:
53     case 32:
54       return true;
55     default:
56       return false;
57   }
58 }
59 
60 // See PDF Reference 1.7, page 315, table 4.32. (Also table 4.34)
ShouldCheckBitsPerFlag(ShadingType type)61 bool ShouldCheckBitsPerFlag(ShadingType type) {
62   switch (type) {
63     case kFreeFormGouraudTriangleMeshShading:
64     case kCoonsPatchMeshShading:
65     case kTensorProductPatchMeshShading:
66       return true;
67     default:
68       return false;
69   }
70 }
71 
72 // Same references as ShouldCheckBitsPerFlag() above.
IsValidBitsPerFlag(uint32_t x)73 bool IsValidBitsPerFlag(uint32_t x) {
74   switch (x) {
75     case 2:
76     case 4:
77     case 8:
78       return true;
79     default:
80       return false;
81   }
82 }
83 
84 }  // namespace
85 
86 CPDF_MeshVertex::CPDF_MeshVertex() = default;
87 
88 CPDF_MeshVertex::CPDF_MeshVertex(const CPDF_MeshVertex&) = default;
89 
90 CPDF_MeshVertex::~CPDF_MeshVertex() = default;
91 
CPDF_MeshStream(ShadingType type,const std::vector<std::unique_ptr<CPDF_Function>> & funcs,CPDF_Stream * pShadingStream,CPDF_ColorSpace * pCS)92 CPDF_MeshStream::CPDF_MeshStream(
93     ShadingType type,
94     const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
95     CPDF_Stream* pShadingStream,
96     CPDF_ColorSpace* pCS)
97     : m_type(type),
98       m_funcs(funcs),
99       m_pShadingStream(pShadingStream),
100       m_pCS(pCS),
101       m_nCoordBits(0),
102       m_nComponentBits(0),
103       m_nFlagBits(0),
104       m_nComponents(0),
105       m_CoordMax(0),
106       m_ComponentMax(0),
107       m_xmin(0),
108       m_xmax(0),
109       m_ymin(0),
110       m_ymax(0),
111       m_pStream(pdfium::MakeRetain<CPDF_StreamAcc>(pShadingStream)) {
112   memset(&m_ColorMin, 0, sizeof(m_ColorMin));
113   memset(&m_ColorMax, 0, sizeof(m_ColorMax));
114 }
115 
~CPDF_MeshStream()116 CPDF_MeshStream::~CPDF_MeshStream() {}
117 
Load()118 bool CPDF_MeshStream::Load() {
119   m_pStream->LoadAllDataFiltered();
120   m_BitStream = pdfium::MakeUnique<CFX_BitStream>(m_pStream->GetData(),
121                                                   m_pStream->GetSize());
122   CPDF_Dictionary* pDict = m_pShadingStream->GetDict();
123   m_nCoordBits = pDict->GetIntegerFor("BitsPerCoordinate");
124   m_nComponentBits = pDict->GetIntegerFor("BitsPerComponent");
125   if (ShouldCheckBPC(m_type)) {
126     if (!IsValidBitsPerCoordinate(m_nCoordBits))
127       return false;
128     if (!IsValidBitsPerComponent(m_nComponentBits))
129       return false;
130   }
131 
132   m_nFlagBits = pDict->GetIntegerFor("BitsPerFlag");
133   if (ShouldCheckBitsPerFlag(m_type) && !IsValidBitsPerFlag(m_nFlagBits))
134     return false;
135 
136   uint32_t nComponents = m_pCS->CountComponents();
137   if (nComponents > kMaxComponents)
138     return false;
139 
140   m_nComponents = m_funcs.empty() ? nComponents : 1;
141   CPDF_Array* pDecode = pDict->GetArrayFor("Decode");
142   if (!pDecode || pDecode->GetCount() != 4 + m_nComponents * 2)
143     return false;
144 
145   m_xmin = pDecode->GetNumberAt(0);
146   m_xmax = pDecode->GetNumberAt(1);
147   m_ymin = pDecode->GetNumberAt(2);
148   m_ymax = pDecode->GetNumberAt(3);
149   for (uint32_t i = 0; i < m_nComponents; ++i) {
150     m_ColorMin[i] = pDecode->GetNumberAt(i * 2 + 4);
151     m_ColorMax[i] = pDecode->GetNumberAt(i * 2 + 5);
152   }
153 
154   if (ShouldCheckBPC(m_type)) {
155     m_CoordMax = m_nCoordBits == 32 ? -1 : (1 << m_nCoordBits) - 1;
156     m_ComponentMax = (1 << m_nComponentBits) - 1;
157   }
158   return true;
159 }
160 
CanReadFlag() const161 bool CPDF_MeshStream::CanReadFlag() const {
162   return m_BitStream->BitsRemaining() >= m_nFlagBits;
163 }
164 
CanReadCoords() const165 bool CPDF_MeshStream::CanReadCoords() const {
166   return m_BitStream->BitsRemaining() / 2 >= m_nCoordBits;
167 }
168 
CanReadColor() const169 bool CPDF_MeshStream::CanReadColor() const {
170   return m_BitStream->BitsRemaining() / m_nComponentBits >= m_nComponents;
171 }
172 
ReadFlag()173 uint32_t CPDF_MeshStream::ReadFlag() {
174   ASSERT(ShouldCheckBitsPerFlag(m_type));
175   return m_BitStream->GetBits(m_nFlagBits) & 0x03;
176 }
177 
ReadCoords()178 CFX_PointF CPDF_MeshStream::ReadCoords() {
179   ASSERT(ShouldCheckBPC(m_type));
180 
181   CFX_PointF pos;
182   if (m_nCoordBits == 32) {
183     pos.x = m_xmin + m_BitStream->GetBits(m_nCoordBits) * (m_xmax - m_xmin) /
184                          static_cast<double>(m_CoordMax);
185     pos.y = m_ymin + m_BitStream->GetBits(m_nCoordBits) * (m_ymax - m_ymin) /
186                          static_cast<double>(m_CoordMax);
187   } else {
188     pos.x = m_xmin +
189             m_BitStream->GetBits(m_nCoordBits) * (m_xmax - m_xmin) / m_CoordMax;
190     pos.y = m_ymin +
191             m_BitStream->GetBits(m_nCoordBits) * (m_ymax - m_ymin) / m_CoordMax;
192   }
193   return pos;
194 }
195 
ReadColor()196 std::tuple<float, float, float> CPDF_MeshStream::ReadColor() {
197   ASSERT(ShouldCheckBPC(m_type));
198 
199   float color_value[kMaxComponents];
200   for (uint32_t i = 0; i < m_nComponents; ++i) {
201     color_value[i] = m_ColorMin[i] + m_BitStream->GetBits(m_nComponentBits) *
202                                          (m_ColorMax[i] - m_ColorMin[i]) /
203                                          m_ComponentMax;
204   }
205 
206   float r = 0.0;
207   float g = 0.0;
208   float b = 0.0;
209   if (m_funcs.empty()) {
210     m_pCS->GetRGB(color_value, &r, &g, &b);
211     return std::tuple<float, float, float>(r, g, b);
212   }
213 
214   float result[kMaxComponents];
215   memset(result, 0, sizeof(result));
216   int nResults;
217   for (const auto& func : m_funcs) {
218     if (func && func->CountOutputs() <= kMaxComponents)
219       func->Call(color_value, 1, result, &nResults);
220   }
221 
222   m_pCS->GetRGB(result, &r, &g, &b);
223   return std::tuple<float, float, float>(r, g, b);
224 }
225 
ReadVertex(const CFX_Matrix & pObject2Bitmap,CPDF_MeshVertex * vertex,uint32_t * flag)226 bool CPDF_MeshStream::ReadVertex(const CFX_Matrix& pObject2Bitmap,
227                                  CPDF_MeshVertex* vertex,
228                                  uint32_t* flag) {
229   if (!CanReadFlag())
230     return false;
231   *flag = ReadFlag();
232 
233   if (!CanReadCoords())
234     return false;
235   vertex->position = pObject2Bitmap.Transform(ReadCoords());
236 
237   if (!CanReadColor())
238     return false;
239   std::tie(vertex->r, vertex->g, vertex->b) = ReadColor();
240   m_BitStream->ByteAlign();
241   return true;
242 }
243 
ReadVertexRow(const CFX_Matrix & pObject2Bitmap,int count)244 std::vector<CPDF_MeshVertex> CPDF_MeshStream::ReadVertexRow(
245     const CFX_Matrix& pObject2Bitmap,
246     int count) {
247   std::vector<CPDF_MeshVertex> vertices;
248   for (int i = 0; i < count; ++i) {
249     if (m_BitStream->IsEOF() || !CanReadCoords())
250       return std::vector<CPDF_MeshVertex>();
251 
252     vertices.push_back(CPDF_MeshVertex());
253     CPDF_MeshVertex& vertex = vertices.back();
254     vertex.position = pObject2Bitmap.Transform(ReadCoords());
255     if (!CanReadColor())
256       return std::vector<CPDF_MeshVertex>();
257 
258     std::tie(vertex.r, vertex.g, vertex.b) = ReadColor();
259     m_BitStream->ByteAlign();
260   }
261   return vertices;
262 }
263