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