| // Copyright 2014 PDFium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| |
| #include "../../../include/fpdfapi/fpdf_render.h" |
| #include "../../../include/fpdfapi/fpdf_pageobj.h" |
| #include "../../../include/fxge/fx_ge.h" |
| #include "../fpdf_page/pageint.h" |
| #include "render_int.h" |
| struct CACHEINFO { |
| FX_DWORD time; |
| CPDF_Stream* pStream; |
| }; |
| extern "C" { |
| static int compare(const void* data1, const void* data2) { |
| return ((CACHEINFO*)data1)->time - ((CACHEINFO*)data2)->time; |
| } |
| }; |
| void CPDF_Page::ClearRenderCache() { |
| if (m_pPageRender) { |
| m_pPageRender->ClearAll(); |
| } |
| } |
| void CPDF_PageRenderCache::ClearAll() { |
| FX_POSITION pos = m_ImageCaches.GetStartPosition(); |
| while (pos) { |
| void* key; |
| void* value; |
| m_ImageCaches.GetNextAssoc(pos, key, value); |
| delete (CPDF_ImageCache*)value; |
| } |
| m_ImageCaches.RemoveAll(); |
| m_nCacheSize = 0; |
| m_nTimeCount = 0; |
| } |
| void CPDF_PageRenderCache::CacheOptimization(int32_t dwLimitCacheSize) { |
| if (m_nCacheSize <= (FX_DWORD)dwLimitCacheSize) { |
| return; |
| } |
| int nCount = m_ImageCaches.GetCount(); |
| CACHEINFO* pCACHEINFO = |
| (CACHEINFO*)FX_Alloc2D(uint8_t, sizeof(CACHEINFO), nCount); |
| FX_POSITION pos = m_ImageCaches.GetStartPosition(); |
| int i = 0; |
| while (pos) { |
| void* key; |
| void* value; |
| m_ImageCaches.GetNextAssoc(pos, key, value); |
| pCACHEINFO[i].time = ((CPDF_ImageCache*)value)->GetTimeCount(); |
| pCACHEINFO[i++].pStream = ((CPDF_ImageCache*)value)->GetStream(); |
| } |
| FXSYS_qsort(pCACHEINFO, nCount, sizeof(CACHEINFO), compare); |
| FX_DWORD nTimeCount = m_nTimeCount; |
| if (nTimeCount + 1 < nTimeCount) { |
| for (i = 0; i < nCount; i++) { |
| ((CPDF_ImageCache*)(m_ImageCaches[pCACHEINFO[i].pStream])) |
| ->m_dwTimeCount = i; |
| } |
| m_nTimeCount = nCount; |
| } |
| i = 0; |
| while (nCount > 15) { |
| ClearImageCache(pCACHEINFO[i++].pStream); |
| nCount--; |
| } |
| while (m_nCacheSize > (FX_DWORD)dwLimitCacheSize) { |
| ClearImageCache(pCACHEINFO[i++].pStream); |
| } |
| FX_Free(pCACHEINFO); |
| } |
| void CPDF_PageRenderCache::ClearImageCache(CPDF_Stream* pStream) { |
| void* value = m_ImageCaches.GetValueAt(pStream); |
| if (value == NULL) { |
| m_ImageCaches.RemoveKey(pStream); |
| return; |
| } |
| m_nCacheSize -= ((CPDF_ImageCache*)value)->EstimateSize(); |
| delete (CPDF_ImageCache*)value; |
| m_ImageCaches.RemoveKey(pStream); |
| } |
| FX_DWORD CPDF_PageRenderCache::EstimateSize() { |
| FX_DWORD dwSize = 0; |
| FX_POSITION pos = m_ImageCaches.GetStartPosition(); |
| while (pos) { |
| void* key; |
| void* value; |
| m_ImageCaches.GetNextAssoc(pos, key, value); |
| dwSize += ((CPDF_ImageCache*)value)->EstimateSize(); |
| } |
| m_nCacheSize = dwSize; |
| return dwSize; |
| } |
| FX_DWORD CPDF_PageRenderCache::GetCachedSize(CPDF_Stream* pStream) const { |
| if (pStream == NULL) { |
| return m_nCacheSize; |
| } |
| CPDF_ImageCache* pImageCache; |
| if (!m_ImageCaches.Lookup(pStream, (void*&)pImageCache)) { |
| return 0; |
| } |
| return pImageCache->EstimateSize(); |
| } |
| void CPDF_PageRenderCache::GetCachedBitmap(CPDF_Stream* pStream, |
| CFX_DIBSource*& pBitmap, |
| CFX_DIBSource*& pMask, |
| FX_DWORD& MatteColor, |
| FX_BOOL bStdCS, |
| FX_DWORD GroupFamily, |
| FX_BOOL bLoadMask, |
| CPDF_RenderStatus* pRenderStatus, |
| int32_t downsampleWidth, |
| int32_t downsampleHeight) { |
| CPDF_ImageCache* pImageCache; |
| FX_BOOL bFind = m_ImageCaches.Lookup(pStream, (void*&)pImageCache); |
| if (!bFind) { |
| pImageCache = new CPDF_ImageCache(m_pPage->m_pDocument, pStream); |
| } |
| m_nTimeCount++; |
| FX_BOOL bCached = pImageCache->GetCachedBitmap( |
| pBitmap, pMask, MatteColor, m_pPage->m_pPageResources, bStdCS, |
| GroupFamily, bLoadMask, pRenderStatus, downsampleWidth, downsampleHeight); |
| if (!bFind) { |
| m_ImageCaches.SetAt(pStream, pImageCache); |
| } |
| if (!bCached) { |
| m_nCacheSize += pImageCache->EstimateSize(); |
| } |
| } |
| FX_BOOL CPDF_PageRenderCache::StartGetCachedBitmap( |
| CPDF_Stream* pStream, |
| FX_BOOL bStdCS, |
| FX_DWORD GroupFamily, |
| FX_BOOL bLoadMask, |
| CPDF_RenderStatus* pRenderStatus, |
| int32_t downsampleWidth, |
| int32_t downsampleHeight) { |
| m_bCurFindCache = m_ImageCaches.Lookup(pStream, (void*&)m_pCurImageCache); |
| if (!m_bCurFindCache) { |
| m_pCurImageCache = new CPDF_ImageCache(m_pPage->m_pDocument, pStream); |
| } |
| int ret = m_pCurImageCache->StartGetCachedBitmap( |
| pRenderStatus->m_pFormResource, m_pPage->m_pPageResources, bStdCS, |
| GroupFamily, bLoadMask, pRenderStatus, downsampleWidth, downsampleHeight); |
| if (ret == 2) { |
| return TRUE; |
| } |
| m_nTimeCount++; |
| if (!m_bCurFindCache) { |
| m_ImageCaches.SetAt(pStream, m_pCurImageCache); |
| } |
| if (!ret) { |
| m_nCacheSize += m_pCurImageCache->EstimateSize(); |
| } |
| return FALSE; |
| } |
| FX_BOOL CPDF_PageRenderCache::Continue(IFX_Pause* pPause) { |
| int ret = m_pCurImageCache->Continue(pPause); |
| if (ret == 2) { |
| return TRUE; |
| } |
| m_nTimeCount++; |
| if (!m_bCurFindCache) { |
| m_ImageCaches.SetAt(m_pCurImageCache->GetStream(), m_pCurImageCache); |
| } |
| if (!ret) { |
| m_nCacheSize += m_pCurImageCache->EstimateSize(); |
| } |
| return FALSE; |
| } |
| void CPDF_PageRenderCache::ResetBitmap(CPDF_Stream* pStream, |
| const CFX_DIBitmap* pBitmap) { |
| CPDF_ImageCache* pImageCache; |
| if (!m_ImageCaches.Lookup(pStream, (void*&)pImageCache)) { |
| if (pBitmap == NULL) { |
| return; |
| } |
| pImageCache = new CPDF_ImageCache(m_pPage->m_pDocument, pStream); |
| m_ImageCaches.SetAt(pStream, pImageCache); |
| } |
| int oldsize = pImageCache->EstimateSize(); |
| pImageCache->Reset(pBitmap); |
| m_nCacheSize = pImageCache->EstimateSize() - oldsize; |
| } |
| CPDF_ImageCache::CPDF_ImageCache(CPDF_Document* pDoc, CPDF_Stream* pStream) |
| : m_dwTimeCount(0), |
| m_pCurBitmap(NULL), |
| m_pCurMask(NULL), |
| m_MatteColor(0), |
| m_pRenderStatus(NULL), |
| m_pDocument(pDoc), |
| m_pStream(pStream), |
| m_pCachedBitmap(NULL), |
| m_pCachedMask(NULL), |
| m_dwCacheSize(0) {} |
| CPDF_ImageCache::~CPDF_ImageCache() { |
| delete m_pCachedBitmap; |
| m_pCachedBitmap = NULL; |
| delete m_pCachedMask; |
| m_pCachedMask = NULL; |
| } |
| void CPDF_ImageCache::Reset(const CFX_DIBitmap* pBitmap) { |
| delete m_pCachedBitmap; |
| m_pCachedBitmap = NULL; |
| if (pBitmap) { |
| m_pCachedBitmap = pBitmap->Clone(); |
| } |
| CalcSize(); |
| } |
| void CPDF_PageRenderCache::ClearImageData() { |
| FX_POSITION pos = m_ImageCaches.GetStartPosition(); |
| while (pos) { |
| void* key; |
| void* value; |
| m_ImageCaches.GetNextAssoc(pos, key, value); |
| ((CPDF_ImageCache*)value)->ClearImageData(); |
| } |
| } |
| void CPDF_ImageCache::ClearImageData() { |
| if (m_pCachedBitmap && m_pCachedBitmap->GetBuffer() == NULL) { |
| ((CPDF_DIBSource*)m_pCachedBitmap)->ClearImageData(); |
| } |
| } |
| static FX_DWORD FPDF_ImageCache_EstimateImageSize(const CFX_DIBSource* pDIB) { |
| return pDIB && pDIB->GetBuffer() |
| ? (FX_DWORD)pDIB->GetHeight() * pDIB->GetPitch() + |
| (FX_DWORD)pDIB->GetPaletteSize() * 4 |
| : 0; |
| } |
| FX_BOOL CPDF_ImageCache::GetCachedBitmap(CFX_DIBSource*& pBitmap, |
| CFX_DIBSource*& pMask, |
| FX_DWORD& MatteColor, |
| CPDF_Dictionary* pPageResources, |
| FX_BOOL bStdCS, |
| FX_DWORD GroupFamily, |
| FX_BOOL bLoadMask, |
| CPDF_RenderStatus* pRenderStatus, |
| int32_t downsampleWidth, |
| int32_t downsampleHeight) { |
| if (m_pCachedBitmap) { |
| pBitmap = m_pCachedBitmap; |
| pMask = m_pCachedMask; |
| MatteColor = m_MatteColor; |
| return TRUE; |
| } |
| if (!pRenderStatus) { |
| return FALSE; |
| } |
| CPDF_RenderContext* pContext = pRenderStatus->GetContext(); |
| CPDF_PageRenderCache* pPageRenderCache = pContext->m_pPageCache; |
| m_dwTimeCount = pPageRenderCache->GetTimeCount(); |
| CPDF_DIBSource* pSrc = new CPDF_DIBSource; |
| CPDF_DIBSource* pMaskSrc = NULL; |
| if (!pSrc->Load(m_pDocument, m_pStream, &pMaskSrc, &MatteColor, |
| pRenderStatus->m_pFormResource, pPageResources, bStdCS, |
| GroupFamily, bLoadMask)) { |
| delete pSrc; |
| pBitmap = NULL; |
| return FALSE; |
| } |
| m_MatteColor = MatteColor; |
| if (pSrc->GetPitch() * pSrc->GetHeight() < FPDF_HUGE_IMAGE_SIZE) { |
| m_pCachedBitmap = pSrc->Clone(); |
| delete pSrc; |
| } else { |
| m_pCachedBitmap = pSrc; |
| } |
| if (pMaskSrc) { |
| m_pCachedMask = pMaskSrc->Clone(); |
| delete pMaskSrc; |
| } |
| |
| pBitmap = m_pCachedBitmap; |
| pMask = m_pCachedMask; |
| CalcSize(); |
| return FALSE; |
| } |
| CFX_DIBSource* CPDF_ImageCache::DetachBitmap() { |
| CFX_DIBSource* pDIBSource = m_pCurBitmap; |
| m_pCurBitmap = NULL; |
| return pDIBSource; |
| } |
| CFX_DIBSource* CPDF_ImageCache::DetachMask() { |
| CFX_DIBSource* pDIBSource = m_pCurMask; |
| m_pCurMask = NULL; |
| return pDIBSource; |
| } |
| int CPDF_ImageCache::StartGetCachedBitmap(CPDF_Dictionary* pFormResources, |
| CPDF_Dictionary* pPageResources, |
| FX_BOOL bStdCS, |
| FX_DWORD GroupFamily, |
| FX_BOOL bLoadMask, |
| CPDF_RenderStatus* pRenderStatus, |
| int32_t downsampleWidth, |
| int32_t downsampleHeight) { |
| if (m_pCachedBitmap) { |
| m_pCurBitmap = m_pCachedBitmap; |
| m_pCurMask = m_pCachedMask; |
| return 1; |
| } |
| if (!pRenderStatus) { |
| return 0; |
| } |
| m_pRenderStatus = pRenderStatus; |
| m_pCurBitmap = new CPDF_DIBSource; |
| int ret = |
| ((CPDF_DIBSource*)m_pCurBitmap) |
| ->StartLoadDIBSource(m_pDocument, m_pStream, TRUE, pFormResources, |
| pPageResources, bStdCS, GroupFamily, bLoadMask); |
| if (ret == 2) { |
| return ret; |
| } |
| if (!ret) { |
| delete m_pCurBitmap; |
| m_pCurBitmap = NULL; |
| return 0; |
| } |
| ContinueGetCachedBitmap(); |
| return 0; |
| } |
| int CPDF_ImageCache::ContinueGetCachedBitmap() { |
| m_MatteColor = ((CPDF_DIBSource*)m_pCurBitmap)->m_MatteColor; |
| m_pCurMask = ((CPDF_DIBSource*)m_pCurBitmap)->DetachMask(); |
| CPDF_RenderContext* pContext = m_pRenderStatus->GetContext(); |
| CPDF_PageRenderCache* pPageRenderCache = pContext->m_pPageCache; |
| m_dwTimeCount = pPageRenderCache->GetTimeCount(); |
| if (m_pCurBitmap->GetPitch() * m_pCurBitmap->GetHeight() < |
| FPDF_HUGE_IMAGE_SIZE) { |
| m_pCachedBitmap = m_pCurBitmap->Clone(); |
| delete m_pCurBitmap; |
| m_pCurBitmap = NULL; |
| } else { |
| m_pCachedBitmap = m_pCurBitmap; |
| } |
| if (m_pCurMask) { |
| m_pCachedMask = m_pCurMask->Clone(); |
| delete m_pCurMask; |
| m_pCurMask = NULL; |
| } |
| m_pCurBitmap = m_pCachedBitmap; |
| m_pCurMask = m_pCachedMask; |
| CalcSize(); |
| return 0; |
| } |
| int CPDF_ImageCache::Continue(IFX_Pause* pPause) { |
| int ret = ((CPDF_DIBSource*)m_pCurBitmap)->ContinueLoadDIBSource(pPause); |
| if (ret == 2) { |
| return ret; |
| } |
| if (!ret) { |
| delete m_pCurBitmap; |
| m_pCurBitmap = NULL; |
| return 0; |
| } |
| ContinueGetCachedBitmap(); |
| return 0; |
| } |
| void CPDF_ImageCache::CalcSize() { |
| m_dwCacheSize = FPDF_ImageCache_EstimateImageSize(m_pCachedBitmap) + |
| FPDF_ImageCache_EstimateImageSize(m_pCachedMask); |
| } |
| void CPDF_Document::ClearRenderFont() { |
| if (m_pDocRender) { |
| CFX_FontCache* pCache = m_pDocRender->GetFontCache(); |
| if (pCache) { |
| pCache->FreeCache(FALSE); |
| } |
| } |
| } |