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 13 namespace { 14 15 // See PDF Reference 1.7, page 315, table 4.32. (Also table 4.33 and 4.34) 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. 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. 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) 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. 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 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 m_pStream(pdfium::MakeRetain<CPDF_StreamAcc>(pShadingStream)) { 112 memset(&m_ColorMin, 0, sizeof(m_ColorMin)); 113 memset(&m_ColorMax, 0, sizeof(m_ColorMax)); 114 } 115 116 CPDF_MeshStream::~CPDF_MeshStream() {} 117 118 bool CPDF_MeshStream::Load() { 119 m_pStream->LoadAllDataFiltered(); 120 m_BitStream = pdfium::MakeUnique<CFX_BitStream>(m_pStream->GetData(), 121 m_pStream->GetSize()); 122 CPDF_Dictionary* pDict = m_pShadingStream->GetDict(); 123 m_nCoordBits = pDict->GetIntegerFor("BitsPerCoordinate"); 124 m_nComponentBits = pDict->GetIntegerFor("BitsPerComponent"); 125 if (ShouldCheckBPC(m_type)) { 126 if (!IsValidBitsPerCoordinate(m_nCoordBits)) 127 return false; 128 if (!IsValidBitsPerComponent(m_nComponentBits)) 129 return false; 130 } 131 132 m_nFlagBits = pDict->GetIntegerFor("BitsPerFlag"); 133 if (ShouldCheckBitsPerFlag(m_type) && !IsValidBitsPerFlag(m_nFlagBits)) 134 return false; 135 136 uint32_t nComponents = m_pCS->CountComponents(); 137 if (nComponents > kMaxComponents) 138 return false; 139 140 m_nComponents = m_funcs.empty() ? nComponents : 1; 141 CPDF_Array* pDecode = pDict->GetArrayFor("Decode"); 142 if (!pDecode || pDecode->GetCount() != 4 + m_nComponents * 2) 143 return false; 144 145 m_xmin = pDecode->GetNumberAt(0); 146 m_xmax = pDecode->GetNumberAt(1); 147 m_ymin = pDecode->GetNumberAt(2); 148 m_ymax = pDecode->GetNumberAt(3); 149 for (uint32_t i = 0; i < m_nComponents; ++i) { 150 m_ColorMin[i] = pDecode->GetNumberAt(i * 2 + 4); 151 m_ColorMax[i] = pDecode->GetNumberAt(i * 2 + 5); 152 } 153 154 if (ShouldCheckBPC(m_type)) { 155 m_CoordMax = m_nCoordBits == 32 ? -1 : (1 << m_nCoordBits) - 1; 156 m_ComponentMax = (1 << m_nComponentBits) - 1; 157 } 158 return true; 159 } 160 161 bool CPDF_MeshStream::CanReadFlag() const { 162 return m_BitStream->BitsRemaining() >= m_nFlagBits; 163 } 164 165 bool CPDF_MeshStream::CanReadCoords() const { 166 return m_BitStream->BitsRemaining() / 2 >= m_nCoordBits; 167 } 168 169 bool CPDF_MeshStream::CanReadColor() const { 170 return m_BitStream->BitsRemaining() / m_nComponentBits >= m_nComponents; 171 } 172 173 uint32_t CPDF_MeshStream::ReadFlag() { 174 ASSERT(ShouldCheckBitsPerFlag(m_type)); 175 return m_BitStream->GetBits(m_nFlagBits) & 0x03; 176 } 177 178 CFX_PointF CPDF_MeshStream::ReadCoords() { 179 ASSERT(ShouldCheckBPC(m_type)); 180 181 CFX_PointF pos; 182 if (m_nCoordBits == 32) { 183 pos.x = m_xmin + m_BitStream->GetBits(m_nCoordBits) * (m_xmax - m_xmin) / 184 static_cast<double>(m_CoordMax); 185 pos.y = m_ymin + m_BitStream->GetBits(m_nCoordBits) * (m_ymax - m_ymin) / 186 static_cast<double>(m_CoordMax); 187 } else { 188 pos.x = m_xmin + 189 m_BitStream->GetBits(m_nCoordBits) * (m_xmax - m_xmin) / m_CoordMax; 190 pos.y = m_ymin + 191 m_BitStream->GetBits(m_nCoordBits) * (m_ymax - m_ymin) / m_CoordMax; 192 } 193 return pos; 194 } 195 196 std::tuple<float, float, float> CPDF_MeshStream::ReadColor() { 197 ASSERT(ShouldCheckBPC(m_type)); 198 199 float color_value[kMaxComponents]; 200 for (uint32_t i = 0; i < m_nComponents; ++i) { 201 color_value[i] = m_ColorMin[i] + m_BitStream->GetBits(m_nComponentBits) * 202 (m_ColorMax[i] - m_ColorMin[i]) / 203 m_ComponentMax; 204 } 205 206 float r = 0.0; 207 float g = 0.0; 208 float b = 0.0; 209 if (m_funcs.empty()) { 210 m_pCS->GetRGB(color_value, &r, &g, &b); 211 return std::tuple<float, float, float>(r, g, b); 212 } 213 214 float result[kMaxComponents]; 215 memset(result, 0, sizeof(result)); 216 int nResults; 217 for (const auto& func : m_funcs) { 218 if (func && func->CountOutputs() <= kMaxComponents) 219 func->Call(color_value, 1, result, &nResults); 220 } 221 222 m_pCS->GetRGB(result, &r, &g, &b); 223 return std::tuple<float, float, float>(r, g, b); 224 } 225 226 bool CPDF_MeshStream::ReadVertex(const CFX_Matrix& pObject2Bitmap, 227 CPDF_MeshVertex* vertex, 228 uint32_t* flag) { 229 if (!CanReadFlag()) 230 return false; 231 *flag = ReadFlag(); 232 233 if (!CanReadCoords()) 234 return false; 235 vertex->position = pObject2Bitmap.Transform(ReadCoords()); 236 237 if (!CanReadColor()) 238 return false; 239 std::tie(vertex->r, vertex->g, vertex->b) = ReadColor(); 240 m_BitStream->ByteAlign(); 241 return true; 242 } 243 244 std::vector<CPDF_MeshVertex> CPDF_MeshStream::ReadVertexRow( 245 const CFX_Matrix& pObject2Bitmap, 246 int count) { 247 std::vector<CPDF_MeshVertex> vertices; 248 for (int i = 0; i < count; ++i) { 249 if (m_BitStream->IsEOF() || !CanReadCoords()) 250 return std::vector<CPDF_MeshVertex>(); 251 252 vertices.push_back(CPDF_MeshVertex()); 253 CPDF_MeshVertex& vertex = vertices.back(); 254 vertex.position = pObject2Bitmap.Transform(ReadCoords()); 255 if (!CanReadColor()) 256 return std::vector<CPDF_MeshVertex>(); 257 258 std::tie(vertex.r, vertex.g, vertex.b) = ReadColor(); 259 m_BitStream->ByteAlign(); 260 } 261 return vertices; 262 } 263