1 // Copyright 2014 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 "pageint.h" 8 9 #include "core/include/fpdfapi/fpdf_page.h" 10 11 namespace { 12 13 const int kSingleCoordinatePair = 1; 14 const int kTensorCoordinatePairs = 16; 15 const int kCoonsCoordinatePairs = 12; 16 17 const int kSingleColorPerPatch = 1; 18 const int kQuadColorsPerPatch = 4; 19 20 ShadingType ToShadingType(int type) { 21 return (type > static_cast<int>(kInvalidShading) && 22 type < static_cast<int>(kMaxShading)) 23 ? static_cast<ShadingType>(type) 24 : kInvalidShading; 25 } 26 27 } // namespace 28 29 CPDF_Pattern::CPDF_Pattern(PatternType type, 30 CPDF_Document* pDoc, 31 CPDF_Object* pObj, 32 const CFX_Matrix* pParentMatrix) 33 : m_PatternType(type), 34 m_pDocument(pDoc), 35 m_pPatternObj(pObj), 36 m_bForceClear(FALSE) { 37 if (pParentMatrix) 38 m_ParentMatrix = *pParentMatrix; 39 } 40 CPDF_Pattern::~CPDF_Pattern() {} 41 CPDF_TilingPattern::CPDF_TilingPattern(CPDF_Document* pDoc, 42 CPDF_Object* pPatternObj, 43 const CFX_Matrix* parentMatrix) 44 : CPDF_Pattern(TILING, pDoc, pPatternObj, parentMatrix) { 45 CPDF_Dictionary* pDict = m_pPatternObj->GetDict(); 46 m_Pattern2Form = pDict->GetMatrix("Matrix"); 47 m_bColored = pDict->GetInteger("PaintType") == 1; 48 if (parentMatrix) { 49 m_Pattern2Form.Concat(*parentMatrix); 50 } 51 m_pForm = NULL; 52 } 53 CPDF_TilingPattern::~CPDF_TilingPattern() { 54 delete m_pForm; 55 m_pForm = NULL; 56 } 57 FX_BOOL CPDF_TilingPattern::Load() { 58 if (m_pForm) 59 return TRUE; 60 61 CPDF_Dictionary* pDict = m_pPatternObj->GetDict(); 62 if (!pDict) 63 return FALSE; 64 65 m_bColored = pDict->GetInteger("PaintType") == 1; 66 m_XStep = (FX_FLOAT)FXSYS_fabs(pDict->GetNumber("XStep")); 67 m_YStep = (FX_FLOAT)FXSYS_fabs(pDict->GetNumber("YStep")); 68 69 CPDF_Stream* pStream = m_pPatternObj->AsStream(); 70 if (!pStream) 71 return FALSE; 72 73 m_pForm = new CPDF_Form(m_pDocument, NULL, pStream); 74 m_pForm->ParseContent(NULL, &m_ParentMatrix, NULL, NULL); 75 m_BBox = pDict->GetRect("BBox"); 76 return TRUE; 77 } 78 CPDF_ShadingPattern::CPDF_ShadingPattern(CPDF_Document* pDoc, 79 CPDF_Object* pPatternObj, 80 FX_BOOL bShading, 81 const CFX_Matrix* parentMatrix) 82 : CPDF_Pattern(SHADING, 83 pDoc, 84 bShading ? nullptr : pPatternObj, 85 parentMatrix), 86 m_ShadingType(kInvalidShading), 87 m_bShadingObj(bShading), 88 m_pShadingObj(pPatternObj), 89 m_pCS(nullptr), 90 m_pCountedCS(nullptr), 91 m_nFuncs(0) { 92 if (!bShading) { 93 CPDF_Dictionary* pDict = m_pPatternObj->GetDict(); 94 m_Pattern2Form = pDict->GetMatrix("Matrix"); 95 m_pShadingObj = pDict->GetElementValue("Shading"); 96 if (parentMatrix) 97 m_Pattern2Form.Concat(*parentMatrix); 98 } 99 for (int i = 0; i < FX_ArraySize(m_pFunctions); ++i) 100 m_pFunctions[i] = nullptr; 101 } 102 103 CPDF_ShadingPattern::~CPDF_ShadingPattern() { 104 for (int i = 0; i < m_nFuncs; ++i) 105 delete m_pFunctions[i]; 106 107 CPDF_ColorSpace* pCS = m_pCountedCS ? m_pCountedCS->get() : NULL; 108 if (pCS && m_pDocument) 109 m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray()); 110 } 111 112 FX_BOOL CPDF_ShadingPattern::Load() { 113 if (m_ShadingType != kInvalidShading) 114 return TRUE; 115 116 CPDF_Dictionary* pShadingDict = 117 m_pShadingObj ? m_pShadingObj->GetDict() : NULL; 118 if (!pShadingDict) { 119 return FALSE; 120 } 121 if (m_nFuncs) { 122 for (int i = 0; i < m_nFuncs; i++) 123 delete m_pFunctions[i]; 124 m_nFuncs = 0; 125 } 126 CPDF_Object* pFunc = pShadingDict->GetElementValue("Function"); 127 if (pFunc) { 128 if (CPDF_Array* pArray = pFunc->AsArray()) { 129 m_nFuncs = std::min<int>(pArray->GetCount(), 4); 130 131 for (int i = 0; i < m_nFuncs; i++) { 132 m_pFunctions[i] = CPDF_Function::Load(pArray->GetElementValue(i)); 133 } 134 } else { 135 m_pFunctions[0] = CPDF_Function::Load(pFunc); 136 m_nFuncs = 1; 137 } 138 } 139 CPDF_Object* pCSObj = pShadingDict->GetElementValue("ColorSpace"); 140 if (!pCSObj) { 141 return FALSE; 142 } 143 CPDF_DocPageData* pDocPageData = m_pDocument->GetPageData(); 144 m_pCS = pDocPageData->GetColorSpace(pCSObj, NULL); 145 if (m_pCS) { 146 m_pCountedCS = pDocPageData->FindColorSpacePtr(m_pCS->GetArray()); 147 } 148 149 m_ShadingType = ToShadingType(pShadingDict->GetInteger("ShadingType")); 150 151 // We expect to have a stream if our shading type is a mesh. 152 if (IsMeshShading() && !ToStream(m_pShadingObj)) 153 return FALSE; 154 155 return TRUE; 156 } 157 FX_BOOL CPDF_MeshStream::Load(CPDF_Stream* pShadingStream, 158 CPDF_Function** pFuncs, 159 int nFuncs, 160 CPDF_ColorSpace* pCS) { 161 m_Stream.LoadAllData(pShadingStream); 162 m_BitStream.Init(m_Stream.GetData(), m_Stream.GetSize()); 163 m_pFuncs = pFuncs; 164 m_nFuncs = nFuncs; 165 m_pCS = pCS; 166 CPDF_Dictionary* pDict = pShadingStream->GetDict(); 167 m_nCoordBits = pDict->GetInteger("BitsPerCoordinate"); 168 m_nCompBits = pDict->GetInteger("BitsPerComponent"); 169 m_nFlagBits = pDict->GetInteger("BitsPerFlag"); 170 if (!m_nCoordBits || !m_nCompBits) { 171 return FALSE; 172 } 173 int nComps = pCS->CountComponents(); 174 if (nComps > 8) { 175 return FALSE; 176 } 177 m_nComps = nFuncs ? 1 : nComps; 178 if (((int)m_nComps < 0) || m_nComps > 8) { 179 return FALSE; 180 } 181 m_CoordMax = m_nCoordBits == 32 ? -1 : (1 << m_nCoordBits) - 1; 182 m_CompMax = (1 << m_nCompBits) - 1; 183 CPDF_Array* pDecode = pDict->GetArray("Decode"); 184 if (!pDecode || pDecode->GetCount() != 4 + m_nComps * 2) { 185 return FALSE; 186 } 187 m_xmin = pDecode->GetNumber(0); 188 m_xmax = pDecode->GetNumber(1); 189 m_ymin = pDecode->GetNumber(2); 190 m_ymax = pDecode->GetNumber(3); 191 for (FX_DWORD i = 0; i < m_nComps; i++) { 192 m_ColorMin[i] = pDecode->GetNumber(i * 2 + 4); 193 m_ColorMax[i] = pDecode->GetNumber(i * 2 + 5); 194 } 195 return TRUE; 196 } 197 FX_DWORD CPDF_MeshStream::GetFlag() { 198 return m_BitStream.GetBits(m_nFlagBits) & 0x03; 199 } 200 void CPDF_MeshStream::GetCoords(FX_FLOAT& x, FX_FLOAT& y) { 201 if (m_nCoordBits == 32) { 202 x = m_xmin + (FX_FLOAT)(m_BitStream.GetBits(m_nCoordBits) * 203 (m_xmax - m_xmin) / (double)m_CoordMax); 204 y = m_ymin + (FX_FLOAT)(m_BitStream.GetBits(m_nCoordBits) * 205 (m_ymax - m_ymin) / (double)m_CoordMax); 206 } else { 207 x = m_xmin + 208 m_BitStream.GetBits(m_nCoordBits) * (m_xmax - m_xmin) / m_CoordMax; 209 y = m_ymin + 210 m_BitStream.GetBits(m_nCoordBits) * (m_ymax - m_ymin) / m_CoordMax; 211 } 212 } 213 void CPDF_MeshStream::GetColor(FX_FLOAT& r, FX_FLOAT& g, FX_FLOAT& b) { 214 FX_DWORD i; 215 FX_FLOAT color_value[8]; 216 for (i = 0; i < m_nComps; i++) { 217 color_value[i] = m_ColorMin[i] + 218 m_BitStream.GetBits(m_nCompBits) * 219 (m_ColorMax[i] - m_ColorMin[i]) / m_CompMax; 220 } 221 if (m_nFuncs) { 222 static const int kMaxResults = 8; 223 FX_FLOAT result[kMaxResults]; 224 int nResults; 225 FXSYS_memset(result, 0, sizeof(result)); 226 for (FX_DWORD i = 0; i < m_nFuncs; i++) { 227 if (m_pFuncs[i] && m_pFuncs[i]->CountOutputs() <= kMaxResults) { 228 m_pFuncs[i]->Call(color_value, 1, result, nResults); 229 } 230 } 231 m_pCS->GetRGB(result, r, g, b); 232 } else { 233 m_pCS->GetRGB(color_value, r, g, b); 234 } 235 } 236 FX_DWORD CPDF_MeshStream::GetVertex(CPDF_MeshVertex& vertex, 237 CFX_Matrix* pObject2Bitmap) { 238 FX_DWORD flag = GetFlag(); 239 GetCoords(vertex.x, vertex.y); 240 pObject2Bitmap->Transform(vertex.x, vertex.y); 241 GetColor(vertex.r, vertex.g, vertex.b); 242 m_BitStream.ByteAlign(); 243 return flag; 244 } 245 FX_BOOL CPDF_MeshStream::GetVertexRow(CPDF_MeshVertex* vertex, 246 int count, 247 CFX_Matrix* pObject2Bitmap) { 248 for (int i = 0; i < count; i++) { 249 if (m_BitStream.IsEOF()) { 250 return FALSE; 251 } 252 GetCoords(vertex[i].x, vertex[i].y); 253 pObject2Bitmap->Transform(vertex[i].x, vertex[i].y); 254 GetColor(vertex[i].r, vertex[i].g, vertex[i].b); 255 m_BitStream.ByteAlign(); 256 } 257 return TRUE; 258 } 259 260 CFX_FloatRect GetShadingBBox(CPDF_Stream* pStream, 261 ShadingType type, 262 const CFX_Matrix* pMatrix, 263 CPDF_Function** pFuncs, 264 int nFuncs, 265 CPDF_ColorSpace* pCS) { 266 if (!pStream || !pStream->IsStream() || !pFuncs || !pCS) 267 return CFX_FloatRect(0, 0, 0, 0); 268 269 CPDF_MeshStream stream; 270 if (!stream.Load(pStream, pFuncs, nFuncs, pCS)) 271 return CFX_FloatRect(0, 0, 0, 0); 272 273 CFX_FloatRect rect; 274 FX_BOOL bStarted = FALSE; 275 FX_BOOL bGouraud = type == kFreeFormGouraudTriangleMeshShading || 276 type == kLatticeFormGouraudTriangleMeshShading; 277 278 int point_count = kSingleCoordinatePair; 279 if (type == kTensorProductPatchMeshShading) 280 point_count = kTensorCoordinatePairs; 281 else if (type == kCoonsPatchMeshShading) 282 point_count = kCoonsCoordinatePairs; 283 284 int color_count = kSingleColorPerPatch; 285 if (type == kCoonsPatchMeshShading || type == kTensorProductPatchMeshShading) 286 color_count = kQuadColorsPerPatch; 287 288 while (!stream.m_BitStream.IsEOF()) { 289 FX_DWORD flag = 0; 290 if (type != kLatticeFormGouraudTriangleMeshShading) 291 flag = stream.GetFlag(); 292 293 if (!bGouraud && flag) { 294 point_count -= 4; 295 color_count -= 2; 296 } 297 298 for (int i = 0; i < point_count; i++) { 299 FX_FLOAT x, y; 300 stream.GetCoords(x, y); 301 if (bStarted) { 302 rect.UpdateRect(x, y); 303 } else { 304 rect.InitRect(x, y); 305 bStarted = TRUE; 306 } 307 } 308 stream.m_BitStream.SkipBits(stream.m_nComps * stream.m_nCompBits * 309 color_count); 310 if (bGouraud) 311 stream.m_BitStream.ByteAlign(); 312 } 313 rect.Transform(pMatrix); 314 return rect; 315 } 316