xref: /aosp_15_r20/external/pdfium/core/fpdfdoc/cpdf_bafontmap.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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   absl::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> pStream = pAPDict->GetMutableStreamFor(m_sAPType);
301   if (!pStream) {
302     pStream = m_pDocument->NewIndirect<CPDF_Stream>();
303     pAPDict->SetNewFor<CPDF_Reference>(m_sAPType, m_pDocument,
304                                        pStream->GetObjNum());
305   }
306 
307   RetainPtr<CPDF_Dictionary> pStreamDict = pStream->GetMutableDict();
308   if (!pStreamDict) {
309     pStreamDict = m_pDocument->New<CPDF_Dictionary>();
310     pStream->InitStreamWithEmptyData(pStreamDict);
311   }
312 
313   RetainPtr<CPDF_Dictionary> pStreamResList =
314       pStreamDict->GetOrCreateDictFor("Resources");
315   RetainPtr<CPDF_Dictionary> pStreamResFontList =
316       pStreamResList->GetMutableDictFor("Font");
317   if (!pStreamResFontList) {
318     pStreamResFontList = m_pDocument->NewIndirect<CPDF_Dictionary>();
319     pStreamResList->SetNewFor<CPDF_Reference>("Font", m_pDocument,
320                                               pStreamResFontList->GetObjNum());
321   }
322   if (!pStreamResFontList->KeyExist(sAlias)) {
323     RetainPtr<const CPDF_Dictionary> pFontDict = pFont->GetFontDict();
324     RetainPtr<CPDF_Object> pObject =
325         pFontDict->IsInline() ? pFontDict->Clone()
326                               : pFontDict->MakeReference(m_pDocument);
327     pStreamResFontList->SetFor(sAlias, std::move(pObject));
328   }
329 }
330 
KnowWord(int32_t nFontIndex,uint16_t word)331 bool CPDF_BAFontMap::KnowWord(int32_t nFontIndex, uint16_t word) {
332   return fxcrt::IndexInBounds(m_Data, nFontIndex) &&
333          CharCodeFromUnicode(nFontIndex, word) >= 0;
334 }
335 
GetFontIndex(const ByteString & sFontName,FX_Charset nCharset,bool bFind)336 int32_t CPDF_BAFontMap::GetFontIndex(const ByteString& sFontName,
337                                      FX_Charset nCharset,
338                                      bool bFind) {
339   int32_t nFontIndex = FindFont(EncodeFontAlias(sFontName, nCharset), nCharset);
340   if (nFontIndex >= 0)
341     return nFontIndex;
342 
343   ByteString sAlias;
344   RetainPtr<CPDF_Font> pFont =
345       bFind ? FindFontSameCharset(&sAlias, nCharset) : nullptr;
346   if (!pFont) {
347     pFont = AddFontToDocument(sFontName, nCharset);
348     sAlias = EncodeFontAlias(sFontName, nCharset);
349   }
350   AddFontToAnnotDict(pFont, sAlias);
351   return AddFontData(pFont, sAlias, nCharset);
352 }
353 
AddFontData(const RetainPtr<CPDF_Font> & pFont,const ByteString & sFontAlias,FX_Charset nCharset)354 int32_t CPDF_BAFontMap::AddFontData(const RetainPtr<CPDF_Font>& pFont,
355                                     const ByteString& sFontAlias,
356                                     FX_Charset nCharset) {
357   auto pNewData = std::make_unique<Data>();
358   pNewData->pFont = pFont;
359   pNewData->sFontName = sFontAlias;
360   pNewData->nCharset = nCharset;
361   m_Data.push_back(std::move(pNewData));
362   return fxcrt::CollectionSize<int32_t>(m_Data) - 1;
363 }
364 
FindFont(const ByteString & sFontName,FX_Charset nCharset)365 int32_t CPDF_BAFontMap::FindFont(const ByteString& sFontName,
366                                  FX_Charset nCharset) {
367   int32_t i = 0;
368   for (const auto& pData : m_Data) {
369     if ((nCharset == FX_Charset::kDefault || nCharset == pData->nCharset) &&
370         (sFontName.IsEmpty() || pData->sFontName == sFontName)) {
371       return i;
372     }
373     ++i;
374   }
375   return -1;
376 }
377 
GetNativeFontName(FX_Charset nCharset)378 ByteString CPDF_BAFontMap::GetNativeFontName(FX_Charset nCharset) {
379   if (nCharset == FX_Charset::kDefault)
380     nCharset = GetNativeCharset();
381 
382   ByteString sFontName = CFX_Font::GetDefaultFontNameByCharset(nCharset);
383   if (!FindNativeTrueTypeFont(sFontName.AsStringView()))
384     return ByteString();
385 
386   return sFontName;
387 }
388 
GetCachedNativeFontName(FX_Charset nCharset)389 ByteString CPDF_BAFontMap::GetCachedNativeFontName(FX_Charset nCharset) {
390   for (const auto& pData : m_NativeFont) {
391     if (pData && pData->nCharset == nCharset)
392       return pData->sFontName;
393   }
394 
395   ByteString sNew = GetNativeFontName(nCharset);
396   if (sNew.IsEmpty())
397     return ByteString();
398 
399   auto pNewData = std::make_unique<Native>();
400   pNewData->nCharset = nCharset;
401   pNewData->sFontName = sNew;
402   m_NativeFont.push_back(std::move(pNewData));
403   return sNew;
404 }
405 
AddFontToDocument(ByteString sFontName,FX_Charset nCharset)406 RetainPtr<CPDF_Font> CPDF_BAFontMap::AddFontToDocument(ByteString sFontName,
407                                                        FX_Charset nCharset) {
408   if (CFX_FontMapper::IsStandardFontName(sFontName))
409     return AddStandardFont(sFontName);
410 
411   return AddSystemFont(sFontName, nCharset);
412 }
413 
AddStandardFont(ByteString sFontName)414 RetainPtr<CPDF_Font> CPDF_BAFontMap::AddStandardFont(ByteString sFontName) {
415   auto* pPageData = CPDF_DocPageData::FromDocument(m_pDocument);
416   if (sFontName == "ZapfDingbats")
417     return pPageData->AddStandardFont(sFontName, nullptr);
418 
419   static const CPDF_FontEncoding fe(FontEncoding::kWinAnsi);
420   return pPageData->AddStandardFont(sFontName, &fe);
421 }
422 
AddSystemFont(ByteString sFontName,FX_Charset nCharset)423 RetainPtr<CPDF_Font> CPDF_BAFontMap::AddSystemFont(ByteString sFontName,
424                                                    FX_Charset nCharset) {
425   if (sFontName.IsEmpty())
426     sFontName = GetNativeFontName(nCharset);
427 
428   if (nCharset == FX_Charset::kDefault)
429     nCharset = GetNativeCharset();
430 
431   return AddNativeTrueTypeFontToPDF(m_pDocument, sFontName, nCharset);
432 }
433