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:
CPDF_PageModule()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:
~CPDF_PageModule()23 ~CPDF_PageModule() override {}
24
CreateDocData(CPDF_Document * pDoc)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
GetFontGlobals()32 CPDF_FontGlobals* GetFontGlobals() override { return &m_FontGlobals; }
33
ClearStockFont(CPDF_Document * pDoc)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
GetStockCS(int family)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
InitPageModule()64 void CPDF_ModuleMgr::InitPageModule() {
65 m_pPageModule.reset(new CPDF_PageModule);
66 }
67
ReleaseDoc(CPDF_Document * pDoc)68 void CPDF_PageModule::ReleaseDoc(CPDF_Document* pDoc) {
69 delete pDoc->GetPageData();
70 }
ClearDoc(CPDF_Document * pDoc)71 void CPDF_PageModule::ClearDoc(CPDF_Document* pDoc) {
72 pDoc->GetPageData()->Clear(FALSE);
73 }
NotifyCJKAvailable()74 void CPDF_PageModule::NotifyCJKAvailable() {
75 m_FontGlobals.m_CMapManager.ReloadAll();
76 }
77
LoadFont(CPDF_Dictionary * pFontDict)78 CPDF_Font* CPDF_Document::LoadFont(CPDF_Dictionary* pFontDict) {
79 ASSERT(pFontDict);
80 return GetValidatePageData()->GetFont(pFontDict, FALSE);
81 }
82
LoadFontFile(CPDF_Stream * pStream)83 CPDF_StreamAcc* CPDF_Document::LoadFontFile(CPDF_Stream* pStream) {
84 return GetValidatePageData()->GetFontFileStreamAcc(pStream);
85 }
86
87 CPDF_ColorSpace* _CSFromName(const CFX_ByteString& name);
LoadColorSpace(CPDF_Object * pCSObj,CPDF_Dictionary * pResources)88 CPDF_ColorSpace* CPDF_Document::LoadColorSpace(CPDF_Object* pCSObj,
89 CPDF_Dictionary* pResources) {
90 return GetValidatePageData()->GetColorSpace(pCSObj, pResources);
91 }
LoadPattern(CPDF_Object * pPatternObj,FX_BOOL bShading,const CFX_Matrix * matrix)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 }
LoadIccProfile(CPDF_Stream * pStream)97 CPDF_IccProfile* CPDF_Document::LoadIccProfile(CPDF_Stream* pStream) {
98 return GetValidatePageData()->GetIccProfile(pStream);
99 }
LoadImageF(CPDF_Object * pObj)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 }
RemoveColorSpaceFromPageData(CPDF_Object * pCSObj)107 void CPDF_Document::RemoveColorSpaceFromPageData(CPDF_Object* pCSObj) {
108 if (!pCSObj) {
109 return;
110 }
111 GetPageData()->ReleaseColorSpace(pCSObj);
112 }
CPDF_DocPageData(CPDF_Document * pPDFDoc)113 CPDF_DocPageData::CPDF_DocPageData(CPDF_Document* pPDFDoc)
114 : m_pPDFDoc(pPDFDoc), m_bForceClear(FALSE) {}
115
~CPDF_DocPageData()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
Clear(FX_BOOL bForceRelease)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
GetFont(CPDF_Dictionary * pFontDict,FX_BOOL findOnly)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
GetStandardFont(const CFX_ByteStringC & fontName,CPDF_FontEncoding * pEncoding)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
ReleaseFont(CPDF_Dictionary * pFontDict)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
GetColorSpace(CPDF_Object * pCSObj,const CPDF_Dictionary * pResources)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
GetCopiedColorSpace(CPDF_Object * pCSObj)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
ReleaseColorSpace(CPDF_Object * pColorSpace)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
GetPattern(CPDF_Object * pPatternObj,FX_BOOL bShading,const CFX_Matrix * matrix)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
ReleasePattern(CPDF_Object * pPatternObj)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
GetImage(CPDF_Object * pImageStream)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
ReleaseImage(CPDF_Object * pImageStream)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
GetIccProfile(CPDF_Stream * pIccProfileStream)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
ReleaseIccProfile(CPDF_IccProfile * pIccProfile)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
GetFontFileStreamAcc(CPDF_Stream * pFontStream)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
ReleaseFontFileStreamAcc(CPDF_Stream * pFontStream,FX_BOOL bForce)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
FindColorSpacePtr(CPDF_Object * pCSObj) const591 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
FindPatternPtr(CPDF_Object * pPatternObj) const600 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