Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cfgas_fontmgr.cpp
Go to the documentation of this file.
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
46namespace {
47
48bool 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
65uint32_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
73uint32_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
87namespace {
88
89struct 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
98int32_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
116const 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
164uint32_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
178int32_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
201std::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
228CFGAS_FontMgr::CFGAS_FontMgr() : m_FontFaces(EnumGdiFonts(nullptr, 0xFEFF)) {}
229
230CFGAS_FontMgr::~CFGAS_FontMgr() = default;
231
232bool CFGAS_FontMgr::EnumFonts() {
233 return true;
234}
235
236RetainPtr<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
268const 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
310namespace {
311
312constexpr auto kCodePages =
377
378uint16_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
387uint16_t FX_GetUnicodeBit(wchar_t wcUnicode) {
388 const FGAS_FONTUSB* x = FGAS_GetUnicodeBitField(wcUnicode);
390}
391
392uint16_t ReadUInt16FromSpanAtOffset(pdfium::span<const uint8_t> data,
393 size_t offset) {
394 return fxcrt::GetUInt16MSBFirst(data.subspan(offset));
395}
396
397extern "C" {
398
399unsigned 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
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
417void ftStreamClose(FXFT_StreamRec* stream) {}
418
419} // extern "C"
420
421std::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
458uint32_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
486RetainPtr<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
495RetainPtr<IFX_SeekableReadStream> CreateFontStream(
496 const ByteString& bsFaceName) {
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
508RetainPtr<CFX_Face> LoadFace(
509 const RetainPtr<IFX_SeekableReadStream>& pFontStream,
510 int32_t iFaceIndex) {
511 if (!pFontStream)
512 return nullptr;
513
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
547bool VerifyUnicodeForFontDescriptor(CFGAS_FontDescriptor* pDesc,
548 wchar_t wcUnicode) {
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
567bool IsPartName(const WideString& name1, const WideString& name2) {
568 return name1.Contains(name2.AsStringView());
569}
570
571int32_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
645
647
648CFGAS_FontMgr::CFGAS_FontMgr() = default;
649
650CFGAS_FontMgr::~CFGAS_FontMgr() = default;
651
652bool CFGAS_FontMgr::EnumFontsFromFontMapper() {
653 CFX_FontMapper* pFontMapper =
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
672 return EnumFontsFromFontMapper();
673}
674
675RetainPtr<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
703RetainPtr<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
718std::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
737void 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
784void 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
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
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);
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
878RetainPtr<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}
fxcrt::ByteString ByteString
Definition bytestring.h:180
#define DCHECK
Definition check.h:33
RetainPtr< CFGAS_GEFont > GetFontByCodePage(FX_CodePage wCodePage, uint32_t dwFontStyles, const wchar_t *pszFontFamily)
RetainPtr< CFGAS_GEFont > GetFontByUnicode(wchar_t wUnicode, uint32_t dwFontStyles, const wchar_t *pszFontFamily)
RetainPtr< CFGAS_GEFont > LoadFont(const wchar_t *pszFontFamily, uint32_t dwFontStyles, FX_CodePage wCodePage)
void * CharMap
Definition cfx_face.h:34
static constexpr uint32_t MakeTag(char c1, char c2, char c3, char c4)
FXFT_LibraryRec * GetFTLibrary() const
Definition cfx_fontmgr.h:74
CFX_FontMapper * GetBuiltinMapper() const
Definition cfx_fontmgr.h:72
static CFX_GEModule * Get()
CFX_FontMgr * GetFontMgr() const
static ByteString Format(const char *pFormat,...)
static WideString FromUTF8(ByteStringView str)
WideString & operator+=(wchar_t ch)
static WideString FromDefANSI(ByteStringView str)
#define UNSAFE_BUFFERS(...)
#define UNSAFE_TODO(...)
const FGAS_FONTUSB * FGAS_GetUnicodeBitField(wchar_t wUnicode)
FX_CodePage
Definition fx_codepage.h:19
@ kChineseTraditional
Definition fx_codepage.h:42
@ kMSWin_EasternEuropean
Definition fx_codepage.h:45
@ kMSDOS_EasternEuropean
Definition fx_codepage.h:27
@ kMSDOS_FrenchCanadian
Definition fx_codepage.h:33
@ kMSWin_WesternEuropean
Definition fx_codepage.h:47
@ kMSDOS_WesternEuropean
Definition fx_codepage.h:26
bool FontStyleIsSerif(uint32_t style)
Definition fx_font.h:79
bool FontStyleIsFixedPitch(uint32_t style)
Definition fx_font.h:67
#define FXFONT_SERIF
Definition fx_font.h:31
#define FXFONT_ITALIC
Definition fx_font.h:35
bool FontStyleIsSymbolic(uint32_t style)
Definition fx_font.h:70
#define FXFONT_SYMBOLIC
Definition fx_font.h:32
bool FontStyleIsItalic(uint32_t style)
Definition fx_font.h:64
#define FXFONT_FORCE_BOLD
Definition fx_font.h:38
bool FontStyleIsForceBold(uint32_t style)
Definition fx_font.h:61
#define FXFONT_FIXED_PITCH
Definition fx_font.h:30
struct FT_LibraryRec_ FXFT_LibraryRec
Definition fx_freetype.h:23
struct FT_StreamRec_ FXFT_StreamRec
Definition fx_freetype.h:25
fxcrt::WideStringView WideStringView
static constexpr uint16_t kNoBitField
uint16_t wBitField
FX_CodePage wCodePage
fxcrt::WideString WideString
Definition widestring.h:207