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