xref: /aosp_15_r20/external/pdfium/core/fpdfapi/page/cpdf_meshstream.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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 "third_party/base/check.h"
19 #include "third_party/base/containers/span.h"
20 
21 namespace {
22 
23 // See PDF Reference 1.7, page 315, table 4.32. (Also table 4.33 and 4.34)
ShouldCheckBPC(ShadingType type)24 bool ShouldCheckBPC(ShadingType type) {
25   switch (type) {
26     case kFreeFormGouraudTriangleMeshShading:
27     case kLatticeFormGouraudTriangleMeshShading:
28     case kCoonsPatchMeshShading:
29     case kTensorProductPatchMeshShading:
30       return true;
31     default:
32       return false;
33   }
34 }
35 
36 // Same references as ShouldCheckBPC() above.
IsValidBitsPerComponent(uint32_t x)37 bool IsValidBitsPerComponent(uint32_t x) {
38   switch (x) {
39     case 1:
40     case 2:
41     case 4:
42     case 8:
43     case 12:
44     case 16:
45       return true;
46     default:
47       return false;
48   }
49 }
50 
51 // Same references as ShouldCheckBPC() above.
IsValidBitsPerCoordinate(uint32_t x)52 bool IsValidBitsPerCoordinate(uint32_t x) {
53   switch (x) {
54     case 1:
55     case 2:
56     case 4:
57     case 8:
58     case 12:
59     case 16:
60     case 24:
61     case 32:
62       return true;
63     default:
64       return false;
65   }
66 }
67 
68 // See PDF Reference 1.7, page 315, table 4.32. (Also table 4.34)
ShouldCheckBitsPerFlag(ShadingType type)69 bool ShouldCheckBitsPerFlag(ShadingType type) {
70   switch (type) {
71     case kFreeFormGouraudTriangleMeshShading:
72     case kCoonsPatchMeshShading:
73     case kTensorProductPatchMeshShading:
74       return true;
75     default:
76       return false;
77   }
78 }
79 
80 // Same references as ShouldCheckBitsPerFlag() above.
IsValidBitsPerFlag(uint32_t x)81 bool IsValidBitsPerFlag(uint32_t x) {
82   switch (x) {
83     case 2:
84     case 4:
85     case 8:
86       return true;
87     default:
88       return false;
89   }
90 }
91 
92 }  // namespace
93 
94 CPDF_MeshVertex::CPDF_MeshVertex() = default;
95 
96 CPDF_MeshVertex::CPDF_MeshVertex(const CPDF_MeshVertex&) = default;
97 
98 CPDF_MeshVertex::~CPDF_MeshVertex() = default;
99 
CPDF_MeshStream(ShadingType type,const std::vector<std::unique_ptr<CPDF_Function>> & funcs,RetainPtr<const CPDF_Stream> pShadingStream,RetainPtr<CPDF_ColorSpace> pCS)100 CPDF_MeshStream::CPDF_MeshStream(
101     ShadingType type,
102     const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
103     RetainPtr<const CPDF_Stream> pShadingStream,
104     RetainPtr<CPDF_ColorSpace> pCS)
105     : m_type(type),
106       m_funcs(funcs),
107       m_pShadingStream(std::move(pShadingStream)),
108       m_pCS(std::move(pCS)),
109       m_pStream(pdfium::MakeRetain<CPDF_StreamAcc>(m_pShadingStream)) {}
110 
111 CPDF_MeshStream::~CPDF_MeshStream() = default;
112 
Load()113 bool CPDF_MeshStream::Load() {
114   m_pStream->LoadAllDataFiltered();
115   m_BitStream = std::make_unique<CFX_BitStream>(m_pStream->GetSpan());
116 
117   RetainPtr<const CPDF_Dictionary> pDict = m_pShadingStream->GetDict();
118   m_nCoordBits = pDict->GetIntegerFor("BitsPerCoordinate");
119   m_nComponentBits = pDict->GetIntegerFor("BitsPerComponent");
120   if (ShouldCheckBPC(m_type)) {
121     if (!IsValidBitsPerCoordinate(m_nCoordBits))
122       return false;
123     if (!IsValidBitsPerComponent(m_nComponentBits))
124       return false;
125   }
126 
127   m_nFlagBits = pDict->GetIntegerFor("BitsPerFlag");
128   if (ShouldCheckBitsPerFlag(m_type) && !IsValidBitsPerFlag(m_nFlagBits))
129     return false;
130 
131   uint32_t nComponents = m_pCS->CountComponents();
132   if (nComponents > kMaxComponents)
133     return false;
134 
135   m_nComponents = m_funcs.empty() ? nComponents : 1;
136   RetainPtr<const CPDF_Array> pDecode = pDict->GetArrayFor("Decode");
137   if (!pDecode || pDecode->size() != 4 + m_nComponents * 2)
138     return false;
139 
140   m_xmin = pDecode->GetFloatAt(0);
141   m_xmax = pDecode->GetFloatAt(1);
142   m_ymin = pDecode->GetFloatAt(2);
143   m_ymax = pDecode->GetFloatAt(3);
144   for (uint32_t i = 0; i < m_nComponents; ++i) {
145     m_ColorMin[i] = pDecode->GetFloatAt(i * 2 + 4);
146     m_ColorMax[i] = pDecode->GetFloatAt(i * 2 + 5);
147   }
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()180 uint32_t CPDF_MeshStream::ReadFlag() {
181   DCHECK(ShouldCheckBitsPerFlag(m_type));
182   return m_BitStream->GetBits(m_nFlagBits) & 0x03;
183 }
184 
ReadCoords()185 CFX_PointF CPDF_MeshStream::ReadCoords() {
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()203 std::tuple<float, float, float> CPDF_MeshStream::ReadColor() {
204   DCHECK(ShouldCheckBPC(m_type));
205 
206   float color_value[kMaxComponents];
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 
213   float r = 0.0;
214   float g = 0.0;
215   float b = 0.0;
216   if (m_funcs.empty()) {
217     m_pCS->GetRGB(color_value, &r, &g, &b);
218     return std::tuple<float, float, float>(r, g, b);
219   }
220 
221   float result[kMaxComponents] = {};
222   for (const auto& func : m_funcs) {
223     if (func && func->CountOutputs() <= kMaxComponents)
224       func->Call(pdfium::make_span(color_value, 1), result);
225   }
226 
227   m_pCS->GetRGB(result, &r, &g, &b);
228   return std::tuple<float, float, float>(r, g, b);
229 }
230 
ReadVertex(const CFX_Matrix & pObject2Bitmap,CPDF_MeshVertex * vertex,uint32_t * flag)231 bool CPDF_MeshStream::ReadVertex(const CFX_Matrix& pObject2Bitmap,
232                                  CPDF_MeshVertex* vertex,
233                                  uint32_t* flag) {
234   if (!CanReadFlag())
235     return false;
236   *flag = ReadFlag();
237 
238   if (!CanReadCoords())
239     return false;
240   vertex->position = pObject2Bitmap.Transform(ReadCoords());
241 
242   if (!CanReadColor())
243     return false;
244   std::tie(vertex->r, vertex->g, vertex->b) = ReadColor();
245   m_BitStream->ByteAlign();
246   return true;
247 }
248 
ReadVertexRow(const CFX_Matrix & pObject2Bitmap,int count)249 std::vector<CPDF_MeshVertex> CPDF_MeshStream::ReadVertexRow(
250     const CFX_Matrix& pObject2Bitmap,
251     int count) {
252   std::vector<CPDF_MeshVertex> vertices;
253   for (int i = 0; i < count; ++i) {
254     if (m_BitStream->IsEOF() || !CanReadCoords())
255       return std::vector<CPDF_MeshVertex>();
256 
257     vertices.emplace_back();
258     CPDF_MeshVertex& vertex = vertices.back();
259     vertex.position = pObject2Bitmap.Transform(ReadCoords());
260     if (!CanReadColor())
261       return std::vector<CPDF_MeshVertex>();
262 
263     std::tie(vertex.r, vertex.g, vertex.b) = ReadColor();
264     m_BitStream->ByteAlign();
265   }
266   return vertices;
267 }
268