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