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