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