// 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) { | |
FX_LPVOID key, value; | |
m_ImageCaches.GetNextAssoc(pos, key, value); | |
delete (CPDF_ImageCache*)value; | |
} | |
m_ImageCaches.RemoveAll(); | |
m_nCacheSize = 0; | |
m_nTimeCount = 0; | |
} | |
void CPDF_PageRenderCache::CacheOptimization(FX_INT32 dwLimitCacheSize) | |
{ | |
if (m_nCacheSize <= (FX_DWORD)dwLimitCacheSize) { | |
return; | |
} | |
int nCount = m_ImageCaches.GetCount(); | |
CACHEINFO* pCACHEINFO = (CACHEINFO*)FX_Alloc(FX_BYTE, (sizeof (CACHEINFO)) * nCount); | |
FX_POSITION pos = m_ImageCaches.GetStartPosition(); | |
int i = 0; | |
while (pos) { | |
FX_LPVOID key, 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) | |
{ | |
FX_LPVOID 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) { | |
FX_LPVOID key, 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, (FX_LPVOID&)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, | |
FX_INT32 downsampleWidth, FX_INT32 downsampleHeight) | |
{ | |
CPDF_ImageCache* pImageCache; | |
FX_BOOL bFind = m_ImageCaches.Lookup(pStream, (FX_LPVOID&)pImageCache); | |
if (!bFind) { | |
pImageCache = FX_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, FX_INT32 downsampleWidth, FX_INT32 downsampleHeight) | |
{ | |
m_bCurFindCache = m_ImageCaches.Lookup(pStream, (FX_LPVOID&)m_pCurImageCache); | |
if (!m_bCurFindCache) { | |
m_pCurImageCache = FX_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, (FX_LPVOID&)pImageCache)) { | |
if (pBitmap == NULL) { | |
return; | |
} | |
pImageCache = FX_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_pDocument(pDoc) | |
, m_pStream(pStream) | |
, m_pCachedBitmap(NULL) | |
, m_pCachedMask(NULL) | |
, m_dwCacheSize(0) | |
, m_dwTimeCount(0) | |
, m_pCurBitmap(NULL) | |
, m_pCurMask(NULL) | |
, m_MatteColor(0) | |
, m_pRenderStatus(NULL) | |
{ | |
} | |
CPDF_ImageCache::~CPDF_ImageCache() | |
{ | |
if (m_pCachedBitmap) { | |
delete m_pCachedBitmap; | |
m_pCachedBitmap = NULL; | |
} | |
if (m_pCachedMask) { | |
delete m_pCachedMask; | |
m_pCachedMask = NULL; | |
} | |
} | |
void CPDF_ImageCache::Reset(const CFX_DIBitmap* pBitmap) | |
{ | |
if (m_pCachedBitmap) { | |
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) { | |
FX_LPVOID key, 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, | |
FX_INT32 downsampleWidth, FX_INT32 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 = FX_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 !defined(_FPDFAPI_MINI_) | |
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; | |
} | |
#else | |
if (pSrc->GetFormat() == FXDIB_8bppRgb && pSrc->GetPalette() && | |
pSrc->GetHeight() * pSrc->GetWidth() * 3 < 1024) { | |
#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ | |
m_pCachedBitmap = pSrc->CloneConvert(FXDIB_Rgb32); | |
#else | |
m_pCachedBitmap = pSrc->CloneConvert(FXDIB_Rgb); | |
#endif | |
delete pSrc; | |
} else if (pSrc->GetPitch() * pSrc->GetHeight() < 102400) { | |
m_pCachedBitmap = pSrc->Clone(); | |
delete pSrc; | |
} else { | |
m_pCachedBitmap = pSrc; | |
} | |
m_pCachedMask = pMaskSrc; | |
#endif | |
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, | |
FX_INT32 downsampleWidth, FX_INT32 downsampleHeight) | |
{ | |
if (m_pCachedBitmap) { | |
m_pCurBitmap = m_pCachedBitmap; | |
m_pCurMask = m_pCachedMask; | |
return 1; | |
} | |
if (!pRenderStatus) { | |
return 0; | |
} | |
m_pRenderStatus = pRenderStatus; | |
m_pCurBitmap = FX_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 !defined(_FPDFAPI_MINI_) | |
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; | |
} | |
#else | |
if (m_pCurBitmap->GetFormat() == FXDIB_8bppRgb && m_pCurBitmap->GetPalette() && | |
m_pCurBitmap->GetHeight() * m_pCurBitmap->GetWidth() * 3 < 1024) { | |
m_pCachedBitmap = m_pCurBitmap->CloneConvert(FXDIB_Rgb32); | |
m_pCachedBitmap = m_pCurBitmap->CloneConvert(FXDIB_Rgb); | |
delete m_pCurBitmap; | |
m_pCurBitmap = NULL; | |
} else if (m_pCurBitmap->GetPitch() * m_pCurBitmap->GetHeight() < 102400) { | |
m_pCachedBitmap = m_pCurBitmap->Clone(); | |
delete m_pCurBitmap; | |
m_pCurBitmap = NULL; | |
} else { | |
m_pCachedBitmap = m_pCurBitmap; | |
} | |
m_pCachedMask = m_pCurMask; | |
#endif | |
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); | |
} | |
} | |
} |