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