• 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 "render_int.h"
8 
9 #include "core/include/fpdfapi/fpdf_pageobj.h"
10 #include "core/include/fpdfapi/fpdf_render.h"
11 #include "core/include/fxge/fx_ge.h"
12 #include "core/src/fpdfapi/fpdf_page/pageint.h"
13 
14 struct CACHEINFO {
15   FX_DWORD time;
16   CPDF_Stream* pStream;
17 };
18 
19 extern "C" {
compare(const void * data1,const void * data2)20 static int compare(const void* data1, const void* data2) {
21   return ((CACHEINFO*)data1)->time - ((CACHEINFO*)data2)->time;
22 }
23 }  // extern "C"
24 
~CPDF_PageRenderCache()25 CPDF_PageRenderCache::~CPDF_PageRenderCache() {
26   for (const auto& it : m_ImageCache)
27     delete it.second;
28 }
CacheOptimization(int32_t dwLimitCacheSize)29 void CPDF_PageRenderCache::CacheOptimization(int32_t dwLimitCacheSize) {
30   if (m_nCacheSize <= (FX_DWORD)dwLimitCacheSize)
31     return;
32 
33   size_t nCount = m_ImageCache.size();
34   CACHEINFO* pCACHEINFO = FX_Alloc(CACHEINFO, nCount);
35   size_t i = 0;
36   for (const auto& it : m_ImageCache) {
37     pCACHEINFO[i].time = it.second->GetTimeCount();
38     pCACHEINFO[i++].pStream = it.second->GetStream();
39   }
40   FXSYS_qsort(pCACHEINFO, nCount, sizeof(CACHEINFO), compare);
41   FX_DWORD nTimeCount = m_nTimeCount;
42 
43   // Check if time value is about to roll over and reset all entries.
44   // The comparision is legal because FX_DWORD is an unsigned type.
45   if (nTimeCount + 1 < nTimeCount) {
46     for (i = 0; i < nCount; i++)
47       m_ImageCache[pCACHEINFO[i].pStream]->m_dwTimeCount = i;
48     m_nTimeCount = nCount;
49   }
50 
51   i = 0;
52   while (i + 15 < nCount)
53     ClearImageCacheEntry(pCACHEINFO[i++].pStream);
54 
55   while (i < nCount && m_nCacheSize > (FX_DWORD)dwLimitCacheSize)
56     ClearImageCacheEntry(pCACHEINFO[i++].pStream);
57 
58   FX_Free(pCACHEINFO);
59 }
ClearImageCacheEntry(CPDF_Stream * pStream)60 void CPDF_PageRenderCache::ClearImageCacheEntry(CPDF_Stream* pStream) {
61   auto it = m_ImageCache.find(pStream);
62   if (it == m_ImageCache.end())
63     return;
64 
65   m_nCacheSize -= it->second->EstimateSize();
66   delete it->second;
67   m_ImageCache.erase(it);
68 }
EstimateSize()69 FX_DWORD CPDF_PageRenderCache::EstimateSize() {
70   FX_DWORD dwSize = 0;
71   for (const auto& it : m_ImageCache)
72     dwSize += it.second->EstimateSize();
73 
74   m_nCacheSize = dwSize;
75   return dwSize;
76 }
GetCachedBitmap(CPDF_Stream * pStream,CFX_DIBSource * & pBitmap,CFX_DIBSource * & pMask,FX_DWORD & MatteColor,FX_BOOL bStdCS,FX_DWORD GroupFamily,FX_BOOL bLoadMask,CPDF_RenderStatus * pRenderStatus,int32_t downsampleWidth,int32_t downsampleHeight)77 void CPDF_PageRenderCache::GetCachedBitmap(CPDF_Stream* pStream,
78                                            CFX_DIBSource*& pBitmap,
79                                            CFX_DIBSource*& pMask,
80                                            FX_DWORD& MatteColor,
81                                            FX_BOOL bStdCS,
82                                            FX_DWORD GroupFamily,
83                                            FX_BOOL bLoadMask,
84                                            CPDF_RenderStatus* pRenderStatus,
85                                            int32_t downsampleWidth,
86                                            int32_t downsampleHeight) {
87   CPDF_ImageCacheEntry* pEntry;
88   const auto it = m_ImageCache.find(pStream);
89   FX_BOOL bFound = it != m_ImageCache.end();
90   if (bFound)
91     pEntry = it->second;
92   else
93     pEntry = new CPDF_ImageCacheEntry(m_pPage->m_pDocument, pStream);
94 
95   m_nTimeCount++;
96   FX_BOOL bAlreadyCached = pEntry->GetCachedBitmap(
97       pBitmap, pMask, MatteColor, m_pPage->m_pPageResources, bStdCS,
98       GroupFamily, bLoadMask, pRenderStatus, downsampleWidth, downsampleHeight);
99 
100   if (!bFound)
101     m_ImageCache[pStream] = pEntry;
102 
103   if (!bAlreadyCached)
104     m_nCacheSize += pEntry->EstimateSize();
105 }
StartGetCachedBitmap(CPDF_Stream * pStream,FX_BOOL bStdCS,FX_DWORD GroupFamily,FX_BOOL bLoadMask,CPDF_RenderStatus * pRenderStatus,int32_t downsampleWidth,int32_t downsampleHeight)106 FX_BOOL CPDF_PageRenderCache::StartGetCachedBitmap(
107     CPDF_Stream* pStream,
108     FX_BOOL bStdCS,
109     FX_DWORD GroupFamily,
110     FX_BOOL bLoadMask,
111     CPDF_RenderStatus* pRenderStatus,
112     int32_t downsampleWidth,
113     int32_t downsampleHeight) {
114   const auto it = m_ImageCache.find(pStream);
115   m_bCurFindCache = it != m_ImageCache.end();
116   if (m_bCurFindCache) {
117     m_pCurImageCacheEntry = it->second;
118   } else {
119     m_pCurImageCacheEntry =
120         new CPDF_ImageCacheEntry(m_pPage->m_pDocument, pStream);
121   }
122   int ret = m_pCurImageCacheEntry->StartGetCachedBitmap(
123       pRenderStatus->m_pFormResource, m_pPage->m_pPageResources, bStdCS,
124       GroupFamily, bLoadMask, pRenderStatus, downsampleWidth, downsampleHeight);
125   if (ret == 2)
126     return TRUE;
127 
128   m_nTimeCount++;
129   if (!m_bCurFindCache)
130     m_ImageCache[pStream] = m_pCurImageCacheEntry;
131 
132   if (!ret)
133     m_nCacheSize += m_pCurImageCacheEntry->EstimateSize();
134 
135   return FALSE;
136 }
Continue(IFX_Pause * pPause)137 FX_BOOL CPDF_PageRenderCache::Continue(IFX_Pause* pPause) {
138   int ret = m_pCurImageCacheEntry->Continue(pPause);
139   if (ret == 2)
140     return TRUE;
141   m_nTimeCount++;
142   if (!m_bCurFindCache)
143     m_ImageCache[m_pCurImageCacheEntry->GetStream()] = m_pCurImageCacheEntry;
144   if (!ret)
145     m_nCacheSize += m_pCurImageCacheEntry->EstimateSize();
146   return FALSE;
147 }
ResetBitmap(CPDF_Stream * pStream,const CFX_DIBitmap * pBitmap)148 void CPDF_PageRenderCache::ResetBitmap(CPDF_Stream* pStream,
149                                        const CFX_DIBitmap* pBitmap) {
150   CPDF_ImageCacheEntry* pEntry;
151   const auto it = m_ImageCache.find(pStream);
152   if (it == m_ImageCache.end()) {
153     if (!pBitmap)
154       return;
155     pEntry = new CPDF_ImageCacheEntry(m_pPage->m_pDocument, pStream);
156     m_ImageCache[pStream] = pEntry;
157   } else {
158     pEntry = it->second;
159   }
160   m_nCacheSize -= pEntry->EstimateSize();
161   pEntry->Reset(pBitmap);
162   m_nCacheSize += pEntry->EstimateSize();
163 }
CPDF_ImageCacheEntry(CPDF_Document * pDoc,CPDF_Stream * pStream)164 CPDF_ImageCacheEntry::CPDF_ImageCacheEntry(CPDF_Document* pDoc,
165                                            CPDF_Stream* pStream)
166     : m_dwTimeCount(0),
167       m_pCurBitmap(NULL),
168       m_pCurMask(NULL),
169       m_MatteColor(0),
170       m_pRenderStatus(NULL),
171       m_pDocument(pDoc),
172       m_pStream(pStream),
173       m_pCachedBitmap(NULL),
174       m_pCachedMask(NULL),
175       m_dwCacheSize(0) {}
~CPDF_ImageCacheEntry()176 CPDF_ImageCacheEntry::~CPDF_ImageCacheEntry() {
177   delete m_pCachedBitmap;
178   delete m_pCachedMask;
179 }
Reset(const CFX_DIBitmap * pBitmap)180 void CPDF_ImageCacheEntry::Reset(const CFX_DIBitmap* pBitmap) {
181   delete m_pCachedBitmap;
182   m_pCachedBitmap = NULL;
183   if (pBitmap) {
184     m_pCachedBitmap = pBitmap->Clone();
185   }
186   CalcSize();
187 }
ClearImageData()188 void CPDF_PageRenderCache::ClearImageData() {
189   for (const auto& it : m_ImageCache)
190     it.second->ClearImageData();
191 }
ClearImageData()192 void CPDF_ImageCacheEntry::ClearImageData() {
193   if (m_pCachedBitmap && !m_pCachedBitmap->GetBuffer()) {
194     ((CPDF_DIBSource*)m_pCachedBitmap)->ClearImageData();
195   }
196 }
FPDF_ImageCache_EstimateImageSize(const CFX_DIBSource * pDIB)197 static FX_DWORD FPDF_ImageCache_EstimateImageSize(const CFX_DIBSource* pDIB) {
198   return pDIB && pDIB->GetBuffer()
199              ? (FX_DWORD)pDIB->GetHeight() * pDIB->GetPitch() +
200                    (FX_DWORD)pDIB->GetPaletteSize() * 4
201              : 0;
202 }
GetCachedBitmap(CFX_DIBSource * & pBitmap,CFX_DIBSource * & pMask,FX_DWORD & MatteColor,CPDF_Dictionary * pPageResources,FX_BOOL bStdCS,FX_DWORD GroupFamily,FX_BOOL bLoadMask,CPDF_RenderStatus * pRenderStatus,int32_t downsampleWidth,int32_t downsampleHeight)203 FX_BOOL CPDF_ImageCacheEntry::GetCachedBitmap(CFX_DIBSource*& pBitmap,
204                                               CFX_DIBSource*& pMask,
205                                               FX_DWORD& MatteColor,
206                                               CPDF_Dictionary* pPageResources,
207                                               FX_BOOL bStdCS,
208                                               FX_DWORD GroupFamily,
209                                               FX_BOOL bLoadMask,
210                                               CPDF_RenderStatus* pRenderStatus,
211                                               int32_t downsampleWidth,
212                                               int32_t downsampleHeight) {
213   if (m_pCachedBitmap) {
214     pBitmap = m_pCachedBitmap;
215     pMask = m_pCachedMask;
216     MatteColor = m_MatteColor;
217     return TRUE;
218   }
219   if (!pRenderStatus) {
220     return FALSE;
221   }
222   CPDF_RenderContext* pContext = pRenderStatus->GetContext();
223   CPDF_PageRenderCache* pPageRenderCache = pContext->GetPageCache();
224   m_dwTimeCount = pPageRenderCache->GetTimeCount();
225   CPDF_DIBSource* pSrc = new CPDF_DIBSource;
226   CPDF_DIBSource* pMaskSrc = NULL;
227   if (!pSrc->Load(m_pDocument, m_pStream, &pMaskSrc, &MatteColor,
228                   pRenderStatus->m_pFormResource, pPageResources, bStdCS,
229                   GroupFamily, bLoadMask)) {
230     delete pSrc;
231     pBitmap = NULL;
232     return FALSE;
233   }
234   m_MatteColor = MatteColor;
235   if (pSrc->GetPitch() * pSrc->GetHeight() < FPDF_HUGE_IMAGE_SIZE) {
236     m_pCachedBitmap = pSrc->Clone();
237     delete pSrc;
238   } else {
239     m_pCachedBitmap = pSrc;
240   }
241   if (pMaskSrc) {
242     m_pCachedMask = pMaskSrc->Clone();
243     delete pMaskSrc;
244   }
245 
246   pBitmap = m_pCachedBitmap;
247   pMask = m_pCachedMask;
248   CalcSize();
249   return FALSE;
250 }
DetachBitmap()251 CFX_DIBSource* CPDF_ImageCacheEntry::DetachBitmap() {
252   CFX_DIBSource* pDIBSource = m_pCurBitmap;
253   m_pCurBitmap = NULL;
254   return pDIBSource;
255 }
DetachMask()256 CFX_DIBSource* CPDF_ImageCacheEntry::DetachMask() {
257   CFX_DIBSource* pDIBSource = m_pCurMask;
258   m_pCurMask = NULL;
259   return pDIBSource;
260 }
StartGetCachedBitmap(CPDF_Dictionary * pFormResources,CPDF_Dictionary * pPageResources,FX_BOOL bStdCS,FX_DWORD GroupFamily,FX_BOOL bLoadMask,CPDF_RenderStatus * pRenderStatus,int32_t downsampleWidth,int32_t downsampleHeight)261 int CPDF_ImageCacheEntry::StartGetCachedBitmap(CPDF_Dictionary* pFormResources,
262                                                CPDF_Dictionary* pPageResources,
263                                                FX_BOOL bStdCS,
264                                                FX_DWORD GroupFamily,
265                                                FX_BOOL bLoadMask,
266                                                CPDF_RenderStatus* pRenderStatus,
267                                                int32_t downsampleWidth,
268                                                int32_t downsampleHeight) {
269   if (m_pCachedBitmap) {
270     m_pCurBitmap = m_pCachedBitmap;
271     m_pCurMask = m_pCachedMask;
272     return 1;
273   }
274   if (!pRenderStatus) {
275     return 0;
276   }
277   m_pRenderStatus = pRenderStatus;
278   m_pCurBitmap = new CPDF_DIBSource;
279   int ret =
280       ((CPDF_DIBSource*)m_pCurBitmap)
281           ->StartLoadDIBSource(m_pDocument, m_pStream, TRUE, pFormResources,
282                                pPageResources, bStdCS, GroupFamily, bLoadMask);
283   if (ret == 2) {
284     return ret;
285   }
286   if (!ret) {
287     delete m_pCurBitmap;
288     m_pCurBitmap = NULL;
289     return 0;
290   }
291   ContinueGetCachedBitmap();
292   return 0;
293 }
ContinueGetCachedBitmap()294 void CPDF_ImageCacheEntry::ContinueGetCachedBitmap() {
295   m_MatteColor = ((CPDF_DIBSource*)m_pCurBitmap)->m_MatteColor;
296   m_pCurMask = ((CPDF_DIBSource*)m_pCurBitmap)->DetachMask();
297   CPDF_RenderContext* pContext = m_pRenderStatus->GetContext();
298   CPDF_PageRenderCache* pPageRenderCache = pContext->GetPageCache();
299   m_dwTimeCount = pPageRenderCache->GetTimeCount();
300   if (m_pCurBitmap->GetPitch() * m_pCurBitmap->GetHeight() <
301       FPDF_HUGE_IMAGE_SIZE) {
302     m_pCachedBitmap = m_pCurBitmap->Clone();
303     delete m_pCurBitmap;
304     m_pCurBitmap = NULL;
305   } else {
306     m_pCachedBitmap = m_pCurBitmap;
307   }
308   if (m_pCurMask) {
309     m_pCachedMask = m_pCurMask->Clone();
310     delete m_pCurMask;
311     m_pCurMask = NULL;
312   }
313   m_pCurBitmap = m_pCachedBitmap;
314   m_pCurMask = m_pCachedMask;
315   CalcSize();
316 }
Continue(IFX_Pause * pPause)317 int CPDF_ImageCacheEntry::Continue(IFX_Pause* pPause) {
318   int ret = ((CPDF_DIBSource*)m_pCurBitmap)->ContinueLoadDIBSource(pPause);
319   if (ret == 2) {
320     return ret;
321   }
322   if (!ret) {
323     delete m_pCurBitmap;
324     m_pCurBitmap = NULL;
325     return 0;
326   }
327   ContinueGetCachedBitmap();
328   return 0;
329 }
CalcSize()330 void CPDF_ImageCacheEntry::CalcSize() {
331   m_dwCacheSize = FPDF_ImageCache_EstimateImageSize(m_pCachedBitmap) +
332                   FPDF_ImageCache_EstimateImageSize(m_pCachedMask);
333 }
ClearRenderFont()334 void CPDF_Document::ClearRenderFont() {
335   if (m_pDocRender) {
336     CFX_FontCache* pCache = m_pDocRender->GetFontCache();
337     if (pCache) {
338       pCache->FreeCache(FALSE);
339     }
340   }
341 }
342