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) 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 memset(&m_ColorMin, 0, sizeof(m_ColorMin)); 112 memset(&m_ColorMax, 0, sizeof(m_ColorMax)); 113 } 114 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 157 bool CPDF_MeshStream::CanReadFlag() const { 158 return m_BitStream.BitsRemaining() >= m_nFlagBits; 159 } 160 161 bool CPDF_MeshStream::CanReadCoords() const { 162 return m_BitStream.BitsRemaining() / 2 >= m_nCoordBits; 163 } 164 165 bool CPDF_MeshStream::CanReadColor() const { 166 return m_BitStream.BitsRemaining() / m_nComponentBits >= m_nComponents; 167 } 168 169 uint32_t CPDF_MeshStream::ReadFlag() { 170 ASSERT(ShouldCheckBitsPerFlag(m_type)); 171 return m_BitStream.GetBits(m_nFlagBits) & 0x03; 172 } 173 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 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 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 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