• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 "core/fpdfdoc/cpdf_bafontmap.h"
8 
9 #include <memory>
10 #include <utility>
11 
12 #include "constants/annotation_common.h"
13 #include "core/fpdfapi/font/cpdf_font.h"
14 #include "core/fpdfapi/font/cpdf_fontencoding.h"
15 #include "core/fpdfapi/page/cpdf_docpagedata.h"
16 #include "core/fpdfapi/page/cpdf_page.h"
17 #include "core/fpdfapi/parser/cpdf_dictionary.h"
18 #include "core/fpdfapi/parser/cpdf_document.h"
19 #include "core/fpdfapi/parser/cpdf_parser.h"
20 #include "core/fpdfapi/parser/cpdf_reference.h"
21 #include "core/fpdfapi/parser/cpdf_stream.h"
22 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
23 #include "core/fpdfdoc/cpdf_defaultappearance.h"
24 #include "core/fpdfdoc/cpdf_formfield.h"
25 #include "core/fpdfdoc/ipvt_fontmap.h"
26 #include "core/fxcrt/fx_codepage.h"
27 #include "core/fxcrt/stl_util.h"
28 #include "core/fxge/cfx_fontmapper.h"
29 #include "core/fxge/cfx_fontmgr.h"
30 #include "core/fxge/cfx_gemodule.h"
31 
32 namespace {
33 
FindNativeTrueTypeFont(ByteStringView sFontFaceName)34 bool FindNativeTrueTypeFont(ByteStringView sFontFaceName) {
35   CFX_FontMgr* pFontMgr = CFX_GEModule::Get()->GetFontMgr();
36   CFX_FontMapper* pFontMapper = pFontMgr->GetBuiltinMapper();
37   pFontMapper->LoadInstalledFonts();
38   return pFontMapper->HasInstalledFont(sFontFaceName) ||
39          pFontMapper->HasLocalizedFont(sFontFaceName);
40 }
41 
AddNativeTrueTypeFontToPDF(CPDF_Document * pDoc,ByteString sFontFaceName,FX_Charset nCharset)42 RetainPtr<CPDF_Font> AddNativeTrueTypeFontToPDF(CPDF_Document* pDoc,
43                                                 ByteString sFontFaceName,
44                                                 FX_Charset nCharset) {
45   if (!pDoc)
46     return nullptr;
47 
48   auto pFXFont = std::make_unique<CFX_Font>();
49   pFXFont->LoadSubst(sFontFaceName, true, 0, 0, 0,
50                      FX_GetCodePageFromCharset(nCharset), false);
51 
52   auto* pDocPageData = CPDF_DocPageData::FromDocument(pDoc);
53   return pDocPageData->AddFont(std::move(pFXFont), nCharset);
54 }
55 
EncodeFontAlias(ByteString sFontName,FX_Charset nCharset)56 ByteString EncodeFontAlias(ByteString sFontName, FX_Charset nCharset) {
57   sFontName.Remove(' ');
58   sFontName += ByteString::Format("_%02X", nCharset);
59   return sFontName;
60 }
61 
62 }  // namespace
63 
64 CPDF_BAFontMap::Data::Data() = default;
65 
66 CPDF_BAFontMap::Data::~Data() = default;
67 
CPDF_BAFontMap(CPDF_Document * pDocument,RetainPtr<CPDF_Dictionary> pAnnotDict,const ByteString & sAPType)68 CPDF_BAFontMap::CPDF_BAFontMap(CPDF_Document* pDocument,
69                                RetainPtr<CPDF_Dictionary> pAnnotDict,
70                                const ByteString& sAPType)
71     : m_pDocument(pDocument),
72       m_pAnnotDict(std::move(pAnnotDict)),
73       m_sAPType(sAPType) {
74   FX_Charset nCharset = FX_Charset::kDefault;
75   m_pDefaultFont = GetAnnotDefaultFont(&m_sDefaultFontName);
76   if (m_pDefaultFont) {
77     auto maybe_charset = m_pDefaultFont->GetSubstFontCharset();
78     if (maybe_charset.has_value()) {
79       nCharset = maybe_charset.value();
80     } else if (m_sDefaultFontName == "Wingdings" ||
81                m_sDefaultFontName == "Wingdings2" ||
82                m_sDefaultFontName == "Wingdings3" ||
83                m_sDefaultFontName == "Webdings") {
84       nCharset = FX_Charset::kSymbol;
85     } else {
86       nCharset = FX_Charset::kANSI;
87     }
88     AddFontData(m_pDefaultFont, m_sDefaultFontName, nCharset);
89     AddFontToAnnotDict(m_pDefaultFont, m_sDefaultFontName);
90   }
91 
92   if (nCharset != FX_Charset::kANSI)
93     GetFontIndex(CFX_Font::kDefaultAnsiFontName, FX_Charset::kANSI, false);
94 }
95 
96 CPDF_BAFontMap::~CPDF_BAFontMap() = default;
97 
GetPDFFont(int32_t nFontIndex)98 RetainPtr<CPDF_Font> CPDF_BAFontMap::GetPDFFont(int32_t nFontIndex) {
99   if (fxcrt::IndexInBounds(m_Data, nFontIndex))
100     return m_Data[nFontIndex]->pFont;
101   return nullptr;
102 }
103 
GetPDFFontAlias(int32_t nFontIndex)104 ByteString CPDF_BAFontMap::GetPDFFontAlias(int32_t nFontIndex) {
105   if (fxcrt::IndexInBounds(m_Data, nFontIndex))
106     return m_Data[nFontIndex]->sFontName;
107   return ByteString();
108 }
109 
GetWordFontIndex(uint16_t word,FX_Charset nCharset,int32_t nFontIndex)110 int32_t CPDF_BAFontMap::GetWordFontIndex(uint16_t word,
111                                          FX_Charset nCharset,
112                                          int32_t nFontIndex) {
113   if (nFontIndex > 0) {
114     if (KnowWord(nFontIndex, word))
115       return nFontIndex;
116   } else {
117     if (!m_Data.empty()) {
118       const Data* pData = m_Data.front().get();
119       if (nCharset == FX_Charset::kDefault ||
120           pData->nCharset == FX_Charset::kSymbol ||
121           nCharset == pData->nCharset) {
122         if (KnowWord(0, word))
123           return 0;
124       }
125     }
126   }
127 
128   int32_t nNewFontIndex =
129       GetFontIndex(GetCachedNativeFontName(nCharset), nCharset, true);
130   if (nNewFontIndex >= 0) {
131     if (KnowWord(nNewFontIndex, word))
132       return nNewFontIndex;
133   }
134   nNewFontIndex = GetFontIndex(CFX_Font::kUniversalDefaultFontName,
135                                FX_Charset::kDefault, false);
136   if (nNewFontIndex >= 0) {
137     if (KnowWord(nNewFontIndex, word))
138       return nNewFontIndex;
139   }
140   return -1;
141 }
142 
CharCodeFromUnicode(int32_t nFontIndex,uint16_t word)143 int32_t CPDF_BAFontMap::CharCodeFromUnicode(int32_t nFontIndex, uint16_t word) {
144   if (!fxcrt::IndexInBounds(m_Data, nFontIndex))
145     return -1;
146 
147   Data* pData = m_Data[nFontIndex].get();
148   if (!pData->pFont)
149     return -1;
150 
151   if (pData->pFont->IsUnicodeCompatible())
152     return pData->pFont->CharCodeFromUnicode(word);
153 
154   return word < 0xFF ? word : -1;
155 }
156 
CharSetFromUnicode(uint16_t word,FX_Charset nOldCharset)157 FX_Charset CPDF_BAFontMap::CharSetFromUnicode(uint16_t word,
158                                               FX_Charset nOldCharset) {
159   // to avoid CJK Font to show ASCII
160   if (word < 0x7F)
161     return FX_Charset::kANSI;
162 
163   // follow the old charset
164   if (nOldCharset != FX_Charset::kDefault)
165     return nOldCharset;
166 
167   return CFX_Font::GetCharSetFromUnicode(word);
168 }
169 
GetNativeCharset()170 FX_Charset CPDF_BAFontMap::GetNativeCharset() {
171   return FX_GetCharsetFromCodePage(FX_GetACP());
172 }
173 
FindFontSameCharset(ByteString * sFontAlias,FX_Charset nCharset)174 RetainPtr<CPDF_Font> CPDF_BAFontMap::FindFontSameCharset(ByteString* sFontAlias,
175                                                          FX_Charset nCharset) {
176   if (m_pAnnotDict->GetNameFor(pdfium::annotation::kSubtype) != "Widget")
177     return nullptr;
178 
179   const CPDF_Dictionary* pRootDict = m_pDocument->GetRoot();
180   if (!pRootDict)
181     return nullptr;
182 
183   RetainPtr<const CPDF_Dictionary> pAcroFormDict =
184       pRootDict->GetDictFor("AcroForm");
185   if (!pAcroFormDict)
186     return nullptr;
187 
188   RetainPtr<const CPDF_Dictionary> pDRDict = pAcroFormDict->GetDictFor("DR");
189   if (!pDRDict)
190     return nullptr;
191 
192   return FindResFontSameCharset(pDRDict.Get(), sFontAlias, nCharset);
193 }
194 
FindResFontSameCharset(const CPDF_Dictionary * pResDict,ByteString * sFontAlias,FX_Charset nCharset)195 RetainPtr<CPDF_Font> CPDF_BAFontMap::FindResFontSameCharset(
196     const CPDF_Dictionary* pResDict,
197     ByteString* sFontAlias,
198     FX_Charset nCharset) {
199   if (!pResDict)
200     return nullptr;
201 
202   RetainPtr<const CPDF_Dictionary> pFonts = pResDict->GetDictFor("Font");
203   if (!pFonts)
204     return nullptr;
205 
206   RetainPtr<CPDF_Font> pFind;
207   CPDF_DictionaryLocker locker(pFonts);
208   for (const auto& it : locker) {
209     const ByteString& csKey = it.first;
210     RetainPtr<CPDF_Dictionary> pElement =
211         ToDictionary(it.second->GetMutableDirect());
212     if (!ValidateDictType(pElement.Get(), "Font"))
213       continue;
214 
215     auto* pData = CPDF_DocPageData::FromDocument(m_pDocument);
216     RetainPtr<CPDF_Font> pFont = pData->GetFont(std::move(pElement));
217     if (!pFont)
218       continue;
219 
220     auto maybe_charset = pFont->GetSubstFontCharset();
221     if (maybe_charset.has_value() && maybe_charset.value() == nCharset) {
222       *sFontAlias = csKey;
223       pFind = std::move(pFont);
224     }
225   }
226   return pFind;
227 }
228 
GetAnnotDefaultFont(ByteString * sAlias)229 RetainPtr<CPDF_Font> CPDF_BAFontMap::GetAnnotDefaultFont(ByteString* sAlias) {
230   RetainPtr<CPDF_Dictionary> pAcroFormDict;
231   const bool bWidget =
232       (m_pAnnotDict->GetNameFor(pdfium::annotation::kSubtype) == "Widget");
233   if (bWidget) {
234     RetainPtr<CPDF_Dictionary> pRootDict = m_pDocument->GetMutableRoot();
235     if (pRootDict)
236       pAcroFormDict = pRootDict->GetMutableDictFor("AcroForm");
237   }
238 
239   ByteString sDA;
240   RetainPtr<const CPDF_Object> pObj =
241       CPDF_FormField::GetFieldAttrForDict(m_pAnnotDict.Get(), "DA");
242   if (pObj)
243     sDA = pObj->GetString();
244 
245   if (bWidget) {
246     if (sDA.IsEmpty()) {
247       pObj = CPDF_FormField::GetFieldAttrForDict(pAcroFormDict.Get(), "DA");
248       sDA = pObj ? pObj->GetString() : ByteString();
249     }
250   }
251   if (sDA.IsEmpty())
252     return nullptr;
253 
254   CPDF_DefaultAppearance appearance(sDA);
255   float font_size;
256   std::optional<ByteString> font = appearance.GetFont(&font_size);
257   *sAlias = font.value_or(ByteString());
258 
259   RetainPtr<CPDF_Dictionary> pFontDict;
260   if (RetainPtr<CPDF_Dictionary> pAPDict =
261           m_pAnnotDict->GetMutableDictFor(pdfium::annotation::kAP)) {
262     if (RetainPtr<CPDF_Dictionary> pNormalDict =
263             pAPDict->GetMutableDictFor("N")) {
264       if (RetainPtr<CPDF_Dictionary> pNormalResDict =
265               pNormalDict->GetMutableDictFor("Resources")) {
266         if (RetainPtr<CPDF_Dictionary> pResFontDict =
267                 pNormalResDict->GetMutableDictFor("Font")) {
268           pFontDict = pResFontDict->GetMutableDictFor(*sAlias);
269         }
270       }
271     }
272   }
273   if (bWidget && !pFontDict && pAcroFormDict) {
274     if (RetainPtr<CPDF_Dictionary> pDRDict =
275             pAcroFormDict->GetMutableDictFor("DR")) {
276       if (RetainPtr<CPDF_Dictionary> pDRFontDict =
277               pDRDict->GetMutableDictFor("Font")) {
278         pFontDict = pDRFontDict->GetMutableDictFor(*sAlias);
279       }
280     }
281   }
282   if (!pFontDict)
283     return nullptr;
284 
285   return CPDF_DocPageData::FromDocument(m_pDocument)->GetFont(pFontDict);
286 }
287 
AddFontToAnnotDict(const RetainPtr<CPDF_Font> & pFont,const ByteString & sAlias)288 void CPDF_BAFontMap::AddFontToAnnotDict(const RetainPtr<CPDF_Font>& pFont,
289                                         const ByteString& sAlias) {
290   if (!pFont)
291     return;
292 
293   RetainPtr<CPDF_Dictionary> pAPDict =
294       m_pAnnotDict->GetOrCreateDictFor(pdfium::annotation::kAP);
295 
296   // to avoid checkbox and radiobutton
297   if (ToDictionary(pAPDict->GetObjectFor(m_sAPType)))
298     return;
299 
300   RetainPtr<CPDF_Stream> stream = pAPDict->GetMutableStreamFor(m_sAPType);
301   if (!stream) {
302     stream = m_pDocument->NewIndirect<CPDF_Stream>(
303         m_pDocument->New<CPDF_Dictionary>());
304     pAPDict->SetNewFor<CPDF_Reference>(m_sAPType, m_pDocument,
305                                        stream->GetObjNum());
306   }
307 
308   RetainPtr<CPDF_Dictionary> pStreamResList =
309       stream->GetMutableDict()->GetOrCreateDictFor("Resources");
310   RetainPtr<CPDF_Dictionary> pStreamResFontList =
311       pStreamResList->GetMutableDictFor("Font");
312   if (!pStreamResFontList) {
313     pStreamResFontList = m_pDocument->NewIndirect<CPDF_Dictionary>();
314     pStreamResList->SetNewFor<CPDF_Reference>("Font", m_pDocument,
315                                               pStreamResFontList->GetObjNum());
316   }
317   if (!pStreamResFontList->KeyExist(sAlias)) {
318     RetainPtr<const CPDF_Dictionary> pFontDict = pFont->GetFontDict();
319     RetainPtr<CPDF_Object> pObject =
320         pFontDict->IsInline() ? pFontDict->Clone()
321                               : pFontDict->MakeReference(m_pDocument);
322     pStreamResFontList->SetFor(sAlias, std::move(pObject));
323   }
324 }
325 
KnowWord(int32_t nFontIndex,uint16_t word)326 bool CPDF_BAFontMap::KnowWord(int32_t nFontIndex, uint16_t word) {
327   return fxcrt::IndexInBounds(m_Data, nFontIndex) &&
328          CharCodeFromUnicode(nFontIndex, word) >= 0;
329 }
330 
GetFontIndex(const ByteString & sFontName,FX_Charset nCharset,bool bFind)331 int32_t CPDF_BAFontMap::GetFontIndex(const ByteString& sFontName,
332                                      FX_Charset nCharset,
333                                      bool bFind) {
334   int32_t nFontIndex = FindFont(EncodeFontAlias(sFontName, nCharset), nCharset);
335   if (nFontIndex >= 0)
336     return nFontIndex;
337 
338   ByteString sAlias;
339   RetainPtr<CPDF_Font> pFont =
340       bFind ? FindFontSameCharset(&sAlias, nCharset) : nullptr;
341   if (!pFont) {
342     pFont = AddFontToDocument(sFontName, nCharset);
343     sAlias = EncodeFontAlias(sFontName, nCharset);
344   }
345   AddFontToAnnotDict(pFont, sAlias);
346   return AddFontData(pFont, sAlias, nCharset);
347 }
348 
AddFontData(const RetainPtr<CPDF_Font> & pFont,const ByteString & sFontAlias,FX_Charset nCharset)349 int32_t CPDF_BAFontMap::AddFontData(const RetainPtr<CPDF_Font>& pFont,
350                                     const ByteString& sFontAlias,
351                                     FX_Charset nCharset) {
352   auto pNewData = std::make_unique<Data>();
353   pNewData->pFont = pFont;
354   pNewData->sFontName = sFontAlias;
355   pNewData->nCharset = nCharset;
356   m_Data.push_back(std::move(pNewData));
357   return fxcrt::CollectionSize<int32_t>(m_Data) - 1;
358 }
359 
FindFont(const ByteString & sFontName,FX_Charset nCharset)360 int32_t CPDF_BAFontMap::FindFont(const ByteString& sFontName,
361                                  FX_Charset nCharset) {
362   int32_t i = 0;
363   for (const auto& pData : m_Data) {
364     if ((nCharset == FX_Charset::kDefault || nCharset == pData->nCharset) &&
365         (sFontName.IsEmpty() || pData->sFontName == sFontName)) {
366       return i;
367     }
368     ++i;
369   }
370   return -1;
371 }
372 
GetNativeFontName(FX_Charset nCharset)373 ByteString CPDF_BAFontMap::GetNativeFontName(FX_Charset nCharset) {
374   if (nCharset == FX_Charset::kDefault)
375     nCharset = GetNativeCharset();
376 
377   ByteString sFontName = CFX_Font::GetDefaultFontNameByCharset(nCharset);
378   if (!FindNativeTrueTypeFont(sFontName.AsStringView()))
379     return ByteString();
380 
381   return sFontName;
382 }
383 
GetCachedNativeFontName(FX_Charset nCharset)384 ByteString CPDF_BAFontMap::GetCachedNativeFontName(FX_Charset nCharset) {
385   for (const auto& pData : m_NativeFont) {
386     if (pData && pData->nCharset == nCharset)
387       return pData->sFontName;
388   }
389 
390   ByteString sNew = GetNativeFontName(nCharset);
391   if (sNew.IsEmpty())
392     return ByteString();
393 
394   auto pNewData = std::make_unique<Native>();
395   pNewData->nCharset = nCharset;
396   pNewData->sFontName = sNew;
397   m_NativeFont.push_back(std::move(pNewData));
398   return sNew;
399 }
400 
AddFontToDocument(ByteString sFontName,FX_Charset nCharset)401 RetainPtr<CPDF_Font> CPDF_BAFontMap::AddFontToDocument(ByteString sFontName,
402                                                        FX_Charset nCharset) {
403   if (CFX_FontMapper::IsStandardFontName(sFontName))
404     return AddStandardFont(sFontName);
405 
406   return AddSystemFont(sFontName, nCharset);
407 }
408 
AddStandardFont(ByteString sFontName)409 RetainPtr<CPDF_Font> CPDF_BAFontMap::AddStandardFont(ByteString sFontName) {
410   auto* pPageData = CPDF_DocPageData::FromDocument(m_pDocument);
411   if (sFontName == "ZapfDingbats")
412     return pPageData->AddStandardFont(sFontName, nullptr);
413 
414   static const CPDF_FontEncoding fe(FontEncoding::kWinAnsi);
415   return pPageData->AddStandardFont(sFontName, &fe);
416 }
417 
AddSystemFont(ByteString sFontName,FX_Charset nCharset)418 RetainPtr<CPDF_Font> CPDF_BAFontMap::AddSystemFont(ByteString sFontName,
419                                                    FX_Charset nCharset) {
420   if (sFontName.IsEmpty())
421     sFontName = GetNativeFontName(nCharset);
422 
423   if (nCharset == FX_Charset::kDefault)
424     nCharset = GetNativeCharset();
425 
426   return AddNativeTrueTypeFontToPDF(m_pDocument, sFontName, nCharset);
427 }
428