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