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 "../../../include/fpdfapi/fpdf_render.h" 8 #include "../../../include/fpdfapi/fpdf_pageobj.h" 9 #include "../../../include/fxge/fx_ge.h" 10 #include "../fpdf_page/pageint.h" 11 #include "render_int.h" 12 struct CACHEINFO { 13 FX_DWORD time; 14 CPDF_Stream* pStream; 15 }; 16 extern "C" { 17 static int compare(const void* data1, const void* data2) 18 { 19 return ((CACHEINFO*)data1)->time - ((CACHEINFO*)data2)->time; 20 } 21 }; 22 void CPDF_Page::ClearRenderCache() 23 { 24 if (m_pPageRender) { 25 m_pPageRender->ClearAll(); 26 } 27 } 28 void CPDF_PageRenderCache::ClearAll() 29 { 30 FX_POSITION pos = m_ImageCaches.GetStartPosition(); 31 while (pos) { 32 FX_LPVOID key, value; 33 m_ImageCaches.GetNextAssoc(pos, key, value); 34 delete (CPDF_ImageCache*)value; 35 } 36 m_ImageCaches.RemoveAll(); 37 m_nCacheSize = 0; 38 m_nTimeCount = 0; 39 } 40 void CPDF_PageRenderCache::CacheOptimization(FX_INT32 dwLimitCacheSize) 41 { 42 if (m_nCacheSize <= (FX_DWORD)dwLimitCacheSize) { 43 return; 44 } 45 int nCount = m_ImageCaches.GetCount(); 46 CACHEINFO* pCACHEINFO = (CACHEINFO*)FX_Alloc(FX_BYTE, (sizeof (CACHEINFO)) * nCount); 47 FX_POSITION pos = m_ImageCaches.GetStartPosition(); 48 int i = 0; 49 while (pos) { 50 FX_LPVOID key, value; 51 m_ImageCaches.GetNextAssoc(pos, key, value); 52 pCACHEINFO[i].time = ((CPDF_ImageCache*)value)->GetTimeCount(); 53 pCACHEINFO[i++].pStream = ((CPDF_ImageCache*)value)->GetStream(); 54 } 55 FXSYS_qsort(pCACHEINFO, nCount, sizeof (CACHEINFO), compare); 56 FX_DWORD nTimeCount = m_nTimeCount; 57 if (nTimeCount + 1 < nTimeCount) { 58 for (i = 0; i < nCount; i ++) { 59 ((CPDF_ImageCache*)(m_ImageCaches[pCACHEINFO[i].pStream]))->m_dwTimeCount = i; 60 } 61 m_nTimeCount = nCount; 62 } 63 i = 0; 64 while(nCount > 15) { 65 ClearImageCache(pCACHEINFO[i++].pStream); 66 nCount--; 67 } 68 while (m_nCacheSize > (FX_DWORD)dwLimitCacheSize) { 69 ClearImageCache(pCACHEINFO[i++].pStream); 70 } 71 FX_Free(pCACHEINFO); 72 } 73 void CPDF_PageRenderCache::ClearImageCache(CPDF_Stream* pStream) 74 { 75 FX_LPVOID value = m_ImageCaches.GetValueAt(pStream); 76 if (value == NULL) { 77 m_ImageCaches.RemoveKey(pStream); 78 return; 79 } 80 m_nCacheSize -= ((CPDF_ImageCache*)value)->EstimateSize(); 81 delete (CPDF_ImageCache*)value; 82 m_ImageCaches.RemoveKey(pStream); 83 } 84 FX_DWORD CPDF_PageRenderCache::EstimateSize() 85 { 86 FX_DWORD dwSize = 0; 87 FX_POSITION pos = m_ImageCaches.GetStartPosition(); 88 while (pos) { 89 FX_LPVOID key, value; 90 m_ImageCaches.GetNextAssoc(pos, key, value); 91 dwSize += ((CPDF_ImageCache*)value)->EstimateSize(); 92 } 93 m_nCacheSize = dwSize; 94 return dwSize; 95 } 96 FX_DWORD CPDF_PageRenderCache::GetCachedSize(CPDF_Stream* pStream) const 97 { 98 if (pStream == NULL) { 99 return m_nCacheSize; 100 } 101 CPDF_ImageCache* pImageCache; 102 if (!m_ImageCaches.Lookup(pStream, (FX_LPVOID&)pImageCache)) { 103 return 0; 104 } 105 return pImageCache->EstimateSize(); 106 } 107 void CPDF_PageRenderCache::GetCachedBitmap(CPDF_Stream* pStream, CFX_DIBSource*& pBitmap, CFX_DIBSource*& pMask, FX_DWORD& MatteColor, 108 FX_BOOL bStdCS, FX_DWORD GroupFamily, FX_BOOL bLoadMask, CPDF_RenderStatus* pRenderStatus, 109 FX_INT32 downsampleWidth, FX_INT32 downsampleHeight) 110 { 111 CPDF_ImageCache* pImageCache; 112 FX_BOOL bFind = m_ImageCaches.Lookup(pStream, (FX_LPVOID&)pImageCache); 113 if (!bFind) { 114 pImageCache = FX_NEW CPDF_ImageCache(m_pPage->m_pDocument, pStream); 115 } 116 m_nTimeCount ++; 117 FX_BOOL bCached = pImageCache->GetCachedBitmap(pBitmap, pMask, MatteColor, m_pPage->m_pPageResources, bStdCS, GroupFamily, bLoadMask, pRenderStatus, downsampleWidth, downsampleHeight); 118 if (!bFind) { 119 m_ImageCaches.SetAt(pStream, pImageCache); 120 } 121 if (!bCached) { 122 m_nCacheSize += pImageCache->EstimateSize(); 123 } 124 } 125 FX_BOOL CPDF_PageRenderCache::StartGetCachedBitmap(CPDF_Stream* pStream, FX_BOOL bStdCS, FX_DWORD GroupFamily, FX_BOOL bLoadMask, CPDF_RenderStatus* pRenderStatus, FX_INT32 downsampleWidth, FX_INT32 downsampleHeight) 126 { 127 m_bCurFindCache = m_ImageCaches.Lookup(pStream, (FX_LPVOID&)m_pCurImageCache); 128 if (!m_bCurFindCache) { 129 m_pCurImageCache = FX_NEW CPDF_ImageCache(m_pPage->m_pDocument, pStream); 130 } 131 int ret = m_pCurImageCache->StartGetCachedBitmap(pRenderStatus->m_pFormResource, m_pPage->m_pPageResources, bStdCS, GroupFamily, bLoadMask, pRenderStatus, downsampleWidth, downsampleHeight); 132 if (ret == 2) { 133 return TRUE; 134 } 135 m_nTimeCount ++; 136 if (!m_bCurFindCache) { 137 m_ImageCaches.SetAt(pStream, m_pCurImageCache); 138 } 139 if (!ret) { 140 m_nCacheSize += m_pCurImageCache->EstimateSize(); 141 } 142 return FALSE; 143 } 144 FX_BOOL CPDF_PageRenderCache::Continue(IFX_Pause* pPause) 145 { 146 int ret = m_pCurImageCache->Continue(pPause); 147 if (ret == 2) { 148 return TRUE; 149 } 150 m_nTimeCount ++; 151 if (!m_bCurFindCache) { 152 m_ImageCaches.SetAt(m_pCurImageCache->GetStream(), m_pCurImageCache); 153 } 154 if (!ret) { 155 m_nCacheSize += m_pCurImageCache->EstimateSize(); 156 } 157 return FALSE; 158 } 159 void CPDF_PageRenderCache::ResetBitmap(CPDF_Stream* pStream, const CFX_DIBitmap* pBitmap) 160 { 161 CPDF_ImageCache* pImageCache; 162 if (!m_ImageCaches.Lookup(pStream, (FX_LPVOID&)pImageCache)) { 163 if (pBitmap == NULL) { 164 return; 165 } 166 pImageCache = FX_NEW CPDF_ImageCache(m_pPage->m_pDocument, pStream); 167 m_ImageCaches.SetAt(pStream, pImageCache); 168 } 169 int oldsize = pImageCache->EstimateSize(); 170 pImageCache->Reset(pBitmap); 171 m_nCacheSize = pImageCache->EstimateSize() - oldsize; 172 } 173 CPDF_ImageCache::CPDF_ImageCache(CPDF_Document* pDoc, CPDF_Stream* pStream) 174 : m_pDocument(pDoc) 175 , m_pStream(pStream) 176 , m_pCachedBitmap(NULL) 177 , m_pCachedMask(NULL) 178 , m_dwCacheSize(0) 179 , m_dwTimeCount(0) 180 , m_pCurBitmap(NULL) 181 , m_pCurMask(NULL) 182 , m_MatteColor(0) 183 , m_pRenderStatus(NULL) 184 { 185 } 186 CPDF_ImageCache::~CPDF_ImageCache() 187 { 188 if (m_pCachedBitmap) { 189 delete m_pCachedBitmap; 190 m_pCachedBitmap = NULL; 191 } 192 if (m_pCachedMask) { 193 delete m_pCachedMask; 194 m_pCachedMask = NULL; 195 } 196 } 197 void CPDF_ImageCache::Reset(const CFX_DIBitmap* pBitmap) 198 { 199 if (m_pCachedBitmap) { 200 delete m_pCachedBitmap; 201 } 202 m_pCachedBitmap = NULL; 203 if (pBitmap) { 204 m_pCachedBitmap = pBitmap->Clone(); 205 } 206 CalcSize(); 207 } 208 void CPDF_PageRenderCache::ClearImageData() 209 { 210 FX_POSITION pos = m_ImageCaches.GetStartPosition(); 211 while (pos) { 212 FX_LPVOID key, value; 213 m_ImageCaches.GetNextAssoc(pos, key, value); 214 ((CPDF_ImageCache*)value)->ClearImageData(); 215 } 216 } 217 void CPDF_ImageCache::ClearImageData() 218 { 219 if (m_pCachedBitmap && m_pCachedBitmap->GetBuffer() == NULL) { 220 ((CPDF_DIBSource*)m_pCachedBitmap)->ClearImageData(); 221 } 222 } 223 static FX_DWORD FPDF_ImageCache_EstimateImageSize(const CFX_DIBSource* pDIB) 224 { 225 return pDIB && pDIB->GetBuffer() ? (FX_DWORD)pDIB->GetHeight() * pDIB->GetPitch() + (FX_DWORD)pDIB->GetPaletteSize() * 4 : 0; 226 } 227 FX_BOOL CPDF_ImageCache::GetCachedBitmap(CFX_DIBSource*& pBitmap, CFX_DIBSource*& pMask, FX_DWORD& MatteColor, CPDF_Dictionary* pPageResources, 228 FX_BOOL bStdCS, FX_DWORD GroupFamily, FX_BOOL bLoadMask, CPDF_RenderStatus* pRenderStatus, 229 FX_INT32 downsampleWidth, FX_INT32 downsampleHeight) 230 { 231 if (m_pCachedBitmap) { 232 pBitmap = m_pCachedBitmap; 233 pMask = m_pCachedMask; 234 MatteColor = m_MatteColor; 235 return TRUE; 236 } 237 if (!pRenderStatus) { 238 return FALSE; 239 } 240 CPDF_RenderContext*pContext = pRenderStatus->GetContext(); 241 CPDF_PageRenderCache* pPageRenderCache = pContext->m_pPageCache; 242 m_dwTimeCount = pPageRenderCache->GetTimeCount(); 243 CPDF_DIBSource* pSrc = FX_NEW CPDF_DIBSource; 244 CPDF_DIBSource* pMaskSrc = NULL; 245 if (!pSrc->Load(m_pDocument, m_pStream, &pMaskSrc, &MatteColor, pRenderStatus->m_pFormResource, pPageResources, bStdCS, GroupFamily, bLoadMask)) { 246 delete pSrc; 247 pBitmap = NULL; 248 return FALSE; 249 } 250 m_MatteColor = MatteColor; 251 #if !defined(_FPDFAPI_MINI_) 252 if (pSrc->GetPitch() * pSrc->GetHeight() < FPDF_HUGE_IMAGE_SIZE) { 253 m_pCachedBitmap = pSrc->Clone(); 254 delete pSrc; 255 } else { 256 m_pCachedBitmap = pSrc; 257 } 258 if (pMaskSrc) { 259 m_pCachedMask = pMaskSrc->Clone(); 260 delete pMaskSrc; 261 } 262 #else 263 if (pSrc->GetFormat() == FXDIB_8bppRgb && pSrc->GetPalette() && 264 pSrc->GetHeight() * pSrc->GetWidth() * 3 < 1024) { 265 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ 266 m_pCachedBitmap = pSrc->CloneConvert(FXDIB_Rgb32); 267 #else 268 m_pCachedBitmap = pSrc->CloneConvert(FXDIB_Rgb); 269 #endif 270 delete pSrc; 271 } else if (pSrc->GetPitch() * pSrc->GetHeight() < 102400) { 272 m_pCachedBitmap = pSrc->Clone(); 273 delete pSrc; 274 } else { 275 m_pCachedBitmap = pSrc; 276 } 277 m_pCachedMask = pMaskSrc; 278 #endif 279 pBitmap = m_pCachedBitmap; 280 pMask = m_pCachedMask; 281 CalcSize(); 282 return FALSE; 283 } 284 CFX_DIBSource* CPDF_ImageCache::DetachBitmap() 285 { 286 CFX_DIBSource* pDIBSource = m_pCurBitmap; 287 m_pCurBitmap = NULL; 288 return pDIBSource; 289 } 290 CFX_DIBSource* CPDF_ImageCache::DetachMask() 291 { 292 CFX_DIBSource* pDIBSource = m_pCurMask; 293 m_pCurMask = NULL; 294 return pDIBSource; 295 } 296 int CPDF_ImageCache::StartGetCachedBitmap(CPDF_Dictionary* pFormResources, CPDF_Dictionary* pPageResources, FX_BOOL bStdCS, 297 FX_DWORD GroupFamily, FX_BOOL bLoadMask, CPDF_RenderStatus* pRenderStatus, 298 FX_INT32 downsampleWidth, FX_INT32 downsampleHeight) 299 { 300 if (m_pCachedBitmap) { 301 m_pCurBitmap = m_pCachedBitmap; 302 m_pCurMask = m_pCachedMask; 303 return 1; 304 } 305 if (!pRenderStatus) { 306 return 0; 307 } 308 m_pRenderStatus = pRenderStatus; 309 m_pCurBitmap = FX_NEW CPDF_DIBSource; 310 int ret = ((CPDF_DIBSource*)m_pCurBitmap)->StartLoadDIBSource(m_pDocument, m_pStream, TRUE, pFormResources, pPageResources, bStdCS, GroupFamily, bLoadMask); 311 if (ret == 2) { 312 return ret; 313 } 314 if (!ret) { 315 delete m_pCurBitmap; 316 m_pCurBitmap = NULL; 317 return 0; 318 } 319 ContinueGetCachedBitmap(); 320 return 0; 321 } 322 int CPDF_ImageCache::ContinueGetCachedBitmap() 323 { 324 m_MatteColor = ((CPDF_DIBSource*)m_pCurBitmap)->m_MatteColor; 325 m_pCurMask = ((CPDF_DIBSource*)m_pCurBitmap)->DetachMask(); 326 CPDF_RenderContext*pContext = m_pRenderStatus->GetContext(); 327 CPDF_PageRenderCache* pPageRenderCache = pContext->m_pPageCache; 328 m_dwTimeCount = pPageRenderCache->GetTimeCount(); 329 #if !defined(_FPDFAPI_MINI_) 330 if (m_pCurBitmap->GetPitch() * m_pCurBitmap->GetHeight() < FPDF_HUGE_IMAGE_SIZE) { 331 m_pCachedBitmap = m_pCurBitmap->Clone(); 332 delete m_pCurBitmap; 333 m_pCurBitmap = NULL; 334 } else { 335 m_pCachedBitmap = m_pCurBitmap; 336 } 337 if (m_pCurMask) { 338 m_pCachedMask = m_pCurMask->Clone(); 339 delete m_pCurMask; 340 m_pCurMask = NULL; 341 } 342 #else 343 if (m_pCurBitmap->GetFormat() == FXDIB_8bppRgb && m_pCurBitmap->GetPalette() && 344 m_pCurBitmap->GetHeight() * m_pCurBitmap->GetWidth() * 3 < 1024) { 345 m_pCachedBitmap = m_pCurBitmap->CloneConvert(FXDIB_Rgb32); 346 m_pCachedBitmap = m_pCurBitmap->CloneConvert(FXDIB_Rgb); 347 delete m_pCurBitmap; 348 m_pCurBitmap = NULL; 349 } else if (m_pCurBitmap->GetPitch() * m_pCurBitmap->GetHeight() < 102400) { 350 m_pCachedBitmap = m_pCurBitmap->Clone(); 351 delete m_pCurBitmap; 352 m_pCurBitmap = NULL; 353 } else { 354 m_pCachedBitmap = m_pCurBitmap; 355 } 356 m_pCachedMask = m_pCurMask; 357 #endif 358 m_pCurBitmap = m_pCachedBitmap; 359 m_pCurMask = m_pCachedMask; 360 CalcSize(); 361 return 0; 362 } 363 int CPDF_ImageCache::Continue(IFX_Pause* pPause) 364 { 365 int ret = ((CPDF_DIBSource*)m_pCurBitmap)->ContinueLoadDIBSource(pPause); 366 if (ret == 2) { 367 return ret; 368 } 369 if (!ret) { 370 delete m_pCurBitmap; 371 m_pCurBitmap = NULL; 372 return 0; 373 } 374 ContinueGetCachedBitmap(); 375 return 0; 376 } 377 void CPDF_ImageCache::CalcSize() 378 { 379 m_dwCacheSize = FPDF_ImageCache_EstimateImageSize(m_pCachedBitmap) + FPDF_ImageCache_EstimateImageSize(m_pCachedMask); 380 } 381 void CPDF_Document::ClearRenderFont() 382 { 383 if (m_pDocRender) { 384 CFX_FontCache* pCache = m_pDocRender->GetFontCache(); 385 if (pCache) { 386 pCache->FreeCache(FALSE); 387 } 388 } 389 } 390