• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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" {
compare(const void * data1,const void * data2)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 
CPDF_PageRenderCache(CPDF_Page * pPage)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 
~CPDF_PageRenderCache()35 CPDF_PageRenderCache::~CPDF_PageRenderCache() {
36   for (const auto& it : m_ImageCache)
37     delete it.second;
38 }
39 
CacheOptimization(int32_t dwLimitCacheSize)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 
ClearImageCacheEntry(CPDF_Stream * pStream)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 
StartGetCachedBitmap(CPDF_Stream * pStream,bool bStdCS,uint32_t GroupFamily,bool bLoadMask,CPDF_RenderStatus * pRenderStatus,int32_t downsampleWidth,int32_t downsampleHeight)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 
Continue(IFX_Pause * pPause)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 
ResetBitmap(CPDF_Stream * pStream,const CFX_DIBitmap * pBitmap)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