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