blob: 95f560f59893d6fb21a8e9a475ca7bc240afd44c [file] [log] [blame]
kumarashishg826308d2023-06-23 13:21:22 +00001// Copyright 2016 The PDFium Authors
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -07002// 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
kumarashishg826308d2023-06-23 13:21:22 +00009#include <utility>
10
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -070011#include "core/fpdfapi/page/cpdf_colorspace.h"
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -070012#include "core/fpdfapi/page/cpdf_function.h"
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -070013#include "core/fpdfapi/parser/cpdf_array.h"
Haibo Huang49cc9302020-04-27 16:14:24 -070014#include "core/fpdfapi/parser/cpdf_dictionary.h"
15#include "core/fpdfapi/parser/cpdf_stream.h"
16#include "core/fpdfapi/parser/cpdf_stream_acc.h"
kumarashishg826308d2023-06-23 13:21:22 +000017#include "core/fxcrt/cfx_bitstream.h"
18#include "third_party/base/check.h"
Haibo Huang49cc9302020-04-27 16:14:24 -070019#include "third_party/base/span.h"
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -070020
21namespace {
22
23// See PDF Reference 1.7, page 315, table 4.32. (Also table 4.33 and 4.34)
24bool 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.
37bool 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.
52bool 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)
69bool 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.
81bool 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
Philip P. Moltmann33357ca2017-05-11 09:25:13 -070094CPDF_MeshVertex::CPDF_MeshVertex() = default;
95
96CPDF_MeshVertex::CPDF_MeshVertex(const CPDF_MeshVertex&) = default;
97
98CPDF_MeshVertex::~CPDF_MeshVertex() = default;
99
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700100CPDF_MeshStream::CPDF_MeshStream(
101 ShadingType type,
102 const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
kumarashishg826308d2023-06-23 13:21:22 +0000103 RetainPtr<const CPDF_Stream> pShadingStream,
104 RetainPtr<CPDF_ColorSpace> pCS)
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700105 : m_type(type),
106 m_funcs(funcs),
kumarashishg826308d2023-06-23 13:21:22 +0000107 m_pShadingStream(std::move(pShadingStream)),
108 m_pCS(std::move(pCS)),
109 m_pStream(pdfium::MakeRetain<CPDF_StreamAcc>(m_pShadingStream)) {}
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700110
kumarashishg826308d2023-06-23 13:21:22 +0000111CPDF_MeshStream::~CPDF_MeshStream() = default;
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700112
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700113bool CPDF_MeshStream::Load() {
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700114 m_pStream->LoadAllDataFiltered();
kumarashishg826308d2023-06-23 13:21:22 +0000115 m_BitStream = std::make_unique<CFX_BitStream>(m_pStream->GetSpan());
116
117 RetainPtr<const CPDF_Dictionary> pDict = m_pShadingStream->GetDict();
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700118 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;
kumarashishg826308d2023-06-23 13:21:22 +0000136 RetainPtr<const CPDF_Array> pDecode = pDict->GetArrayFor("Decode");
Haibo Huang49cc9302020-04-27 16:14:24 -0700137 if (!pDecode || pDecode->size() != 4 + m_nComponents * 2)
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700138 return false;
139
kumarashishg826308d2023-06-23 13:21:22 +0000140 m_xmin = pDecode->GetFloatAt(0);
141 m_xmax = pDecode->GetFloatAt(1);
142 m_ymin = pDecode->GetFloatAt(2);
143 m_ymax = pDecode->GetFloatAt(3);
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700144 for (uint32_t i = 0; i < m_nComponents; ++i) {
kumarashishg826308d2023-06-23 13:21:22 +0000145 m_ColorMin[i] = pDecode->GetFloatAt(i * 2 + 4);
146 m_ColorMax[i] = pDecode->GetFloatAt(i * 2 + 5);
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700147 }
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
kumarashishg826308d2023-06-23 13:21:22 +0000156void CPDF_MeshStream::SkipBits(uint32_t nbits) {
157 m_BitStream->SkipBits(nbits);
158}
159
160void CPDF_MeshStream::ByteAlign() {
161 m_BitStream->ByteAlign();
162}
163
164bool CPDF_MeshStream::IsEOF() const {
165 return m_BitStream->IsEOF();
166}
167
Philip P. Moltmann33357ca2017-05-11 09:25:13 -0700168bool CPDF_MeshStream::CanReadFlag() const {
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700169 return m_BitStream->BitsRemaining() >= m_nFlagBits;
Philip P. Moltmann33357ca2017-05-11 09:25:13 -0700170}
171
172bool CPDF_MeshStream::CanReadCoords() const {
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700173 return m_BitStream->BitsRemaining() / 2 >= m_nCoordBits;
Philip P. Moltmann33357ca2017-05-11 09:25:13 -0700174}
175
176bool CPDF_MeshStream::CanReadColor() const {
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700177 return m_BitStream->BitsRemaining() / m_nComponentBits >= m_nComponents;
Philip P. Moltmann33357ca2017-05-11 09:25:13 -0700178}
179
180uint32_t CPDF_MeshStream::ReadFlag() {
kumarashishg826308d2023-06-23 13:21:22 +0000181 DCHECK(ShouldCheckBitsPerFlag(m_type));
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700182 return m_BitStream->GetBits(m_nFlagBits) & 0x03;
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700183}
184
Philip P. Moltmann33357ca2017-05-11 09:25:13 -0700185CFX_PointF CPDF_MeshStream::ReadCoords() {
kumarashishg826308d2023-06-23 13:21:22 +0000186 DCHECK(ShouldCheckBPC(m_type));
Philip P. Moltmann33357ca2017-05-11 09:25:13 -0700187
188 CFX_PointF pos;
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700189 if (m_nCoordBits == 32) {
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700190 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);
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700194 } else {
Philip P. Moltmann33357ca2017-05-11 09:25:13 -0700195 pos.x = m_xmin +
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700196 m_BitStream->GetBits(m_nCoordBits) * (m_xmax - m_xmin) / m_CoordMax;
Philip P. Moltmann33357ca2017-05-11 09:25:13 -0700197 pos.y = m_ymin +
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700198 m_BitStream->GetBits(m_nCoordBits) * (m_ymax - m_ymin) / m_CoordMax;
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700199 }
Philip P. Moltmann33357ca2017-05-11 09:25:13 -0700200 return pos;
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700201}
202
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700203std::tuple<float, float, float> CPDF_MeshStream::ReadColor() {
kumarashishg826308d2023-06-23 13:21:22 +0000204 DCHECK(ShouldCheckBPC(m_type));
Philip P. Moltmann33357ca2017-05-11 09:25:13 -0700205
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700206 float color_value[kMaxComponents];
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700207 for (uint32_t i = 0; i < m_nComponents; ++i) {
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700208 color_value[i] = m_ColorMin[i] + m_BitStream->GetBits(m_nComponentBits) *
209 (m_ColorMax[i] - m_ColorMin[i]) /
210 m_ComponentMax;
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700211 }
Philip P. Moltmann33357ca2017-05-11 09:25:13 -0700212
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700213 float r = 0.0;
214 float g = 0.0;
215 float b = 0.0;
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700216 if (m_funcs.empty()) {
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700217 m_pCS->GetRGB(color_value, &r, &g, &b);
218 return std::tuple<float, float, float>(r, g, b);
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700219 }
220
kumarashishg826308d2023-06-23 13:21:22 +0000221 float result[kMaxComponents] = {};
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700222 for (const auto& func : m_funcs) {
223 if (func && func->CountOutputs() <= kMaxComponents)
kumarashishg826308d2023-06-23 13:21:22 +0000224 func->Call(pdfium::make_span(color_value, 1), result);
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700225 }
Philip P. Moltmann33357ca2017-05-11 09:25:13 -0700226
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700227 m_pCS->GetRGB(result, &r, &g, &b);
228 return std::tuple<float, float, float>(r, g, b);
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700229}
230
Philip P. Moltmann33357ca2017-05-11 09:25:13 -0700231bool 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();
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700245 m_BitStream->ByteAlign();
Philip P. Moltmann33357ca2017-05-11 09:25:13 -0700246 return true;
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700247}
248
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700249std::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>();
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700256
kumarashishg826308d2023-06-23 13:21:22 +0000257 vertices.emplace_back();
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700258 CPDF_MeshVertex& vertex = vertices.back();
259 vertex.position = pObject2Bitmap.Transform(ReadCoords());
Philip P. Moltmann33357ca2017-05-11 09:25:13 -0700260 if (!CanReadColor())
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700261 return std::vector<CPDF_MeshVertex>();
Philip P. Moltmann33357ca2017-05-11 09:25:13 -0700262
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700263 std::tie(vertex.r, vertex.g, vertex.b) = ReadColor();
264 m_BitStream->ByteAlign();
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700265 }
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700266 return vertices;
Philip P. Moltmann4d3acf42017-03-20 11:05:52 -0700267}