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/fdrm/fx_crypt.h" 10 #include "core/include/fpdfapi/fpdf_module.h" 11 #include "core/include/fpdfapi/fpdf_page.h" 12 #include "core/src/fpdfapi/fpdf_font/font_int.h" 13 14 class CPDF_PageModule : public IPDF_PageModule { 15 public: 16 CPDF_PageModule() 17 : m_StockGrayCS(nullptr, PDFCS_DEVICEGRAY), 18 m_StockRGBCS(nullptr, PDFCS_DEVICERGB), 19 m_StockCMYKCS(nullptr, PDFCS_DEVICECMYK), 20 m_StockPatternCS(nullptr) {} 21 22 private: 23 ~CPDF_PageModule() override {} 24 25 CPDF_DocPageData* CreateDocData(CPDF_Document* pDoc) override { 26 return new CPDF_DocPageData(pDoc); 27 } 28 29 void ReleaseDoc(CPDF_Document* pDoc) override; 30 void ClearDoc(CPDF_Document* pDoc) override; 31 32 CPDF_FontGlobals* GetFontGlobals() override { return &m_FontGlobals; } 33 34 void ClearStockFont(CPDF_Document* pDoc) override { 35 m_FontGlobals.Clear(pDoc); 36 } 37 38 CPDF_ColorSpace* GetStockCS(int family) override; 39 void NotifyCJKAvailable() override; 40 41 CPDF_FontGlobals m_FontGlobals; 42 CPDF_DeviceCS m_StockGrayCS; 43 CPDF_DeviceCS m_StockRGBCS; 44 CPDF_DeviceCS m_StockCMYKCS; 45 CPDF_PatternCS m_StockPatternCS; 46 }; 47 48 CPDF_ColorSpace* CPDF_PageModule::GetStockCS(int family) { 49 if (family == PDFCS_DEVICEGRAY) { 50 return &m_StockGrayCS; 51 } 52 if (family == PDFCS_DEVICERGB) { 53 return &m_StockRGBCS; 54 } 55 if (family == PDFCS_DEVICECMYK) { 56 return &m_StockCMYKCS; 57 } 58 if (family == PDFCS_PATTERN) { 59 return &m_StockPatternCS; 60 } 61 return NULL; 62 } 63 64 void CPDF_ModuleMgr::InitPageModule() { 65 m_pPageModule.reset(new CPDF_PageModule); 66 } 67 68 void CPDF_PageModule::ReleaseDoc(CPDF_Document* pDoc) { 69 delete pDoc->GetPageData(); 70 } 71 void CPDF_PageModule::ClearDoc(CPDF_Document* pDoc) { 72 pDoc->GetPageData()->Clear(FALSE); 73 } 74 void CPDF_PageModule::NotifyCJKAvailable() { 75 m_FontGlobals.m_CMapManager.ReloadAll(); 76 } 77 78 CPDF_Font* CPDF_Document::LoadFont(CPDF_Dictionary* pFontDict) { 79 ASSERT(pFontDict); 80 return GetValidatePageData()->GetFont(pFontDict, FALSE); 81 } 82 83 CPDF_StreamAcc* CPDF_Document::LoadFontFile(CPDF_Stream* pStream) { 84 return GetValidatePageData()->GetFontFileStreamAcc(pStream); 85 } 86 87 CPDF_ColorSpace* _CSFromName(const CFX_ByteString& name); 88 CPDF_ColorSpace* CPDF_Document::LoadColorSpace(CPDF_Object* pCSObj, 89 CPDF_Dictionary* pResources) { 90 return GetValidatePageData()->GetColorSpace(pCSObj, pResources); 91 } 92 CPDF_Pattern* CPDF_Document::LoadPattern(CPDF_Object* pPatternObj, 93 FX_BOOL bShading, 94 const CFX_Matrix* matrix) { 95 return GetValidatePageData()->GetPattern(pPatternObj, bShading, matrix); 96 } 97 CPDF_IccProfile* CPDF_Document::LoadIccProfile(CPDF_Stream* pStream) { 98 return GetValidatePageData()->GetIccProfile(pStream); 99 } 100 CPDF_Image* CPDF_Document::LoadImageF(CPDF_Object* pObj) { 101 if (!pObj) { 102 return NULL; 103 } 104 FXSYS_assert(pObj->GetObjNum()); 105 return GetValidatePageData()->GetImage(pObj); 106 } 107 void CPDF_Document::RemoveColorSpaceFromPageData(CPDF_Object* pCSObj) { 108 if (!pCSObj) { 109 return; 110 } 111 GetPageData()->ReleaseColorSpace(pCSObj); 112 } 113 CPDF_DocPageData::CPDF_DocPageData(CPDF_Document* pPDFDoc) 114 : m_pPDFDoc(pPDFDoc), m_bForceClear(FALSE) {} 115 116 CPDF_DocPageData::~CPDF_DocPageData() { 117 Clear(FALSE); 118 Clear(TRUE); 119 120 for (auto& it : m_PatternMap) 121 delete it.second; 122 m_PatternMap.clear(); 123 124 for (auto& it : m_FontMap) 125 delete it.second; 126 m_FontMap.clear(); 127 128 for (auto& it : m_ColorSpaceMap) 129 delete it.second; 130 m_ColorSpaceMap.clear(); 131 } 132 133 void CPDF_DocPageData::Clear(FX_BOOL bForceRelease) { 134 m_bForceClear = bForceRelease; 135 136 for (auto& it : m_PatternMap) { 137 CPDF_CountedPattern* ptData = it.second; 138 if (!ptData->get()) 139 continue; 140 141 if (bForceRelease || ptData->use_count() < 2) { 142 ptData->get()->SetForceClear(bForceRelease); 143 ptData->clear(); 144 } 145 } 146 147 for (auto& it : m_FontMap) { 148 CPDF_CountedFont* fontData = it.second; 149 if (!fontData->get()) 150 continue; 151 152 if (bForceRelease || fontData->use_count() < 2) { 153 fontData->clear(); 154 } 155 } 156 157 for (auto& it : m_ColorSpaceMap) { 158 CPDF_CountedColorSpace* csData = it.second; 159 if (!csData->get()) 160 continue; 161 162 if (bForceRelease || csData->use_count() < 2) { 163 csData->get()->ReleaseCS(); 164 csData->reset(nullptr); 165 } 166 } 167 168 for (auto it = m_IccProfileMap.begin(); it != m_IccProfileMap.end();) { 169 auto curr_it = it++; 170 CPDF_CountedIccProfile* ipData = curr_it->second; 171 if (!ipData->get()) 172 continue; 173 174 if (bForceRelease || ipData->use_count() < 2) { 175 for (auto hash_it = m_HashProfileMap.begin(); 176 hash_it != m_HashProfileMap.end(); ++hash_it) { 177 if (curr_it->first == hash_it->second) { 178 m_HashProfileMap.erase(hash_it); 179 break; 180 } 181 } 182 delete ipData->get(); 183 delete ipData; 184 m_IccProfileMap.erase(curr_it); 185 } 186 } 187 188 for (auto it = m_FontFileMap.begin(); it != m_FontFileMap.end();) { 189 auto curr_it = it++; 190 CPDF_CountedStreamAcc* ftData = curr_it->second; 191 if (!ftData->get()) 192 continue; 193 194 if (bForceRelease || ftData->use_count() < 2) { 195 delete ftData->get(); 196 delete ftData; 197 m_FontFileMap.erase(curr_it); 198 } 199 } 200 201 for (auto it = m_ImageMap.begin(); it != m_ImageMap.end();) { 202 auto curr_it = it++; 203 CPDF_CountedImage* imageData = curr_it->second; 204 if (!imageData->get()) 205 continue; 206 207 if (bForceRelease || imageData->use_count() < 2) { 208 delete imageData->get(); 209 delete imageData; 210 m_ImageMap.erase(curr_it); 211 } 212 } 213 } 214 215 CPDF_Font* CPDF_DocPageData::GetFont(CPDF_Dictionary* pFontDict, 216 FX_BOOL findOnly) { 217 if (!pFontDict) { 218 return NULL; 219 } 220 if (findOnly) { 221 auto it = m_FontMap.find(pFontDict); 222 if (it != m_FontMap.end() && it->second->get()) { 223 return it->second->AddRef(); 224 } 225 return nullptr; 226 } 227 228 CPDF_CountedFont* fontData = nullptr; 229 auto it = m_FontMap.find(pFontDict); 230 if (it != m_FontMap.end()) { 231 fontData = it->second; 232 if (fontData->get()) { 233 return fontData->AddRef(); 234 } 235 } 236 237 CPDF_Font* pFont = CPDF_Font::CreateFontF(m_pPDFDoc, pFontDict); 238 if (!pFont) { 239 return nullptr; 240 } 241 if (!fontData) { 242 fontData = new CPDF_CountedFont(pFont); 243 m_FontMap[pFontDict] = fontData; 244 } else { 245 fontData->reset(pFont); 246 } 247 return fontData->AddRef(); 248 } 249 250 CPDF_Font* CPDF_DocPageData::GetStandardFont(const CFX_ByteStringC& fontName, 251 CPDF_FontEncoding* pEncoding) { 252 if (fontName.IsEmpty()) 253 return nullptr; 254 255 for (auto& it : m_FontMap) { 256 CPDF_CountedFont* fontData = it.second; 257 CPDF_Font* pFont = fontData->get(); 258 if (!pFont) 259 continue; 260 if (pFont->GetBaseFont() != fontName) 261 continue; 262 if (pFont->IsEmbedded()) 263 continue; 264 if (pFont->GetFontType() != PDFFONT_TYPE1) 265 continue; 266 if (pFont->GetFontDict()->KeyExist("Widths")) 267 continue; 268 269 CPDF_Type1Font* pT1Font = pFont->GetType1Font(); 270 if (pEncoding && !pT1Font->GetEncoding()->IsIdentical(pEncoding)) 271 continue; 272 273 return fontData->AddRef(); 274 } 275 276 CPDF_Dictionary* pDict = new CPDF_Dictionary; 277 pDict->SetAtName("Type", "Font"); 278 pDict->SetAtName("Subtype", "Type1"); 279 pDict->SetAtName("BaseFont", fontName); 280 if (pEncoding) { 281 pDict->SetAt("Encoding", pEncoding->Realize()); 282 } 283 m_pPDFDoc->AddIndirectObject(pDict); 284 CPDF_Font* pFont = CPDF_Font::CreateFontF(m_pPDFDoc, pDict); 285 if (!pFont) { 286 return nullptr; 287 } 288 CPDF_CountedFont* fontData = new CPDF_CountedFont(pFont); 289 m_FontMap[pDict] = fontData; 290 return fontData->AddRef(); 291 } 292 293 void CPDF_DocPageData::ReleaseFont(CPDF_Dictionary* pFontDict) { 294 if (!pFontDict) 295 return; 296 297 auto it = m_FontMap.find(pFontDict); 298 if (it == m_FontMap.end()) 299 return; 300 301 CPDF_CountedFont* fontData = it->second; 302 if (fontData->get()) { 303 fontData->RemoveRef(); 304 if (fontData->use_count() == 0) { 305 fontData->clear(); 306 } 307 } 308 } 309 310 CPDF_ColorSpace* CPDF_DocPageData::GetColorSpace( 311 CPDF_Object* pCSObj, 312 const CPDF_Dictionary* pResources) { 313 if (!pCSObj) 314 return nullptr; 315 316 if (pCSObj->IsName()) { 317 CFX_ByteString name = pCSObj->GetConstString(); 318 CPDF_ColorSpace* pCS = _CSFromName(name); 319 if (!pCS && pResources) { 320 CPDF_Dictionary* pList = pResources->GetDict("ColorSpace"); 321 if (pList) { 322 pCSObj = pList->GetElementValue(name); 323 return GetColorSpace(pCSObj, nullptr); 324 } 325 } 326 if (!pCS || !pResources) 327 return pCS; 328 329 CPDF_Dictionary* pColorSpaces = pResources->GetDict("ColorSpace"); 330 if (!pColorSpaces) 331 return pCS; 332 333 CPDF_Object* pDefaultCS = nullptr; 334 switch (pCS->GetFamily()) { 335 case PDFCS_DEVICERGB: 336 pDefaultCS = pColorSpaces->GetElementValue("DefaultRGB"); 337 break; 338 case PDFCS_DEVICEGRAY: 339 pDefaultCS = pColorSpaces->GetElementValue("DefaultGray"); 340 break; 341 case PDFCS_DEVICECMYK: 342 pDefaultCS = pColorSpaces->GetElementValue("DefaultCMYK"); 343 break; 344 } 345 return pDefaultCS ? GetColorSpace(pDefaultCS, nullptr) : pCS; 346 } 347 348 CPDF_Array* pArray = pCSObj->AsArray(); 349 if (!pArray || pArray->GetCount() == 0) 350 return nullptr; 351 if (pArray->GetCount() == 1) 352 return GetColorSpace(pArray->GetElementValue(0), pResources); 353 354 CPDF_CountedColorSpace* csData = nullptr; 355 auto it = m_ColorSpaceMap.find(pCSObj); 356 if (it != m_ColorSpaceMap.end()) { 357 csData = it->second; 358 if (csData->get()) { 359 return csData->AddRef(); 360 } 361 } 362 363 CPDF_ColorSpace* pCS = CPDF_ColorSpace::Load(m_pPDFDoc, pArray); 364 if (!pCS) 365 return nullptr; 366 367 if (!csData) { 368 csData = new CPDF_CountedColorSpace(pCS); 369 m_ColorSpaceMap[pCSObj] = csData; 370 } else { 371 csData->reset(pCS); 372 } 373 return csData->AddRef(); 374 } 375 376 CPDF_ColorSpace* CPDF_DocPageData::GetCopiedColorSpace(CPDF_Object* pCSObj) { 377 if (!pCSObj) 378 return nullptr; 379 380 auto it = m_ColorSpaceMap.find(pCSObj); 381 if (it != m_ColorSpaceMap.end()) 382 return it->second->AddRef(); 383 384 return nullptr; 385 } 386 387 void CPDF_DocPageData::ReleaseColorSpace(CPDF_Object* pColorSpace) { 388 if (!pColorSpace) 389 return; 390 391 auto it = m_ColorSpaceMap.find(pColorSpace); 392 if (it == m_ColorSpaceMap.end()) 393 return; 394 395 CPDF_CountedColorSpace* csData = it->second; 396 if (csData->get()) { 397 csData->RemoveRef(); 398 if (csData->use_count() == 0) { 399 csData->get()->ReleaseCS(); 400 csData->reset(nullptr); 401 } 402 } 403 } 404 405 CPDF_Pattern* CPDF_DocPageData::GetPattern(CPDF_Object* pPatternObj, 406 FX_BOOL bShading, 407 const CFX_Matrix* matrix) { 408 if (!pPatternObj) 409 return nullptr; 410 411 CPDF_CountedPattern* ptData = nullptr; 412 auto it = m_PatternMap.find(pPatternObj); 413 if (it != m_PatternMap.end()) { 414 ptData = it->second; 415 if (ptData->get()) { 416 return ptData->AddRef(); 417 } 418 } 419 CPDF_Pattern* pPattern = nullptr; 420 if (bShading) { 421 pPattern = 422 new CPDF_ShadingPattern(m_pPDFDoc, pPatternObj, bShading, matrix); 423 } else { 424 CPDF_Dictionary* pDict = pPatternObj ? pPatternObj->GetDict() : nullptr; 425 if (pDict) { 426 int type = pDict->GetInteger("PatternType"); 427 if (type == 1) { 428 pPattern = new CPDF_TilingPattern(m_pPDFDoc, pPatternObj, matrix); 429 } else if (type == 2) { 430 pPattern = 431 new CPDF_ShadingPattern(m_pPDFDoc, pPatternObj, FALSE, matrix); 432 } 433 } 434 } 435 if (!pPattern) 436 return nullptr; 437 438 if (!ptData) { 439 ptData = new CPDF_CountedPattern(pPattern); 440 m_PatternMap[pPatternObj] = ptData; 441 } else { 442 ptData->reset(pPattern); 443 } 444 return ptData->AddRef(); 445 } 446 447 void CPDF_DocPageData::ReleasePattern(CPDF_Object* pPatternObj) { 448 if (!pPatternObj) 449 return; 450 451 auto it = m_PatternMap.find(pPatternObj); 452 if (it == m_PatternMap.end()) 453 return; 454 455 CPDF_CountedPattern* ptData = it->second; 456 if (ptData->get()) { 457 ptData->RemoveRef(); 458 if (ptData->use_count() == 0) { 459 ptData->clear(); 460 } 461 } 462 } 463 464 CPDF_Image* CPDF_DocPageData::GetImage(CPDF_Object* pImageStream) { 465 if (!pImageStream) 466 return nullptr; 467 468 const FX_DWORD dwImageObjNum = pImageStream->GetObjNum(); 469 auto it = m_ImageMap.find(dwImageObjNum); 470 if (it != m_ImageMap.end()) { 471 return it->second->AddRef(); 472 } 473 474 CPDF_Image* pImage = new CPDF_Image(m_pPDFDoc); 475 pImage->LoadImageF(pImageStream->AsStream(), FALSE); 476 477 CPDF_CountedImage* imageData = new CPDF_CountedImage(pImage); 478 m_ImageMap[dwImageObjNum] = imageData; 479 return imageData->AddRef(); 480 } 481 482 void CPDF_DocPageData::ReleaseImage(CPDF_Object* pImageStream) { 483 if (!pImageStream || !pImageStream->GetObjNum()) 484 return; 485 486 auto it = m_ImageMap.find(pImageStream->GetObjNum()); 487 if (it == m_ImageMap.end()) 488 return; 489 490 CPDF_CountedImage* image = it->second; 491 if (!image) 492 return; 493 494 image->RemoveRef(); 495 if (image->use_count() == 0) { 496 delete image->get(); 497 delete image; 498 m_ImageMap.erase(it); 499 } 500 } 501 502 CPDF_IccProfile* CPDF_DocPageData::GetIccProfile( 503 CPDF_Stream* pIccProfileStream) { 504 if (!pIccProfileStream) 505 return NULL; 506 507 auto it = m_IccProfileMap.find(pIccProfileStream); 508 if (it != m_IccProfileMap.end()) { 509 return it->second->AddRef(); 510 } 511 512 CPDF_StreamAcc stream; 513 stream.LoadAllData(pIccProfileStream, FALSE); 514 uint8_t digest[20]; 515 CRYPT_SHA1Generate(stream.GetData(), stream.GetSize(), digest); 516 auto hash_it = m_HashProfileMap.find(CFX_ByteStringC(digest, 20)); 517 if (hash_it != m_HashProfileMap.end()) { 518 auto it_copied_stream = m_IccProfileMap.find(hash_it->second); 519 return it_copied_stream->second->AddRef(); 520 } 521 CPDF_IccProfile* pProfile = 522 new CPDF_IccProfile(stream.GetData(), stream.GetSize()); 523 CPDF_CountedIccProfile* ipData = new CPDF_CountedIccProfile(pProfile); 524 m_IccProfileMap[pIccProfileStream] = ipData; 525 m_HashProfileMap[CFX_ByteStringC(digest, 20)] = pIccProfileStream; 526 return ipData->AddRef(); 527 } 528 529 void CPDF_DocPageData::ReleaseIccProfile(CPDF_IccProfile* pIccProfile) { 530 ASSERT(pIccProfile); 531 532 for (auto it = m_IccProfileMap.begin(); it != m_IccProfileMap.end(); ++it) { 533 CPDF_CountedIccProfile* profile = it->second; 534 if (profile->get() != pIccProfile) 535 continue; 536 537 profile->RemoveRef(); 538 if (profile->use_count() == 0) { 539 delete profile->get(); 540 delete profile; 541 m_IccProfileMap.erase(it); 542 return; 543 } 544 } 545 } 546 547 CPDF_StreamAcc* CPDF_DocPageData::GetFontFileStreamAcc( 548 CPDF_Stream* pFontStream) { 549 ASSERT(pFontStream); 550 551 auto it = m_FontFileMap.find(pFontStream); 552 if (it != m_FontFileMap.end()) 553 return it->second->AddRef(); 554 555 CPDF_Dictionary* pFontDict = pFontStream->GetDict(); 556 int32_t org_size = pFontDict->GetInteger("Length1") + 557 pFontDict->GetInteger("Length2") + 558 pFontDict->GetInteger("Length3"); 559 if (org_size < 0) 560 org_size = 0; 561 562 CPDF_StreamAcc* pFontFile = new CPDF_StreamAcc; 563 pFontFile->LoadAllData(pFontStream, FALSE, org_size); 564 565 CPDF_CountedStreamAcc* ftData = new CPDF_CountedStreamAcc(pFontFile); 566 m_FontFileMap[pFontStream] = ftData; 567 return ftData->AddRef(); 568 } 569 570 void CPDF_DocPageData::ReleaseFontFileStreamAcc(CPDF_Stream* pFontStream, 571 FX_BOOL bForce) { 572 if (!pFontStream) 573 return; 574 575 auto it = m_FontFileMap.find(pFontStream); 576 if (it == m_FontFileMap.end()) 577 return; 578 579 CPDF_CountedStreamAcc* findData = it->second; 580 if (!findData) 581 return; 582 583 findData->RemoveRef(); 584 if (findData->use_count() == 0 || bForce) { 585 delete findData->get(); 586 delete findData; 587 m_FontFileMap.erase(it); 588 } 589 } 590 591 CPDF_CountedColorSpace* CPDF_DocPageData::FindColorSpacePtr( 592 CPDF_Object* pCSObj) const { 593 if (!pCSObj) 594 return nullptr; 595 596 auto it = m_ColorSpaceMap.find(pCSObj); 597 return it != m_ColorSpaceMap.end() ? it->second : nullptr; 598 } 599 600 CPDF_CountedPattern* CPDF_DocPageData::FindPatternPtr( 601 CPDF_Object* pPatternObj) const { 602 if (!pPatternObj) 603 return nullptr; 604 605 auto it = m_PatternMap.find(pPatternObj); 606 return it != m_PatternMap.end() ? it->second : nullptr; 607 } 608