|  | // Copyright 2017 PDFium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 
|  |  | 
|  | #include "xfa/fxfa/cxfa_pdffontmgr.h" | 
|  |  | 
|  | #include <algorithm> | 
|  |  | 
|  | #include "core/fpdfapi/font/cpdf_font.h" | 
|  | #include "xfa/fgas/font/cfgas_gefont.h" | 
|  | #include "xfa/fxfa/cxfa_ffapp.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // The 5 names per entry are: PsName, Normal, Bold, Italic, BoldItalic. | 
|  | const char* const g_XFAPDFFontName[][5] = { | 
|  | {"Adobe PI Std", "AdobePIStd", "AdobePIStd", "AdobePIStd", "AdobePIStd"}, | 
|  | {"Myriad Pro Light", "MyriadPro-Light", "MyriadPro-Semibold", | 
|  | "MyriadPro-LightIt", "MyriadPro-SemiboldIt"}, | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | CXFA_PDFFontMgr::CXFA_PDFFontMgr(CXFA_FFDoc* pDoc) : m_pDoc(pDoc) {} | 
|  |  | 
|  | CXFA_PDFFontMgr::~CXFA_PDFFontMgr() {} | 
|  |  | 
|  | CFX_RetainPtr<CFGAS_GEFont> CXFA_PDFFontMgr::FindFont( | 
|  | const CFX_ByteString& strPsName, | 
|  | bool bBold, | 
|  | bool bItalic, | 
|  | CPDF_Font** pDstPDFFont, | 
|  | bool bStrictMatch) { | 
|  | CPDF_Document* pDoc = m_pDoc->GetPDFDoc(); | 
|  | if (!pDoc) | 
|  | return nullptr; | 
|  |  | 
|  | CPDF_Dictionary* pFontSetDict = | 
|  | pDoc->GetRoot()->GetDictFor("AcroForm")->GetDictFor("DR"); | 
|  | if (!pFontSetDict) | 
|  | return nullptr; | 
|  |  | 
|  | pFontSetDict = pFontSetDict->GetDictFor("Font"); | 
|  | if (!pFontSetDict) | 
|  | return nullptr; | 
|  |  | 
|  | CFX_ByteString name = strPsName; | 
|  | name.Remove(' '); | 
|  | CFGAS_FontMgr* pFDEFontMgr = m_pDoc->GetApp()->GetFDEFontMgr(); | 
|  | for (const auto& it : *pFontSetDict) { | 
|  | const CFX_ByteString& key = it.first; | 
|  | CPDF_Object* pObj = it.second.get(); | 
|  | if (!PsNameMatchDRFontName(name.AsStringC(), bBold, bItalic, key, | 
|  | bStrictMatch)) { | 
|  | continue; | 
|  | } | 
|  | CPDF_Dictionary* pFontDict = ToDictionary(pObj->GetDirect()); | 
|  | if (!pFontDict || pFontDict->GetStringFor("Type") != "Font") { | 
|  | return nullptr; | 
|  | } | 
|  | CPDF_Font* pPDFFont = pDoc->LoadFont(pFontDict); | 
|  | if (!pPDFFont) { | 
|  | return nullptr; | 
|  | } | 
|  | if (!pPDFFont->IsEmbedded()) { | 
|  | *pDstPDFFont = pPDFFont; | 
|  | return nullptr; | 
|  | } | 
|  | return CFGAS_GEFont::LoadFont(pPDFFont->GetFont(), pFDEFontMgr); | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | CFX_RetainPtr<CFGAS_GEFont> CXFA_PDFFontMgr::GetFont( | 
|  | const CFX_WideStringC& wsFontFamily, | 
|  | uint32_t dwFontStyles, | 
|  | CPDF_Font** pPDFFont, | 
|  | bool bStrictMatch) { | 
|  | uint32_t dwHashCode = FX_HashCode_GetW(wsFontFamily, false); | 
|  | CFX_ByteString strKey; | 
|  | strKey.Format("%u%u", dwHashCode, dwFontStyles); | 
|  | auto it = m_FontMap.find(strKey); | 
|  | if (it != m_FontMap.end()) | 
|  | return it->second; | 
|  | CFX_ByteString bsPsName = | 
|  | CFX_ByteString::FromUnicode(CFX_WideString(wsFontFamily)); | 
|  | bool bBold = (dwFontStyles & FX_FONTSTYLE_Bold) == FX_FONTSTYLE_Bold; | 
|  | bool bItalic = (dwFontStyles & FX_FONTSTYLE_Italic) == FX_FONTSTYLE_Italic; | 
|  | CFX_ByteString strFontName = PsNameToFontName(bsPsName, bBold, bItalic); | 
|  | CFX_RetainPtr<CFGAS_GEFont> pFont = | 
|  | FindFont(strFontName, bBold, bItalic, pPDFFont, bStrictMatch); | 
|  | if (pFont) | 
|  | m_FontMap[strKey] = pFont; | 
|  | return pFont; | 
|  | } | 
|  |  | 
|  | CFX_ByteString CXFA_PDFFontMgr::PsNameToFontName( | 
|  | const CFX_ByteString& strPsName, | 
|  | bool bBold, | 
|  | bool bItalic) { | 
|  | for (size_t i = 0; i < FX_ArraySize(g_XFAPDFFontName); ++i) { | 
|  | if (strPsName == g_XFAPDFFontName[i][0]) { | 
|  | size_t index = 1; | 
|  | if (bBold) | 
|  | ++index; | 
|  | if (bItalic) | 
|  | index += 2; | 
|  | return g_XFAPDFFontName[i][index]; | 
|  | } | 
|  | } | 
|  | return strPsName; | 
|  | } | 
|  |  | 
|  | bool CXFA_PDFFontMgr::PsNameMatchDRFontName(const CFX_ByteStringC& bsPsName, | 
|  | bool bBold, | 
|  | bool bItalic, | 
|  | const CFX_ByteString& bsDRFontName, | 
|  | bool bStrictMatch) { | 
|  | CFX_ByteString bsDRName = bsDRFontName; | 
|  | bsDRName.Remove('-'); | 
|  | FX_STRSIZE iPsLen = bsPsName.GetLength(); | 
|  | FX_STRSIZE nIndex = bsDRName.Find(bsPsName); | 
|  | if (nIndex != FX_STRNPOS && !bStrictMatch) | 
|  | return true; | 
|  |  | 
|  | if (nIndex != 0) | 
|  | return false; | 
|  |  | 
|  | int32_t iDifferLength = bsDRName.GetLength() - iPsLen; | 
|  | if (iDifferLength > 1 || (bBold || bItalic)) { | 
|  | FX_STRSIZE iBoldIndex = bsDRName.Find("Bold"); | 
|  | bool bBoldFont = iBoldIndex != FX_STRNPOS; | 
|  | if (bBold != bBoldFont) | 
|  | return false; | 
|  |  | 
|  | if (bBoldFont) { | 
|  | iDifferLength = | 
|  | std::min(iDifferLength - 4, bsDRName.GetLength() - iBoldIndex - 4); | 
|  | } | 
|  | bool bItalicFont = true; | 
|  | if (bsDRName.Find("Italic") != FX_STRNPOS) { | 
|  | iDifferLength -= 6; | 
|  | } else if (bsDRName.Find("It") != FX_STRNPOS) { | 
|  | iDifferLength -= 2; | 
|  | } else if (bsDRName.Find("Oblique") != FX_STRNPOS) { | 
|  | iDifferLength -= 7; | 
|  | } else { | 
|  | bItalicFont = false; | 
|  | } | 
|  | if (bItalic != bItalicFont) | 
|  | return false; | 
|  |  | 
|  | if (iDifferLength > 1) { | 
|  | CFX_ByteString bsDRTailer = bsDRName.Right(iDifferLength); | 
|  | if (bsDRTailer == "MT" || bsDRTailer == "PSMT" || | 
|  | bsDRTailer == "Regular" || bsDRTailer == "Reg") { | 
|  | return true; | 
|  | } | 
|  | if (bBoldFont || bItalicFont) | 
|  | return false; | 
|  |  | 
|  | bool bMatch = false; | 
|  | switch (bsPsName.GetAt(iPsLen - 1)) { | 
|  | case 'L': { | 
|  | if (bsDRName.Right(5) == "Light") { | 
|  | bMatch = true; | 
|  | } | 
|  | } break; | 
|  | case 'R': { | 
|  | if (bsDRName.Right(7) == "Regular" || bsDRName.Right(3) == "Reg") { | 
|  | bMatch = true; | 
|  | } | 
|  | } break; | 
|  | case 'M': { | 
|  | if (bsDRName.Right(5) == "Medium") { | 
|  | bMatch = true; | 
|  | } | 
|  | } break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | return bMatch; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool CXFA_PDFFontMgr::GetCharWidth(const CFX_RetainPtr<CFGAS_GEFont>& pFont, | 
|  | wchar_t wUnicode, | 
|  | bool bCharCode, | 
|  | int32_t* pWidth) { | 
|  | if (wUnicode != 0x20 || bCharCode) | 
|  | return false; | 
|  |  | 
|  | auto it = m_FDE2PDFFont.find(pFont); | 
|  | if (it == m_FDE2PDFFont.end()) | 
|  | return false; | 
|  |  | 
|  | CPDF_Font* pPDFFont = it->second; | 
|  | *pWidth = pPDFFont->GetCharWidthF(pPDFFont->CharCodeFromUnicode(wUnicode)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void CXFA_PDFFontMgr::SetFont(const CFX_RetainPtr<CFGAS_GEFont>& pFont, | 
|  | CPDF_Font* pPDFFont) { | 
|  | m_FDE2PDFFont[pFont] = pPDFFont; | 
|  | } |