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