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/pageint.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 memset(&m_ColorMin, 0, sizeof(m_ColorMin));
112 memset(&m_ColorMax, 0, sizeof(m_ColorMax));
113 }
114
Load()115 bool CPDF_MeshStream::Load() {
116 m_Stream.LoadAllData(m_pShadingStream);
117 m_BitStream.Init(m_Stream.GetData(), m_Stream.GetSize());
118 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->CountComponents();
133 if (nComponents > kMaxComponents)
134 return false;
135
136 m_nComponents = m_funcs.empty() ? nComponents : 1;
137 CPDF_Array* pDecode = pDict->GetArrayFor("Decode");
138 if (!pDecode || pDecode->GetCount() != 4 + m_nComponents * 2)
139 return false;
140
141 m_xmin = pDecode->GetNumberAt(0);
142 m_xmax = pDecode->GetNumberAt(1);
143 m_ymin = pDecode->GetNumberAt(2);
144 m_ymax = pDecode->GetNumberAt(3);
145 for (uint32_t i = 0; i < m_nComponents; ++i) {
146 m_ColorMin[i] = pDecode->GetNumberAt(i * 2 + 4);
147 m_ColorMax[i] = pDecode->GetNumberAt(i * 2 + 5);
148 }
149
150 if (ShouldCheckBPC(m_type)) {
151 m_CoordMax = m_nCoordBits == 32 ? -1 : (1 << m_nCoordBits) - 1;
152 m_ComponentMax = (1 << m_nComponentBits) - 1;
153 }
154 return true;
155 }
156
CanReadFlag() const157 bool CPDF_MeshStream::CanReadFlag() const {
158 return m_BitStream.BitsRemaining() >= m_nFlagBits;
159 }
160
CanReadCoords() const161 bool CPDF_MeshStream::CanReadCoords() const {
162 return m_BitStream.BitsRemaining() / 2 >= m_nCoordBits;
163 }
164
CanReadColor() const165 bool CPDF_MeshStream::CanReadColor() const {
166 return m_BitStream.BitsRemaining() / m_nComponentBits >= m_nComponents;
167 }
168
ReadFlag()169 uint32_t CPDF_MeshStream::ReadFlag() {
170 ASSERT(ShouldCheckBitsPerFlag(m_type));
171 return m_BitStream.GetBits(m_nFlagBits) & 0x03;
172 }
173
ReadCoords()174 CFX_PointF CPDF_MeshStream::ReadCoords() {
175 ASSERT(ShouldCheckBPC(m_type));
176
177 CFX_PointF pos;
178 if (m_nCoordBits == 32) {
179 pos.x = m_xmin +
180 m_BitStream.GetBits(m_nCoordBits) * (m_xmax - m_xmin) /
181 static_cast<double>(m_CoordMax);
182 pos.y = m_ymin +
183 m_BitStream.GetBits(m_nCoordBits) * (m_ymax - m_ymin) /
184 static_cast<double>(m_CoordMax);
185 } else {
186 pos.x = m_xmin +
187 m_BitStream.GetBits(m_nCoordBits) * (m_xmax - m_xmin) / m_CoordMax;
188 pos.y = m_ymin +
189 m_BitStream.GetBits(m_nCoordBits) * (m_ymax - m_ymin) / m_CoordMax;
190 }
191 return pos;
192 }
193
ReadColor()194 std::tuple<FX_FLOAT, FX_FLOAT, FX_FLOAT> CPDF_MeshStream::ReadColor() {
195 ASSERT(ShouldCheckBPC(m_type));
196
197 FX_FLOAT color_value[kMaxComponents];
198 for (uint32_t i = 0; i < m_nComponents; ++i) {
199 color_value[i] = m_ColorMin[i] +
200 m_BitStream.GetBits(m_nComponentBits) *
201 (m_ColorMax[i] - m_ColorMin[i]) / m_ComponentMax;
202 }
203
204 FX_FLOAT r;
205 FX_FLOAT g;
206 FX_FLOAT b;
207 if (m_funcs.empty()) {
208 m_pCS->GetRGB(color_value, r, g, b);
209 return std::tuple<FX_FLOAT, FX_FLOAT, FX_FLOAT>(r, g, b);
210 }
211
212 FX_FLOAT result[kMaxComponents];
213 FXSYS_memset(result, 0, sizeof(result));
214 int nResults;
215 for (const auto& func : m_funcs) {
216 if (func && func->CountOutputs() <= kMaxComponents)
217 func->Call(color_value, 1, result, nResults);
218 }
219
220 m_pCS->GetRGB(result, r, g, b);
221 return std::tuple<FX_FLOAT, FX_FLOAT, FX_FLOAT>(r, g, b);
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 std::tie(vertex->r, vertex->g, vertex->b) = ReadColor();
238 m_BitStream.ByteAlign();
239 return true;
240 }
241
ReadVertexRow(const CFX_Matrix & pObject2Bitmap,int count,CPDF_MeshVertex * vertex)242 bool CPDF_MeshStream::ReadVertexRow(const CFX_Matrix& pObject2Bitmap,
243 int count,
244 CPDF_MeshVertex* vertex) {
245 for (int i = 0; i < count; i++) {
246 if (m_BitStream.IsEOF() || !CanReadCoords())
247 return false;
248
249 vertex[i].position = pObject2Bitmap.Transform(ReadCoords());
250 if (!CanReadColor())
251 return false;
252
253 std::tie(vertex[i].r, vertex[i].g, vertex[i].b) = ReadColor();
254 m_BitStream.ByteAlign();
255 }
256 return true;
257 }
258