Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 PDFium Authors. All rights reserved. | 1 // Copyright 2014 PDFium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| 6 | 6 |
| 7 #include <map> | |
| 8 #include <vector> | |
| 7 #include "JBig2_Context.h" | 9 #include "JBig2_Context.h" |
| 10 | |
| 11 // Implement a very small least recently used (LRU) cache. It is very | |
| 12 // common for a JBIG2 dictionary to span multiple page in a PDF file, | |
| 13 // and we do not want to decode the same dictionary over an over | |
| 14 // again. We key off of the memory location of the dictionary. The | |
| 15 // vector keeps track of when an entry should be deleted, to make space | |
| 16 // for a new one. Even a tiny cache size like 2 makes a dramatic difference | |
| 17 // for Google Books PDF files. | |
| 18 const int kMaxCacheSize = 2; | |
| 19 static std::map<FX_BYTE*, CJBig2_SymbolDict*> cache; | |
| 20 static std::vector<FX_BYTE*> cache_keys; | |
| 21 | |
| 22 | |
| 8 void OutputBitmap(CJBig2_Image* pImage) | 23 void OutputBitmap(CJBig2_Image* pImage) |
| 9 { | 24 { |
| 10 if(!pImage) { | 25 if(!pImage) { |
| 11 return; | 26 return; |
| 12 } | 27 } |
| 13 } | 28 } |
| 14 CJBig2_Context *CJBig2_Context::CreateContext(CJBig2_Module *pModule, FX_BYTE *p GlobalData, FX_DWORD dwGlobalLength, | 29 CJBig2_Context *CJBig2_Context::CreateContext(CJBig2_Module *pModule, FX_BYTE *p GlobalData, FX_DWORD dwGlobalLength, |
| 15 FX_BYTE *pData, FX_DWORD dwLength, FX_INT32 nStreamType, IFX_Pause* pPau se) | 30 FX_BYTE *pData, FX_DWORD dwLength, FX_INT32 nStreamType, IFX_Pause* pPau se) |
| 16 { | 31 { |
| 17 return new(pModule) CJBig2_Context(pGlobalData, dwGlobalLength, pData, dwLen gth, nStreamType, pPause); | 32 return new(pModule) CJBig2_Context(pGlobalData, dwGlobalLength, pData, dwLen gth, nStreamType, pPause); |
| (...skipping 589 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 607 FX_BYTE cSDHUFFDH, cSDHUFFDW, cSDHUFFBMSIZE, cSDHUFFAGGINST; | 622 FX_BYTE cSDHUFFDH, cSDHUFFDW, cSDHUFFBMSIZE, cSDHUFFAGGINST; |
| 608 CJBig2_HuffmanTable *Table_B1 = NULL, *Table_B2 = NULL, *Table_B3 = NULL, *T able_B4 = NULL, *Table_B5 = NULL; | 623 CJBig2_HuffmanTable *Table_B1 = NULL, *Table_B2 = NULL, *Table_B3 = NULL, *T able_B4 = NULL, *Table_B5 = NULL; |
| 609 FX_INT32 i, nIndex, nRet; | 624 FX_INT32 i, nIndex, nRet; |
| 610 CJBig2_Segment *pSeg = NULL, *pLRSeg = NULL; | 625 CJBig2_Segment *pSeg = NULL, *pLRSeg = NULL; |
| 611 FX_BOOL bUsed; | 626 FX_BOOL bUsed; |
| 612 CJBig2_Image ** SDINSYMS = NULL; | 627 CJBig2_Image ** SDINSYMS = NULL; |
| 613 CJBig2_SDDProc *pSymbolDictDecoder; | 628 CJBig2_SDDProc *pSymbolDictDecoder; |
| 614 JBig2ArithCtx *gbContext = NULL, *grContext = NULL; | 629 JBig2ArithCtx *gbContext = NULL, *grContext = NULL; |
| 615 CJBig2_ArithDecoder *pArithDecoder; | 630 CJBig2_ArithDecoder *pArithDecoder; |
| 616 JBIG2_ALLOC(pSymbolDictDecoder, CJBig2_SDDProc()); | 631 JBIG2_ALLOC(pSymbolDictDecoder, CJBig2_SDDProc()); |
| 632 FX_BYTE *key = pSegment->m_pData; | |
| 617 if(m_pStream->readShortInteger(&wFlags) != 0) { | 633 if(m_pStream->readShortInteger(&wFlags) != 0) { |
| 618 m_pModule->JBig2_Error("symbol dictionary segment : data header too shor t."); | 634 m_pModule->JBig2_Error("symbol dictionary segment : data header too shor t."); |
| 619 nRet = JBIG2_ERROR_TOO_SHORT; | 635 nRet = JBIG2_ERROR_TOO_SHORT; |
| 620 goto failed; | 636 goto failed; |
| 621 } | 637 } |
| 622 pSymbolDictDecoder->SDHUFF = wFlags & 0x0001; | 638 pSymbolDictDecoder->SDHUFF = wFlags & 0x0001; |
| 623 pSymbolDictDecoder->SDREFAGG = (wFlags >> 1) & 0x0001; | 639 pSymbolDictDecoder->SDREFAGG = (wFlags >> 1) & 0x0001; |
| 624 pSymbolDictDecoder->SDTEMPLATE = (wFlags >> 10) & 0x0003; | 640 pSymbolDictDecoder->SDTEMPLATE = (wFlags >> 10) & 0x0003; |
| 625 pSymbolDictDecoder->SDRTEMPLATE = (wFlags >> 12) & 0x0003; | 641 pSymbolDictDecoder->SDRTEMPLATE = (wFlags >> 12) & 0x0003; |
| 626 cSDHUFFDH = (wFlags >> 2) & 0x0003; | 642 cSDHUFFDH = (wFlags >> 2) & 0x0003; |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 784 gbContext = (JBig2ArithCtx*)m_pModule->JBig2_Malloc2(sizeof(JBig2Ari thCtx), dwTemp); | 800 gbContext = (JBig2ArithCtx*)m_pModule->JBig2_Malloc2(sizeof(JBig2Ari thCtx), dwTemp); |
| 785 JBIG2_memset(gbContext, 0, sizeof(JBig2ArithCtx)*dwTemp); | 801 JBIG2_memset(gbContext, 0, sizeof(JBig2ArithCtx)*dwTemp); |
| 786 } | 802 } |
| 787 if (pSymbolDictDecoder->SDREFAGG == 1) { | 803 if (pSymbolDictDecoder->SDREFAGG == 1) { |
| 788 dwTemp = pSymbolDictDecoder->SDRTEMPLATE ? 1 << 10 : 1 << 13; | 804 dwTemp = pSymbolDictDecoder->SDRTEMPLATE ? 1 << 10 : 1 << 13; |
| 789 grContext = (JBig2ArithCtx*)m_pModule->JBig2_Malloc2(sizeof(JBig2Ari thCtx), dwTemp); | 805 grContext = (JBig2ArithCtx*)m_pModule->JBig2_Malloc2(sizeof(JBig2Ari thCtx), dwTemp); |
| 790 JBIG2_memset(grContext, 0, sizeof(JBig2ArithCtx)*dwTemp); | 806 JBIG2_memset(grContext, 0, sizeof(JBig2ArithCtx)*dwTemp); |
| 791 } | 807 } |
| 792 } | 808 } |
| 793 pSegment->m_nResultType = JBIG2_SYMBOL_DICT_POINTER; | 809 pSegment->m_nResultType = JBIG2_SYMBOL_DICT_POINTER; |
| 794 if(pSymbolDictDecoder->SDHUFF == 0) { | 810 if (cache.find(key) != cache.end()) { |
| 811 pSegment->m_Result.sd = cache[key]->DeepCopy(); | |
| 812 for(std::vector<FX_BYTE*>::iterator it = cache_keys.begin(); | |
| 813 it != cache_keys.end(); ++it) { | |
| 814 if (*it == key) { | |
| 815 cache_keys.erase(cache_keys.begin()); | |
|
Bo Xu
2014/12/06 05:59:43
Should line 815 be: "cache_keys.erase(it);" ? I gu
jab
2014/12/08 21:00:02
Done.
(I made the front hold the freshest entries
| |
| 816 break; | |
|
Bo Xu
2014/12/07 19:22:50
Or can we use std:list to replace the std:vector h
jab
2014/12/08 21:00:02
Done.
| |
| 817 } | |
| 818 } | |
| 819 cache_keys.push_back(key); | |
| 820 } else if(pSymbolDictDecoder->SDHUFF == 0) { | |
| 795 JBIG2_ALLOC(pArithDecoder, CJBig2_ArithDecoder(m_pStream)); | 821 JBIG2_ALLOC(pArithDecoder, CJBig2_ArithDecoder(m_pStream)); |
| 796 pSegment->m_Result.sd = pSymbolDictDecoder->decode_Arith(pArithDecoder, gbContext, grContext); | 822 pSegment->m_Result.sd = pSymbolDictDecoder->decode_Arith(pArithDecoder, gbContext, grContext); |
| 797 delete pArithDecoder; | 823 delete pArithDecoder; |
| 798 if(pSegment->m_Result.sd == NULL) { | 824 if(pSegment->m_Result.sd == NULL) { |
| 799 nRet = JBIG2_ERROR_FETAL; | 825 nRet = JBIG2_ERROR_FETAL; |
| 800 goto failed; | 826 goto failed; |
| 801 } | 827 } |
| 802 m_pStream->alignByte(); | 828 m_pStream->alignByte(); |
| 803 m_pStream->offset(2); | 829 m_pStream->offset(2); |
| 804 } else { | 830 } else { |
| 805 pSegment->m_Result.sd = pSymbolDictDecoder->decode_Huffman(m_pStream, gb Context, grContext, pPause); | 831 pSegment->m_Result.sd = pSymbolDictDecoder->decode_Huffman(m_pStream, gb Context, grContext, pPause); |
| 806 if(pSegment->m_Result.sd == NULL) { | 832 if(pSegment->m_Result.sd == NULL) { |
| 807 nRet = JBIG2_ERROR_FETAL; | 833 nRet = JBIG2_ERROR_FETAL; |
| 808 goto failed; | 834 goto failed; |
| 809 } | 835 } |
| 810 m_pStream->alignByte(); | 836 m_pStream->alignByte(); |
| 811 } | 837 } |
| 838 if (cache.find(key) == cache.end()) { | |
| 839 CJBig2_SymbolDict *value = pSegment->m_Result.sd->DeepCopy(); | |
|
Bo Xu
2014/12/06 05:59:43
should |value| be deleted after use?
jab
2014/12/08 21:00:02
That you. I think I need to free the memory when w
Bo Xu
2014/12/08 23:00:17
How about making the cache member variable of the
jab
2014/12/08 23:21:04
I made an explicit call to delete. Is that okay? I
Bo Xu
2014/12/08 23:29:54
Sure, the explicit delete is ok here.
I am thinki
| |
| 840 if (value) { | |
| 841 while (cache_keys.size() >= kMaxCacheSize) { | |
| 842 cache.erase(cache_keys[0]); | |
| 843 cache_keys.erase(cache_keys.begin()); | |
| 844 } | |
| 845 cache.insert(std::pair<FX_BYTE*, CJBig2_SymbolDict*>(key, value)); | |
| 846 cache_keys.push_back(key); | |
| 847 } | |
| 848 } | |
| 812 if(wFlags & 0x0200) { | 849 if(wFlags & 0x0200) { |
| 813 pSegment->m_Result.sd->m_bContextRetained = TRUE; | 850 pSegment->m_Result.sd->m_bContextRetained = TRUE; |
| 814 if(pSymbolDictDecoder->SDHUFF == 0) { | 851 if(pSymbolDictDecoder->SDHUFF == 0) { |
| 815 pSegment->m_Result.sd->m_gbContext = gbContext; | 852 pSegment->m_Result.sd->m_gbContext = gbContext; |
| 816 } | 853 } |
| 817 if(pSymbolDictDecoder->SDREFAGG == 1) { | 854 if(pSymbolDictDecoder->SDREFAGG == 1) { |
| 818 pSegment->m_Result.sd->m_grContext = grContext; | 855 pSegment->m_Result.sd->m_grContext = grContext; |
| 819 } | 856 } |
| 820 bUsed = TRUE; | 857 bUsed = TRUE; |
| 821 } else { | 858 } else { |
| (...skipping 981 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1803 SBSYMCODES[CURTEMP].code = CURCODE; | 1840 SBSYMCODES[CURTEMP].code = CURCODE; |
| 1804 CURCODE = CURCODE + 1; | 1841 CURCODE = CURCODE + 1; |
| 1805 } | 1842 } |
| 1806 CURTEMP = CURTEMP + 1; | 1843 CURTEMP = CURTEMP + 1; |
| 1807 } | 1844 } |
| 1808 CURLEN = CURLEN + 1; | 1845 CURLEN = CURLEN + 1; |
| 1809 } | 1846 } |
| 1810 m_pModule->JBig2_Free(LENCOUNT); | 1847 m_pModule->JBig2_Free(LENCOUNT); |
| 1811 m_pModule->JBig2_Free(FIRSTCODE); | 1848 m_pModule->JBig2_Free(FIRSTCODE); |
| 1812 } | 1849 } |
| OLD | NEW |