• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "core/fpdfapi/page/cpdf_docpagedata.h"
8 
9 #include <algorithm>
10 #include <memory>
11 #include <set>
12 #include <utility>
13 
14 #include "core/fdrm/crypto/fx_crypt.h"
15 #include "core/fpdfapi/cpdf_modulemgr.h"
16 #include "core/fpdfapi/font/cpdf_type1font.h"
17 #include "core/fpdfapi/font/font_int.h"
18 #include "core/fpdfapi/page/cpdf_image.h"
19 #include "core/fpdfapi/page/cpdf_pagemodule.h"
20 #include "core/fpdfapi/page/cpdf_pattern.h"
21 #include "core/fpdfapi/page/cpdf_shadingpattern.h"
22 #include "core/fpdfapi/page/cpdf_tilingpattern.h"
23 #include "core/fpdfapi/parser/cpdf_array.h"
24 #include "core/fpdfapi/parser/cpdf_dictionary.h"
25 #include "core/fpdfapi/parser/cpdf_document.h"
26 #include "core/fpdfapi/parser/cpdf_name.h"
27 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
28 #include "third_party/base/stl_util.h"
29 
CPDF_DocPageData(CPDF_Document * pPDFDoc)30 CPDF_DocPageData::CPDF_DocPageData(CPDF_Document* pPDFDoc)
31     : m_pPDFDoc(pPDFDoc), m_bForceClear(false) {}
32 
~CPDF_DocPageData()33 CPDF_DocPageData::~CPDF_DocPageData() {
34   Clear(false);
35   Clear(true);
36 
37   for (auto& it : m_PatternMap)
38     delete it.second;
39   m_PatternMap.clear();
40 
41   for (auto& it : m_FontMap)
42     delete it.second;
43   m_FontMap.clear();
44 
45   for (auto& it : m_ColorSpaceMap)
46     delete it.second;
47   m_ColorSpaceMap.clear();
48 }
49 
Clear(bool bForceRelease)50 void CPDF_DocPageData::Clear(bool bForceRelease) {
51   m_bForceClear = bForceRelease;
52 
53   for (auto& it : m_PatternMap) {
54     CPDF_CountedPattern* ptData = it.second;
55     if (!ptData->get())
56       continue;
57 
58     if (bForceRelease || ptData->use_count() < 2)
59       ptData->clear();
60   }
61 
62   for (auto& it : m_FontMap) {
63     CPDF_CountedFont* fontData = it.second;
64     if (!fontData->get())
65       continue;
66 
67     if (bForceRelease || fontData->use_count() < 2) {
68       fontData->clear();
69     }
70   }
71 
72   for (auto& it : m_ColorSpaceMap) {
73     CPDF_CountedColorSpace* csData = it.second;
74     if (!csData->get())
75       continue;
76 
77     if (bForceRelease || csData->use_count() < 2) {
78       csData->get()->Release();
79       csData->reset(nullptr);
80     }
81   }
82 
83   for (auto it = m_IccProfileMap.begin(); it != m_IccProfileMap.end();) {
84     auto curr_it = it++;
85     CPDF_CountedIccProfile* ipData = curr_it->second;
86     if (!ipData->get())
87       continue;
88 
89     if (bForceRelease || ipData->use_count() < 2) {
90       for (auto hash_it = m_HashProfileMap.begin();
91            hash_it != m_HashProfileMap.end(); ++hash_it) {
92         if (curr_it->first == hash_it->second) {
93           m_HashProfileMap.erase(hash_it);
94           break;
95         }
96       }
97       delete ipData->get();
98       delete ipData;
99       m_IccProfileMap.erase(curr_it);
100     }
101   }
102 
103   for (auto it = m_FontFileMap.begin(); it != m_FontFileMap.end();) {
104     auto curr_it = it++;
105     CPDF_CountedStreamAcc* pCountedFont = curr_it->second;
106     if (!pCountedFont->get())
107       continue;
108 
109     if (bForceRelease || pCountedFont->use_count() < 2) {
110       delete pCountedFont->get();
111       delete pCountedFont;
112       m_FontFileMap.erase(curr_it);
113     }
114   }
115 
116   for (auto it = m_ImageMap.begin(); it != m_ImageMap.end();) {
117     auto curr_it = it++;
118     CPDF_CountedImage* pCountedImage = curr_it->second;
119     if (!pCountedImage->get())
120       continue;
121 
122     if (bForceRelease || pCountedImage->use_count() < 2) {
123       delete pCountedImage->get();
124       delete pCountedImage;
125       m_ImageMap.erase(curr_it);
126     }
127   }
128 }
129 
GetFont(CPDF_Dictionary * pFontDict)130 CPDF_Font* CPDF_DocPageData::GetFont(CPDF_Dictionary* pFontDict) {
131   if (!pFontDict)
132     return nullptr;
133 
134   CPDF_CountedFont* pFontData = nullptr;
135   auto it = m_FontMap.find(pFontDict);
136   if (it != m_FontMap.end()) {
137     pFontData = it->second;
138     if (pFontData->get()) {
139       return pFontData->AddRef();
140     }
141   }
142   std::unique_ptr<CPDF_Font> pFont = CPDF_Font::Create(m_pPDFDoc, pFontDict);
143   if (!pFont)
144     return nullptr;
145 
146   if (pFontData) {
147     pFontData->reset(std::move(pFont));
148   } else {
149     pFontData = new CPDF_CountedFont(std::move(pFont));
150     m_FontMap[pFontDict] = pFontData;
151   }
152   return pFontData->AddRef();
153 }
154 
GetStandardFont(const CFX_ByteString & fontName,CPDF_FontEncoding * pEncoding)155 CPDF_Font* CPDF_DocPageData::GetStandardFont(const CFX_ByteString& fontName,
156                                              CPDF_FontEncoding* pEncoding) {
157   if (fontName.IsEmpty())
158     return nullptr;
159 
160   for (auto& it : m_FontMap) {
161     CPDF_CountedFont* fontData = it.second;
162     CPDF_Font* pFont = fontData->get();
163     if (!pFont)
164       continue;
165     if (pFont->GetBaseFont() != fontName)
166       continue;
167     if (pFont->IsEmbedded())
168       continue;
169     if (!pFont->IsType1Font())
170       continue;
171     if (pFont->GetFontDict()->KeyExist("Widths"))
172       continue;
173 
174     CPDF_Type1Font* pT1Font = pFont->AsType1Font();
175     if (pEncoding && !pT1Font->GetEncoding()->IsIdentical(pEncoding))
176       continue;
177 
178     return fontData->AddRef();
179   }
180 
181   CPDF_Dictionary* pDict = m_pPDFDoc->NewIndirect<CPDF_Dictionary>();
182   pDict->SetNewFor<CPDF_Name>("Type", "Font");
183   pDict->SetNewFor<CPDF_Name>("Subtype", "Type1");
184   pDict->SetNewFor<CPDF_Name>("BaseFont", fontName);
185   if (pEncoding) {
186     pDict->SetFor("Encoding",
187                   pEncoding->Realize(m_pPDFDoc->GetByteStringPool()));
188   }
189 
190   std::unique_ptr<CPDF_Font> pFont = CPDF_Font::Create(m_pPDFDoc, pDict);
191   if (!pFont)
192     return nullptr;
193 
194   CPDF_CountedFont* fontData = new CPDF_CountedFont(std::move(pFont));
195   m_FontMap[pDict] = fontData;
196   return fontData->AddRef();
197 }
198 
ReleaseFont(const CPDF_Dictionary * pFontDict)199 void CPDF_DocPageData::ReleaseFont(const CPDF_Dictionary* pFontDict) {
200   if (!pFontDict)
201     return;
202 
203   auto it = m_FontMap.find(pFontDict);
204   if (it == m_FontMap.end())
205     return;
206 
207   CPDF_CountedFont* pFontData = it->second;
208   if (!pFontData->get())
209     return;
210 
211   pFontData->RemoveRef();
212   if (pFontData->use_count() > 1)
213     return;
214 
215   // We have font data only in m_FontMap cache. Clean it.
216   pFontData->clear();
217 }
218 
GetColorSpace(CPDF_Object * pCSObj,const CPDF_Dictionary * pResources)219 CPDF_ColorSpace* CPDF_DocPageData::GetColorSpace(
220     CPDF_Object* pCSObj,
221     const CPDF_Dictionary* pResources) {
222   std::set<CPDF_Object*> visited;
223   return GetColorSpaceImpl(pCSObj, pResources, &visited);
224 }
225 
GetColorSpaceImpl(CPDF_Object * pCSObj,const CPDF_Dictionary * pResources,std::set<CPDF_Object * > * pVisited)226 CPDF_ColorSpace* CPDF_DocPageData::GetColorSpaceImpl(
227     CPDF_Object* pCSObj,
228     const CPDF_Dictionary* pResources,
229     std::set<CPDF_Object*>* pVisited) {
230   if (!pCSObj)
231     return nullptr;
232 
233   if (pdfium::ContainsKey(*pVisited, pCSObj))
234     return nullptr;
235 
236   if (pCSObj->IsName()) {
237     CFX_ByteString name = pCSObj->GetString();
238     CPDF_ColorSpace* pCS = CPDF_ColorSpace::ColorspaceFromName(name);
239     if (!pCS && pResources) {
240       CPDF_Dictionary* pList = pResources->GetDictFor("ColorSpace");
241       if (pList) {
242         pdfium::ScopedSetInsertion<CPDF_Object*> insertion(pVisited, pCSObj);
243         return GetColorSpaceImpl(pList->GetDirectObjectFor(name), nullptr,
244                                  pVisited);
245       }
246     }
247     if (!pCS || !pResources)
248       return pCS;
249 
250     CPDF_Dictionary* pColorSpaces = pResources->GetDictFor("ColorSpace");
251     if (!pColorSpaces)
252       return pCS;
253 
254     CPDF_Object* pDefaultCS = nullptr;
255     switch (pCS->GetFamily()) {
256       case PDFCS_DEVICERGB:
257         pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultRGB");
258         break;
259       case PDFCS_DEVICEGRAY:
260         pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultGray");
261         break;
262       case PDFCS_DEVICECMYK:
263         pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultCMYK");
264         break;
265     }
266     if (!pDefaultCS)
267       return pCS;
268 
269     pdfium::ScopedSetInsertion<CPDF_Object*> insertion(pVisited, pCSObj);
270     return GetColorSpaceImpl(pDefaultCS, nullptr, pVisited);
271   }
272 
273   CPDF_Array* pArray = pCSObj->AsArray();
274   if (!pArray || pArray->IsEmpty())
275     return nullptr;
276 
277   if (pArray->GetCount() == 1) {
278     pdfium::ScopedSetInsertion<CPDF_Object*> insertion(pVisited, pCSObj);
279     return GetColorSpaceImpl(pArray->GetDirectObjectAt(0), pResources,
280                              pVisited);
281   }
282 
283   CPDF_CountedColorSpace* csData = nullptr;
284   auto it = m_ColorSpaceMap.find(pCSObj);
285   if (it != m_ColorSpaceMap.end()) {
286     csData = it->second;
287     if (csData->get()) {
288       return csData->AddRef();
289     }
290   }
291 
292   std::unique_ptr<CPDF_ColorSpace> pCS =
293       CPDF_ColorSpace::Load(m_pPDFDoc, pArray);
294   if (!pCS)
295     return nullptr;
296 
297   if (csData) {
298     csData->reset(std::move(pCS));
299   } else {
300     csData = new CPDF_CountedColorSpace(std::move(pCS));
301     m_ColorSpaceMap[pCSObj] = csData;
302   }
303   return csData->AddRef();
304 }
305 
GetCopiedColorSpace(CPDF_Object * pCSObj)306 CPDF_ColorSpace* CPDF_DocPageData::GetCopiedColorSpace(CPDF_Object* pCSObj) {
307   if (!pCSObj)
308     return nullptr;
309 
310   auto it = m_ColorSpaceMap.find(pCSObj);
311   if (it != m_ColorSpaceMap.end())
312     return it->second->AddRef();
313 
314   return nullptr;
315 }
316 
ReleaseColorSpace(const CPDF_Object * pColorSpace)317 void CPDF_DocPageData::ReleaseColorSpace(const CPDF_Object* pColorSpace) {
318   if (!pColorSpace)
319     return;
320 
321   auto it = m_ColorSpaceMap.find(pColorSpace);
322   if (it == m_ColorSpaceMap.end())
323     return;
324 
325   CPDF_CountedColorSpace* pCountedColorSpace = it->second;
326   if (!pCountedColorSpace->get())
327     return;
328 
329   pCountedColorSpace->RemoveRef();
330   if (pCountedColorSpace->use_count() > 1)
331     return;
332 
333   // We have item only in m_ColorSpaceMap cache. Clean it.
334   pCountedColorSpace->get()->Release();
335   pCountedColorSpace->reset(nullptr);
336 }
337 
GetPattern(CPDF_Object * pPatternObj,bool bShading,const CFX_Matrix & matrix)338 CPDF_Pattern* CPDF_DocPageData::GetPattern(CPDF_Object* pPatternObj,
339                                            bool bShading,
340                                            const CFX_Matrix& matrix) {
341   if (!pPatternObj)
342     return nullptr;
343 
344   CPDF_CountedPattern* ptData = nullptr;
345   auto it = m_PatternMap.find(pPatternObj);
346   if (it != m_PatternMap.end()) {
347     ptData = it->second;
348     if (ptData->get()) {
349       return ptData->AddRef();
350     }
351   }
352   std::unique_ptr<CPDF_Pattern> pPattern;
353   if (bShading) {
354     pPattern = pdfium::MakeUnique<CPDF_ShadingPattern>(m_pPDFDoc, pPatternObj,
355                                                        true, matrix);
356   } else {
357     CPDF_Dictionary* pDict = pPatternObj ? pPatternObj->GetDict() : nullptr;
358     if (pDict) {
359       int type = pDict->GetIntegerFor("PatternType");
360       if (type == CPDF_Pattern::TILING) {
361         pPattern = pdfium::MakeUnique<CPDF_TilingPattern>(m_pPDFDoc,
362                                                           pPatternObj, matrix);
363       } else if (type == CPDF_Pattern::SHADING) {
364         pPattern = pdfium::MakeUnique<CPDF_ShadingPattern>(
365             m_pPDFDoc, pPatternObj, false, matrix);
366       }
367     }
368   }
369   if (!pPattern)
370     return nullptr;
371 
372   if (ptData) {
373     ptData->reset(std::move(pPattern));
374   } else {
375     ptData = new CPDF_CountedPattern(std::move(pPattern));
376     m_PatternMap[pPatternObj] = ptData;
377   }
378   return ptData->AddRef();
379 }
380 
ReleasePattern(const CPDF_Object * pPatternObj)381 void CPDF_DocPageData::ReleasePattern(const CPDF_Object* pPatternObj) {
382   if (!pPatternObj)
383     return;
384 
385   auto it = m_PatternMap.find(pPatternObj);
386   if (it == m_PatternMap.end())
387     return;
388 
389   CPDF_CountedPattern* pPattern = it->second;
390   if (!pPattern->get())
391     return;
392 
393   pPattern->RemoveRef();
394   if (pPattern->use_count() > 1)
395     return;
396 
397   // We have item only in m_PatternMap cache. Clean it.
398   pPattern->clear();
399 }
400 
GetImage(uint32_t dwStreamObjNum)401 CPDF_Image* CPDF_DocPageData::GetImage(uint32_t dwStreamObjNum) {
402   ASSERT(dwStreamObjNum);
403   auto it = m_ImageMap.find(dwStreamObjNum);
404   if (it != m_ImageMap.end())
405     return it->second->AddRef();
406 
407   CPDF_CountedImage* pCountedImage = new CPDF_CountedImage(
408       pdfium::MakeUnique<CPDF_Image>(m_pPDFDoc, dwStreamObjNum));
409   m_ImageMap[dwStreamObjNum] = pCountedImage;
410   return pCountedImage->AddRef();
411 }
412 
ReleaseImage(uint32_t dwStreamObjNum)413 void CPDF_DocPageData::ReleaseImage(uint32_t dwStreamObjNum) {
414   ASSERT(dwStreamObjNum);
415   auto it = m_ImageMap.find(dwStreamObjNum);
416   if (it == m_ImageMap.end())
417     return;
418 
419   CPDF_CountedImage* pCountedImage = it->second;
420   if (!pCountedImage)
421     return;
422 
423   pCountedImage->RemoveRef();
424   if (pCountedImage->use_count() > 1)
425     return;
426 
427   // We have item only in m_ImageMap cache. Clean it.
428   delete pCountedImage->get();
429   delete pCountedImage;
430   m_ImageMap.erase(it);
431 }
432 
GetIccProfile(CPDF_Stream * pIccProfileStream)433 CPDF_IccProfile* CPDF_DocPageData::GetIccProfile(
434     CPDF_Stream* pIccProfileStream) {
435   if (!pIccProfileStream)
436     return nullptr;
437 
438   auto it = m_IccProfileMap.find(pIccProfileStream);
439   if (it != m_IccProfileMap.end())
440     return it->second->AddRef();
441 
442   CPDF_StreamAcc stream;
443   stream.LoadAllData(pIccProfileStream, false);
444   uint8_t digest[20];
445   CRYPT_SHA1Generate(stream.GetData(), stream.GetSize(), digest);
446   CFX_ByteString bsDigest(digest, 20);
447   auto hash_it = m_HashProfileMap.find(bsDigest);
448   if (hash_it != m_HashProfileMap.end()) {
449     auto it_copied_stream = m_IccProfileMap.find(hash_it->second);
450     if (it_copied_stream != m_IccProfileMap.end())
451       return it_copied_stream->second->AddRef();
452   }
453   CPDF_CountedIccProfile* ipData = new CPDF_CountedIccProfile(
454       pdfium::MakeUnique<CPDF_IccProfile>(stream.GetData(), stream.GetSize()));
455   m_IccProfileMap[pIccProfileStream] = ipData;
456   m_HashProfileMap[bsDigest] = pIccProfileStream;
457   return ipData->AddRef();
458 }
459 
ReleaseIccProfile(const CPDF_IccProfile * pIccProfile)460 void CPDF_DocPageData::ReleaseIccProfile(const CPDF_IccProfile* pIccProfile) {
461   ASSERT(pIccProfile);
462 
463   for (auto it = m_IccProfileMap.begin(); it != m_IccProfileMap.end(); ++it) {
464     CPDF_CountedIccProfile* profile = it->second;
465     if (profile->get() != pIccProfile)
466       continue;
467 
468     profile->RemoveRef();
469     if (profile->use_count() > 1)
470       continue;
471     // We have item only in m_IccProfileMap cache. Clean it.
472     delete profile->get();
473     delete profile;
474     m_IccProfileMap.erase(it);
475     return;
476   }
477 }
478 
GetFontFileStreamAcc(CPDF_Stream * pFontStream)479 CPDF_StreamAcc* CPDF_DocPageData::GetFontFileStreamAcc(
480     CPDF_Stream* pFontStream) {
481   ASSERT(pFontStream);
482 
483   auto it = m_FontFileMap.find(pFontStream);
484   if (it != m_FontFileMap.end())
485     return it->second->AddRef();
486 
487   CPDF_Dictionary* pFontDict = pFontStream->GetDict();
488   int32_t org_size = pFontDict->GetIntegerFor("Length1") +
489                      pFontDict->GetIntegerFor("Length2") +
490                      pFontDict->GetIntegerFor("Length3");
491   org_size = std::max(org_size, 0);
492 
493   auto pFontAcc = pdfium::MakeUnique<CPDF_StreamAcc>();
494   pFontAcc->LoadAllData(pFontStream, false, org_size);
495 
496   CPDF_CountedStreamAcc* pCountedFont =
497       new CPDF_CountedStreamAcc(std::move(pFontAcc));
498   m_FontFileMap[pFontStream] = pCountedFont;
499   return pCountedFont->AddRef();
500 }
501 
ReleaseFontFileStreamAcc(const CPDF_Stream * pFontStream)502 void CPDF_DocPageData::ReleaseFontFileStreamAcc(
503     const CPDF_Stream* pFontStream) {
504   if (!pFontStream)
505     return;
506 
507   auto it = m_FontFileMap.find(pFontStream);
508   if (it == m_FontFileMap.end())
509     return;
510 
511   CPDF_CountedStreamAcc* pCountedStream = it->second;
512   if (!pCountedStream)
513     return;
514 
515   pCountedStream->RemoveRef();
516   if (pCountedStream->use_count() > 1)
517     return;
518 
519   // We have item only in m_FontFileMap cache. Clean it.
520   delete pCountedStream->get();
521   delete pCountedStream;
522   m_FontFileMap.erase(it);
523 }
524 
FindColorSpacePtr(CPDF_Object * pCSObj) const525 CPDF_CountedColorSpace* CPDF_DocPageData::FindColorSpacePtr(
526     CPDF_Object* pCSObj) const {
527   if (!pCSObj)
528     return nullptr;
529 
530   auto it = m_ColorSpaceMap.find(pCSObj);
531   return it != m_ColorSpaceMap.end() ? it->second : nullptr;
532 }
533 
FindPatternPtr(CPDF_Object * pPatternObj) const534 CPDF_CountedPattern* CPDF_DocPageData::FindPatternPtr(
535     CPDF_Object* pPatternObj) const {
536   if (!pPatternObj)
537     return nullptr;
538 
539   auto it = m_PatternMap.find(pPatternObj);
540   return it != m_PatternMap.end() ? it->second : nullptr;
541 }
542