| 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 |