Home | History | Annotate | Download | only in render
      1 // Copyright 2016 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/render/cpdf_pagerendercache.h"
      8 
      9 #include "core/fpdfapi/page/cpdf_page.h"
     10 #include "core/fpdfapi/render/cpdf_imagecacheentry.h"
     11 #include "core/fpdfapi/render/cpdf_renderstatus.h"
     12 
     13 namespace {
     14 
     15 struct CACHEINFO {
     16   uint32_t time;
     17   CPDF_Stream* pStream;
     18 };
     19 
     20 extern "C" {
     21 static int compare(const void* data1, const void* data2) {
     22   return ((CACHEINFO*)data1)->time - ((CACHEINFO*)data2)->time;
     23 }
     24 }  // extern "C"
     25 
     26 }  // namespace
     27 
     28 CPDF_PageRenderCache::CPDF_PageRenderCache(CPDF_Page* pPage)
     29     : m_pPage(pPage),
     30       m_pCurImageCacheEntry(nullptr),
     31       m_nTimeCount(0),
     32       m_nCacheSize(0),
     33       m_bCurFindCache(false) {}
     34 
     35 CPDF_PageRenderCache::~CPDF_PageRenderCache() {
     36   for (const auto& it : m_ImageCache)
     37     delete it.second;
     38 }
     39 
     40 void CPDF_PageRenderCache::CacheOptimization(int32_t dwLimitCacheSize) {
     41   if (m_nCacheSize <= (uint32_t)dwLimitCacheSize)
     42     return;
     43 
     44   size_t nCount = m_ImageCache.size();
     45   CACHEINFO* pCACHEINFO = FX_Alloc(CACHEINFO, nCount);
     46   size_t i = 0;
     47   for (const auto& it : m_ImageCache) {
     48     pCACHEINFO[i].time = it.second->GetTimeCount();
     49     pCACHEINFO[i++].pStream = it.second->GetStream();
     50   }
     51   FXSYS_qsort(pCACHEINFO, nCount, sizeof(CACHEINFO), compare);
     52   uint32_t nTimeCount = m_nTimeCount;
     53 
     54   // Check if time value is about to roll over and reset all entries.
     55   // The comparision is legal because uint32_t is an unsigned type.
     56   if (nTimeCount + 1 < nTimeCount) {
     57     for (i = 0; i < nCount; i++)
     58       m_ImageCache[pCACHEINFO[i].pStream]->m_dwTimeCount = i;
     59     m_nTimeCount = nCount;
     60   }
     61 
     62   i = 0;
     63   while (i + 15 < nCount)
     64     ClearImageCacheEntry(pCACHEINFO[i++].pStream);
     65 
     66   while (i < nCount && m_nCacheSize > (uint32_t)dwLimitCacheSize)
     67     ClearImageCacheEntry(pCACHEINFO[i++].pStream);
     68 
     69   FX_Free(pCACHEINFO);
     70 }
     71 
     72 void CPDF_PageRenderCache::ClearImageCacheEntry(CPDF_Stream* pStream) {
     73   auto it = m_ImageCache.find(pStream);
     74   if (it == m_ImageCache.end())
     75     return;
     76 
     77   m_nCacheSize -= it->second->EstimateSize();
     78   delete it->second;
     79   m_ImageCache.erase(it);
     80 }
     81 
     82 bool CPDF_PageRenderCache::StartGetCachedBitmap(
     83     CPDF_Stream* pStream,
     84     bool bStdCS,
     85     uint32_t GroupFamily,
     86     bool bLoadMask,
     87     CPDF_RenderStatus* pRenderStatus,
     88     int32_t downsampleWidth,
     89     int32_t downsampleHeight) {
     90   const auto it = m_ImageCache.find(pStream);
     91   m_bCurFindCache = it != m_ImageCache.end();
     92   if (m_bCurFindCache) {
     93     m_pCurImageCacheEntry = it->second;
     94   } else {
     95     m_pCurImageCacheEntry =
     96         new CPDF_ImageCacheEntry(m_pPage->m_pDocument, pStream);
     97   }
     98   int ret = m_pCurImageCacheEntry->StartGetCachedBitmap(
     99       pRenderStatus->m_pFormResource, m_pPage->m_pPageResources, bStdCS,
    100       GroupFamily, bLoadMask, pRenderStatus, downsampleWidth, downsampleHeight);
    101   if (ret == 2)
    102     return true;
    103 
    104   m_nTimeCount++;
    105   if (!m_bCurFindCache)
    106     m_ImageCache[pStream] = m_pCurImageCacheEntry;
    107 
    108   if (!ret)
    109     m_nCacheSize += m_pCurImageCacheEntry->EstimateSize();
    110 
    111   return false;
    112 }
    113 
    114 bool CPDF_PageRenderCache::Continue(IFX_Pause* pPause) {
    115   int ret = m_pCurImageCacheEntry->Continue(pPause);
    116   if (ret == 2)
    117     return true;
    118 
    119   m_nTimeCount++;
    120   if (!m_bCurFindCache)
    121     m_ImageCache[m_pCurImageCacheEntry->GetStream()] = m_pCurImageCacheEntry;
    122   if (!ret)
    123     m_nCacheSize += m_pCurImageCacheEntry->EstimateSize();
    124   return false;
    125 }
    126 
    127 void CPDF_PageRenderCache::ResetBitmap(CPDF_Stream* pStream,
    128                                        const CFX_DIBitmap* pBitmap) {
    129   CPDF_ImageCacheEntry* pEntry;
    130   const auto it = m_ImageCache.find(pStream);
    131   if (it == m_ImageCache.end()) {
    132     if (!pBitmap)
    133       return;
    134 
    135     pEntry = new CPDF_ImageCacheEntry(m_pPage->m_pDocument, pStream);
    136     m_ImageCache[pStream] = pEntry;
    137   } else {
    138     pEntry = it->second;
    139   }
    140   m_nCacheSize -= pEntry->EstimateSize();
    141   pEntry->Reset(pBitmap);
    142   m_nCacheSize += pEntry->EstimateSize();
    143 }
    144