1 // Copyright 2016 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/render/cpdf_pagerendercache.h" 8 9 #include "core/fpdfapi/page/cpdf_page.h" 10 #include "core/fpdfapi/render/cpdf_imagecacheentry.h" 11 #include "core/fpdfapi/render/cpdf_renderstatus.h" 12 13 namespace { 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 } // namespace 27 28 CPDF_PageRenderCache::CPDF_PageRenderCache(CPDF_Page* pPage) 29 : m_pPage(pPage), 30 m_pCurImageCacheEntry(nullptr), 31 m_nTimeCount(0), 32 m_nCacheSize(0), 33 m_bCurFindCache(false) {} 34 35 CPDF_PageRenderCache::~CPDF_PageRenderCache() { 36 for (const auto& it : m_ImageCache) 37 delete it.second; 38 } 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 72 void CPDF_PageRenderCache::ClearImageCacheEntry(CPDF_Stream* pStream) { 73 auto it = m_ImageCache.find(pStream); 74 if (it == m_ImageCache.end()) 75 return; 76 77 m_nCacheSize -= it->second->EstimateSize(); 78 delete it->second; 79 m_ImageCache.erase(it); 80 } 81 82 bool CPDF_PageRenderCache::StartGetCachedBitmap( 83 CPDF_Stream* pStream, 84 bool bStdCS, 85 uint32_t GroupFamily, 86 bool bLoadMask, 87 CPDF_RenderStatus* pRenderStatus, 88 int32_t downsampleWidth, 89 int32_t downsampleHeight) { 90 const auto it = m_ImageCache.find(pStream); 91 m_bCurFindCache = it != m_ImageCache.end(); 92 if (m_bCurFindCache) { 93 m_pCurImageCacheEntry = it->second; 94 } else { 95 m_pCurImageCacheEntry = 96 new CPDF_ImageCacheEntry(m_pPage->m_pDocument, pStream); 97 } 98 int ret = m_pCurImageCacheEntry->StartGetCachedBitmap( 99 pRenderStatus->m_pFormResource, m_pPage->m_pPageResources, bStdCS, 100 GroupFamily, bLoadMask, pRenderStatus, downsampleWidth, downsampleHeight); 101 if (ret == 2) 102 return true; 103 104 m_nTimeCount++; 105 if (!m_bCurFindCache) 106 m_ImageCache[pStream] = m_pCurImageCacheEntry; 107 108 if (!ret) 109 m_nCacheSize += m_pCurImageCacheEntry->EstimateSize(); 110 111 return false; 112 } 113 114 bool CPDF_PageRenderCache::Continue(IFX_Pause* pPause) { 115 int ret = m_pCurImageCacheEntry->Continue(pPause); 116 if (ret == 2) 117 return true; 118 119 m_nTimeCount++; 120 if (!m_bCurFindCache) 121 m_ImageCache[m_pCurImageCacheEntry->GetStream()] = m_pCurImageCacheEntry; 122 if (!ret) 123 m_nCacheSize += m_pCurImageCacheEntry->EstimateSize(); 124 return false; 125 } 126 127 void CPDF_PageRenderCache::ResetBitmap(CPDF_Stream* pStream, 128 const CFX_DIBitmap* pBitmap) { 129 CPDF_ImageCacheEntry* pEntry; 130 const auto it = m_ImageCache.find(pStream); 131 if (it == m_ImageCache.end()) { 132 if (!pBitmap) 133 return; 134 135 pEntry = new CPDF_ImageCacheEntry(m_pPage->m_pDocument, pStream); 136 m_ImageCache[pStream] = pEntry; 137 } else { 138 pEntry = it->second; 139 } 140 m_nCacheSize -= pEntry->EstimateSize(); 141 pEntry->Reset(pBitmap); 142 m_nCacheSize += pEntry->EstimateSize(); 143 } 144