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