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