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