| // 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/fgas/font/cfgas_pdffontmgr.h" |
| |
| #include <algorithm> |
| |
| #include "core/fpdfapi/font/cpdf_font.h" |
| #include "core/fpdfapi/page/cpdf_docpagedata.h" |
| #include "core/fpdfapi/parser/cpdf_dictionary.h" |
| #include "core/fpdfapi/parser/cpdf_document.h" |
| #include "core/fxge/fx_font.h" |
| #include "xfa/fgas/font/cfgas_fontmgr.h" |
| #include "xfa/fgas/font/cfgas_gefont.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 |
| |
| CFGAS_PDFFontMgr::CFGAS_PDFFontMgr(CPDF_Document* pDoc, CFGAS_FontMgr* pFontMgr) |
| : m_pDoc(pDoc), m_pFontMgr(pFontMgr) { |
| ASSERT(pDoc); |
| ASSERT(pFontMgr); |
| } |
| |
| CFGAS_PDFFontMgr::~CFGAS_PDFFontMgr() {} |
| |
| RetainPtr<CFGAS_GEFont> CFGAS_PDFFontMgr::FindFont(const ByteString& strPsName, |
| bool bBold, |
| bool bItalic, |
| bool bStrictMatch) { |
| CPDF_Dictionary* pFontSetDict = |
| m_pDoc->GetRoot()->GetDictFor("AcroForm")->GetDictFor("DR"); |
| if (!pFontSetDict) |
| return nullptr; |
| |
| pFontSetDict = pFontSetDict->GetDictFor("Font"); |
| if (!pFontSetDict) |
| return nullptr; |
| |
| ByteString name = strPsName; |
| name.Remove(' '); |
| |
| auto* pData = CPDF_DocPageData::FromDocument(m_pDoc.Get()); |
| CPDF_DictionaryLocker locker(pFontSetDict); |
| for (const auto& it : locker) { |
| const ByteString& key = it.first; |
| CPDF_Object* pObj = it.second.Get(); |
| if (!PsNameMatchDRFontName(name.AsStringView(), bBold, bItalic, key, |
| bStrictMatch)) { |
| continue; |
| } |
| CPDF_Dictionary* pFontDict = ToDictionary(pObj->GetDirect()); |
| if (!pFontDict || pFontDict->GetStringFor("Type") != "Font") |
| return nullptr; |
| |
| RetainPtr<CPDF_Font> pPDFFont = pData->GetFont(pFontDict); |
| if (!pPDFFont || !pPDFFont->IsEmbedded()) |
| return nullptr; |
| |
| return CFGAS_GEFont::LoadFont(pPDFFont, m_pFontMgr.Get()); |
| } |
| return nullptr; |
| } |
| |
| RetainPtr<CFGAS_GEFont> CFGAS_PDFFontMgr::GetFont(WideStringView wsFontFamily, |
| uint32_t dwFontStyles, |
| bool bStrictMatch) { |
| uint32_t dwHashCode = FX_HashCode_GetW(wsFontFamily, false); |
| ByteString strKey = ByteString::Format("%u%u", dwHashCode, dwFontStyles); |
| auto it = m_FontMap.find(strKey); |
| if (it != m_FontMap.end()) |
| return it->second; |
| |
| ByteString bsPsName = WideString(wsFontFamily).ToDefANSI(); |
| bool bBold = FontStyleIsForceBold(dwFontStyles); |
| bool bItalic = FontStyleIsItalic(dwFontStyles); |
| ByteString strFontName = PsNameToFontName(bsPsName, bBold, bItalic); |
| RetainPtr<CFGAS_GEFont> pFont = |
| FindFont(strFontName, bBold, bItalic, bStrictMatch); |
| if (pFont) |
| m_FontMap[strKey] = pFont; |
| |
| return pFont; |
| } |
| |
| ByteString CFGAS_PDFFontMgr::PsNameToFontName(const 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 CFGAS_PDFFontMgr::PsNameMatchDRFontName(ByteStringView bsPsName, |
| bool bBold, |
| bool bItalic, |
| const ByteString& bsDRFontName, |
| bool bStrictMatch) { |
| ByteString bsDRName = bsDRFontName; |
| bsDRName.Remove('-'); |
| size_t iPsLen = bsPsName.GetLength(); |
| auto nIndex = bsDRName.Find(bsPsName); |
| if (nIndex.has_value() && !bStrictMatch) |
| return true; |
| |
| if (!nIndex.has_value() || nIndex.value() != 0) |
| return false; |
| |
| size_t iDifferLength = bsDRName.GetLength() - iPsLen; |
| if (iDifferLength > 1 || (bBold || bItalic)) { |
| auto iBoldIndex = bsDRName.Find("Bold"); |
| if (bBold != iBoldIndex.has_value()) |
| return false; |
| |
| if (iBoldIndex.has_value()) { |
| iDifferLength = std::min(iDifferLength - 4, |
| bsDRName.GetLength() - iBoldIndex.value() - 4); |
| } |
| bool bItalicFont = true; |
| if (bsDRName.Contains("Italic")) |
| iDifferLength -= 6; |
| else if (bsDRName.Contains("It")) |
| iDifferLength -= 2; |
| else if (bsDRName.Contains("Oblique")) |
| iDifferLength -= 7; |
| else |
| bItalicFont = false; |
| |
| if (bItalic != bItalicFont) |
| return false; |
| |
| if (iDifferLength > 1) { |
| ByteString bsDRTailer = bsDRName.Right(iDifferLength); |
| if (bsDRTailer == "MT" || bsDRTailer == "PSMT" || |
| bsDRTailer == "Regular" || bsDRTailer == "Reg") { |
| return true; |
| } |
| if (iBoldIndex.has_value() || bItalicFont) |
| return false; |
| |
| bool bMatch = false; |
| switch (bsPsName[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; |
| } |