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