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, int nComponents)
112 return GetValidatePageData()->GetIccProfile(pStream, nComponents);
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)
138 m_FontMap.InitHashTable(64);
139 m_ColorSpaceMap.InitHashTable(32);
140 m_PatternMap.InitHashTable(16);
141 m_ImageMap.InitHashTable(64);
142 m_IccProfileMap.InitHashTable(16);
143 m_FontFileMap.InitHashTable(32);
145 CPDF_DocPageData::~CPDF_DocPageData()
149 FX_POSITION pos = NULL;
151 void CPDF_DocPageData::Clear(FX_BOOL bRelease)
156 pos = m_PatternMap.GetStartPosition();
159 CPDF_CountedObject<CPDF_Pattern*>* ptData;
160 m_PatternMap.GetNextAssoc(pos, ptObj, ptData);
161 nCount = ptData->m_nCount;
162 if (bRelease || nCount < 2) {
163 delete ptData->m_Obj;
164 ptData->m_Obj = NULL;
169 pos = m_FontMap.GetStartPosition();
171 CPDF_Dictionary* fontDict;
172 CPDF_CountedObject<CPDF_Font*>* fontData;
173 m_FontMap.GetNextAssoc(pos, fontDict, fontData);
174 nCount = fontData->m_nCount;
175 if (bRelease || nCount < 2) {
176 delete fontData->m_Obj;
177 fontData->m_Obj = NULL;
182 pos = m_ImageMap.GetStartPosition();
185 CPDF_CountedObject<CPDF_Image*>* imageData;
186 m_ImageMap.GetNextAssoc(pos, objNum, imageData);
187 nCount = imageData->m_nCount;
188 if (bRelease || nCount < 2) {
189 delete imageData->m_Obj;
191 m_ImageMap.RemoveKey(objNum);
196 pos = m_ColorSpaceMap.GetStartPosition();
199 CPDF_CountedObject<CPDF_ColorSpace*>* csData;
200 m_ColorSpaceMap.GetNextAssoc(pos, csKey, csData);
201 nCount = csData->m_nCount;
202 if (bRelease || nCount < 2) {
203 csData->m_Obj->ReleaseCS();
204 csData->m_Obj = NULL;
209 pos = m_IccProfileMap.GetStartPosition();
212 CPDF_CountedObject<CPDF_IccProfile*>* ipData;
213 m_IccProfileMap.GetNextAssoc(pos, ipKey, ipData);
214 nCount = ipData->m_nCount;
215 if (bRelease || nCount < 2) {
216 FX_POSITION pos2 = m_HashProfileMap.GetStartPosition();
218 CFX_ByteString bsKey;
219 CPDF_Stream* pFindStream = NULL;
220 m_HashProfileMap.GetNextAssoc(pos2, bsKey, (void*&)pFindStream);
221 if (ipKey == pFindStream) {
222 m_HashProfileMap.RemoveKey(bsKey);
226 delete ipData->m_Obj;
228 m_IccProfileMap.RemoveKey(ipKey);
233 pos = m_FontFileMap.GetStartPosition();
236 CPDF_CountedObject<CPDF_StreamAcc*>* ftData;
237 m_FontFileMap.GetNextAssoc(pos, ftKey, ftData);
238 nCount = ftData->m_nCount;
239 if (bRelease || nCount < 2) {
240 delete ftData->m_Obj;
242 m_FontFileMap.RemoveKey(ftKey);
247 CPDF_Font* CPDF_DocPageData::GetFont(CPDF_Dictionary* pFontDict, FX_BOOL findOnly)
253 CPDF_CountedObject<CPDF_Font*>* fontData;
254 if (m_FontMap.Lookup(pFontDict, fontData)) {
255 if (!fontData->m_Obj) {
258 fontData->m_nCount ++;
259 return fontData->m_Obj;
263 CPDF_CountedObject<CPDF_Font*>* fontData = NULL;
264 if (m_FontMap.Lookup(pFontDict, fontData)) {
265 if (fontData->m_Obj) {
266 fontData->m_nCount ++;
267 return fontData->m_Obj;
270 FX_BOOL bNew = FALSE;
272 fontData = FX_NEW CPDF_CountedObject<CPDF_Font*>;
278 CPDF_Font* pFont = CPDF_Font::CreateFontF(m_pPDFDoc, pFontDict);
285 fontData->m_nCount = 2;
286 fontData->m_Obj = pFont;
287 m_FontMap.SetAt(pFontDict, fontData);
290 CPDF_Font* CPDF_DocPageData::GetStandardFont(FX_BSTR fontName, CPDF_FontEncoding* pEncoding)
292 if (fontName.IsEmpty()) {
295 FX_POSITION pos = m_FontMap.GetStartPosition();
297 CPDF_Dictionary* fontDict;
298 CPDF_CountedObject<CPDF_Font*>* fontData;
299 m_FontMap.GetNextAssoc(pos, fontDict, fontData);
300 CPDF_Font* pFont = fontData->m_Obj;
304 if (pFont->GetBaseFont() != fontName) {
307 if (pFont->IsEmbedded()) {
310 if (pFont->GetFontType() != PDFFONT_TYPE1) {
313 if (pFont->GetFontDict()->KeyExist(FX_BSTRC("Widths"))) {
316 CPDF_Type1Font* pT1Font = pFont->GetType1Font();
317 if (pEncoding && !pT1Font->GetEncoding()->IsIdentical(pEncoding)) {
320 fontData->m_nCount ++;
323 CPDF_Dictionary* pDict = FX_NEW CPDF_Dictionary;
324 pDict->SetAtName(FX_BSTRC("Type"), FX_BSTRC("Font"));
325 pDict->SetAtName(FX_BSTRC("Subtype"), FX_BSTRC("Type1"));
326 pDict->SetAtName(FX_BSTRC("BaseFont"), fontName);
328 pDict->SetAt(FX_BSTRC("Encoding"), pEncoding->Realize());
330 m_pPDFDoc->AddIndirectObject(pDict);
331 CPDF_CountedObject<CPDF_Font*>* fontData = FX_NEW CPDF_CountedObject<CPDF_Font*>;
335 CPDF_Font* pFont = CPDF_Font::CreateFontF(m_pPDFDoc, pDict);
340 fontData->m_nCount = 2;
341 fontData->m_Obj = pFont;
342 m_FontMap.SetAt(pDict, fontData);
345 void CPDF_DocPageData::ReleaseFont(CPDF_Dictionary* pFontDict)
350 CPDF_CountedObject<CPDF_Font*>* fontData;
351 if (!m_FontMap.Lookup(pFontDict, fontData)) {
354 if (fontData->m_Obj && --fontData->m_nCount == 0) {
355 delete fontData->m_Obj;
356 fontData->m_Obj = NULL;
359 CPDF_ColorSpace* CPDF_DocPageData::GetColorSpace(CPDF_Object* pCSObj, CPDF_Dictionary* pResources)
364 if (pCSObj->GetType() == PDFOBJ_NAME) {
365 CFX_ByteString name = pCSObj->GetConstString();
366 CPDF_ColorSpace* pCS = _CSFromName(name);
367 if (!pCS && pResources) {
368 CPDF_Dictionary* pList = pResources->GetDict(FX_BSTRC("ColorSpace"));
370 pCSObj = pList->GetElementValue(name);
371 return GetColorSpace(pCSObj, NULL);
374 if (pCS == NULL || pResources == NULL) {
377 CPDF_Dictionary* pColorSpaces = pResources->GetDict(FX_BSTRC("ColorSpace"));
378 if (pColorSpaces == NULL) {
381 CPDF_Object* pDefaultCS = NULL;
382 switch (pCS->GetFamily()) {
383 case PDFCS_DEVICERGB:
384 pDefaultCS = pColorSpaces->GetElementValue(FX_BSTRC("DefaultRGB"));
386 case PDFCS_DEVICEGRAY:
387 pDefaultCS = pColorSpaces->GetElementValue(FX_BSTRC("DefaultGray"));
389 case PDFCS_DEVICECMYK:
390 pDefaultCS = pColorSpaces->GetElementValue(FX_BSTRC("DefaultCMYK"));
393 if (pDefaultCS == NULL) {
396 return GetColorSpace(pDefaultCS, NULL);
398 if (pCSObj->GetType() != PDFOBJ_ARRAY) {
401 CPDF_Array* pArray = (CPDF_Array*)pCSObj;
402 if (pArray->GetCount() == 0) {
405 if (pArray->GetCount() == 1) {
406 return GetColorSpace(pArray->GetElementValue(0), pResources);
408 CPDF_CountedObject<CPDF_ColorSpace*>* csData = NULL;
409 if (m_ColorSpaceMap.Lookup(pCSObj, csData)) {
412 return csData->m_Obj;
415 FX_BOOL bNew = FALSE;
417 csData = FX_NEW CPDF_CountedObject<CPDF_ColorSpace*>;
423 CPDF_ColorSpace* pCS = CPDF_ColorSpace::Load(m_pPDFDoc, pArray);
430 csData->m_nCount = 2;
432 m_ColorSpaceMap.SetAt(pCSObj, csData);
435 CPDF_ColorSpace* CPDF_DocPageData::GetCopiedColorSpace(CPDF_Object* pCSObj)
440 CPDF_CountedObject<CPDF_ColorSpace*>* csData;
441 if (!m_ColorSpaceMap.Lookup(pCSObj, csData)) {
444 if (!csData->m_Obj) {
448 return csData->m_Obj;
450 void CPDF_DocPageData::ReleaseColorSpace(CPDF_Object* pColorSpace)
455 CPDF_CountedObject<CPDF_ColorSpace*>* csData;
456 if (!m_ColorSpaceMap.Lookup(pColorSpace, csData)) {
459 if (csData->m_Obj && --csData->m_nCount == 0) {
460 csData->m_Obj->ReleaseCS();
461 csData->m_Obj = NULL;
464 CPDF_Pattern* CPDF_DocPageData::GetPattern(CPDF_Object* pPatternObj, FX_BOOL bShading, const CFX_AffineMatrix* matrix)
469 CPDF_CountedObject<CPDF_Pattern*>* ptData = NULL;
470 if (m_PatternMap.Lookup(pPatternObj, ptData)) {
473 return ptData->m_Obj;
476 FX_BOOL bNew = FALSE;
478 ptData = FX_NEW CPDF_CountedObject<CPDF_Pattern*>;
484 CPDF_Pattern* pPattern = NULL;
486 pPattern = FX_NEW CPDF_ShadingPattern(m_pPDFDoc, pPatternObj, bShading, matrix);
488 CPDF_Dictionary* pDict = pPatternObj->GetDict();
490 int type = pDict->GetInteger(FX_BSTRC("PatternType"));
492 pPattern = FX_NEW CPDF_TilingPattern(m_pPDFDoc, pPatternObj, matrix);
493 } else if (type == 2) {
494 pPattern = FX_NEW CPDF_ShadingPattern(m_pPDFDoc, pPatternObj, FALSE, matrix);
504 ptData->m_nCount = 2;
505 ptData->m_Obj = pPattern;
506 m_PatternMap.SetAt(pPatternObj, ptData);
509 void CPDF_DocPageData::ReleasePattern(CPDF_Object* pPatternObj)
514 CPDF_CountedObject<CPDF_Pattern*>* ptData;
515 if (!m_PatternMap.Lookup(pPatternObj, ptData)) {
518 if (ptData->m_Obj && --ptData->m_nCount == 0) {
519 delete ptData->m_Obj;
520 ptData->m_Obj = NULL;
523 CPDF_Image* CPDF_DocPageData::GetImage(CPDF_Object* pImageStream)
528 FX_DWORD dwImageObjNum = pImageStream->GetObjNum();
529 CPDF_CountedObject<CPDF_Image*>* imageData;
530 if (m_ImageMap.Lookup(dwImageObjNum, imageData)) {
531 imageData->m_nCount ++;
532 return imageData->m_Obj;
534 imageData = FX_NEW CPDF_CountedObject<CPDF_Image*>;
538 CPDF_Image* pImage = FX_NEW CPDF_Image(m_pPDFDoc);
543 pImage->LoadImageF((CPDF_Stream*)pImageStream, FALSE);
544 imageData->m_nCount = 2;
545 imageData->m_Obj = pImage;
546 m_ImageMap.SetAt(dwImageObjNum, imageData);
549 void CPDF_DocPageData::ReleaseImage(CPDF_Object* pImageStream)
554 PDF_DocPageData_Release<FX_DWORD, CPDF_Image*>(m_ImageMap, pImageStream->GetObjNum(), NULL);
556 CPDF_IccProfile* CPDF_DocPageData::GetIccProfile(CPDF_Stream* pIccProfileStream, FX_INT32 nComponents)
558 if (!pIccProfileStream) {
561 CPDF_CountedObject<CPDF_IccProfile*>* ipData = NULL;
562 if (m_IccProfileMap.Lookup(pIccProfileStream, ipData)) {
564 return ipData->m_Obj;
566 CPDF_StreamAcc stream;
567 stream.LoadAllData(pIccProfileStream, FALSE);
569 CPDF_Stream* pCopiedStream = NULL;
570 CRYPT_SHA1Generate(stream.GetData(), stream.GetSize(), digest);
571 if (m_HashProfileMap.Lookup(CFX_ByteStringC(digest, 20), (void*&)pCopiedStream)) {
572 m_IccProfileMap.Lookup(pCopiedStream, ipData);
574 return ipData->m_Obj;
576 CPDF_IccProfile* pProfile = FX_NEW CPDF_IccProfile(stream.GetData(), stream.GetSize(), nComponents);
580 ipData = FX_NEW CPDF_CountedObject<CPDF_IccProfile*>;
585 ipData->m_nCount = 2;
586 ipData->m_Obj = pProfile;
587 m_IccProfileMap.SetAt(pIccProfileStream, ipData);
588 m_HashProfileMap.SetAt(CFX_ByteStringC(digest, 20), pIccProfileStream);
591 void CPDF_DocPageData::ReleaseIccProfile(CPDF_Stream* pIccProfileStream, CPDF_IccProfile* pIccProfile)
593 if (!pIccProfileStream && !pIccProfile) {
596 CPDF_CountedObject<CPDF_IccProfile*>* ipData = NULL;
597 if (m_IccProfileMap.Lookup(pIccProfileStream, ipData) && ipData->m_nCount < 2) {
598 FX_POSITION pos = m_HashProfileMap.GetStartPosition();
601 CPDF_Stream* pFindStream = NULL;
602 m_HashProfileMap.GetNextAssoc(pos, key, (void*&)pFindStream);
603 if (pIccProfileStream == pFindStream) {
604 m_HashProfileMap.RemoveKey(key);
609 PDF_DocPageData_Release<CPDF_Stream*, CPDF_IccProfile*>(m_IccProfileMap, pIccProfileStream, pIccProfile);
611 CPDF_StreamAcc* CPDF_DocPageData::GetFontFileStreamAcc(CPDF_Stream* pFontStream)
616 CPDF_CountedObject<CPDF_StreamAcc*>* ftData;
617 if (m_FontFileMap.Lookup(pFontStream, ftData)) {
619 return ftData->m_Obj;
621 ftData = FX_NEW CPDF_CountedObject<CPDF_StreamAcc*>;
625 CPDF_StreamAcc* pFontFile = FX_NEW CPDF_StreamAcc;
630 CPDF_Dictionary* pFontDict = pFontStream->GetDict();
631 FX_INT32 org_size = pFontDict->GetInteger(FX_BSTRC("Length1")) + pFontDict->GetInteger(FX_BSTRC("Length2")) + pFontDict->GetInteger(FX_BSTRC("Length3"));
635 pFontFile->LoadAllData(pFontStream, FALSE, org_size);
636 ftData->m_nCount = 2;
637 ftData->m_Obj = pFontFile;
638 m_FontFileMap.SetAt(pFontStream, ftData);
641 void CPDF_DocPageData::ReleaseFontFileStreamAcc(CPDF_Stream* pFontStream, FX_BOOL bForce)
646 PDF_DocPageData_Release<CPDF_Stream*, CPDF_StreamAcc*>(m_FontFileMap, pFontStream, NULL, bForce);