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