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