• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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" {
compare(const void * data1,const void * data2)17     static int compare(const void* data1, const void* data2)
18     {
19         return ((CACHEINFO*)data1)->time - ((CACHEINFO*)data2)->time;
20     }
21 };
ClearRenderCache()22 void CPDF_Page::ClearRenderCache()
23 {
24     if (m_pPageRender) {
25         m_pPageRender->ClearAll();
26     }
27 }
ClearAll()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 }
CacheOptimization(FX_INT32 dwLimitCacheSize)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 }
ClearImageCache(CPDF_Stream * pStream)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 }
EstimateSize()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 }
GetCachedSize(CPDF_Stream * pStream) const96 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 }
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)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 }
StartGetCachedBitmap(CPDF_Stream * pStream,FX_BOOL bStdCS,FX_DWORD GroupFamily,FX_BOOL bLoadMask,CPDF_RenderStatus * pRenderStatus,FX_INT32 downsampleWidth,FX_INT32 downsampleHeight)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 }
Continue(IFX_Pause * pPause)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 }
ResetBitmap(CPDF_Stream * pStream,const CFX_DIBitmap * pBitmap)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 }
CPDF_ImageCache(CPDF_Document * pDoc,CPDF_Stream * pStream)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 }
~CPDF_ImageCache()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 }
Reset(const CFX_DIBitmap * pBitmap)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 }
ClearImageData()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 }
ClearImageData()217 void CPDF_ImageCache::ClearImageData()
218 {
219     if (m_pCachedBitmap && m_pCachedBitmap->GetBuffer() == NULL) {
220         ((CPDF_DIBSource*)m_pCachedBitmap)->ClearImageData();
221     }
222 }
FPDF_ImageCache_EstimateImageSize(const CFX_DIBSource * pDIB)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 }
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)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 }
DetachBitmap()284 CFX_DIBSource* CPDF_ImageCache::DetachBitmap()
285 {
286     CFX_DIBSource* pDIBSource = m_pCurBitmap;
287     m_pCurBitmap = NULL;
288     return pDIBSource;
289 }
DetachMask()290 CFX_DIBSource* CPDF_ImageCache::DetachMask()
291 {
292     CFX_DIBSource* pDIBSource = m_pCurMask;
293     m_pCurMask = NULL;
294     return pDIBSource;
295 }
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)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 }
ContinueGetCachedBitmap()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 }
Continue(IFX_Pause * pPause)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 }
CalcSize()377 void CPDF_ImageCache::CalcSize()
378 {
379     m_dwCacheSize = FPDF_ImageCache_EstimateImageSize(m_pCachedBitmap) + FPDF_ImageCache_EstimateImageSize(m_pCachedMask);
380 }
ClearRenderFont()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