• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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