Chromium Code Reviews| Index: core/src/fxcodec/jbig2/JBig2_Context.cpp |
| diff --git a/core/src/fxcodec/jbig2/JBig2_Context.cpp b/core/src/fxcodec/jbig2/JBig2_Context.cpp |
| index 83ded6fbe18f15ac81bde0b7d0de95d9b25ad2be..d8e81540d8f3e0fca6384540cf3c0bcda1f60a56 100644 |
| --- a/core/src/fxcodec/jbig2/JBig2_Context.cpp |
| +++ b/core/src/fxcodec/jbig2/JBig2_Context.cpp |
| @@ -4,7 +4,21 @@ |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| +#include <map> |
| +#include <list> |
| #include "JBig2_Context.h" |
| + |
| +// Implement a very small least recently used (LRU) cache. It is very |
| +// common for a JBIG2 dictionary to span multiple page in a PDF file, |
|
Tom Sepez
2014/12/15 19:58:14
nit: pages
jab
2014/12/15 21:00:08
Done.
|
| +// and we do not want to decode the same dictionary over an over |
|
Tom Sepez
2014/12/15 19:58:14
nit: over and over
jab
2014/12/15 21:00:08
Done.
|
| +// again. We key off of the memory location of the dictionary. The |
| +// list keeps track of the freshness of enties, with freshest ones are |
|
Lei Zhang
2014/12/15 19:28:09
typo: enties -> entities
grammar: "with freshest o
jab
2014/12/15 21:00:08
Done.
|
| +// at the front. Even a tiny cache size like 2 makes a dramatic |
| +// difference for typical JBIG2 documents. |
| +const int kSymbolDictCacheMaxSize = 2; |
| +typedef std::pair<FX_BYTE*, CJBig2_SymbolDict*> cache_pair; |
|
Tom Sepez
2014/12/15 19:58:14
nit: to match up with the style conventions of thi
jab
2014/12/15 21:00:08
Done.
|
| +static std::list<cache_pair> symbol_dict_cache; |
|
Tom Sepez
2014/12/15 19:58:14
nit: they're less consistent about naming of globa
jab
2014/12/15 21:00:08
Done.
|
| + |
| void OutputBitmap(CJBig2_Image* pImage) |
| { |
| if(!pImage) { |
| @@ -614,6 +628,8 @@ FX_INT32 CJBig2_Context::parseSymbolDict(CJBig2_Segment *pSegment, IFX_Pause* pP |
| JBig2ArithCtx *gbContext = NULL, *grContext = NULL; |
| CJBig2_ArithDecoder *pArithDecoder; |
| JBIG2_ALLOC(pSymbolDictDecoder, CJBig2_SDDProc()); |
| + FX_BYTE *key = pSegment->m_pData; |
| + FX_BOOL cache_hit = false; |
| if(m_pStream->readShortInteger(&wFlags) != 0) { |
| m_pModule->JBig2_Error("symbol dictionary segment : data header too short."); |
| nRet = JBIG2_ERROR_TOO_SHORT; |
| @@ -791,23 +807,43 @@ FX_INT32 CJBig2_Context::parseSymbolDict(CJBig2_Segment *pSegment, IFX_Pause* pP |
| } |
| } |
| pSegment->m_nResultType = JBIG2_SYMBOL_DICT_POINTER; |
| - if(pSymbolDictDecoder->SDHUFF == 0) { |
| - JBIG2_ALLOC(pArithDecoder, CJBig2_ArithDecoder(m_pStream)); |
| - pSegment->m_Result.sd = pSymbolDictDecoder->decode_Arith(pArithDecoder, gbContext, grContext); |
| - delete pArithDecoder; |
| - if(pSegment->m_Result.sd == NULL) { |
| - nRet = JBIG2_ERROR_FETAL; |
| - goto failed; |
| + for(std::list<cache_pair>::iterator it = |
|
Tom Sepez
2014/12/15 19:58:14
nit: auto& it = .. would be more concise here. S
jab
2014/12/15 21:00:08
I'm really sorry, but this code is too sophisticat
jab
2014/12/16 07:30:57
please let me know if there is a required change o
|
| + symbol_dict_cache.begin(); it != symbol_dict_cache.end(); ++it) { |
| + if (it->first == key) { |
| + pSegment->m_Result.sd = it->second->DeepCopy(); |
| + symbol_dict_cache.erase(it); |
|
Lei Zhang
2014/12/15 19:28:09
Is |it| still valid after you call erase() on it?
jab
2014/12/15 21:00:08
I am not a C++ guru, but I can say that the code c
Lei Zhang
2014/12/16 08:19:31
I guess I should have said "|it| is not valid afte
|
| + symbol_dict_cache.push_front(*it); |
| + cache_hit = true; |
| + break; |
| } |
| - m_pStream->alignByte(); |
| - m_pStream->offset(2); |
| - } else { |
| - pSegment->m_Result.sd = pSymbolDictDecoder->decode_Huffman(m_pStream, gbContext, grContext, pPause); |
| - if(pSegment->m_Result.sd == NULL) { |
| - nRet = JBIG2_ERROR_FETAL; |
| - goto failed; |
| + } |
| + if (!cache_hit) { |
| + if(pSymbolDictDecoder->SDHUFF == 0) { |
| + JBIG2_ALLOC(pArithDecoder, CJBig2_ArithDecoder(m_pStream)); |
| + pSegment->m_Result.sd = pSymbolDictDecoder->decode_Arith(pArithDecoder, gbContext, grContext); |
| + delete pArithDecoder; |
| + if(pSegment->m_Result.sd == NULL) { |
| + nRet = JBIG2_ERROR_FETAL; |
| + goto failed; |
| + } |
| + m_pStream->alignByte(); |
| + m_pStream->offset(2); |
| + } else { |
| + pSegment->m_Result.sd = pSymbolDictDecoder->decode_Huffman(m_pStream, gbContext, grContext, pPause); |
| + if(pSegment->m_Result.sd == NULL) { |
| + nRet = JBIG2_ERROR_FETAL; |
| + goto failed; |
| + } |
| + m_pStream->alignByte(); |
| + } |
| + CJBig2_SymbolDict *value = pSegment->m_Result.sd->DeepCopy(); |
| + if (value) { |
| + while (symbol_dict_cache.size() >= kSymbolDictCacheMaxSize) { |
| + delete symbol_dict_cache.back().second; |
| + symbol_dict_cache.pop_back(); |
| + } |
| + symbol_dict_cache.push_front(cache_pair(key, value)); |
| } |
| - m_pStream->alignByte(); |
| } |
| if(wFlags & 0x0200) { |
| pSegment->m_Result.sd->m_bContextRetained = TRUE; |