7#include "xfa/fgas/font/cfgas_fontmgr.h"
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"
43#include "core/fxcrt/win/win_util.h"
48bool VerifyUnicode(
const RetainPtr<CFGAS_GEFont>& pFont,
wchar_t wcUnicode) {
49 RetainPtr<CFX_Face> pFace = pFont->GetDevFont()->GetFace();
53 CFX_Face::
CharMap charmap = pFace->GetCurrentCharMap();
58 if (pFace->GetCharIndex(wcUnicode) == 0) {
59 pFace->SetCharMap(charmap);
66 uint32_t dwFontStyles,
69 bsHash += FX_UTF8Encode(wsFontFamily);
70 return FX_HashCode_GetA(bsHash.AsStringView());
75 uint32_t dwFontStyles,
79 bsHash += FX_UTF8Encode(wsFontFamily);
80 return FX_HashCode_GetA(bsHash.AsStringView());
89struct FX_FONTMATCHPARAMS {
90 const wchar_t* pwsFamily;
91 uint32_t dwFontStyles;
93 bool matchParagraphStyle;
95 FX_CodePage wCodePage;
98int32_t GetSimilarityScore(FX_FONTDESCRIPTOR
const* pFont,
99 uint32_t dwFontStyles) {
101 if (FontStyleIsSymbolic(dwFontStyles) ==
102 FontStyleIsSymbolic(pFont->dwFontStyles)) {
105 if (FontStyleIsFixedPitch(dwFontStyles) ==
106 FontStyleIsFixedPitch(pFont->dwFontStyles)) {
109 if (FontStyleIsSerif(dwFontStyles) == FontStyleIsSerif(pFont->dwFontStyles))
111 if (FontStyleIsScript(dwFontStyles) == FontStyleIsScript(pFont->dwFontStyles))
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)) {
127 if (pParams->pwsFamily) {
128 if (FXSYS_wcsicmp(pParams->pwsFamily, font.wsFontFace))
130 if (font.uCharSet == FX_Charset::kSymbol)
133 if (font.uCharSet == FX_Charset::kSymbol)
135 if (pParams->wCodePage != FX_CodePage::kFailure) {
136 if (FX_GetCodePageFromCharset(font.uCharSet) != pParams->wCodePage)
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)
146 if (pParams->matchParagraphStyle) {
147 if ((font.dwFontStyles & 0x0F) == (pParams->dwFontStyles & 0x0F))
151 if (pParams->pwsFamily) {
152 if (FXSYS_wcsicmp(pParams->pwsFamily, font.wsFontFace) == 0)
155 int32_t iSimilarValue = GetSimilarityScore(&font, pParams->dwFontStyles);
156 if (iBestSimilar < iSimilarValue) {
157 iBestSimilar = iSimilarValue;
161 return iBestSimilar < 1 ?
nullptr : pBestFont;
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;
178int32_t CALLBACK GdiFontEnumProc(ENUMLOGFONTEX* lpelfe,
179 NEWTEXTMETRICEX* lpntme,
182 if (dwFontType != TRUETYPE_FONTTYPE)
184 const LOGFONTW& lf = ((LPENUMLOGFONTEXW)lpelfe)->elfLogFont;
185 if (lf.lfFaceName[0] == L'@')
187 FX_FONTDESCRIPTOR font = {};
188 static_assert(std::is_aggregate_v<
decltype(font)>);
189 font.uCharSet = FX_GetCharsetFromInt(lf.lfCharSet);
190 font.dwFontStyles = GetGdiFontStyles(lf);
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));
197 reinterpret_cast<std::deque<FX_FONTDESCRIPTOR>*>(lParam)->push_back(font);
201std::deque<FX_FONTDESCRIPTOR> EnumGdiFonts(
const wchar_t* pwsFaceName,
203 std::deque<FX_FONTDESCRIPTOR> fonts;
204 if (!pdfium::IsUser32AndGdi32Available()) {
210 LOGFONTW lfFind = {};
211 static_assert(std::is_aggregate_v<
decltype(lfFind)>);
212 lfFind.lfCharSet = DEFAULT_CHARSET;
215 FXSYS_wcsncpy(lfFind.lfFaceName, pwsFaceName, 31);
216 lfFind.lfFaceName[31] = 0;
219 HDC hDC = ::GetDC(
nullptr);
220 EnumFontFamiliesExW(hDC, (LPLOGFONTW)&lfFind, (FONTENUMPROCW)GdiFontEnumProc,
222 ::ReleaseDC(
nullptr, hDC);
228CFGAS_FontMgr::CFGAS_FontMgr() : m_FontFaces(EnumGdiFonts(
nullptr, 0xFEFF)) {}
230CFGAS_FontMgr::~CFGAS_FontMgr() =
default;
232bool CFGAS_FontMgr::EnumFonts() {
236RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByUnicodeImpl(
238 uint32_t dwFontStyles,
239 const wchar_t* pszFontFamily,
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) {
247 FindFont(
nullptr, dwFontStyles,
false, wCodePage, wBitField, wUnicode);
252 FX_CodePage newCodePage = FX_GetCodePageFromCharset(pFD->uCharSet);
253 RetainPtr<CFGAS_GEFont> pFont =
254 CFGAS_GEFont::LoadFont(pFD->wsFontFace, dwFontStyles, newCodePage);
258 pFont->SetLogicalFontStyle(dwFontStyles);
259 if (!VerifyUnicode(pFont, wUnicode)) {
260 m_FailedUnicodesSet.insert(wUnicode);
264 m_Hash2Fonts[dwHash].push_back(pFont);
268const FX_FONTDESCRIPTOR* CFGAS_FontMgr::FindFont(
const wchar_t* pszFontFamily,
269 uint32_t dwFontStyles,
270 bool matchParagraphStyle,
271 FX_CodePage wCodePage,
274 FX_FONTMATCHPARAMS params = {};
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;
283 const FX_FONTDESCRIPTOR* pDesc = MatchDefaultFont(¶ms, m_FontFaces);
293 std::deque<FX_FONTDESCRIPTOR> namedFonts =
294 EnumGdiFonts(pszFontFamily, wUnicode);
295 params.pwsFamily =
nullptr;
296 pDesc = MatchDefaultFont(¶ms, namedFonts);
300 auto it = std::find(m_FontFaces.rbegin(), m_FontFaces.rend(), *pDesc);
301 if (it != m_FontFaces.rend())
304 m_FontFaces.push_back(*pDesc);
305 return &m_FontFaces.back();
312constexpr auto kCodePages =
379 for (size_t i = 0; i < kCodePages.size(); ++i) {
380 if (kCodePages[i] == wCodePage) {
381 return static_cast<uint16_t>(i);
384 return static_cast<uint16_t>(-1);
387uint16_t FX_GetUnicodeBit(
wchar_t wcUnicode) {
392uint16_t ReadUInt16FromSpanAtOffset(pdfium::span<
const uint8_t> data,
394 return fxcrt::GetUInt16MSBFirst(data.subspan(offset));
400 unsigned long offset,
401 unsigned char* buffer,
402 unsigned long count) {
410 if (!pFile->ReadBlockAtOffset(
421std::vector<WideString> GetNames(pdfium::span<
const uint8_t> name_table) {
422 std::vector<WideString> results;
423 if (name_table.empty())
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);
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) {
440 for (uint16_t j = 0; j < nNameLength / 2; ++j) {
441 wchar_t wcTemp = ReadUInt16FromSpanAtOffset(str, nNameOffset + j * 2);
444 results.push_back(wsFamily);
449 for (uint16_t j = 0; j < nNameLength; ++j) {
450 wchar_t wcTemp = str[nNameOffset + j];
453 results.push_back(wsFamily);
458uint32_t GetFlags(
const RetainPtr<CFX_Face>& face) {
460 if (face->IsBold()) {
463 if (face->IsItalic()) {
466 if (face->IsFixedWidth()) {
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))) {
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) {
488 FixedSizeDataVector<uint8_t> buffer = pFontMapper->RawBytesForIndex(index);
489 if (buffer.empty()) {
492 return pdfium::MakeRetain<CFX_ReadOnlyVectorStream>(
std::move(buffer));
501 for (size_t i = 0; i < pFontMapper->GetFaceSize(); ++i) {
502 if (pFontMapper->GetFaceName(i) == bsFaceName)
503 return CreateFontStream(pFontMapper, i);
510 int32_t iFaceIndex) {
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());
529 ftStream->size =
static_cast<
unsigned long>(pFontStream->GetSize());
530 ftStream->read = ftStreamRead;
531 ftStream->close = ftStreamClose;
533 FT_Open_Args ftArgs = {};
534 static_assert(std::is_aggregate_v<
decltype(ftArgs)>);
535 ftArgs.flags |= FT_OPEN_STREAM;
536 ftArgs.stream = ftStream;
538 RetainPtr<CFX_Face> pFace = CFX_Face::Open(library, &ftArgs, iFaceIndex);
543 pFace->SetPixelSize(0, 64);
550 CreateFontStream(pDesc->m_wsFaceName.ToUTF8());
554 RetainPtr<CFX_Face> pFace = LoadFace(pFileRead, pDesc->m_nFaceIndex);
558 bool select_charmap_result =
560 int ret_index = pFace->GetCharIndex(wcUnicode);
562 pFace->ClearExternalStream();
564 return select_charmap_result && ret_index;
568 return name1.Contains(name2.AsStringView());
573 uint32_t dwFontStyles,
576 int32_t nPenalty = 30000;
577 if (FontName.GetLength() != 0) {
578 if (FontName != pInstalled->m_wsFaceName) {
580 for (i = 0; i < pInstalled->m_wsFamilyNames.size(); ++i) {
581 if (pInstalled->m_wsFamilyNames[i] == FontName)
584 if (i == pInstalled->m_wsFamilyNames.size())
591 if (nPenalty == 30000 && !IsPartName(pInstalled->m_wsFaceName, FontName)) {
593 for (i = 0; i < pInstalled->m_wsFamilyNames.size(); i++) {
594 if (IsPartName(pInstalled->m_wsFamilyNames[i], FontName))
597 if (i == pInstalled->m_wsFamilyNames.size())
616 if (nPenalty >= 0xFFFF)
621 ?
static_cast<uint16_t>(-1)
622 : FX_GetCodePageBit(wCodePage);
623 if (wBit !=
static_cast<uint16_t>(-1)) {
625 if ((pInstalled->m_dwCsb[wBit / 32] & (1 << (wBit % 32))) == 0)
631 : FX_GetUnicodeBit(wcUnicode);
634 if ((pInstalled->m_dwUsb[wBit / 32] & (1 << (wBit % 32))) == 0)
657 for (size_t i = 0; i < pFontMapper->GetFaceSize(); ++i) {
659 CreateFontStream(pFontMapper, i);
665 RegisterFaces(pFontStream, wsFaceName);
668 return !m_InstalledFonts.empty();
672 return EnumFontsFromFontMapper();
677 uint32_t dwFontStyles,
678 const wchar_t* pszFontFamily,
682 if (!pdfium::Contains(m_Hash2CandidateList, dwHash)) {
683 m_Hash2CandidateList[dwHash] =
684 MatchFonts(wCodePage, dwFontStyles, pszFontFamily, wUnicode);
686 for (
const auto& info : m_Hash2CandidateList[dwHash]) {
687 CFGAS_FontDescriptor* pDesc = info.pFont;
688 if (!VerifyUnicodeForFontDescriptor(pDesc, wUnicode))
690 RetainPtr<CFGAS_GEFont> pFont =
691 LoadFontInternal(pDesc->m_wsFaceName, pDesc->m_nFaceIndex);
694 pFont->SetLogicalFontStyle(dwFontStyles);
695 m_Hash2Fonts[dwHash].push_back(pFont);
699 m_FailedUnicodesSet.insert(wUnicode);
705 int32_t iFaceIndex) {
707 CreateFontStream(wsFaceName.ToUTF8());
712 if (!pInternalFont->LoadFile(
std::move(pFontStream), iFaceIndex))
715 return CFGAS_GEFont::LoadFont(
std::move(pInternalFont));
718std::vector<CFGAS_FontDescriptorInfo>
CFGAS_FontMgr::MatchFonts(
720 uint32_t dwFontStyles,
723 std::vector<CFGAS_FontDescriptorInfo> matched_fonts;
724 for (
const auto& pFont : m_InstalledFonts) {
726 CalcPenalty(pFont.get(), wCodePage, dwFontStyles, FontName, wcUnicode);
727 if (nPenalty >= 0xffff)
729 matched_fonts.push_back({pFont.get(), nPenalty});
730 if (matched_fonts.size() == 0xffff)
733 std::stable_sort(matched_fonts.begin(), matched_fonts.end());
734 return matched_fonts;
739 if (!pFace->IsScalable()) {
744 pFont->m_dwFontStyles |= GetFlags(pFace);
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);
753 fxcrt::Fill(pFont->m_dwUsb, 0);
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);
761 fxcrt::Fill(pFont->m_dwCsb, 0);
764 static constexpr uint32_t kNameTag =
767 DataVector<uint8_t> table;
768 size_t table_size = pFace->GetSfntTable(kNameTag, table);
770 table.resize(table_size);
771 if (!pFace->GetSfntTable(kNameTag, table)) {
775 pFont->m_wsFamilyNames = GetNames(table);
776 pFont->m_wsFamilyNames.push_back(
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));
788 int32_t num_faces = 0;
790 RetainPtr<CFX_Face> pFace = LoadFace(pFontStream, index++);
794 if (num_faces == 0) {
795 num_faces =
pdfium::checked_cast<int32_t>(pFace->GetRec()->num_faces);
797 RegisterFace(pFace, wsFaceName);
798 pFace->ClearExternalStream();
799 }
while (index < num_faces);
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)
819 const FX_FONTDESCRIPTOR* pFD =
820 FindFont(pszFontFamily, dwFontStyles,
true, wCodePage,
821 FGAS_FONTUSB::kNoBitField, 0);
823 pFD = FindFont(
nullptr, dwFontStyles,
true, wCodePage,
824 FGAS_FONTUSB::kNoBitField, 0);
827 pFD = FindFont(
nullptr, dwFontStyles,
false, wCodePage,
828 FGAS_FONTUSB::kNoBitField, 0);
833 RetainPtr<CFGAS_GEFont> pFont =
834 CFGAS_GEFont::LoadFont(pFD->wsFontFace, dwFontStyles, wCodePage);
836 if (!pdfium::Contains(m_Hash2CandidateList, dwHash)) {
837 m_Hash2CandidateList[dwHash] =
838 MatchFonts(wCodePage, dwFontStyles, WideString(pszFontFamily), 0);
840 if (m_Hash2CandidateList[dwHash].empty())
845 LoadFontInternal(pDesc->m_wsFaceName, pDesc->m_nFaceIndex);
851 pFont->SetLogicalFontStyle(dwFontStyles);
852 pFontVector->push_back(pFont);
858 uint32_t dwFontStyles,
859 const wchar_t* pszFontFamily) {
860 if (pdfium::Contains(m_FailedUnicodesSet, wUnicode))
868 ? LongFormHash(wCodePage, wBitField, dwFontStyles, pszFontFamily)
869 : ShortFormHash(wCodePage, dwFontStyles, pszFontFamily);
870 for (
auto& pFont : m_Hash2Fonts[dwHash]) {
871 if (VerifyUnicode(pFont, wUnicode))
874 return GetFontByUnicodeImpl(wUnicode, dwFontStyles, pszFontFamily, dwHash,
875 wCodePage, wBitField);
879 uint32_t dwFontStyles,
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();
887 const FX_FONTDESCRIPTOR* pFD =
888 FindFont(pszFontFamily, dwFontStyles,
true, wCodePage,
889 FGAS_FONTUSB::kNoBitField, 0);
891 pFD = FindFont(pszFontFamily, dwFontStyles,
false, wCodePage,
892 FGAS_FONTUSB::kNoBitField, 0);
897 RetainPtr<CFGAS_GEFont> pFont =
898 CFGAS_GEFont::LoadFont(pFD->wsFontFace, dwFontStyles, wCodePage);
902 pFont->SetLogicalFontStyle(dwFontStyles);
903 pFontArray->push_back(pFont);
906 return GetFontByCodePage(wCodePage, dwFontStyles, pszFontFamily);
fxcrt::ByteString ByteString
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)
static constexpr uint32_t MakeTag(char c1, char c2, char c3, char c4)
void LoadInstalledFonts()
FXFT_LibraryRec * GetFTLibrary() const
CFX_FontMapper * GetBuiltinMapper() const
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(...)
const FGAS_FONTUSB * FGAS_GetUnicodeBitField(wchar_t wUnicode)
bool FontStyleIsSerif(uint32_t style)
bool FontStyleIsFixedPitch(uint32_t style)
bool FontStyleIsSymbolic(uint32_t style)
bool FontStyleIsItalic(uint32_t style)
#define FXFONT_FORCE_BOLD
bool FontStyleIsForceBold(uint32_t style)
#define FXFONT_FIXED_PITCH
struct FT_LibraryRec_ FXFT_LibraryRec
struct FT_StreamRec_ FXFT_StreamRec
fxcrt::WideStringView WideStringView
static constexpr uint16_t kNoBitField
fxcrt::WideString WideString