Home | History | Annotate | Download | only in page
      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 
     30 CPDF_DocPageData::CPDF_DocPageData(CPDF_Document* pPDFDoc)
     31     : m_pPDFDoc(pPDFDoc), m_bForceClear(false) {}
     32 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    525 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 
    534 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