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