kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 1 | // Copyright 2016 The PDFium Authors |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 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 | |
kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 9 | #include <utility> |
| 10 | |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 11 | #include "core/fpdfapi/page/cpdf_colorspace.h" |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 12 | #include "core/fpdfapi/page/cpdf_function.h" |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 13 | #include "core/fpdfapi/parser/cpdf_array.h" |
Haibo Huang | 49cc930 | 2020-04-27 16:14:24 -0700 | [diff] [blame] | 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" |
kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 17 | #include "core/fxcrt/cfx_bitstream.h" |
| 18 | #include "third_party/base/check.h" |
Haibo Huang | 49cc930 | 2020-04-27 16:14:24 -0700 | [diff] [blame] | 19 | #include "third_party/base/span.h" |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 20 | |
| 21 | namespace { |
| 22 | |
| 23 | // See PDF Reference 1.7, page 315, table 4.32. (Also table 4.33 and 4.34) |
| 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. |
| 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. |
| 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) |
| 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. |
| 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 | |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 94 | CPDF_MeshVertex::CPDF_MeshVertex() = default; |
| 95 | |
| 96 | CPDF_MeshVertex::CPDF_MeshVertex(const CPDF_MeshVertex&) = default; |
| 97 | |
| 98 | CPDF_MeshVertex::~CPDF_MeshVertex() = default; |
| 99 | |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 100 | CPDF_MeshStream::CPDF_MeshStream( |
| 101 | ShadingType type, |
| 102 | const std::vector<std::unique_ptr<CPDF_Function>>& funcs, |
kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 103 | RetainPtr<const CPDF_Stream> pShadingStream, |
| 104 | RetainPtr<CPDF_ColorSpace> pCS) |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 105 | : m_type(type), |
| 106 | m_funcs(funcs), |
kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 107 | m_pShadingStream(std::move(pShadingStream)), |
| 108 | m_pCS(std::move(pCS)), |
| 109 | m_pStream(pdfium::MakeRetain<CPDF_StreamAcc>(m_pShadingStream)) {} |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 110 | |
kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 111 | CPDF_MeshStream::~CPDF_MeshStream() = default; |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 112 | |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 113 | bool CPDF_MeshStream::Load() { |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 114 | m_pStream->LoadAllDataFiltered(); |
kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 115 | m_BitStream = std::make_unique<CFX_BitStream>(m_pStream->GetSpan()); |
| 116 | |
| 117 | RetainPtr<const CPDF_Dictionary> pDict = m_pShadingStream->GetDict(); |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 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; |
kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 136 | RetainPtr<const CPDF_Array> pDecode = pDict->GetArrayFor("Decode"); |
Haibo Huang | 49cc930 | 2020-04-27 16:14:24 -0700 | [diff] [blame] | 137 | if (!pDecode || pDecode->size() != 4 + m_nComponents * 2) |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 138 | return false; |
| 139 | |
kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 140 | 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. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 144 | for (uint32_t i = 0; i < m_nComponents; ++i) { |
kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 145 | m_ColorMin[i] = pDecode->GetFloatAt(i * 2 + 4); |
| 146 | m_ColorMax[i] = pDecode->GetFloatAt(i * 2 + 5); |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 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 | |
kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 156 | void CPDF_MeshStream::SkipBits(uint32_t nbits) { |
| 157 | m_BitStream->SkipBits(nbits); |
| 158 | } |
| 159 | |
| 160 | void CPDF_MeshStream::ByteAlign() { |
| 161 | m_BitStream->ByteAlign(); |
| 162 | } |
| 163 | |
| 164 | bool CPDF_MeshStream::IsEOF() const { |
| 165 | return m_BitStream->IsEOF(); |
| 166 | } |
| 167 | |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 168 | bool CPDF_MeshStream::CanReadFlag() const { |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 169 | return m_BitStream->BitsRemaining() >= m_nFlagBits; |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 170 | } |
| 171 | |
| 172 | bool CPDF_MeshStream::CanReadCoords() const { |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 173 | return m_BitStream->BitsRemaining() / 2 >= m_nCoordBits; |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 174 | } |
| 175 | |
| 176 | bool CPDF_MeshStream::CanReadColor() const { |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 177 | return m_BitStream->BitsRemaining() / m_nComponentBits >= m_nComponents; |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 178 | } |
| 179 | |
| 180 | uint32_t CPDF_MeshStream::ReadFlag() { |
kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 181 | DCHECK(ShouldCheckBitsPerFlag(m_type)); |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 182 | return m_BitStream->GetBits(m_nFlagBits) & 0x03; |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 183 | } |
| 184 | |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 185 | CFX_PointF CPDF_MeshStream::ReadCoords() { |
kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 186 | DCHECK(ShouldCheckBPC(m_type)); |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 187 | |
| 188 | CFX_PointF pos; |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 189 | if (m_nCoordBits == 32) { |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 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); |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 194 | } else { |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 195 | pos.x = m_xmin + |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 196 | m_BitStream->GetBits(m_nCoordBits) * (m_xmax - m_xmin) / m_CoordMax; |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 197 | pos.y = m_ymin + |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 198 | m_BitStream->GetBits(m_nCoordBits) * (m_ymax - m_ymin) / m_CoordMax; |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 199 | } |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 200 | return pos; |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 201 | } |
| 202 | |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 203 | std::tuple<float, float, float> CPDF_MeshStream::ReadColor() { |
kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 204 | DCHECK(ShouldCheckBPC(m_type)); |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 205 | |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 206 | float color_value[kMaxComponents]; |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 207 | for (uint32_t i = 0; i < m_nComponents; ++i) { |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 208 | color_value[i] = m_ColorMin[i] + m_BitStream->GetBits(m_nComponentBits) * |
| 209 | (m_ColorMax[i] - m_ColorMin[i]) / |
| 210 | m_ComponentMax; |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 211 | } |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 212 | |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 213 | float r = 0.0; |
| 214 | float g = 0.0; |
| 215 | float b = 0.0; |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 216 | if (m_funcs.empty()) { |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 217 | m_pCS->GetRGB(color_value, &r, &g, &b); |
| 218 | return std::tuple<float, float, float>(r, g, b); |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 219 | } |
| 220 | |
kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 221 | float result[kMaxComponents] = {}; |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 222 | for (const auto& func : m_funcs) { |
| 223 | if (func && func->CountOutputs() <= kMaxComponents) |
kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 224 | func->Call(pdfium::make_span(color_value, 1), result); |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 225 | } |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 226 | |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 227 | m_pCS->GetRGB(result, &r, &g, &b); |
| 228 | return std::tuple<float, float, float>(r, g, b); |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 229 | } |
| 230 | |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 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(); |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 245 | m_BitStream->ByteAlign(); |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 246 | return true; |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 247 | } |
| 248 | |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 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>(); |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 256 | |
kumarashishg | 826308d | 2023-06-23 13:21:22 +0000 | [diff] [blame] | 257 | vertices.emplace_back(); |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 258 | CPDF_MeshVertex& vertex = vertices.back(); |
| 259 | vertex.position = pObject2Bitmap.Transform(ReadCoords()); |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 260 | if (!CanReadColor()) |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 261 | return std::vector<CPDF_MeshVertex>(); |
Philip P. Moltmann | 33357ca | 2017-05-11 09:25:13 -0700 | [diff] [blame] | 262 | |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 263 | std::tie(vertex.r, vertex.g, vertex.b) = ReadColor(); |
| 264 | m_BitStream->ByteAlign(); |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 265 | } |
Philip P. Moltmann | d904c1e | 2018-03-19 09:26:45 -0700 | [diff] [blame] | 266 | return vertices; |
Philip P. Moltmann | 4d3acf4 | 2017-03-20 11:05:52 -0700 | [diff] [blame] | 267 | } |