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