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/fpdfapi/fpdf_render/cpdf_pagerendercache.h" | |
8 | |
9 #include "core/fpdfapi/fpdf_render/cpdf_rendercontext.h" | |
10 #include "core/fpdfapi/fpdf_render/render_int.h" | |
11 #include "core/fpdfapi/page/cpdf_page.h" | |
12 #include "core/fpdfapi/page/pageint.h" | |
13 #include "core/fpdfapi/parser/cpdf_document.h" | |
14 | |
15 struct CACHEINFO { | |
16 uint32_t 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(CPDF_Page* pPage) | |
27 : m_pPage(pPage), | |
28 m_pCurImageCacheEntry(nullptr), | |
29 m_nTimeCount(0), | |
30 m_nCacheSize(0), | |
31 m_bCurFindCache(FALSE) {} | |
32 | |
33 CPDF_PageRenderCache::~CPDF_PageRenderCache() { | |
34 for (const auto& it : m_ImageCache) | |
35 delete it.second; | |
36 } | |
37 void CPDF_PageRenderCache::CacheOptimization(int32_t dwLimitCacheSize) { | |
38 if (m_nCacheSize <= (uint32_t)dwLimitCacheSize) | |
39 return; | |
40 | |
41 size_t nCount = m_ImageCache.size(); | |
42 CACHEINFO* pCACHEINFO = FX_Alloc(CACHEINFO, nCount); | |
43 size_t i = 0; | |
44 for (const auto& it : m_ImageCache) { | |
45 pCACHEINFO[i].time = it.second->GetTimeCount(); | |
46 pCACHEINFO[i++].pStream = it.second->GetStream(); | |
47 } | |
48 FXSYS_qsort(pCACHEINFO, nCount, sizeof(CACHEINFO), compare); | |
49 uint32_t nTimeCount = m_nTimeCount; | |
50 | |
51 // Check if time value is about to roll over and reset all entries. | |
52 // The comparision is legal because uint32_t is an unsigned type. | |
53 if (nTimeCount + 1 < nTimeCount) { | |
54 for (i = 0; i < nCount; i++) | |
55 m_ImageCache[pCACHEINFO[i].pStream]->m_dwTimeCount = i; | |
56 m_nTimeCount = nCount; | |
57 } | |
58 | |
59 i = 0; | |
60 while (i + 15 < nCount) | |
61 ClearImageCacheEntry(pCACHEINFO[i++].pStream); | |
62 | |
63 while (i < nCount && m_nCacheSize > (uint32_t)dwLimitCacheSize) | |
64 ClearImageCacheEntry(pCACHEINFO[i++].pStream); | |
65 | |
66 FX_Free(pCACHEINFO); | |
67 } | |
68 void CPDF_PageRenderCache::ClearImageCacheEntry(CPDF_Stream* pStream) { | |
69 auto it = m_ImageCache.find(pStream); | |
70 if (it == m_ImageCache.end()) | |
71 return; | |
72 | |
73 m_nCacheSize -= it->second->EstimateSize(); | |
74 delete it->second; | |
75 m_ImageCache.erase(it); | |
76 } | |
77 uint32_t CPDF_PageRenderCache::EstimateSize() { | |
78 uint32_t dwSize = 0; | |
79 for (const auto& it : m_ImageCache) | |
80 dwSize += it.second->EstimateSize(); | |
81 | |
82 m_nCacheSize = dwSize; | |
83 return dwSize; | |
84 } | |
85 void CPDF_PageRenderCache::GetCachedBitmap(CPDF_Stream* pStream, | |
86 CFX_DIBSource*& pBitmap, | |
87 CFX_DIBSource*& pMask, | |
88 uint32_t& MatteColor, | |
89 FX_BOOL bStdCS, | |
90 uint32_t GroupFamily, | |
91 FX_BOOL bLoadMask, | |
92 CPDF_RenderStatus* pRenderStatus, | |
93 int32_t downsampleWidth, | |
94 int32_t downsampleHeight) { | |
95 CPDF_ImageCacheEntry* pEntry; | |
96 const auto it = m_ImageCache.find(pStream); | |
97 FX_BOOL bFound = it != m_ImageCache.end(); | |
98 if (bFound) | |
99 pEntry = it->second; | |
100 else | |
101 pEntry = new CPDF_ImageCacheEntry(m_pPage->m_pDocument, pStream); | |
102 | |
103 m_nTimeCount++; | |
104 FX_BOOL bAlreadyCached = pEntry->GetCachedBitmap( | |
105 pBitmap, pMask, MatteColor, m_pPage->m_pPageResources, bStdCS, | |
106 GroupFamily, bLoadMask, pRenderStatus, downsampleWidth, downsampleHeight); | |
107 | |
108 if (!bFound) | |
109 m_ImageCache[pStream] = pEntry; | |
110 | |
111 if (!bAlreadyCached) | |
112 m_nCacheSize += pEntry->EstimateSize(); | |
113 } | |
114 FX_BOOL CPDF_PageRenderCache::StartGetCachedBitmap( | |
115 CPDF_Stream* pStream, | |
116 FX_BOOL bStdCS, | |
117 uint32_t GroupFamily, | |
118 FX_BOOL bLoadMask, | |
119 CPDF_RenderStatus* pRenderStatus, | |
120 int32_t downsampleWidth, | |
121 int32_t downsampleHeight) { | |
122 const auto it = m_ImageCache.find(pStream); | |
123 m_bCurFindCache = it != m_ImageCache.end(); | |
124 if (m_bCurFindCache) { | |
125 m_pCurImageCacheEntry = it->second; | |
126 } else { | |
127 m_pCurImageCacheEntry = | |
128 new CPDF_ImageCacheEntry(m_pPage->m_pDocument, pStream); | |
129 } | |
130 int ret = m_pCurImageCacheEntry->StartGetCachedBitmap( | |
131 pRenderStatus->m_pFormResource, m_pPage->m_pPageResources, bStdCS, | |
132 GroupFamily, bLoadMask, pRenderStatus, downsampleWidth, downsampleHeight); | |
133 if (ret == 2) | |
134 return TRUE; | |
135 | |
136 m_nTimeCount++; | |
137 if (!m_bCurFindCache) | |
138 m_ImageCache[pStream] = m_pCurImageCacheEntry; | |
139 | |
140 if (!ret) | |
141 m_nCacheSize += m_pCurImageCacheEntry->EstimateSize(); | |
142 | |
143 return FALSE; | |
144 } | |
145 FX_BOOL CPDF_PageRenderCache::Continue(IFX_Pause* pPause) { | |
146 int ret = m_pCurImageCacheEntry->Continue(pPause); | |
147 if (ret == 2) | |
148 return TRUE; | |
149 m_nTimeCount++; | |
150 if (!m_bCurFindCache) | |
151 m_ImageCache[m_pCurImageCacheEntry->GetStream()] = m_pCurImageCacheEntry; | |
152 if (!ret) | |
153 m_nCacheSize += m_pCurImageCacheEntry->EstimateSize(); | |
154 return FALSE; | |
155 } | |
156 void CPDF_PageRenderCache::ResetBitmap(CPDF_Stream* pStream, | |
157 const CFX_DIBitmap* pBitmap) { | |
158 CPDF_ImageCacheEntry* pEntry; | |
159 const auto it = m_ImageCache.find(pStream); | |
160 if (it == m_ImageCache.end()) { | |
161 if (!pBitmap) | |
162 return; | |
163 pEntry = new CPDF_ImageCacheEntry(m_pPage->m_pDocument, pStream); | |
164 m_ImageCache[pStream] = pEntry; | |
165 } else { | |
166 pEntry = it->second; | |
167 } | |
168 m_nCacheSize -= pEntry->EstimateSize(); | |
169 pEntry->Reset(pBitmap); | |
170 m_nCacheSize += pEntry->EstimateSize(); | |
171 } | |
172 CPDF_ImageCacheEntry::CPDF_ImageCacheEntry(CPDF_Document* pDoc, | |
173 CPDF_Stream* pStream) | |
174 : m_dwTimeCount(0), | |
175 m_pCurBitmap(nullptr), | |
176 m_pCurMask(nullptr), | |
177 m_MatteColor(0), | |
178 m_pRenderStatus(nullptr), | |
179 m_pDocument(pDoc), | |
180 m_pStream(pStream), | |
181 m_pCachedBitmap(nullptr), | |
182 m_pCachedMask(nullptr), | |
183 m_dwCacheSize(0) {} | |
184 CPDF_ImageCacheEntry::~CPDF_ImageCacheEntry() { | |
185 delete m_pCachedBitmap; | |
186 delete m_pCachedMask; | |
187 } | |
188 void CPDF_ImageCacheEntry::Reset(const CFX_DIBitmap* pBitmap) { | |
189 delete m_pCachedBitmap; | |
190 m_pCachedBitmap = nullptr; | |
191 if (pBitmap) { | |
192 m_pCachedBitmap = pBitmap->Clone(); | |
193 } | |
194 CalcSize(); | |
195 } | |
196 | |
197 static uint32_t FPDF_ImageCache_EstimateImageSize(const CFX_DIBSource* pDIB) { | |
198 return pDIB && pDIB->GetBuffer() | |
199 ? (uint32_t)pDIB->GetHeight() * pDIB->GetPitch() + | |
200 (uint32_t)pDIB->GetPaletteSize() * 4 | |
201 : 0; | |
202 } | |
203 FX_BOOL CPDF_ImageCacheEntry::GetCachedBitmap(CFX_DIBSource*& pBitmap, | |
204 CFX_DIBSource*& pMask, | |
205 uint32_t& MatteColor, | |
206 CPDF_Dictionary* pPageResources, | |
207 FX_BOOL bStdCS, | |
208 uint32_t 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 = nullptr; | |
227 if (!pSrc->Load(m_pDocument, m_pStream, &pMaskSrc, &MatteColor, | |
228 pRenderStatus->m_pFormResource, pPageResources, bStdCS, | |
229 GroupFamily, bLoadMask)) { | |
230 delete pSrc; | |
231 pBitmap = nullptr; | |
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 } | |
251 CFX_DIBSource* CPDF_ImageCacheEntry::DetachBitmap() { | |
252 CFX_DIBSource* pDIBSource = m_pCurBitmap; | |
253 m_pCurBitmap = nullptr; | |
254 return pDIBSource; | |
255 } | |
256 CFX_DIBSource* CPDF_ImageCacheEntry::DetachMask() { | |
257 CFX_DIBSource* pDIBSource = m_pCurMask; | |
258 m_pCurMask = nullptr; | |
259 return pDIBSource; | |
260 } | |
261 int CPDF_ImageCacheEntry::StartGetCachedBitmap(CPDF_Dictionary* pFormResources, | |
262 CPDF_Dictionary* pPageResources, | |
263 FX_BOOL bStdCS, | |
264 uint32_t 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 = nullptr; | |
289 return 0; | |
290 } | |
291 ContinueGetCachedBitmap(); | |
292 return 0; | |
293 } | |
294 void CPDF_ImageCacheEntry::ContinueGetCachedBitmap() { | |
295 m_MatteColor = ((CPDF_DIBSource*)m_pCurBitmap)->GetMatteColor(); | |
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 = nullptr; | |
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 = nullptr; | |
312 } | |
313 m_pCurBitmap = m_pCachedBitmap; | |
314 m_pCurMask = m_pCachedMask; | |
315 CalcSize(); | |
316 } | |
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 = nullptr; | |
325 return 0; | |
326 } | |
327 ContinueGetCachedBitmap(); | |
328 return 0; | |
329 } | |
330 void CPDF_ImageCacheEntry::CalcSize() { | |
331 m_dwCacheSize = FPDF_ImageCache_EstimateImageSize(m_pCachedBitmap) + | |
332 FPDF_ImageCache_EstimateImageSize(m_pCachedMask); | |
333 } | |
OLD | NEW |