xref: /aosp_15_r20/external/pdfium/xfa/fgas/font/cfgas_fontmgr.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2015 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 "xfa/fgas/font/cfgas_fontmgr.h"
8 
9 #include <stdint.h>
10 
11 #include <algorithm>
12 #include <iterator>
13 #include <memory>
14 #include <utility>
15 
16 #include "build/build_config.h"
17 #include "core/fxcrt/cfx_read_only_vector_stream.h"
18 #include "core/fxcrt/data_vector.h"
19 #include "core/fxcrt/fixed_uninit_data_vector.h"
20 #include "core/fxcrt/fx_codepage.h"
21 #include "core/fxcrt/fx_extension.h"
22 #include "core/fxcrt/fx_memory_wrappers.h"
23 #include "core/fxcrt/fx_system.h"
24 #include "core/fxge/cfx_font.h"
25 #include "core/fxge/cfx_fontmapper.h"
26 #include "core/fxge/cfx_fontmgr.h"
27 #include "core/fxge/cfx_gemodule.h"
28 #include "core/fxge/fx_font.h"
29 #include "third_party/base/check.h"
30 #include "third_party/base/containers/contains.h"
31 #include "third_party/base/containers/span.h"
32 #include "third_party/base/numerics/safe_conversions.h"
33 #include "xfa/fgas/font/cfgas_gefont.h"
34 #include "xfa/fgas/font/fgas_fontutils.h"
35 
36 namespace {
37 
VerifyUnicode(const RetainPtr<CFGAS_GEFont> & pFont,wchar_t wcUnicode)38 bool VerifyUnicode(const RetainPtr<CFGAS_GEFont>& pFont, wchar_t wcUnicode) {
39   RetainPtr<CFX_Face> pFace = pFont->GetDevFont()->GetFace();
40   if (!pFace)
41     return false;
42 
43   FXFT_FaceRec* pFaceRec = pFace->GetRec();
44   FT_CharMap charmap = pFaceRec->charmap;
45   if (FXFT_Select_Charmap(pFaceRec, FT_ENCODING_UNICODE) != 0)
46     return false;
47 
48   if (FT_Get_Char_Index(pFaceRec, wcUnicode) == 0) {
49     FT_Set_Charmap(pFaceRec, charmap);
50     return false;
51   }
52   return true;
53 }
54 
ShortFormHash(FX_CodePage wCodePage,uint32_t dwFontStyles,WideStringView wsFontFamily)55 uint32_t ShortFormHash(FX_CodePage wCodePage,
56                        uint32_t dwFontStyles,
57                        WideStringView wsFontFamily) {
58   ByteString bsHash = ByteString::Format("%d, %d", wCodePage, dwFontStyles);
59   bsHash += FX_UTF8Encode(wsFontFamily);
60   return FX_HashCode_GetA(bsHash.AsStringView());
61 }
62 
LongFormHash(FX_CodePage wCodePage,uint16_t wBitField,uint32_t dwFontStyles,WideStringView wsFontFamily)63 uint32_t LongFormHash(FX_CodePage wCodePage,
64                       uint16_t wBitField,
65                       uint32_t dwFontStyles,
66                       WideStringView wsFontFamily) {
67   ByteString bsHash =
68       ByteString::Format("%d, %d, %d", wCodePage, wBitField, dwFontStyles);
69   bsHash += FX_UTF8Encode(wsFontFamily);
70   return FX_HashCode_GetA(bsHash.AsStringView());
71 }
72 
73 }  // namespace
74 
75 #if BUILDFLAG(IS_WIN)
76 
77 namespace {
78 
79 struct FX_FONTMATCHPARAMS {
80   const wchar_t* pwsFamily;
81   uint32_t dwFontStyles;
82   uint32_t dwUSB;
83   bool matchParagraphStyle;
84   wchar_t wUnicode;
85   FX_CodePage wCodePage;
86 };
87 
GetSimilarityScore(FX_FONTDESCRIPTOR const * pFont,uint32_t dwFontStyles)88 int32_t GetSimilarityScore(FX_FONTDESCRIPTOR const* pFont,
89                            uint32_t dwFontStyles) {
90   int32_t iValue = 0;
91   if (FontStyleIsSymbolic(dwFontStyles) ==
92       FontStyleIsSymbolic(pFont->dwFontStyles)) {
93     iValue += 64;
94   }
95   if (FontStyleIsFixedPitch(dwFontStyles) ==
96       FontStyleIsFixedPitch(pFont->dwFontStyles)) {
97     iValue += 32;
98   }
99   if (FontStyleIsSerif(dwFontStyles) == FontStyleIsSerif(pFont->dwFontStyles))
100     iValue += 16;
101   if (FontStyleIsScript(dwFontStyles) == FontStyleIsScript(pFont->dwFontStyles))
102     iValue += 8;
103   return iValue;
104 }
105 
MatchDefaultFont(FX_FONTMATCHPARAMS * pParams,const std::deque<FX_FONTDESCRIPTOR> & fonts)106 const FX_FONTDESCRIPTOR* MatchDefaultFont(
107     FX_FONTMATCHPARAMS* pParams,
108     const std::deque<FX_FONTDESCRIPTOR>& fonts) {
109   const FX_FONTDESCRIPTOR* pBestFont = nullptr;
110   int32_t iBestSimilar = 0;
111   for (const auto& font : fonts) {
112     if (FontStyleIsForceBold(font.dwFontStyles) &&
113         FontStyleIsItalic(font.dwFontStyles)) {
114       continue;
115     }
116 
117     if (pParams->pwsFamily) {
118       if (FXSYS_wcsicmp(pParams->pwsFamily, font.wsFontFace))
119         continue;
120       if (font.uCharSet == FX_Charset::kSymbol)
121         return &font;
122     }
123     if (font.uCharSet == FX_Charset::kSymbol)
124       continue;
125     if (pParams->wCodePage != FX_CodePage::kFailure) {
126       if (FX_GetCodePageFromCharset(font.uCharSet) != pParams->wCodePage)
127         continue;
128     } else {
129       if (pParams->dwUSB < 128) {
130         uint32_t dwByte = pParams->dwUSB / 32;
131         uint32_t dwUSB = 1 << (pParams->dwUSB % 32);
132         if ((font.FontSignature.fsUsb[dwByte] & dwUSB) == 0)
133           continue;
134       }
135     }
136     if (pParams->matchParagraphStyle) {
137       if ((font.dwFontStyles & 0x0F) == (pParams->dwFontStyles & 0x0F))
138         return &font;
139       continue;
140     }
141     if (pParams->pwsFamily) {
142       if (FXSYS_wcsicmp(pParams->pwsFamily, font.wsFontFace) == 0)
143         return &font;
144     }
145     int32_t iSimilarValue = GetSimilarityScore(&font, pParams->dwFontStyles);
146     if (iBestSimilar < iSimilarValue) {
147       iBestSimilar = iSimilarValue;
148       pBestFont = &font;
149     }
150   }
151   return iBestSimilar < 1 ? nullptr : pBestFont;
152 }
153 
GetGdiFontStyles(const LOGFONTW & lf)154 uint32_t GetGdiFontStyles(const LOGFONTW& lf) {
155   uint32_t dwStyles = 0;
156   if ((lf.lfPitchAndFamily & 0x03) == FIXED_PITCH)
157     dwStyles |= FXFONT_FIXED_PITCH;
158   uint8_t nFamilies = lf.lfPitchAndFamily & 0xF0;
159   if (nFamilies == FF_ROMAN)
160     dwStyles |= FXFONT_SERIF;
161   if (nFamilies == FF_SCRIPT)
162     dwStyles |= FXFONT_SCRIPT;
163   if (lf.lfCharSet == SYMBOL_CHARSET)
164     dwStyles |= FXFONT_SYMBOLIC;
165   return dwStyles;
166 }
167 
GdiFontEnumProc(ENUMLOGFONTEX * lpelfe,NEWTEXTMETRICEX * lpntme,DWORD dwFontType,LPARAM lParam)168 int32_t CALLBACK GdiFontEnumProc(ENUMLOGFONTEX* lpelfe,
169                                  NEWTEXTMETRICEX* lpntme,
170                                  DWORD dwFontType,
171                                  LPARAM lParam) {
172   if (dwFontType != TRUETYPE_FONTTYPE)
173     return 1;
174   const LOGFONTW& lf = ((LPENUMLOGFONTEXW)lpelfe)->elfLogFont;
175   if (lf.lfFaceName[0] == L'@')
176     return 1;
177   FX_FONTDESCRIPTOR font;
178   memset(&font, 0, sizeof(FX_FONTDESCRIPTOR));
179   font.uCharSet = FX_GetCharsetFromInt(lf.lfCharSet);
180   font.dwFontStyles = GetGdiFontStyles(lf);
181   FXSYS_wcsncpy(font.wsFontFace, (const wchar_t*)lf.lfFaceName, 31);
182   font.wsFontFace[31] = 0;
183   memcpy(&font.FontSignature, &lpntme->ntmFontSig, sizeof(lpntme->ntmFontSig));
184   reinterpret_cast<std::deque<FX_FONTDESCRIPTOR>*>(lParam)->push_back(font);
185   return 1;
186 }
187 
EnumGdiFonts(const wchar_t * pwsFaceName,wchar_t wUnicode)188 std::deque<FX_FONTDESCRIPTOR> EnumGdiFonts(const wchar_t* pwsFaceName,
189                                            wchar_t wUnicode) {
190   std::deque<FX_FONTDESCRIPTOR> fonts;
191   LOGFONTW lfFind;
192   memset(&lfFind, 0, sizeof(lfFind));
193   lfFind.lfCharSet = DEFAULT_CHARSET;
194   if (pwsFaceName) {
195     FXSYS_wcsncpy(lfFind.lfFaceName, pwsFaceName, 31);
196     lfFind.lfFaceName[31] = 0;
197   }
198   HDC hDC = ::GetDC(nullptr);
199   EnumFontFamiliesExW(hDC, (LPLOGFONTW)&lfFind, (FONTENUMPROCW)GdiFontEnumProc,
200                       (LPARAM)&fonts, 0);
201   ::ReleaseDC(nullptr, hDC);
202   return fonts;
203 }
204 
205 }  // namespace
206 
CFGAS_FontMgr()207 CFGAS_FontMgr::CFGAS_FontMgr() : m_FontFaces(EnumGdiFonts(nullptr, 0xFEFF)) {}
208 
209 CFGAS_FontMgr::~CFGAS_FontMgr() = default;
210 
EnumFonts()211 bool CFGAS_FontMgr::EnumFonts() {
212   return true;
213 }
214 
GetFontByUnicodeImpl(wchar_t wUnicode,uint32_t dwFontStyles,const wchar_t * pszFontFamily,uint32_t dwHash,FX_CodePage wCodePage,uint16_t wBitField)215 RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByUnicodeImpl(
216     wchar_t wUnicode,
217     uint32_t dwFontStyles,
218     const wchar_t* pszFontFamily,
219     uint32_t dwHash,
220     FX_CodePage wCodePage,
221     uint16_t wBitField) {
222   const FX_FONTDESCRIPTOR* pFD = FindFont(pszFontFamily, dwFontStyles, false,
223                                           wCodePage, wBitField, wUnicode);
224   if (!pFD && pszFontFamily) {
225     pFD =
226         FindFont(nullptr, dwFontStyles, false, wCodePage, wBitField, wUnicode);
227   }
228   if (!pFD)
229     return nullptr;
230 
231   FX_CodePage newCodePage = FX_GetCodePageFromCharset(pFD->uCharSet);
232   RetainPtr<CFGAS_GEFont> pFont =
233       CFGAS_GEFont::LoadFont(pFD->wsFontFace, dwFontStyles, newCodePage);
234   if (!pFont)
235     return nullptr;
236 
237   pFont->SetLogicalFontStyle(dwFontStyles);
238   if (!VerifyUnicode(pFont, wUnicode)) {
239     m_FailedUnicodesSet.insert(wUnicode);
240     return nullptr;
241   }
242 
243   m_Hash2Fonts[dwHash].push_back(pFont);
244   return pFont;
245 }
246 
FindFont(const wchar_t * pszFontFamily,uint32_t dwFontStyles,bool matchParagraphStyle,FX_CodePage wCodePage,uint32_t dwUSB,wchar_t wUnicode)247 const FX_FONTDESCRIPTOR* CFGAS_FontMgr::FindFont(const wchar_t* pszFontFamily,
248                                                  uint32_t dwFontStyles,
249                                                  bool matchParagraphStyle,
250                                                  FX_CodePage wCodePage,
251                                                  uint32_t dwUSB,
252                                                  wchar_t wUnicode) {
253   FX_FONTMATCHPARAMS params;
254   memset(&params, 0, sizeof(params));
255   params.dwUSB = dwUSB;
256   params.wUnicode = wUnicode;
257   params.wCodePage = wCodePage;
258   params.pwsFamily = pszFontFamily;
259   params.dwFontStyles = dwFontStyles;
260   params.matchParagraphStyle = matchParagraphStyle;
261 
262   const FX_FONTDESCRIPTOR* pDesc = MatchDefaultFont(&params, m_FontFaces);
263   if (pDesc)
264     return pDesc;
265 
266   if (!pszFontFamily)
267     return nullptr;
268 
269   // Use a named object to store the returned value of EnumGdiFonts() instead
270   // of using a temporary object. This can prevent use-after-free issues since
271   // pDesc may point to one of std::deque object's elements.
272   std::deque<FX_FONTDESCRIPTOR> namedFonts =
273       EnumGdiFonts(pszFontFamily, wUnicode);
274   params.pwsFamily = nullptr;
275   pDesc = MatchDefaultFont(&params, namedFonts);
276   if (!pDesc)
277     return nullptr;
278 
279   auto it = std::find(m_FontFaces.rbegin(), m_FontFaces.rend(), *pDesc);
280   if (it != m_FontFaces.rend())
281     return &*it;
282 
283   m_FontFaces.push_back(*pDesc);
284   return &m_FontFaces.back();
285 }
286 
287 #else  // BUILDFLAG(IS_WIN)
288 
289 namespace {
290 
291 const FX_CodePage kCodePages[] = {FX_CodePage::kMSWin_WesternEuropean,
292                                   FX_CodePage::kMSWin_EasternEuropean,
293                                   FX_CodePage::kMSWin_Cyrillic,
294                                   FX_CodePage::kMSWin_Greek,
295                                   FX_CodePage::kMSWin_Turkish,
296                                   FX_CodePage::kMSWin_Hebrew,
297                                   FX_CodePage::kMSWin_Arabic,
298                                   FX_CodePage::kMSWin_Baltic,
299                                   FX_CodePage::kMSWin_Vietnamese,
300                                   FX_CodePage::kDefANSI,
301                                   FX_CodePage::kDefANSI,
302                                   FX_CodePage::kDefANSI,
303                                   FX_CodePage::kDefANSI,
304                                   FX_CodePage::kDefANSI,
305                                   FX_CodePage::kDefANSI,
306                                   FX_CodePage::kDefANSI,
307                                   FX_CodePage::kMSDOS_Thai,
308                                   FX_CodePage::kShiftJIS,
309                                   FX_CodePage::kChineseSimplified,
310                                   FX_CodePage::kHangul,
311                                   FX_CodePage::kChineseTraditional,
312                                   FX_CodePage::kJohab,
313                                   FX_CodePage::kDefANSI,
314                                   FX_CodePage::kDefANSI,
315                                   FX_CodePage::kDefANSI,
316                                   FX_CodePage::kDefANSI,
317                                   FX_CodePage::kDefANSI,
318                                   FX_CodePage::kDefANSI,
319                                   FX_CodePage::kDefANSI,
320                                   FX_CodePage::kDefANSI,
321                                   FX_CodePage::kDefANSI,
322                                   FX_CodePage::kDefANSI,
323                                   FX_CodePage::kDefANSI,
324                                   FX_CodePage::kDefANSI,
325                                   FX_CodePage::kDefANSI,
326                                   FX_CodePage::kDefANSI,
327                                   FX_CodePage::kDefANSI,
328                                   FX_CodePage::kDefANSI,
329                                   FX_CodePage::kDefANSI,
330                                   FX_CodePage::kDefANSI,
331                                   FX_CodePage::kDefANSI,
332                                   FX_CodePage::kDefANSI,
333                                   FX_CodePage::kDefANSI,
334                                   FX_CodePage::kDefANSI,
335                                   FX_CodePage::kDefANSI,
336                                   FX_CodePage::kDefANSI,
337                                   FX_CodePage::kDefANSI,
338                                   FX_CodePage::kDefANSI,
339                                   FX_CodePage::kMSDOS_Greek2,
340                                   FX_CodePage::kMSDOS_Russian,
341                                   FX_CodePage::kMSDOS_Norwegian,
342                                   FX_CodePage::kMSDOS_Arabic,
343                                   FX_CodePage::kMSDOS_FrenchCanadian,
344                                   FX_CodePage::kMSDOS_Hebrew,
345                                   FX_CodePage::kMSDOS_Icelandic,
346                                   FX_CodePage::kMSDOS_Portuguese,
347                                   FX_CodePage::kMSDOS_Turkish,
348                                   FX_CodePage::kMSDOS_Cyrillic,
349                                   FX_CodePage::kMSDOS_EasternEuropean,
350                                   FX_CodePage::kMSDOS_Baltic,
351                                   FX_CodePage::kMSDOS_Greek1,
352                                   FX_CodePage::kArabic_ASMO708,
353                                   FX_CodePage::kMSDOS_WesternEuropean,
354                                   FX_CodePage::kMSDOS_US};
355 
FX_GetCodePageBit(FX_CodePage wCodePage)356 uint16_t FX_GetCodePageBit(FX_CodePage wCodePage) {
357   for (size_t i = 0; i < std::size(kCodePages); ++i) {
358     if (kCodePages[i] == wCodePage)
359       return static_cast<uint16_t>(i);
360   }
361   return static_cast<uint16_t>(-1);
362 }
363 
FX_GetUnicodeBit(wchar_t wcUnicode)364 uint16_t FX_GetUnicodeBit(wchar_t wcUnicode) {
365   const FGAS_FONTUSB* x = FGAS_GetUnicodeBitField(wcUnicode);
366   return x ? x->wBitField : FGAS_FONTUSB::kNoBitField;
367 }
368 
ReadUInt16FromSpanAtOffset(pdfium::span<const uint8_t> data,size_t offset)369 uint16_t ReadUInt16FromSpanAtOffset(pdfium::span<const uint8_t> data,
370                                     size_t offset) {
371   const uint8_t* p = &data[offset];
372   return FXSYS_UINT16_GET_MSBFIRST(p);
373 }
374 
375 extern "C" {
376 
ftStreamRead(FXFT_StreamRec * stream,unsigned long offset,unsigned char * buffer,unsigned long count)377 unsigned long ftStreamRead(FXFT_StreamRec* stream,
378                            unsigned long offset,
379                            unsigned char* buffer,
380                            unsigned long count) {
381   if (count == 0)
382     return 0;
383 
384   IFX_SeekableReadStream* pFile =
385       static_cast<IFX_SeekableReadStream*>(stream->descriptor.pointer);
386   if (!pFile->ReadBlockAtOffset({buffer, count}, offset))
387     return 0;
388 
389   return count;
390 }
391 
ftStreamClose(FXFT_StreamRec * stream)392 void ftStreamClose(FXFT_StreamRec* stream) {}
393 
394 }  // extern "C"
395 
GetNames(pdfium::span<const uint8_t> name_table)396 std::vector<WideString> GetNames(pdfium::span<const uint8_t> name_table) {
397   std::vector<WideString> results;
398   if (name_table.empty())
399     return results;
400 
401   uint16_t nNameCount = ReadUInt16FromSpanAtOffset(name_table, 2);
402   pdfium::span<const uint8_t> str =
403       name_table.subspan(ReadUInt16FromSpanAtOffset(name_table, 4));
404   pdfium::span<const uint8_t> name_record = name_table.subspan(6);
405   for (uint16_t i = 0; i < nNameCount; ++i) {
406     uint16_t nNameID = ReadUInt16FromSpanAtOffset(name_table, i * 12 + 6);
407     if (nNameID != 1)
408       continue;
409 
410     uint16_t nPlatformID = ReadUInt16FromSpanAtOffset(name_record, i * 12);
411     uint16_t nNameLength = ReadUInt16FromSpanAtOffset(name_record, i * 12 + 8);
412     uint16_t nNameOffset = ReadUInt16FromSpanAtOffset(name_record, i * 12 + 10);
413     if (nPlatformID != 1) {
414       WideString wsFamily;
415       for (uint16_t j = 0; j < nNameLength / 2; ++j) {
416         wchar_t wcTemp = ReadUInt16FromSpanAtOffset(str, nNameOffset + j * 2);
417         wsFamily += wcTemp;
418       }
419       results.push_back(wsFamily);
420       continue;
421     }
422 
423     WideString wsFamily;
424     for (uint16_t j = 0; j < nNameLength; ++j) {
425       wchar_t wcTemp = str[nNameOffset + j];
426       wsFamily += wcTemp;
427     }
428     results.push_back(wsFamily);
429   }
430   return results;
431 }
432 
GetUSBCSB(FXFT_FaceRec * pFace,uint32_t * USB,uint32_t * CSB)433 void GetUSBCSB(FXFT_FaceRec* pFace, uint32_t* USB, uint32_t* CSB) {
434   TT_OS2* pOS2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(pFace, ft_sfnt_os2));
435   if (!pOS2) {
436     USB[0] = 0;
437     USB[1] = 0;
438     USB[2] = 0;
439     USB[3] = 0;
440     CSB[0] = 0;
441     CSB[1] = 0;
442     return;
443   }
444   USB[0] = static_cast<uint32_t>(pOS2->ulUnicodeRange1);
445   USB[1] = static_cast<uint32_t>(pOS2->ulUnicodeRange2);
446   USB[2] = static_cast<uint32_t>(pOS2->ulUnicodeRange3);
447   USB[3] = static_cast<uint32_t>(pOS2->ulUnicodeRange4);
448   CSB[0] = static_cast<uint32_t>(pOS2->ulCodePageRange1);
449   CSB[1] = static_cast<uint32_t>(pOS2->ulCodePageRange2);
450 }
451 
GetFlags(FXFT_FaceRec * pFace)452 uint32_t GetFlags(FXFT_FaceRec* pFace) {
453   uint32_t flags = 0;
454   if (FXFT_Is_Face_Bold(pFace))
455     flags |= FXFONT_FORCE_BOLD;
456   if (FXFT_Is_Face_Italic(pFace))
457     flags |= FXFONT_ITALIC;
458   if (FT_IS_FIXED_WIDTH(pFace))
459     flags |= FXFONT_FIXED_PITCH;
460 
461   TT_OS2* pOS2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(pFace, ft_sfnt_os2));
462   if (!pOS2)
463     return flags;
464 
465   if (pOS2->ulCodePageRange1 & (1 << 31))
466     flags |= FXFONT_SYMBOLIC;
467   if (pOS2->panose[0] == 2) {
468     uint8_t uSerif = pOS2->panose[1];
469     if ((uSerif > 1 && uSerif < 10) || uSerif > 13)
470       flags |= FXFONT_SERIF;
471   }
472   return flags;
473 }
474 
CreateFontStream(CFX_FontMapper * pFontMapper,size_t index)475 RetainPtr<IFX_SeekableReadStream> CreateFontStream(CFX_FontMapper* pFontMapper,
476                                                    size_t index) {
477   FixedUninitDataVector<uint8_t> buffer = pFontMapper->RawBytesForIndex(index);
478   if (buffer.empty())
479     return nullptr;
480 
481   return pdfium::MakeRetain<CFX_ReadOnlyVectorStream>(std::move(buffer));
482 }
483 
CreateFontStream(const ByteString & bsFaceName)484 RetainPtr<IFX_SeekableReadStream> CreateFontStream(
485     const ByteString& bsFaceName) {
486   CFX_FontMgr* pFontMgr = CFX_GEModule::Get()->GetFontMgr();
487   CFX_FontMapper* pFontMapper = pFontMgr->GetBuiltinMapper();
488   pFontMapper->LoadInstalledFonts();
489 
490   for (size_t i = 0; i < pFontMapper->GetFaceSize(); ++i) {
491     if (pFontMapper->GetFaceName(i) == bsFaceName)
492       return CreateFontStream(pFontMapper, i);
493   }
494   return nullptr;
495 }
496 
LoadFace(const RetainPtr<IFX_SeekableReadStream> & pFontStream,int32_t iFaceIndex)497 RetainPtr<CFX_Face> LoadFace(
498     const RetainPtr<IFX_SeekableReadStream>& pFontStream,
499     int32_t iFaceIndex) {
500   if (!pFontStream)
501     return nullptr;
502 
503   CFX_FontMgr* pFontMgr = CFX_GEModule::Get()->GetFontMgr();
504   FXFT_LibraryRec* library = pFontMgr->GetFTLibrary();
505   if (!library)
506     return nullptr;
507 
508   // TODO(palmer): This memory will be freed with |ft_free| (which is |free|).
509   // Ultimately, we want to change this to:
510   //   FXFT_Stream ftStream = FX_Alloc(FXFT_StreamRec, 1);
511   // https://bugs.chromium.org/p/pdfium/issues/detail?id=690
512   FXFT_StreamRec* ftStream =
513       static_cast<FXFT_StreamRec*>(ft_scalloc(sizeof(FXFT_StreamRec), 1));
514   memset(ftStream, 0, sizeof(FXFT_StreamRec));
515   ftStream->base = nullptr;
516   ftStream->descriptor.pointer = static_cast<void*>(pFontStream.Get());
517   ftStream->pos = 0;
518   ftStream->size = static_cast<unsigned long>(pFontStream->GetSize());
519   ftStream->read = ftStreamRead;
520   ftStream->close = ftStreamClose;
521 
522   FT_Open_Args ftArgs;
523   memset(&ftArgs, 0, sizeof(FT_Open_Args));
524   ftArgs.flags |= FT_OPEN_STREAM;
525   ftArgs.stream = ftStream;
526 
527   RetainPtr<CFX_Face> pFace = CFX_Face::Open(library, &ftArgs, iFaceIndex);
528   if (!pFace) {
529     ft_sfree(ftStream);
530     return nullptr;
531   }
532   FT_Set_Pixel_Sizes(pFace->GetRec(), 0, 64);
533   return pFace;
534 }
535 
VerifyUnicodeForFontDescriptor(CFGAS_FontDescriptor * pDesc,wchar_t wcUnicode)536 bool VerifyUnicodeForFontDescriptor(CFGAS_FontDescriptor* pDesc,
537                                     wchar_t wcUnicode) {
538   RetainPtr<IFX_SeekableReadStream> pFileRead =
539       CreateFontStream(pDesc->m_wsFaceName.ToUTF8());
540   if (!pFileRead)
541     return false;
542 
543   RetainPtr<CFX_Face> pFace = LoadFace(pFileRead, pDesc->m_nFaceIndex);
544   if (!pFace)
545     return false;
546 
547   FT_Error retCharmap =
548       FXFT_Select_Charmap(pFace->GetRec(), FT_ENCODING_UNICODE);
549   FT_Error retIndex = FT_Get_Char_Index(pFace->GetRec(), wcUnicode);
550 
551   if (FXFT_Get_Face_External_Stream(pFace->GetRec()))
552     FXFT_Clear_Face_External_Stream(pFace->GetRec());
553 
554   return !retCharmap && retIndex;
555 }
556 
IsPartName(const WideString & name1,const WideString & name2)557 bool IsPartName(const WideString& name1, const WideString& name2) {
558   return name1.Contains(name2.AsStringView());
559 }
560 
CalcPenalty(CFGAS_FontDescriptor * pInstalled,FX_CodePage wCodePage,uint32_t dwFontStyles,const WideString & FontName,wchar_t wcUnicode)561 int32_t CalcPenalty(CFGAS_FontDescriptor* pInstalled,
562                     FX_CodePage wCodePage,
563                     uint32_t dwFontStyles,
564                     const WideString& FontName,
565                     wchar_t wcUnicode) {
566   int32_t nPenalty = 30000;
567   if (FontName.GetLength() != 0) {
568     if (FontName != pInstalled->m_wsFaceName) {
569       size_t i;
570       for (i = 0; i < pInstalled->m_wsFamilyNames.size(); ++i) {
571         if (pInstalled->m_wsFamilyNames[i] == FontName)
572           break;
573       }
574       if (i == pInstalled->m_wsFamilyNames.size())
575         nPenalty += 0xFFFF;
576       else
577         nPenalty -= 28000;
578     } else {
579       nPenalty -= 30000;
580     }
581     if (nPenalty == 30000 && !IsPartName(pInstalled->m_wsFaceName, FontName)) {
582       size_t i;
583       for (i = 0; i < pInstalled->m_wsFamilyNames.size(); i++) {
584         if (IsPartName(pInstalled->m_wsFamilyNames[i], FontName))
585           break;
586       }
587       if (i == pInstalled->m_wsFamilyNames.size())
588         nPenalty += 0xFFFF;
589       else
590         nPenalty -= 26000;
591     } else {
592       nPenalty -= 27000;
593     }
594   }
595   uint32_t dwStyleMask = pInstalled->m_dwFontStyles ^ dwFontStyles;
596   if (FontStyleIsForceBold(dwStyleMask))
597     nPenalty += 4500;
598   if (FontStyleIsFixedPitch(dwStyleMask))
599     nPenalty += 10000;
600   if (FontStyleIsItalic(dwStyleMask))
601     nPenalty += 10000;
602   if (FontStyleIsSerif(dwStyleMask))
603     nPenalty += 500;
604   if (FontStyleIsSymbolic(dwStyleMask))
605     nPenalty += 0xFFFF;
606   if (nPenalty >= 0xFFFF)
607     return 0xFFFF;
608 
609   uint16_t wBit =
610       (wCodePage == FX_CodePage::kDefANSI || wCodePage == FX_CodePage::kFailure)
611           ? static_cast<uint16_t>(-1)
612           : FX_GetCodePageBit(wCodePage);
613   if (wBit != static_cast<uint16_t>(-1)) {
614     DCHECK(wBit < 64);
615     if ((pInstalled->m_dwCsb[wBit / 32] & (1 << (wBit % 32))) == 0)
616       nPenalty += 0xFFFF;
617     else
618       nPenalty -= 60000;
619   }
620   wBit = (wcUnicode == 0 || wcUnicode == 0xFFFE) ? FGAS_FONTUSB::kNoBitField
621                                                  : FX_GetUnicodeBit(wcUnicode);
622   if (wBit != FGAS_FONTUSB::kNoBitField) {
623     DCHECK(wBit < 128);
624     if ((pInstalled->m_dwUsb[wBit / 32] & (1 << (wBit % 32))) == 0)
625       nPenalty += 0xFFFF;
626     else
627       nPenalty -= 60000;
628   }
629   return nPenalty;
630 }
631 
632 }  // namespace
633 
634 CFGAS_FontDescriptor::CFGAS_FontDescriptor() = default;
635 
636 CFGAS_FontDescriptor::~CFGAS_FontDescriptor() = default;
637 
638 CFGAS_FontMgr::CFGAS_FontMgr() = default;
639 
640 CFGAS_FontMgr::~CFGAS_FontMgr() = default;
641 
EnumFontsFromFontMapper()642 bool CFGAS_FontMgr::EnumFontsFromFontMapper() {
643   CFX_FontMapper* pFontMapper =
644       CFX_GEModule::Get()->GetFontMgr()->GetBuiltinMapper();
645   pFontMapper->LoadInstalledFonts();
646 
647   for (size_t i = 0; i < pFontMapper->GetFaceSize(); ++i) {
648     RetainPtr<IFX_SeekableReadStream> pFontStream =
649         CreateFontStream(pFontMapper, i);
650     if (!pFontStream)
651       continue;
652 
653     WideString wsFaceName =
654         WideString::FromDefANSI(pFontMapper->GetFaceName(i).AsStringView());
655     RegisterFaces(pFontStream, wsFaceName);
656   }
657 
658   return !m_InstalledFonts.empty();
659 }
660 
EnumFonts()661 bool CFGAS_FontMgr::EnumFonts() {
662   return EnumFontsFromFontMapper();
663 }
664 
GetFontByUnicodeImpl(wchar_t wUnicode,uint32_t dwFontStyles,const wchar_t * pszFontFamily,uint32_t dwHash,FX_CodePage wCodePage,uint16_t)665 RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByUnicodeImpl(
666     wchar_t wUnicode,
667     uint32_t dwFontStyles,
668     const wchar_t* pszFontFamily,
669     uint32_t dwHash,
670     FX_CodePage wCodePage,
671     uint16_t /* wBitField*/) {
672   if (!pdfium::Contains(m_Hash2CandidateList, dwHash)) {
673     m_Hash2CandidateList[dwHash] =
674         MatchFonts(wCodePage, dwFontStyles, pszFontFamily, wUnicode);
675   }
676   for (const auto& info : m_Hash2CandidateList[dwHash]) {
677     CFGAS_FontDescriptor* pDesc = info.pFont;
678     if (!VerifyUnicodeForFontDescriptor(pDesc, wUnicode))
679       continue;
680     RetainPtr<CFGAS_GEFont> pFont =
681         LoadFontInternal(pDesc->m_wsFaceName, pDesc->m_nFaceIndex);
682     if (!pFont)
683       continue;
684     pFont->SetLogicalFontStyle(dwFontStyles);
685     m_Hash2Fonts[dwHash].push_back(pFont);
686     return pFont;
687   }
688   if (!pszFontFamily)
689     m_FailedUnicodesSet.insert(wUnicode);
690   return nullptr;
691 }
692 
LoadFontInternal(const WideString & wsFaceName,int32_t iFaceIndex)693 RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::LoadFontInternal(
694     const WideString& wsFaceName,
695     int32_t iFaceIndex) {
696   RetainPtr<IFX_SeekableReadStream> pFontStream =
697       CreateFontStream(wsFaceName.ToUTF8());
698   if (!pFontStream)
699     return nullptr;
700 
701   auto pInternalFont = std::make_unique<CFX_Font>();
702   if (!pInternalFont->LoadFile(std::move(pFontStream), iFaceIndex))
703     return nullptr;
704 
705   return CFGAS_GEFont::LoadFont(std::move(pInternalFont));
706 }
707 
MatchFonts(FX_CodePage wCodePage,uint32_t dwFontStyles,const WideString & FontName,wchar_t wcUnicode)708 std::vector<CFGAS_FontDescriptorInfo> CFGAS_FontMgr::MatchFonts(
709     FX_CodePage wCodePage,
710     uint32_t dwFontStyles,
711     const WideString& FontName,
712     wchar_t wcUnicode) {
713   std::vector<CFGAS_FontDescriptorInfo> matched_fonts;
714   for (const auto& pFont : m_InstalledFonts) {
715     int32_t nPenalty =
716         CalcPenalty(pFont.get(), wCodePage, dwFontStyles, FontName, wcUnicode);
717     if (nPenalty >= 0xffff)
718       continue;
719     matched_fonts.push_back({pFont.get(), nPenalty});
720     if (matched_fonts.size() == 0xffff)
721       break;
722   }
723   std::stable_sort(matched_fonts.begin(), matched_fonts.end());
724   return matched_fonts;
725 }
726 
RegisterFace(RetainPtr<CFX_Face> pFace,const WideString & wsFaceName)727 void CFGAS_FontMgr::RegisterFace(RetainPtr<CFX_Face> pFace,
728                                  const WideString& wsFaceName) {
729   if ((pFace->GetRec()->face_flags & FT_FACE_FLAG_SCALABLE) == 0)
730     return;
731 
732   auto pFont = std::make_unique<CFGAS_FontDescriptor>();
733   pFont->m_dwFontStyles |= GetFlags(pFace->GetRec());
734 
735   GetUSBCSB(pFace->GetRec(), pFont->m_dwUsb, pFont->m_dwCsb);
736 
737   FT_ULong dwTag;
738   FT_ENC_TAG(dwTag, 'n', 'a', 'm', 'e');
739 
740   DataVector<uint8_t> table;
741   unsigned long nLength = 0;
742   unsigned int error =
743       FT_Load_Sfnt_Table(pFace->GetRec(), dwTag, 0, nullptr, &nLength);
744   if (error == 0 && nLength != 0) {
745     table.resize(nLength);
746     if (FT_Load_Sfnt_Table(pFace->GetRec(), dwTag, 0, table.data(), nullptr))
747       table.clear();
748   }
749   pFont->m_wsFamilyNames = GetNames(table);
750   pFont->m_wsFamilyNames.push_back(
751       WideString::FromUTF8(pFace->GetRec()->family_name));
752   pFont->m_wsFaceName = wsFaceName;
753   pFont->m_nFaceIndex =
754       pdfium::base::checked_cast<int32_t>(pFace->GetRec()->face_index);
755   m_InstalledFonts.push_back(std::move(pFont));
756 }
757 
RegisterFaces(const RetainPtr<IFX_SeekableReadStream> & pFontStream,const WideString & wsFaceName)758 void CFGAS_FontMgr::RegisterFaces(
759     const RetainPtr<IFX_SeekableReadStream>& pFontStream,
760     const WideString& wsFaceName) {
761   int32_t index = 0;
762   int32_t num_faces = 0;
763   do {
764     RetainPtr<CFX_Face> pFace = LoadFace(pFontStream, index++);
765     if (!pFace)
766       continue;
767     // All faces keep number of faces. It can be retrieved from any one face.
768     if (num_faces == 0) {
769       num_faces =
770           pdfium::base::checked_cast<int32_t>(pFace->GetRec()->num_faces);
771     }
772     RegisterFace(pFace, wsFaceName);
773     if (FXFT_Get_Face_External_Stream(pFace->GetRec()))
774       FXFT_Clear_Face_External_Stream(pFace->GetRec());
775   } while (index < num_faces);
776 }
777 
778 #endif  // BUILDFLAG(IS_WIN)
779 
GetFontByCodePage(FX_CodePage wCodePage,uint32_t dwFontStyles,const wchar_t * pszFontFamily)780 RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByCodePage(
781     FX_CodePage wCodePage,
782     uint32_t dwFontStyles,
783     const wchar_t* pszFontFamily) {
784   uint32_t dwHash = ShortFormHash(wCodePage, dwFontStyles, pszFontFamily);
785   auto* pFontVector = &m_Hash2Fonts[dwHash];
786   if (!pFontVector->empty()) {
787     for (auto iter = pFontVector->begin(); iter != pFontVector->end(); ++iter) {
788       if (*iter != nullptr)
789         return *iter;
790     }
791     return nullptr;
792   }
793 
794 #if BUILDFLAG(IS_WIN)
795   const FX_FONTDESCRIPTOR* pFD =
796       FindFont(pszFontFamily, dwFontStyles, true, wCodePage,
797                FGAS_FONTUSB::kNoBitField, 0);
798   if (!pFD) {
799     pFD = FindFont(nullptr, dwFontStyles, true, wCodePage,
800                    FGAS_FONTUSB::kNoBitField, 0);
801   }
802   if (!pFD) {
803     pFD = FindFont(nullptr, dwFontStyles, false, wCodePage,
804                    FGAS_FONTUSB::kNoBitField, 0);
805   }
806   if (!pFD)
807     return nullptr;
808 
809   RetainPtr<CFGAS_GEFont> pFont =
810       CFGAS_GEFont::LoadFont(pFD->wsFontFace, dwFontStyles, wCodePage);
811 #else   // BUILDFLAG(IS_WIN)
812   if (!pdfium::Contains(m_Hash2CandidateList, dwHash)) {
813     m_Hash2CandidateList[dwHash] =
814         MatchFonts(wCodePage, dwFontStyles, WideString(pszFontFamily), 0);
815   }
816   if (m_Hash2CandidateList[dwHash].empty())
817     return nullptr;
818 
819   CFGAS_FontDescriptor* pDesc = m_Hash2CandidateList[dwHash].front().pFont;
820   RetainPtr<CFGAS_GEFont> pFont =
821       LoadFontInternal(pDesc->m_wsFaceName, pDesc->m_nFaceIndex);
822 #endif  // BUILDFLAG(IS_WIN)
823 
824   if (!pFont)
825     return nullptr;
826 
827   pFont->SetLogicalFontStyle(dwFontStyles);
828   pFontVector->push_back(pFont);
829   return pFont;
830 }
831 
GetFontByUnicode(wchar_t wUnicode,uint32_t dwFontStyles,const wchar_t * pszFontFamily)832 RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByUnicode(
833     wchar_t wUnicode,
834     uint32_t dwFontStyles,
835     const wchar_t* pszFontFamily) {
836   if (pdfium::Contains(m_FailedUnicodesSet, wUnicode))
837     return nullptr;
838 
839   const FGAS_FONTUSB* x = FGAS_GetUnicodeBitField(wUnicode);
840   FX_CodePage wCodePage = x ? x->wCodePage : FX_CodePage::kFailure;
841   uint16_t wBitField = x ? x->wBitField : FGAS_FONTUSB::kNoBitField;
842   uint32_t dwHash =
843       wCodePage == FX_CodePage::kFailure
844           ? LongFormHash(wCodePage, wBitField, dwFontStyles, pszFontFamily)
845           : ShortFormHash(wCodePage, dwFontStyles, pszFontFamily);
846   for (auto& pFont : m_Hash2Fonts[dwHash]) {
847     if (VerifyUnicode(pFont, wUnicode))
848       return pFont;
849   }
850   return GetFontByUnicodeImpl(wUnicode, dwFontStyles, pszFontFamily, dwHash,
851                               wCodePage, wBitField);
852 }
853 
LoadFont(const wchar_t * pszFontFamily,uint32_t dwFontStyles,FX_CodePage wCodePage)854 RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::LoadFont(const wchar_t* pszFontFamily,
855                                                 uint32_t dwFontStyles,
856                                                 FX_CodePage wCodePage) {
857 #if BUILDFLAG(IS_WIN)
858   uint32_t dwHash = ShortFormHash(wCodePage, dwFontStyles, pszFontFamily);
859   std::vector<RetainPtr<CFGAS_GEFont>>* pFontArray = &m_Hash2Fonts[dwHash];
860   if (!pFontArray->empty())
861     return pFontArray->front();
862 
863   const FX_FONTDESCRIPTOR* pFD =
864       FindFont(pszFontFamily, dwFontStyles, true, wCodePage,
865                FGAS_FONTUSB::kNoBitField, 0);
866   if (!pFD) {
867     pFD = FindFont(pszFontFamily, dwFontStyles, false, wCodePage,
868                    FGAS_FONTUSB::kNoBitField, 0);
869   }
870   if (!pFD)
871     return nullptr;
872 
873   RetainPtr<CFGAS_GEFont> pFont =
874       CFGAS_GEFont::LoadFont(pFD->wsFontFace, dwFontStyles, wCodePage);
875   if (!pFont)
876     return nullptr;
877 
878   pFont->SetLogicalFontStyle(dwFontStyles);
879   pFontArray->push_back(pFont);
880   return pFont;
881 #else   // BUILDFLAG(IS_WIN)
882   return GetFontByCodePage(wCodePage, dwFontStyles, pszFontFamily);
883 #endif  // BUILDFLAG(IS_WIN)
884 }
885