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