| // Copyright 2017 The PDFium Authors |
| // 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 <iterator> |
| #include <utility> |
| |
| #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/fpdfapi/parser/fpdf_parser_utility.h" |
| #include "core/fxge/fx_font.h" |
| #include "third_party/base/check.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 kXFAPDFFontName[][5] = { |
| {"Adobe PI Std", "AdobePIStd", "AdobePIStd", "AdobePIStd", "AdobePIStd"}, |
| {"Myriad Pro Light", "MyriadPro-Light", "MyriadPro-Semibold", |
| "MyriadPro-LightIt", "MyriadPro-SemiboldIt"}, |
| }; |
| |
| } // namespace |
| |
| CFGAS_PDFFontMgr::CFGAS_PDFFontMgr(const CPDF_Document* pDoc) : m_pDoc(pDoc) { |
| DCHECK(pDoc); |
| } |
| |
| CFGAS_PDFFontMgr::~CFGAS_PDFFontMgr() = default; |
| |
| RetainPtr<CFGAS_GEFont> CFGAS_PDFFontMgr::FindFont(const ByteString& strPsName, |
| bool bBold, |
| bool bItalic, |
| bool bStrictMatch) { |
| RetainPtr<const 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); |
| CPDF_DictionaryLocker locker(pFontSetDict); |
| for (const auto& it : locker) { |
| const ByteString& key = it.first; |
| const RetainPtr<CPDF_Object>& pObj = it.second; |
| if (!PsNameMatchDRFontName(name.AsStringView(), bBold, bItalic, key, |
| bStrictMatch)) { |
| continue; |
| } |
| RetainPtr<CPDF_Dictionary> pFontDict = |
| ToDictionary(pObj->GetMutableDirect()); |
| if (!ValidateDictType(pFontDict.Get(), "Font")) |
| return nullptr; |
| |
| RetainPtr<CPDF_Font> pPDFFont = pData->GetFont(pFontDict); |
| if (!pPDFFont || !pPDFFont->IsEmbedded()) |
| return nullptr; |
| |
| return CFGAS_GEFont::LoadFont(std::move(pPDFFont)); |
| } |
| return nullptr; |
| } |
| |
| RetainPtr<CFGAS_GEFont> CFGAS_PDFFontMgr::GetFont( |
| const WideString& wsFontFamily, |
| uint32_t dwFontStyles, |
| bool bStrictMatch) { |
| auto key = std::make_pair(wsFontFamily, dwFontStyles); |
| auto it = m_FontMap.find(key); |
| 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) |
| return nullptr; |
| |
| m_FontMap[key] = pFont; |
| return pFont; |
| } |
| |
| ByteString CFGAS_PDFFontMgr::PsNameToFontName(const ByteString& strPsName, |
| bool bBold, |
| bool bItalic) { |
| for (size_t i = 0; i < std::size(kXFAPDFFontName); ++i) { |
| if (strPsName == kXFAPDFFontName[i][0]) { |
| size_t index = 1; |
| if (bBold) |
| ++index; |
| if (bItalic) |
| index += 2; |
| return kXFAPDFFontName[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.Last(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.Last(5) == "Light") |
| bMatch = true; |
| |
| break; |
| case 'R': |
| if (bsDRName.Last(7) == "Regular" || bsDRName.Last(3) == "Reg") |
| bMatch = true; |
| |
| break; |
| case 'M': |
| if (bsDRName.Last(5) == "Medium") |
| bMatch = true; |
| break; |
| default: |
| break; |
| } |
| return bMatch; |
| } |
| } |
| return true; |
| } |