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