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