| Index: core/src/fpdfapi/fpdf_font/fpdf_font.cpp | 
| diff --git a/core/src/fpdfapi/fpdf_font/fpdf_font.cpp b/core/src/fpdfapi/fpdf_font/fpdf_font.cpp | 
| index 0529d3d35b7e1605e548d568f22a356885c05159..07f9dda6531d42d9b6edd66b4239e98d960e7914 100644 | 
| --- a/core/src/fpdfapi/fpdf_font/fpdf_font.cpp | 
| +++ b/core/src/fpdfapi/fpdf_font/fpdf_font.cpp | 
| @@ -1643,27 +1643,20 @@ void CPDF_TrueTypeFont::LoadGlyphMap() { | 
| m_GlyphIndex[charcode] = charcode; | 
| } | 
| } | 
| -CPDF_Type3Font::CPDF_Type3Font() : CPDF_SimpleFont(PDFFONT_TYPE3) { | 
| -  m_pPageResources = NULL; | 
| -  FXSYS_memset(m_CharWidthL, 0, sizeof m_CharWidthL); | 
| + | 
| +CPDF_Type3Font::CPDF_Type3Font() | 
| +    : CPDF_SimpleFont(PDFFONT_TYPE3), | 
| +      m_pCharProcs(nullptr), | 
| +      m_pPageResources(nullptr), | 
| +      m_pFontResources(nullptr) { | 
| +  FXSYS_memset(m_CharWidthL, 0, sizeof(m_CharWidthL)); | 
| } | 
| + | 
| CPDF_Type3Font::~CPDF_Type3Font() { | 
| -  FX_POSITION pos = m_CacheMap.GetStartPosition(); | 
| -  while (pos) { | 
| -    void* key; | 
| -    void* value; | 
| -    m_CacheMap.GetNextAssoc(pos, key, value); | 
| -    delete (CPDF_Type3Char*)value; | 
| -  } | 
| -  m_CacheMap.RemoveAll(); | 
| -  pos = m_DeletedMap.GetStartPosition(); | 
| -  while (pos) { | 
| -    void* key; | 
| -    void* value; | 
| -    m_DeletedMap.GetNextAssoc(pos, key, value); | 
| -    delete (CPDF_Type3Char*)key; | 
| -  } | 
| +  for (auto it : m_CacheMap) | 
| +    delete it.second; | 
| } | 
| + | 
| FX_BOOL CPDF_Type3Font::_Load() { | 
| m_pFontResources = m_pFontDict->GetDict(FX_BSTRC("Resources")); | 
| CPDF_Array* pMatrix = m_pFontDict->GetArray(FX_BSTRC("FontMatrix")); | 
| @@ -1714,19 +1707,15 @@ FX_BOOL CPDF_Type3Font::_Load() { | 
| void CPDF_Type3Font::CheckType3FontMetrics() { | 
| CheckFontMetrics(); | 
| } | 
| + | 
| CPDF_Type3Char* CPDF_Type3Font::LoadChar(FX_DWORD charcode, int level) { | 
| if (level >= _FPDF_MAX_TYPE3_FORM_LEVEL_) | 
| return nullptr; | 
|  | 
| -  CPDF_Type3Char* pChar = nullptr; | 
| -  if (m_CacheMap.Lookup((void*)(uintptr_t)charcode, (void*&)pChar)) { | 
| -    if (pChar->m_bPageRequired && m_pPageResources) { | 
| -      delete pChar; | 
| -      m_CacheMap.RemoveKey((void*)(uintptr_t)charcode); | 
| -      return LoadChar(charcode, level + 1); | 
| -    } | 
| -    return pChar; | 
| -  } | 
| +  auto it = m_CacheMap.find(charcode); | 
| +  if (it != m_CacheMap.end()) | 
| +    return it->second; | 
| + | 
| const FX_CHAR* name = | 
| GetAdobeCharName(m_BaseEncoding, m_pCharNames, charcode); | 
| if (!name) | 
| @@ -1737,59 +1726,70 @@ CPDF_Type3Char* CPDF_Type3Font::LoadChar(FX_DWORD charcode, int level) { | 
| if (!pStream) | 
| return nullptr; | 
|  | 
| -  pChar = new CPDF_Type3Char; | 
| -  pChar->m_pForm = new CPDF_Form( | 
| +  nonstd::unique_ptr<CPDF_Type3Char> pNewChar(new CPDF_Type3Char(new CPDF_Form( | 
| m_pDocument, m_pFontResources ? m_pFontResources : m_pPageResources, | 
| -      pStream, nullptr); | 
| -  pChar->m_pForm->ParseContent(nullptr, nullptr, pChar, nullptr, level + 1); | 
| +      pStream, nullptr))); | 
| + | 
| +  // This can trigger recursion into this method. The content of |m_CacheMap| | 
| +  // can change as a result. Thus after it returns, check the cache again for | 
| +  // a cache hit. | 
| +  pNewChar->m_pForm->ParseContent(nullptr, nullptr, pNewChar.get(), nullptr, | 
| +                                  level + 1); | 
| +  it = m_CacheMap.find(charcode); | 
| +  if (it != m_CacheMap.end()) | 
| +    return it->second; | 
| + | 
| FX_FLOAT scale = m_FontMatrix.GetXUnit(); | 
| -  pChar->m_Width = (int32_t)(pChar->m_Width * scale + 0.5f); | 
| -  FX_RECT& rcBBox = pChar->m_BBox; | 
| +  pNewChar->m_Width = (int32_t)(pNewChar->m_Width * scale + 0.5f); | 
| +  FX_RECT& rcBBox = pNewChar->m_BBox; | 
| CFX_FloatRect char_rect( | 
| (FX_FLOAT)rcBBox.left / 1000.0f, (FX_FLOAT)rcBBox.bottom / 1000.0f, | 
| (FX_FLOAT)rcBBox.right / 1000.0f, (FX_FLOAT)rcBBox.top / 1000.0f); | 
| -  if (rcBBox.right <= rcBBox.left || rcBBox.bottom >= rcBBox.top) { | 
| -    char_rect = pChar->m_pForm->CalcBoundingBox(); | 
| -  } | 
| +  if (rcBBox.right <= rcBBox.left || rcBBox.bottom >= rcBBox.top) | 
| +    char_rect = pNewChar->m_pForm->CalcBoundingBox(); | 
| + | 
| char_rect.Transform(&m_FontMatrix); | 
| rcBBox.left = FXSYS_round(char_rect.left * 1000); | 
| rcBBox.right = FXSYS_round(char_rect.right * 1000); | 
| rcBBox.top = FXSYS_round(char_rect.top * 1000); | 
| rcBBox.bottom = FXSYS_round(char_rect.bottom * 1000); | 
| -  m_CacheMap.SetAt((void*)(uintptr_t)charcode, pChar); | 
| -  if (pChar->m_pForm->CountObjects() == 0) { | 
| -    delete pChar->m_pForm; | 
| -    pChar->m_pForm = nullptr; | 
| + | 
| +  FXSYS_assert(m_CacheMap.find(charcode) == m_CacheMap.end()); | 
| +  CPDF_Type3Char* pCachedChar = pNewChar.release(); | 
| +  m_CacheMap[charcode] = pCachedChar; | 
| +  if (pCachedChar->m_pForm->CountObjects() == 0) { | 
| +    delete pCachedChar->m_pForm; | 
| +    pCachedChar->m_pForm = nullptr; | 
| } | 
| -  return pChar; | 
| +  return pCachedChar; | 
| } | 
| + | 
| int CPDF_Type3Font::GetCharWidthF(FX_DWORD charcode, int level) { | 
| -  if (charcode > 0xff) { | 
| +  if (charcode >= FX_ArraySize(m_CharWidthL)) | 
| charcode = 0; | 
| -  } | 
| -  if (m_CharWidthL[charcode]) { | 
| + | 
| +  if (m_CharWidthL[charcode]) | 
| return m_CharWidthL[charcode]; | 
| -  } | 
| -  CPDF_Type3Char* pChar = LoadChar(charcode, level); | 
| -  if (pChar == NULL) { | 
| -    return 0; | 
| -  } | 
| -  return pChar->m_Width; | 
| + | 
| +  const CPDF_Type3Char* pChar = LoadChar(charcode, level); | 
| +  return pChar ? pChar->m_Width : 0; | 
| } | 
| + | 
| void CPDF_Type3Font::GetCharBBox(FX_DWORD charcode, FX_RECT& rect, int level) { | 
| -  CPDF_Type3Char* pChar = LoadChar(charcode, level); | 
| -  if (pChar == NULL) { | 
| -    rect.left = rect.right = rect.top = rect.bottom = 0; | 
| +  const CPDF_Type3Char* pChar = LoadChar(charcode, level); | 
| +  if (!pChar) { | 
| +    rect.left = 0; | 
| +    rect.right = 0; | 
| +    rect.top = 0; | 
| +    rect.bottom = 0; | 
| return; | 
| } | 
| rect = pChar->m_BBox; | 
| } | 
| -CPDF_Type3Char::CPDF_Type3Char() { | 
| -  m_pForm = NULL; | 
| -  m_pBitmap = NULL; | 
| -  m_bPageRequired = FALSE; | 
| -  m_bColored = FALSE; | 
| -} | 
| + | 
| +CPDF_Type3Char::CPDF_Type3Char(CPDF_Form* pForm) | 
| +    : m_pForm(pForm), m_pBitmap(nullptr), m_bColored(FALSE) {} | 
| + | 
| CPDF_Type3Char::~CPDF_Type3Char() { | 
| delete m_pForm; | 
| delete m_pBitmap; | 
|  |