xref: /aosp_15_r20/external/pdfium/xfa/fgas/font/cfgas_pdffontmgr.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2017 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "xfa/fgas/font/cfgas_pdffontmgr.h"
8 
9 #include <algorithm>
10 #include <iterator>
11 #include <utility>
12 
13 #include "core/fpdfapi/font/cpdf_font.h"
14 #include "core/fpdfapi/page/cpdf_docpagedata.h"
15 #include "core/fpdfapi/parser/cpdf_dictionary.h"
16 #include "core/fpdfapi/parser/cpdf_document.h"
17 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
18 #include "core/fxge/fx_font.h"
19 #include "third_party/base/check.h"
20 #include "xfa/fgas/font/cfgas_fontmgr.h"
21 #include "xfa/fgas/font/cfgas_gefont.h"
22 
23 namespace {
24 
25 // The 5 names per entry are: PsName, Normal, Bold, Italic, BoldItalic.
26 const char* const kXFAPDFFontName[][5] = {
27     {"Adobe PI Std", "AdobePIStd", "AdobePIStd", "AdobePIStd", "AdobePIStd"},
28     {"Myriad Pro Light", "MyriadPro-Light", "MyriadPro-Semibold",
29      "MyriadPro-LightIt", "MyriadPro-SemiboldIt"},
30 };
31 
32 }  // namespace
33 
CFGAS_PDFFontMgr(const CPDF_Document * pDoc)34 CFGAS_PDFFontMgr::CFGAS_PDFFontMgr(const CPDF_Document* pDoc) : m_pDoc(pDoc) {
35   DCHECK(pDoc);
36 }
37 
38 CFGAS_PDFFontMgr::~CFGAS_PDFFontMgr() = default;
39 
FindFont(const ByteString & strPsName,bool bBold,bool bItalic,bool bStrictMatch)40 RetainPtr<CFGAS_GEFont> CFGAS_PDFFontMgr::FindFont(const ByteString& strPsName,
41                                                    bool bBold,
42                                                    bool bItalic,
43                                                    bool bStrictMatch) {
44   RetainPtr<const CPDF_Dictionary> pFontSetDict =
45       m_pDoc->GetRoot()->GetDictFor("AcroForm")->GetDictFor("DR");
46   if (!pFontSetDict)
47     return nullptr;
48 
49   pFontSetDict = pFontSetDict->GetDictFor("Font");
50   if (!pFontSetDict)
51     return nullptr;
52 
53   ByteString name = strPsName;
54   name.Remove(' ');
55 
56   auto* pData = CPDF_DocPageData::FromDocument(m_pDoc);
57   CPDF_DictionaryLocker locker(pFontSetDict);
58   for (const auto& it : locker) {
59     const ByteString& key = it.first;
60     const RetainPtr<CPDF_Object>& pObj = it.second;
61     if (!PsNameMatchDRFontName(name.AsStringView(), bBold, bItalic, key,
62                                bStrictMatch)) {
63       continue;
64     }
65     RetainPtr<CPDF_Dictionary> pFontDict =
66         ToDictionary(pObj->GetMutableDirect());
67     if (!ValidateDictType(pFontDict.Get(), "Font"))
68       return nullptr;
69 
70     RetainPtr<CPDF_Font> pPDFFont = pData->GetFont(pFontDict);
71     if (!pPDFFont || !pPDFFont->IsEmbedded())
72       return nullptr;
73 
74     return CFGAS_GEFont::LoadFont(std::move(pPDFFont));
75   }
76   return nullptr;
77 }
78 
GetFont(const WideString & wsFontFamily,uint32_t dwFontStyles,bool bStrictMatch)79 RetainPtr<CFGAS_GEFont> CFGAS_PDFFontMgr::GetFont(
80     const WideString& wsFontFamily,
81     uint32_t dwFontStyles,
82     bool bStrictMatch) {
83   auto key = std::make_pair(wsFontFamily, dwFontStyles);
84   auto it = m_FontMap.find(key);
85   if (it != m_FontMap.end())
86     return it->second;
87 
88   ByteString bsPsName = WideString(wsFontFamily).ToDefANSI();
89   bool bBold = FontStyleIsForceBold(dwFontStyles);
90   bool bItalic = FontStyleIsItalic(dwFontStyles);
91   ByteString strFontName = PsNameToFontName(bsPsName, bBold, bItalic);
92   RetainPtr<CFGAS_GEFont> pFont =
93       FindFont(strFontName, bBold, bItalic, bStrictMatch);
94   if (!pFont)
95     return nullptr;
96 
97   m_FontMap[key] = pFont;
98   return pFont;
99 }
100 
PsNameToFontName(const ByteString & strPsName,bool bBold,bool bItalic)101 ByteString CFGAS_PDFFontMgr::PsNameToFontName(const ByteString& strPsName,
102                                               bool bBold,
103                                               bool bItalic) {
104   for (size_t i = 0; i < std::size(kXFAPDFFontName); ++i) {
105     if (strPsName == kXFAPDFFontName[i][0]) {
106       size_t index = 1;
107       if (bBold)
108         ++index;
109       if (bItalic)
110         index += 2;
111       return kXFAPDFFontName[i][index];
112     }
113   }
114   return strPsName;
115 }
116 
PsNameMatchDRFontName(ByteStringView bsPsName,bool bBold,bool bItalic,const ByteString & bsDRFontName,bool bStrictMatch)117 bool CFGAS_PDFFontMgr::PsNameMatchDRFontName(ByteStringView bsPsName,
118                                              bool bBold,
119                                              bool bItalic,
120                                              const ByteString& bsDRFontName,
121                                              bool bStrictMatch) {
122   ByteString bsDRName = bsDRFontName;
123   bsDRName.Remove('-');
124   size_t iPsLen = bsPsName.GetLength();
125   auto nIndex = bsDRName.Find(bsPsName);
126   if (nIndex.has_value() && !bStrictMatch)
127     return true;
128 
129   if (!nIndex.has_value() || nIndex.value() != 0)
130     return false;
131 
132   size_t iDifferLength = bsDRName.GetLength() - iPsLen;
133   if (iDifferLength > 1 || (bBold || bItalic)) {
134     auto iBoldIndex = bsDRName.Find("Bold");
135     if (bBold != iBoldIndex.has_value())
136       return false;
137 
138     if (iBoldIndex.has_value()) {
139       iDifferLength = std::min(iDifferLength - 4,
140                                bsDRName.GetLength() - iBoldIndex.value() - 4);
141     }
142     bool bItalicFont = true;
143     if (bsDRName.Contains("Italic"))
144       iDifferLength -= 6;
145     else if (bsDRName.Contains("It"))
146       iDifferLength -= 2;
147     else if (bsDRName.Contains("Oblique"))
148       iDifferLength -= 7;
149     else
150       bItalicFont = false;
151 
152     if (bItalic != bItalicFont)
153       return false;
154 
155     if (iDifferLength > 1) {
156       ByteString bsDRTailer = bsDRName.Last(iDifferLength);
157       if (bsDRTailer == "MT" || bsDRTailer == "PSMT" ||
158           bsDRTailer == "Regular" || bsDRTailer == "Reg") {
159         return true;
160       }
161       if (iBoldIndex.has_value() || bItalicFont)
162         return false;
163 
164       bool bMatch = false;
165       switch (bsPsName[iPsLen - 1]) {
166         case 'L':
167           if (bsDRName.Last(5) == "Light")
168             bMatch = true;
169 
170           break;
171         case 'R':
172           if (bsDRName.Last(7) == "Regular" || bsDRName.Last(3) == "Reg")
173             bMatch = true;
174 
175           break;
176         case 'M':
177           if (bsDRName.Last(5) == "Medium")
178             bMatch = true;
179           break;
180         default:
181           break;
182       }
183       return bMatch;
184     }
185   }
186   return true;
187 }
188