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 "core/fpdfapi/page/cpdf_docpagedata.h" 8 9 #include <algorithm> 10 #include <memory> 11 #include <set> 12 #include <utility> 13 14 #include "core/fdrm/crypto/fx_crypt.h" 15 #include "core/fpdfapi/cpdf_modulemgr.h" 16 #include "core/fpdfapi/font/cpdf_type1font.h" 17 #include "core/fpdfapi/font/font_int.h" 18 #include "core/fpdfapi/page/cpdf_image.h" 19 #include "core/fpdfapi/page/cpdf_pagemodule.h" 20 #include "core/fpdfapi/page/cpdf_pattern.h" 21 #include "core/fpdfapi/page/cpdf_shadingpattern.h" 22 #include "core/fpdfapi/page/cpdf_tilingpattern.h" 23 #include "core/fpdfapi/parser/cpdf_array.h" 24 #include "core/fpdfapi/parser/cpdf_dictionary.h" 25 #include "core/fpdfapi/parser/cpdf_document.h" 26 #include "core/fpdfapi/parser/cpdf_name.h" 27 #include "core/fpdfapi/parser/cpdf_stream_acc.h" 28 #include "third_party/base/stl_util.h" 29 30 CPDF_DocPageData::CPDF_DocPageData(CPDF_Document* pPDFDoc) 31 : m_pPDFDoc(pPDFDoc), m_bForceClear(false) {} 32 33 CPDF_DocPageData::~CPDF_DocPageData() { 34 Clear(false); 35 Clear(true); 36 37 for (auto& it : m_PatternMap) 38 delete it.second; 39 m_PatternMap.clear(); 40 41 for (auto& it : m_FontMap) 42 delete it.second; 43 m_FontMap.clear(); 44 45 for (auto& it : m_ColorSpaceMap) 46 delete it.second; 47 m_ColorSpaceMap.clear(); 48 } 49 50 void CPDF_DocPageData::Clear(bool bForceRelease) { 51 m_bForceClear = bForceRelease; 52 53 for (auto& it : m_PatternMap) { 54 CPDF_CountedPattern* ptData = it.second; 55 if (!ptData->get()) 56 continue; 57 58 if (bForceRelease || ptData->use_count() < 2) 59 ptData->clear(); 60 } 61 62 for (auto& it : m_FontMap) { 63 CPDF_CountedFont* fontData = it.second; 64 if (!fontData->get()) 65 continue; 66 67 if (bForceRelease || fontData->use_count() < 2) { 68 fontData->clear(); 69 } 70 } 71 72 for (auto& it : m_ColorSpaceMap) { 73 CPDF_CountedColorSpace* csData = it.second; 74 if (!csData->get()) 75 continue; 76 77 if (bForceRelease || csData->use_count() < 2) { 78 csData->get()->Release(); 79 csData->reset(nullptr); 80 } 81 } 82 83 for (auto it = m_IccProfileMap.begin(); it != m_IccProfileMap.end();) { 84 auto curr_it = it++; 85 CPDF_CountedIccProfile* ipData = curr_it->second; 86 if (!ipData->get()) 87 continue; 88 89 if (bForceRelease || ipData->use_count() < 2) { 90 for (auto hash_it = m_HashProfileMap.begin(); 91 hash_it != m_HashProfileMap.end(); ++hash_it) { 92 if (curr_it->first == hash_it->second) { 93 m_HashProfileMap.erase(hash_it); 94 break; 95 } 96 } 97 delete ipData->get(); 98 delete ipData; 99 m_IccProfileMap.erase(curr_it); 100 } 101 } 102 103 for (auto it = m_FontFileMap.begin(); it != m_FontFileMap.end();) { 104 auto curr_it = it++; 105 CPDF_CountedStreamAcc* pCountedFont = curr_it->second; 106 if (!pCountedFont->get()) 107 continue; 108 109 if (bForceRelease || pCountedFont->use_count() < 2) { 110 delete pCountedFont->get(); 111 delete pCountedFont; 112 m_FontFileMap.erase(curr_it); 113 } 114 } 115 116 for (auto it = m_ImageMap.begin(); it != m_ImageMap.end();) { 117 auto curr_it = it++; 118 CPDF_CountedImage* pCountedImage = curr_it->second; 119 if (!pCountedImage->get()) 120 continue; 121 122 if (bForceRelease || pCountedImage->use_count() < 2) { 123 delete pCountedImage->get(); 124 delete pCountedImage; 125 m_ImageMap.erase(curr_it); 126 } 127 } 128 } 129 130 CPDF_Font* CPDF_DocPageData::GetFont(CPDF_Dictionary* pFontDict) { 131 if (!pFontDict) 132 return nullptr; 133 134 CPDF_CountedFont* pFontData = nullptr; 135 auto it = m_FontMap.find(pFontDict); 136 if (it != m_FontMap.end()) { 137 pFontData = it->second; 138 if (pFontData->get()) { 139 return pFontData->AddRef(); 140 } 141 } 142 std::unique_ptr<CPDF_Font> pFont = CPDF_Font::Create(m_pPDFDoc, pFontDict); 143 if (!pFont) 144 return nullptr; 145 146 if (pFontData) { 147 pFontData->reset(std::move(pFont)); 148 } else { 149 pFontData = new CPDF_CountedFont(std::move(pFont)); 150 m_FontMap[pFontDict] = pFontData; 151 } 152 return pFontData->AddRef(); 153 } 154 155 CPDF_Font* CPDF_DocPageData::GetStandardFont(const CFX_ByteString& fontName, 156 CPDF_FontEncoding* pEncoding) { 157 if (fontName.IsEmpty()) 158 return nullptr; 159 160 for (auto& it : m_FontMap) { 161 CPDF_CountedFont* fontData = it.second; 162 CPDF_Font* pFont = fontData->get(); 163 if (!pFont) 164 continue; 165 if (pFont->GetBaseFont() != fontName) 166 continue; 167 if (pFont->IsEmbedded()) 168 continue; 169 if (!pFont->IsType1Font()) 170 continue; 171 if (pFont->GetFontDict()->KeyExist("Widths")) 172 continue; 173 174 CPDF_Type1Font* pT1Font = pFont->AsType1Font(); 175 if (pEncoding && !pT1Font->GetEncoding()->IsIdentical(pEncoding)) 176 continue; 177 178 return fontData->AddRef(); 179 } 180 181 CPDF_Dictionary* pDict = m_pPDFDoc->NewIndirect<CPDF_Dictionary>(); 182 pDict->SetNewFor<CPDF_Name>("Type", "Font"); 183 pDict->SetNewFor<CPDF_Name>("Subtype", "Type1"); 184 pDict->SetNewFor<CPDF_Name>("BaseFont", fontName); 185 if (pEncoding) { 186 pDict->SetFor("Encoding", 187 pEncoding->Realize(m_pPDFDoc->GetByteStringPool())); 188 } 189 190 std::unique_ptr<CPDF_Font> pFont = CPDF_Font::Create(m_pPDFDoc, pDict); 191 if (!pFont) 192 return nullptr; 193 194 CPDF_CountedFont* fontData = new CPDF_CountedFont(std::move(pFont)); 195 m_FontMap[pDict] = fontData; 196 return fontData->AddRef(); 197 } 198 199 void CPDF_DocPageData::ReleaseFont(const CPDF_Dictionary* pFontDict) { 200 if (!pFontDict) 201 return; 202 203 auto it = m_FontMap.find(pFontDict); 204 if (it == m_FontMap.end()) 205 return; 206 207 CPDF_CountedFont* pFontData = it->second; 208 if (!pFontData->get()) 209 return; 210 211 pFontData->RemoveRef(); 212 if (pFontData->use_count() > 1) 213 return; 214 215 // We have font data only in m_FontMap cache. Clean it. 216 pFontData->clear(); 217 } 218 219 CPDF_ColorSpace* CPDF_DocPageData::GetColorSpace( 220 CPDF_Object* pCSObj, 221 const CPDF_Dictionary* pResources) { 222 std::set<CPDF_Object*> visited; 223 return GetColorSpaceImpl(pCSObj, pResources, &visited); 224 } 225 226 CPDF_ColorSpace* CPDF_DocPageData::GetColorSpaceImpl( 227 CPDF_Object* pCSObj, 228 const CPDF_Dictionary* pResources, 229 std::set<CPDF_Object*>* pVisited) { 230 if (!pCSObj) 231 return nullptr; 232 233 if (pdfium::ContainsKey(*pVisited, pCSObj)) 234 return nullptr; 235 236 if (pCSObj->IsName()) { 237 CFX_ByteString name = pCSObj->GetString(); 238 CPDF_ColorSpace* pCS = CPDF_ColorSpace::ColorspaceFromName(name); 239 if (!pCS && pResources) { 240 CPDF_Dictionary* pList = pResources->GetDictFor("ColorSpace"); 241 if (pList) { 242 pdfium::ScopedSetInsertion<CPDF_Object*> insertion(pVisited, pCSObj); 243 return GetColorSpaceImpl(pList->GetDirectObjectFor(name), nullptr, 244 pVisited); 245 } 246 } 247 if (!pCS || !pResources) 248 return pCS; 249 250 CPDF_Dictionary* pColorSpaces = pResources->GetDictFor("ColorSpace"); 251 if (!pColorSpaces) 252 return pCS; 253 254 CPDF_Object* pDefaultCS = nullptr; 255 switch (pCS->GetFamily()) { 256 case PDFCS_DEVICERGB: 257 pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultRGB"); 258 break; 259 case PDFCS_DEVICEGRAY: 260 pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultGray"); 261 break; 262 case PDFCS_DEVICECMYK: 263 pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultCMYK"); 264 break; 265 } 266 if (!pDefaultCS) 267 return pCS; 268 269 pdfium::ScopedSetInsertion<CPDF_Object*> insertion(pVisited, pCSObj); 270 return GetColorSpaceImpl(pDefaultCS, nullptr, pVisited); 271 } 272 273 CPDF_Array* pArray = pCSObj->AsArray(); 274 if (!pArray || pArray->IsEmpty()) 275 return nullptr; 276 277 if (pArray->GetCount() == 1) { 278 pdfium::ScopedSetInsertion<CPDF_Object*> insertion(pVisited, pCSObj); 279 return GetColorSpaceImpl(pArray->GetDirectObjectAt(0), pResources, 280 pVisited); 281 } 282 283 CPDF_CountedColorSpace* csData = nullptr; 284 auto it = m_ColorSpaceMap.find(pCSObj); 285 if (it != m_ColorSpaceMap.end()) { 286 csData = it->second; 287 if (csData->get()) { 288 return csData->AddRef(); 289 } 290 } 291 292 std::unique_ptr<CPDF_ColorSpace> pCS = 293 CPDF_ColorSpace::Load(m_pPDFDoc, pArray); 294 if (!pCS) 295 return nullptr; 296 297 if (csData) { 298 csData->reset(std::move(pCS)); 299 } else { 300 csData = new CPDF_CountedColorSpace(std::move(pCS)); 301 m_ColorSpaceMap[pCSObj] = csData; 302 } 303 return csData->AddRef(); 304 } 305 306 CPDF_ColorSpace* CPDF_DocPageData::GetCopiedColorSpace(CPDF_Object* pCSObj) { 307 if (!pCSObj) 308 return nullptr; 309 310 auto it = m_ColorSpaceMap.find(pCSObj); 311 if (it != m_ColorSpaceMap.end()) 312 return it->second->AddRef(); 313 314 return nullptr; 315 } 316 317 void CPDF_DocPageData::ReleaseColorSpace(const CPDF_Object* pColorSpace) { 318 if (!pColorSpace) 319 return; 320 321 auto it = m_ColorSpaceMap.find(pColorSpace); 322 if (it == m_ColorSpaceMap.end()) 323 return; 324 325 CPDF_CountedColorSpace* pCountedColorSpace = it->second; 326 if (!pCountedColorSpace->get()) 327 return; 328 329 pCountedColorSpace->RemoveRef(); 330 if (pCountedColorSpace->use_count() > 1) 331 return; 332 333 // We have item only in m_ColorSpaceMap cache. Clean it. 334 pCountedColorSpace->get()->Release(); 335 pCountedColorSpace->reset(nullptr); 336 } 337 338 CPDF_Pattern* CPDF_DocPageData::GetPattern(CPDF_Object* pPatternObj, 339 bool bShading, 340 const CFX_Matrix& matrix) { 341 if (!pPatternObj) 342 return nullptr; 343 344 CPDF_CountedPattern* ptData = nullptr; 345 auto it = m_PatternMap.find(pPatternObj); 346 if (it != m_PatternMap.end()) { 347 ptData = it->second; 348 if (ptData->get()) { 349 return ptData->AddRef(); 350 } 351 } 352 std::unique_ptr<CPDF_Pattern> pPattern; 353 if (bShading) { 354 pPattern = pdfium::MakeUnique<CPDF_ShadingPattern>(m_pPDFDoc, pPatternObj, 355 true, matrix); 356 } else { 357 CPDF_Dictionary* pDict = pPatternObj ? pPatternObj->GetDict() : nullptr; 358 if (pDict) { 359 int type = pDict->GetIntegerFor("PatternType"); 360 if (type == CPDF_Pattern::TILING) { 361 pPattern = pdfium::MakeUnique<CPDF_TilingPattern>(m_pPDFDoc, 362 pPatternObj, matrix); 363 } else if (type == CPDF_Pattern::SHADING) { 364 pPattern = pdfium::MakeUnique<CPDF_ShadingPattern>( 365 m_pPDFDoc, pPatternObj, false, matrix); 366 } 367 } 368 } 369 if (!pPattern) 370 return nullptr; 371 372 if (ptData) { 373 ptData->reset(std::move(pPattern)); 374 } else { 375 ptData = new CPDF_CountedPattern(std::move(pPattern)); 376 m_PatternMap[pPatternObj] = ptData; 377 } 378 return ptData->AddRef(); 379 } 380 381 void CPDF_DocPageData::ReleasePattern(const CPDF_Object* pPatternObj) { 382 if (!pPatternObj) 383 return; 384 385 auto it = m_PatternMap.find(pPatternObj); 386 if (it == m_PatternMap.end()) 387 return; 388 389 CPDF_CountedPattern* pPattern = it->second; 390 if (!pPattern->get()) 391 return; 392 393 pPattern->RemoveRef(); 394 if (pPattern->use_count() > 1) 395 return; 396 397 // We have item only in m_PatternMap cache. Clean it. 398 pPattern->clear(); 399 } 400 401 CPDF_Image* CPDF_DocPageData::GetImage(uint32_t dwStreamObjNum) { 402 ASSERT(dwStreamObjNum); 403 auto it = m_ImageMap.find(dwStreamObjNum); 404 if (it != m_ImageMap.end()) 405 return it->second->AddRef(); 406 407 CPDF_CountedImage* pCountedImage = new CPDF_CountedImage( 408 pdfium::MakeUnique<CPDF_Image>(m_pPDFDoc, dwStreamObjNum)); 409 m_ImageMap[dwStreamObjNum] = pCountedImage; 410 return pCountedImage->AddRef(); 411 } 412 413 void CPDF_DocPageData::ReleaseImage(uint32_t dwStreamObjNum) { 414 ASSERT(dwStreamObjNum); 415 auto it = m_ImageMap.find(dwStreamObjNum); 416 if (it == m_ImageMap.end()) 417 return; 418 419 CPDF_CountedImage* pCountedImage = it->second; 420 if (!pCountedImage) 421 return; 422 423 pCountedImage->RemoveRef(); 424 if (pCountedImage->use_count() > 1) 425 return; 426 427 // We have item only in m_ImageMap cache. Clean it. 428 delete pCountedImage->get(); 429 delete pCountedImage; 430 m_ImageMap.erase(it); 431 } 432 433 CPDF_IccProfile* CPDF_DocPageData::GetIccProfile( 434 CPDF_Stream* pIccProfileStream) { 435 if (!pIccProfileStream) 436 return nullptr; 437 438 auto it = m_IccProfileMap.find(pIccProfileStream); 439 if (it != m_IccProfileMap.end()) 440 return it->second->AddRef(); 441 442 CPDF_StreamAcc stream; 443 stream.LoadAllData(pIccProfileStream, false); 444 uint8_t digest[20]; 445 CRYPT_SHA1Generate(stream.GetData(), stream.GetSize(), digest); 446 CFX_ByteString bsDigest(digest, 20); 447 auto hash_it = m_HashProfileMap.find(bsDigest); 448 if (hash_it != m_HashProfileMap.end()) { 449 auto it_copied_stream = m_IccProfileMap.find(hash_it->second); 450 if (it_copied_stream != m_IccProfileMap.end()) 451 return it_copied_stream->second->AddRef(); 452 } 453 CPDF_CountedIccProfile* ipData = new CPDF_CountedIccProfile( 454 pdfium::MakeUnique<CPDF_IccProfile>(stream.GetData(), stream.GetSize())); 455 m_IccProfileMap[pIccProfileStream] = ipData; 456 m_HashProfileMap[bsDigest] = pIccProfileStream; 457 return ipData->AddRef(); 458 } 459 460 void CPDF_DocPageData::ReleaseIccProfile(const CPDF_IccProfile* pIccProfile) { 461 ASSERT(pIccProfile); 462 463 for (auto it = m_IccProfileMap.begin(); it != m_IccProfileMap.end(); ++it) { 464 CPDF_CountedIccProfile* profile = it->second; 465 if (profile->get() != pIccProfile) 466 continue; 467 468 profile->RemoveRef(); 469 if (profile->use_count() > 1) 470 continue; 471 // We have item only in m_IccProfileMap cache. Clean it. 472 delete profile->get(); 473 delete profile; 474 m_IccProfileMap.erase(it); 475 return; 476 } 477 } 478 479 CPDF_StreamAcc* CPDF_DocPageData::GetFontFileStreamAcc( 480 CPDF_Stream* pFontStream) { 481 ASSERT(pFontStream); 482 483 auto it = m_FontFileMap.find(pFontStream); 484 if (it != m_FontFileMap.end()) 485 return it->second->AddRef(); 486 487 CPDF_Dictionary* pFontDict = pFontStream->GetDict(); 488 int32_t org_size = pFontDict->GetIntegerFor("Length1") + 489 pFontDict->GetIntegerFor("Length2") + 490 pFontDict->GetIntegerFor("Length3"); 491 org_size = std::max(org_size, 0); 492 493 auto pFontAcc = pdfium::MakeUnique<CPDF_StreamAcc>(); 494 pFontAcc->LoadAllData(pFontStream, false, org_size); 495 496 CPDF_CountedStreamAcc* pCountedFont = 497 new CPDF_CountedStreamAcc(std::move(pFontAcc)); 498 m_FontFileMap[pFontStream] = pCountedFont; 499 return pCountedFont->AddRef(); 500 } 501 502 void CPDF_DocPageData::ReleaseFontFileStreamAcc( 503 const CPDF_Stream* pFontStream) { 504 if (!pFontStream) 505 return; 506 507 auto it = m_FontFileMap.find(pFontStream); 508 if (it == m_FontFileMap.end()) 509 return; 510 511 CPDF_CountedStreamAcc* pCountedStream = it->second; 512 if (!pCountedStream) 513 return; 514 515 pCountedStream->RemoveRef(); 516 if (pCountedStream->use_count() > 1) 517 return; 518 519 // We have item only in m_FontFileMap cache. Clean it. 520 delete pCountedStream->get(); 521 delete pCountedStream; 522 m_FontFileMap.erase(it); 523 } 524 525 CPDF_CountedColorSpace* CPDF_DocPageData::FindColorSpacePtr( 526 CPDF_Object* pCSObj) const { 527 if (!pCSObj) 528 return nullptr; 529 530 auto it = m_ColorSpaceMap.find(pCSObj); 531 return it != m_ColorSpaceMap.end() ? it->second : nullptr; 532 } 533 534 CPDF_CountedPattern* CPDF_DocPageData::FindPatternPtr( 535 CPDF_Object* pPatternObj) const { 536 if (!pPatternObj) 537 return nullptr; 538 539 auto it = m_PatternMap.find(pPatternObj); 540 return it != m_PatternMap.end() ? it->second : nullptr; 541 } 542