Home | History | Annotate | Download | only in fpdf_render
      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