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.
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
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"
12 class CPDF_PageModule : public CPDF_PageModuleDef
15 CPDF_PageModule() : m_StockGrayCS(PDFCS_DEVICEGRAY), m_StockRGBCS(PDFCS_DEVICERGB),
16 m_StockCMYKCS(PDFCS_DEVICECMYK) {}
17 virtual ~CPDF_PageModule() {}
18 virtual FX_BOOL Installed()
22 virtual CPDF_DocPageData* CreateDocData(CPDF_Document* pDoc)
24 return FX_NEW CPDF_DocPageData(pDoc);
26 virtual void ReleaseDoc(CPDF_Document* pDoc);
27 virtual void ClearDoc(CPDF_Document* pDoc);
28 virtual CPDF_FontGlobals* GetFontGlobals()
30 return &m_FontGlobals;
32 virtual void ClearStockFont(CPDF_Document* pDoc)
34 m_FontGlobals.Clear(pDoc);
36 virtual CPDF_ColorSpace* GetStockCS(int family);
37 virtual void NotifyCJKAvailable();
38 CPDF_FontGlobals m_FontGlobals;
39 CPDF_DeviceCS m_StockGrayCS;
40 CPDF_DeviceCS m_StockRGBCS;
41 CPDF_DeviceCS m_StockCMYKCS;
42 CPDF_PatternCS m_StockPatternCS;
44 CPDF_ColorSpace* CPDF_PageModule::GetStockCS(int family)
46 if (family == PDFCS_DEVICEGRAY) {
47 return &m_StockGrayCS;
49 if (family == PDFCS_DEVICERGB) {
52 if (family == PDFCS_DEVICECMYK) {
53 return &m_StockCMYKCS;
55 if (family == PDFCS_PATTERN) {
56 return &m_StockPatternCS;
60 void CPDF_ModuleMgr::InitPageModule()
65 CPDF_PageModule* pPageModule = FX_NEW CPDF_PageModule;
66 m_pPageModule = pPageModule;
68 void CPDF_PageModule::ReleaseDoc(CPDF_Document* pDoc)
70 delete pDoc->GetPageData();
72 void CPDF_PageModule::ClearDoc(CPDF_Document* pDoc)
74 pDoc->GetPageData()->Clear(FALSE);
76 void CPDF_PageModule::NotifyCJKAvailable()
78 m_FontGlobals.m_CMapManager.ReloadAll();
80 CPDF_Font* CPDF_Document::LoadFont(CPDF_Dictionary* pFontDict)
85 return GetValidatePageData()->GetFont(pFontDict, FALSE);
87 CPDF_Font* CPDF_Document::FindFont(CPDF_Dictionary* pFontDict)
92 return GetValidatePageData()->GetFont(pFontDict, TRUE);
94 CPDF_StreamAcc* CPDF_Document::LoadFontFile(CPDF_Stream* pStream)
96 if (pStream == NULL) {
99 return GetValidatePageData()->GetFontFileStreamAcc(pStream);
101 CPDF_ColorSpace* _CSFromName(const CFX_ByteString& name);
102 CPDF_ColorSpace* CPDF_Document::LoadColorSpace(CPDF_Object* pCSObj, CPDF_Dictionary* pResources)
104 return GetValidatePageData()->GetColorSpace(pCSObj, pResources);
106 CPDF_Pattern* CPDF_Document::LoadPattern(CPDF_Object* pPatternObj, FX_BOOL bShading, const CFX_AffineMatrix* matrix)
108 return GetValidatePageData()->GetPattern(pPatternObj, bShading, matrix);
110 CPDF_IccProfile* CPDF_Document::LoadIccProfile(CPDF_Stream* pStream)
112 return GetValidatePageData()->GetIccProfile(pStream);
114 CPDF_Image* CPDF_Document::LoadImageF(CPDF_Object* pObj)
119 FXSYS_assert(pObj->GetObjNum());
120 return GetValidatePageData()->GetImage(pObj);
122 void CPDF_Document::RemoveColorSpaceFromPageData(CPDF_Object* pCSObj)
127 GetPageData()->ReleaseColorSpace(pCSObj);
129 CPDF_DocPageData::CPDF_DocPageData(CPDF_Document *pPDFDoc)
137 , m_bForceClear(FALSE)
139 m_FontMap.InitHashTable(64);
140 m_ColorSpaceMap.InitHashTable(32);
141 m_PatternMap.InitHashTable(16);
142 m_ImageMap.InitHashTable(64);
143 m_IccProfileMap.InitHashTable(16);
144 m_FontFileMap.InitHashTable(32);
146 CPDF_DocPageData::~CPDF_DocPageData()
151 void CPDF_DocPageData::Clear(FX_BOOL bForceRelease)
155 m_bForceClear = bForceRelease;
157 // Release objects saved in the resource maps like font map and color space map.
158 // The compound objects shall be released before simple ones.
159 pos = m_FontMap.GetStartPosition();
161 CPDF_Dictionary* fontDict;
162 CPDF_CountedObject<CPDF_Font*>* fontData;
163 m_FontMap.GetNextAssoc(pos, fontDict, fontData);
164 if (!fontData->m_Obj) {
167 if (bForceRelease || fontData->m_nCount < 2) {
168 delete fontData->m_Obj;
169 fontData->m_Obj = NULL;
172 pos = m_ColorSpaceMap.GetStartPosition();
175 CPDF_CountedObject<CPDF_ColorSpace*>* csData;
176 m_ColorSpaceMap.GetNextAssoc(pos, csKey, csData);
177 if (!csData->m_Obj) {
180 if (bForceRelease || csData->m_nCount < 2) {
181 // csData->m_Obj is deleted in the function of ReleaseCS().
182 csData->m_Obj->ReleaseCS();
183 csData->m_Obj = NULL;
186 pos = m_IccProfileMap.GetStartPosition();
189 CPDF_CountedObject<CPDF_IccProfile*>* ipData;
190 m_IccProfileMap.GetNextAssoc(pos, ipKey, ipData);
191 if (!ipData->m_Obj) {
194 if (bForceRelease || ipData->m_nCount < 2) {
195 FX_POSITION pos2 = m_HashProfileMap.GetStartPosition();
197 CFX_ByteString bsKey;
198 CPDF_Stream* pFindStream = NULL;
199 m_HashProfileMap.GetNextAssoc(pos2, bsKey, (void*&)pFindStream);
200 if (ipKey == pFindStream) {
201 m_HashProfileMap.RemoveKey(bsKey);
205 delete ipData->m_Obj;
206 ipData->m_Obj = NULL;
208 m_IccProfileMap.RemoveKey(ipKey);
211 pos = m_FontFileMap.GetStartPosition();
214 CPDF_CountedObject<CPDF_StreamAcc*>* ftData;
215 m_FontFileMap.GetNextAssoc(pos, ftKey, ftData);
216 if (!ftData->m_Obj) {
219 if (bForceRelease || ftData->m_nCount < 2) {
220 delete ftData->m_Obj;
221 ftData->m_Obj = NULL;
223 m_FontFileMap.RemoveKey(ftKey);
226 pos = m_PatternMap.GetStartPosition();
229 CPDF_CountedObject<CPDF_Pattern*>* ptData;
230 m_PatternMap.GetNextAssoc(pos, ptObj, ptData);
231 if (!ptData->m_Obj) {
234 if (bForceRelease || ptData->m_nCount < 2) {
235 ptData->m_Obj->SetForceClear(bForceRelease);
236 delete ptData->m_Obj;
237 ptData->m_Obj = NULL;
240 pos = m_ImageMap.GetStartPosition();
243 CPDF_CountedObject<CPDF_Image*>* imageData;
244 m_ImageMap.GetNextAssoc(pos, objNum, imageData);
245 if (!imageData->m_Obj) {
248 if (bForceRelease || imageData->m_nCount < 2) {
249 delete imageData->m_Obj;
250 imageData->m_Obj = NULL;
252 m_ImageMap.RemoveKey(objNum);
256 CPDF_Font* CPDF_DocPageData::GetFont(CPDF_Dictionary* pFontDict, FX_BOOL findOnly)
262 CPDF_CountedObject<CPDF_Font*>* fontData;
263 if (m_FontMap.Lookup(pFontDict, fontData)) {
264 if (!fontData->m_Obj) {
267 fontData->m_nCount ++;
268 return fontData->m_Obj;
272 CPDF_CountedObject<CPDF_Font*>* fontData = NULL;
273 if (m_FontMap.Lookup(pFontDict, fontData)) {
274 if (fontData->m_Obj) {
275 fontData->m_nCount ++;
276 return fontData->m_Obj;
279 FX_BOOL bNew = FALSE;
281 fontData = FX_NEW CPDF_CountedObject<CPDF_Font*>;
287 CPDF_Font* pFont = CPDF_Font::CreateFontF(m_pPDFDoc, pFontDict);
294 fontData->m_nCount = 2;
295 fontData->m_Obj = pFont;
296 m_FontMap.SetAt(pFontDict, fontData);
299 CPDF_Font* CPDF_DocPageData::GetStandardFont(FX_BSTR fontName, CPDF_FontEncoding* pEncoding)
301 if (fontName.IsEmpty()) {
304 FX_POSITION pos = m_FontMap.GetStartPosition();
306 CPDF_Dictionary* fontDict;
307 CPDF_CountedObject<CPDF_Font*>* fontData;
308 m_FontMap.GetNextAssoc(pos, fontDict, fontData);
309 CPDF_Font* pFont = fontData->m_Obj;
313 if (pFont->GetBaseFont() != fontName) {
316 if (pFont->IsEmbedded()) {
319 if (pFont->GetFontType() != PDFFONT_TYPE1) {
322 if (pFont->GetFontDict()->KeyExist(FX_BSTRC("Widths"))) {
325 CPDF_Type1Font* pT1Font = pFont->GetType1Font();
326 if (pEncoding && !pT1Font->GetEncoding()->IsIdentical(pEncoding)) {
329 fontData->m_nCount ++;
332 CPDF_Dictionary* pDict = FX_NEW CPDF_Dictionary;
333 pDict->SetAtName(FX_BSTRC("Type"), FX_BSTRC("Font"));
334 pDict->SetAtName(FX_BSTRC("Subtype"), FX_BSTRC("Type1"));
335 pDict->SetAtName(FX_BSTRC("BaseFont"), fontName);
337 pDict->SetAt(FX_BSTRC("Encoding"), pEncoding->Realize());
339 m_pPDFDoc->AddIndirectObject(pDict);
340 CPDF_CountedObject<CPDF_Font*>* fontData = FX_NEW CPDF_CountedObject<CPDF_Font*>;
344 CPDF_Font* pFont = CPDF_Font::CreateFontF(m_pPDFDoc, pDict);
349 fontData->m_nCount = 2;
350 fontData->m_Obj = pFont;
351 m_FontMap.SetAt(pDict, fontData);
354 void CPDF_DocPageData::ReleaseFont(CPDF_Dictionary* pFontDict)
359 CPDF_CountedObject<CPDF_Font*>* fontData;
360 if (!m_FontMap.Lookup(pFontDict, fontData)) {
363 if (fontData->m_Obj && --fontData->m_nCount == 0) {
364 delete fontData->m_Obj;
365 fontData->m_Obj = NULL;
368 CPDF_ColorSpace* CPDF_DocPageData::GetColorSpace(CPDF_Object* pCSObj, CPDF_Dictionary* pResources)
373 if (pCSObj->GetType() == PDFOBJ_NAME) {
374 CFX_ByteString name = pCSObj->GetConstString();
375 CPDF_ColorSpace* pCS = _CSFromName(name);
376 if (!pCS && pResources) {
377 CPDF_Dictionary* pList = pResources->GetDict(FX_BSTRC("ColorSpace"));
379 pCSObj = pList->GetElementValue(name);
380 return GetColorSpace(pCSObj, NULL);
383 if (pCS == NULL || pResources == NULL) {
386 CPDF_Dictionary* pColorSpaces = pResources->GetDict(FX_BSTRC("ColorSpace"));
387 if (pColorSpaces == NULL) {
390 CPDF_Object* pDefaultCS = NULL;
391 switch (pCS->GetFamily()) {
392 case PDFCS_DEVICERGB:
393 pDefaultCS = pColorSpaces->GetElementValue(FX_BSTRC("DefaultRGB"));
395 case PDFCS_DEVICEGRAY:
396 pDefaultCS = pColorSpaces->GetElementValue(FX_BSTRC("DefaultGray"));
398 case PDFCS_DEVICECMYK:
399 pDefaultCS = pColorSpaces->GetElementValue(FX_BSTRC("DefaultCMYK"));
402 if (pDefaultCS == NULL) {
405 return GetColorSpace(pDefaultCS, NULL);
407 if (pCSObj->GetType() != PDFOBJ_ARRAY) {
410 CPDF_Array* pArray = (CPDF_Array*)pCSObj;
411 if (pArray->GetCount() == 0) {
414 if (pArray->GetCount() == 1) {
415 return GetColorSpace(pArray->GetElementValue(0), pResources);
417 CPDF_CountedObject<CPDF_ColorSpace*>* csData = NULL;
418 if (m_ColorSpaceMap.Lookup(pCSObj, csData)) {
421 return csData->m_Obj;
424 FX_BOOL bNew = FALSE;
426 csData = FX_NEW CPDF_CountedObject<CPDF_ColorSpace*>;
432 CPDF_ColorSpace* pCS = CPDF_ColorSpace::Load(m_pPDFDoc, pArray);
439 csData->m_nCount = 2;
441 m_ColorSpaceMap.SetAt(pCSObj, csData);
444 CPDF_ColorSpace* CPDF_DocPageData::GetCopiedColorSpace(CPDF_Object* pCSObj)
449 CPDF_CountedObject<CPDF_ColorSpace*>* csData;
450 if (!m_ColorSpaceMap.Lookup(pCSObj, csData)) {
453 if (!csData->m_Obj) {
457 return csData->m_Obj;
459 void CPDF_DocPageData::ReleaseColorSpace(CPDF_Object* pColorSpace)
464 CPDF_CountedObject<CPDF_ColorSpace*>* csData;
465 if (!m_ColorSpaceMap.Lookup(pColorSpace, csData)) {
468 if (csData->m_Obj && --csData->m_nCount == 0) {
469 csData->m_Obj->ReleaseCS();
470 csData->m_Obj = NULL;
473 CPDF_Pattern* CPDF_DocPageData::GetPattern(CPDF_Object* pPatternObj, FX_BOOL bShading, const CFX_AffineMatrix* matrix)
478 CPDF_CountedObject<CPDF_Pattern*>* ptData = NULL;
479 if (m_PatternMap.Lookup(pPatternObj, ptData)) {
482 return ptData->m_Obj;
485 FX_BOOL bNew = FALSE;
487 ptData = FX_NEW CPDF_CountedObject<CPDF_Pattern*>;
493 CPDF_Pattern* pPattern = NULL;
495 pPattern = FX_NEW CPDF_ShadingPattern(m_pPDFDoc, pPatternObj, bShading, matrix);
497 CPDF_Dictionary* pDict = pPatternObj ? pPatternObj->GetDict() : NULL;
499 int type = pDict->GetInteger(FX_BSTRC("PatternType"));
501 pPattern = FX_NEW CPDF_TilingPattern(m_pPDFDoc, pPatternObj, matrix);
502 } else if (type == 2) {
503 pPattern = FX_NEW CPDF_ShadingPattern(m_pPDFDoc, pPatternObj, FALSE, matrix);
513 ptData->m_nCount = 2;
514 ptData->m_Obj = pPattern;
515 m_PatternMap.SetAt(pPatternObj, ptData);
518 void CPDF_DocPageData::ReleasePattern(CPDF_Object* pPatternObj)
523 CPDF_CountedObject<CPDF_Pattern*>* ptData;
524 if (!m_PatternMap.Lookup(pPatternObj, ptData)) {
527 if (ptData->m_Obj && --ptData->m_nCount == 0) {
528 delete ptData->m_Obj;
529 ptData->m_Obj = NULL;
532 CPDF_Image* CPDF_DocPageData::GetImage(CPDF_Object* pImageStream)
537 FX_DWORD dwImageObjNum = pImageStream->GetObjNum();
538 CPDF_CountedObject<CPDF_Image*>* imageData;
539 if (m_ImageMap.Lookup(dwImageObjNum, imageData)) {
540 imageData->m_nCount ++;
541 return imageData->m_Obj;
543 imageData = FX_NEW CPDF_CountedObject<CPDF_Image*>;
547 CPDF_Image* pImage = FX_NEW CPDF_Image(m_pPDFDoc);
552 pImage->LoadImageF((CPDF_Stream*)pImageStream, FALSE);
553 imageData->m_nCount = 2;
554 imageData->m_Obj = pImage;
555 m_ImageMap.SetAt(dwImageObjNum, imageData);
558 void CPDF_DocPageData::ReleaseImage(CPDF_Object* pImageStream)
563 PDF_DocPageData_Release<FX_DWORD, CPDF_Image*>(m_ImageMap, pImageStream->GetObjNum(), NULL);
565 CPDF_IccProfile* CPDF_DocPageData::GetIccProfile(CPDF_Stream* pIccProfileStream)
567 if (!pIccProfileStream) {
570 CPDF_CountedObject<CPDF_IccProfile*>* ipData = NULL;
571 if (m_IccProfileMap.Lookup(pIccProfileStream, ipData)) {
573 return ipData->m_Obj;
575 CPDF_StreamAcc stream;
576 stream.LoadAllData(pIccProfileStream, FALSE);
578 CPDF_Stream* pCopiedStream = NULL;
579 CRYPT_SHA1Generate(stream.GetData(), stream.GetSize(), digest);
580 if (m_HashProfileMap.Lookup(CFX_ByteStringC(digest, 20), (void*&)pCopiedStream)) {
581 m_IccProfileMap.Lookup(pCopiedStream, ipData);
583 return ipData->m_Obj;
585 CPDF_IccProfile* pProfile = FX_NEW CPDF_IccProfile(stream.GetData(), stream.GetSize());
589 ipData = FX_NEW CPDF_CountedObject<CPDF_IccProfile*>;
594 ipData->m_nCount = 2;
595 ipData->m_Obj = pProfile;
596 m_IccProfileMap.SetAt(pIccProfileStream, ipData);
597 m_HashProfileMap.SetAt(CFX_ByteStringC(digest, 20), pIccProfileStream);
600 void CPDF_DocPageData::ReleaseIccProfile(CPDF_Stream* pIccProfileStream, CPDF_IccProfile* pIccProfile)
602 if (!pIccProfileStream && !pIccProfile) {
605 CPDF_CountedObject<CPDF_IccProfile*>* ipData = NULL;
606 if (m_IccProfileMap.Lookup(pIccProfileStream, ipData) && ipData->m_nCount < 2) {
607 FX_POSITION pos = m_HashProfileMap.GetStartPosition();
610 CPDF_Stream* pFindStream = NULL;
611 m_HashProfileMap.GetNextAssoc(pos, key, (void*&)pFindStream);
612 if (pIccProfileStream == pFindStream) {
613 m_HashProfileMap.RemoveKey(key);
618 PDF_DocPageData_Release<CPDF_Stream*, CPDF_IccProfile*>(m_IccProfileMap, pIccProfileStream, pIccProfile);
620 CPDF_StreamAcc* CPDF_DocPageData::GetFontFileStreamAcc(CPDF_Stream* pFontStream)
625 CPDF_CountedObject<CPDF_StreamAcc*>* ftData;
626 if (m_FontFileMap.Lookup(pFontStream, ftData)) {
628 return ftData->m_Obj;
630 ftData = FX_NEW CPDF_CountedObject<CPDF_StreamAcc*>;
634 CPDF_StreamAcc* pFontFile = FX_NEW CPDF_StreamAcc;
639 CPDF_Dictionary* pFontDict = pFontStream->GetDict();
640 FX_INT32 org_size = pFontDict->GetInteger(FX_BSTRC("Length1")) + pFontDict->GetInteger(FX_BSTRC("Length2")) + pFontDict->GetInteger(FX_BSTRC("Length3"));
644 pFontFile->LoadAllData(pFontStream, FALSE, org_size);
645 ftData->m_nCount = 2;
646 ftData->m_Obj = pFontFile;
647 m_FontFileMap.SetAt(pFontStream, ftData);
650 void CPDF_DocPageData::ReleaseFontFileStreamAcc(CPDF_Stream* pFontStream, FX_BOOL bForce)
655 PDF_DocPageData_Release<CPDF_Stream*, CPDF_StreamAcc*>(m_FontFileMap, pFontStream, NULL, bForce);