7#include "xfa/fgas/font/cfgas_fontmgr.h"
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_size_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/fxcrt/span_util.h"
25#include "core/fxge/cfx_font.h"
26#include "core/fxge/cfx_fontmapper.h"
27#include "core/fxge/cfx_fontmgr.h"
28#include "core/fxge/cfx_gemodule.h"
29#include "core/fxge/fx_font.h"
30#include "core/fxge/fx_fontencoding.h"
31#include "third_party/base/check.h"
32#include "third_party/base/containers/contains.h"
33#include "third_party/base/containers/span.h"
34#include "third_party/base/numerics/safe_conversions.h"
35#include "xfa/fgas/font/cfgas_gefont.h"
36#include "xfa/fgas/font/fgas_fontutils.h"
40bool VerifyUnicode(
const RetainPtr<CFGAS_GEFont>& pFont,
wchar_t wcUnicode) {
41 RetainPtr<CFX_Face> pFace = pFont->GetDevFont()->GetFace();
45 CFX_Face::CharMap charmap = pFace->GetCurrentCharMap();
50 if (pFace->GetCharIndex(wcUnicode) == 0) {
51 pFace->SetCharMap(charmap);
58 uint32_t dwFontStyles,
59 WideStringView wsFontFamily) {
60 ByteString bsHash = ByteString
::Format("%d, %d", wCodePage
, dwFontStyles
);
61 bsHash += FX_UTF8Encode(wsFontFamily);
62 return FX_HashCode_GetA(bsHash.AsStringView());
67 uint32_t dwFontStyles,
68 WideStringView wsFontFamily) {
70 ByteString
::Format("%d, %d, %d", wCodePage
, wBitField
, dwFontStyles
);
71 bsHash += FX_UTF8Encode(wsFontFamily);
72 return FX_HashCode_GetA(bsHash.AsStringView());
81struct FX_FONTMATCHPARAMS {
82 const wchar_t* pwsFamily;
83 uint32_t dwFontStyles;
85 bool matchParagraphStyle;
87 FX_CodePage wCodePage;
90int32_t GetSimilarityScore(FX_FONTDESCRIPTOR
const* pFont,
91 uint32_t dwFontStyles) {
93 if (FontStyleIsSymbolic(dwFontStyles) ==
94 FontStyleIsSymbolic(pFont->dwFontStyles)) {
97 if (FontStyleIsFixedPitch(dwFontStyles) ==
98 FontStyleIsFixedPitch(pFont->dwFontStyles)) {
101 if (FontStyleIsSerif(dwFontStyles) == FontStyleIsSerif(pFont->dwFontStyles))
103 if (FontStyleIsScript(dwFontStyles) == FontStyleIsScript(pFont->dwFontStyles))
108const FX_FONTDESCRIPTOR* MatchDefaultFont(
109 FX_FONTMATCHPARAMS* pParams,
110 const std::deque<FX_FONTDESCRIPTOR>& fonts) {
111 const FX_FONTDESCRIPTOR* pBestFont =
nullptr;
112 int32_t iBestSimilar = 0;
113 for (
const auto& font : fonts) {
114 if (FontStyleIsForceBold(font.dwFontStyles) &&
115 FontStyleIsItalic(font.dwFontStyles)) {
119 if (pParams->pwsFamily) {
120 if (FXSYS_wcsicmp(pParams->pwsFamily, font.wsFontFace))
122 if (font.uCharSet == FX_Charset::kSymbol)
125 if (font.uCharSet == FX_Charset::kSymbol)
127 if (pParams->wCodePage != FX_CodePage::kFailure) {
128 if (FX_GetCodePageFromCharset(font.uCharSet) != pParams->wCodePage)
131 if (pParams->dwUSB < 128) {
132 uint32_t dwByte = pParams->dwUSB / 32;
133 uint32_t dwUSB = 1 << (pParams->dwUSB % 32);
134 if ((font.FontSignature.fsUsb[dwByte] & dwUSB) == 0)
138 if (pParams->matchParagraphStyle) {
139 if ((font.dwFontStyles & 0x0F) == (pParams->dwFontStyles & 0x0F))
143 if (pParams->pwsFamily) {
144 if (FXSYS_wcsicmp(pParams->pwsFamily, font.wsFontFace) == 0)
147 int32_t iSimilarValue = GetSimilarityScore(&font, pParams->dwFontStyles);
148 if (iBestSimilar < iSimilarValue) {
149 iBestSimilar = iSimilarValue;
153 return iBestSimilar < 1 ?
nullptr : pBestFont;
156uint32_t GetGdiFontStyles(
const LOGFONTW& lf) {
157 uint32_t dwStyles = 0;
158 if ((lf.lfPitchAndFamily & 0x03) == FIXED_PITCH)
159 dwStyles |= FXFONT_FIXED_PITCH;
160 uint8_t nFamilies = lf.lfPitchAndFamily & 0xF0;
161 if (nFamilies == FF_ROMAN)
162 dwStyles |= FXFONT_SERIF;
163 if (nFamilies == FF_SCRIPT)
164 dwStyles |= FXFONT_SCRIPT;
165 if (lf.lfCharSet == SYMBOL_CHARSET)
166 dwStyles |= FXFONT_SYMBOLIC;
170int32_t CALLBACK GdiFontEnumProc(ENUMLOGFONTEX* lpelfe,
171 NEWTEXTMETRICEX* lpntme,
174 if (dwFontType != TRUETYPE_FONTTYPE)
176 const LOGFONTW& lf = ((LPENUMLOGFONTEXW)lpelfe)->elfLogFont;
177 if (lf.lfFaceName[0] == L'@')
179 FX_FONTDESCRIPTOR font;
180 memset(&font, 0,
sizeof(FX_FONTDESCRIPTOR));
181 font.uCharSet = FX_GetCharsetFromInt(lf.lfCharSet);
182 font.dwFontStyles = GetGdiFontStyles(lf);
183 FXSYS_wcsncpy(font.wsFontFace, (
const wchar_t*)lf.lfFaceName, 31);
184 font.wsFontFace[31] = 0;
185 memcpy(&font.FontSignature, &lpntme->ntmFontSig,
sizeof(lpntme->ntmFontSig));
186 reinterpret_cast<std::deque<FX_FONTDESCRIPTOR>*>(lParam)->push_back(font);
190std::deque<FX_FONTDESCRIPTOR> EnumGdiFonts(
const wchar_t* pwsFaceName,
192 std::deque<FX_FONTDESCRIPTOR> fonts;
194 memset(&lfFind, 0,
sizeof(lfFind));
195 lfFind.lfCharSet = DEFAULT_CHARSET;
197 FXSYS_wcsncpy(lfFind.lfFaceName, pwsFaceName, 31);
198 lfFind.lfFaceName[31] = 0;
200 HDC hDC = ::GetDC(
nullptr);
201 EnumFontFamiliesExW(hDC, (LPLOGFONTW)&lfFind, (FONTENUMPROCW)GdiFontEnumProc,
203 ::ReleaseDC(
nullptr, hDC);
209CFGAS_FontMgr::CFGAS_FontMgr() : m_FontFaces(EnumGdiFonts(
nullptr, 0xFEFF)) {}
211CFGAS_FontMgr::~CFGAS_FontMgr() =
default;
213bool CFGAS_FontMgr::EnumFonts() {
217RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByUnicodeImpl(
219 uint32_t dwFontStyles,
220 const wchar_t* pszFontFamily,
222 FX_CodePage wCodePage,
223 uint16_t wBitField) {
224 const FX_FONTDESCRIPTOR* pFD = FindFont(pszFontFamily, dwFontStyles,
false,
225 wCodePage, wBitField, wUnicode);
226 if (!pFD && pszFontFamily) {
228 FindFont(
nullptr, dwFontStyles,
false, wCodePage, wBitField, wUnicode);
233 FX_CodePage newCodePage = FX_GetCodePageFromCharset(pFD->uCharSet);
234 RetainPtr<CFGAS_GEFont> pFont =
235 CFGAS_GEFont::LoadFont(pFD->wsFontFace, dwFontStyles, newCodePage);
239 pFont->SetLogicalFontStyle(dwFontStyles);
240 if (!VerifyUnicode(pFont, wUnicode)) {
241 m_FailedUnicodesSet.insert(wUnicode);
245 m_Hash2Fonts[dwHash].push_back(pFont);
249const FX_FONTDESCRIPTOR* CFGAS_FontMgr::FindFont(
const wchar_t* pszFontFamily,
250 uint32_t dwFontStyles,
251 bool matchParagraphStyle,
252 FX_CodePage wCodePage,
255 FX_FONTMATCHPARAMS params;
256 memset(¶ms, 0,
sizeof(params));
257 params.dwUSB = dwUSB;
258 params.wUnicode = wUnicode;
259 params.wCodePage = wCodePage;
260 params.pwsFamily = pszFontFamily;
261 params.dwFontStyles = dwFontStyles;
262 params.matchParagraphStyle = matchParagraphStyle;
264 const FX_FONTDESCRIPTOR* pDesc = MatchDefaultFont(¶ms, m_FontFaces);
274 std::deque<FX_FONTDESCRIPTOR> namedFonts =
275 EnumGdiFonts(pszFontFamily, wUnicode);
276 params.pwsFamily =
nullptr;
277 pDesc = MatchDefaultFont(¶ms, namedFonts);
281 auto it = std::find(m_FontFaces.rbegin(), m_FontFaces.rend(), *pDesc);
282 if (it != m_FontFaces.rend())
285 m_FontFaces.push_back(*pDesc);
286 return &m_FontFaces.back();
359 for (size_t i = 0; i <
std::size(kCodePages); ++i) {
360 if (kCodePages[i] == wCodePage)
361 return static_cast<uint16_t>(i);
363 return static_cast<uint16_t>(-1);
366uint16_t FX_GetUnicodeBit(
wchar_t wcUnicode) {
371uint16_t ReadUInt16FromSpanAtOffset(pdfium::span<
const uint8_t> data,
373 const uint8_t* p = &data[offset];
374 return FXSYS_UINT16_GET_MSBFIRST(p);
379unsigned long ftStreamRead(FXFT_StreamRec* stream,
380 unsigned long offset,
381 unsigned char* buffer,
382 unsigned long count) {
394void ftStreamClose(FXFT_StreamRec* stream) {}
398std::vector<WideString> GetNames(pdfium::span<
const uint8_t> name_table) {
399 std::vector<WideString> results;
400 if (name_table.empty())
403 uint16_t nNameCount = ReadUInt16FromSpanAtOffset(name_table, 2);
404 pdfium::span<
const uint8_t> str =
405 name_table.subspan(ReadUInt16FromSpanAtOffset(name_table, 4));
406 pdfium::span<
const uint8_t> name_record = name_table.subspan(6);
407 for (uint16_t i = 0; i < nNameCount; ++i) {
408 uint16_t nNameID = ReadUInt16FromSpanAtOffset(name_table, i * 12 + 6);
412 uint16_t nPlatformID = ReadUInt16FromSpanAtOffset(name_record, i * 12);
413 uint16_t nNameLength = ReadUInt16FromSpanAtOffset(name_record, i * 12 + 8);
414 uint16_t nNameOffset = ReadUInt16FromSpanAtOffset(name_record, i * 12 + 10);
415 if (nPlatformID != 1) {
417 for (uint16_t j = 0; j < nNameLength / 2; ++j) {
418 wchar_t wcTemp = ReadUInt16FromSpanAtOffset(str, nNameOffset + j * 2);
421 results.push_back(wsFamily);
426 for (uint16_t j = 0; j < nNameLength; ++j) {
427 wchar_t wcTemp = str[nNameOffset + j];
430 results.push_back(wsFamily);
435uint32_t GetFlags(
const RetainPtr<CFX_Face>& face) {
437 if (face->IsBold()) {
440 if (face->IsItalic()) {
443 if (face->IsFixedWidth()) {
447 absl::optional<std::array<uint32_t, 2>> code_page_range =
448 face->GetOs2CodePageRange();
449 if (code_page_range.has_value() && (code_page_range.value()[0] & (1 << 31))) {
453 absl::optional<std::array<uint8_t, 2>> panose = face->GetOs2Panose();
454 if (panose.has_value() && panose.value()[0] == 2) {
455 uint8_t serif = panose.value()[1];
456 if ((serif > 1 && serif < 10) || serif > 13) {
466 if (buffer.empty()) {
469 return pdfium::MakeRetain<CFX_ReadOnlyVectorStream>(
std::move(buffer));
473 const ByteString& bsFaceName) {
478 for (size_t i = 0; i < pFontMapper->GetFaceSize(); ++i) {
479 if (pFontMapper->GetFaceName(i) == bsFaceName)
480 return CreateFontStream(pFontMapper, i);
487 int32_t iFaceIndex) {
500 FXFT_StreamRec* ftStream =
501 static_cast<FXFT_StreamRec*>(ft_scalloc(
sizeof(FXFT_StreamRec), 1));
502 memset(ftStream, 0,
sizeof(FXFT_StreamRec));
503 ftStream->base =
nullptr;
504 ftStream->descriptor.pointer =
static_cast<
void*>(pFontStream.Get());
506 ftStream->size =
static_cast<
unsigned long>(pFontStream->GetSize());
507 ftStream->read = ftStreamRead;
508 ftStream->close = ftStreamClose;
511 memset(&ftArgs, 0,
sizeof(FT_Open_Args));
512 ftArgs.flags |= FT_OPEN_STREAM;
513 ftArgs.stream = ftStream;
515 RetainPtr<CFX_Face> pFace = CFX_Face::Open(library, &ftArgs, iFaceIndex);
520 FT_Set_Pixel_Sizes(pFace->GetRec(), 0, 64);
527 CreateFontStream(pDesc->m_wsFaceName.ToUTF8());
531 RetainPtr<CFX_Face> pFace = LoadFace(pFileRead, pDesc->m_nFaceIndex);
535 bool select_charmap_result =
537 int ret_index = pFace->GetCharIndex(wcUnicode);
539 pFace->ClearExternalStream();
541 return select_charmap_result && ret_index;
544bool IsPartName(
const WideString& name1,
const WideString& name2) {
545 return name1.Contains(name2.AsStringView());
550 uint32_t dwFontStyles,
551 const WideString& FontName,
553 int32_t nPenalty = 30000;
554 if (FontName.GetLength() != 0) {
555 if (FontName != pInstalled->m_wsFaceName) {
557 for (i = 0; i < pInstalled->m_wsFamilyNames.size(); ++i) {
558 if (pInstalled->m_wsFamilyNames[i] == FontName)
561 if (i == pInstalled->m_wsFamilyNames.size())
568 if (nPenalty == 30000 && !IsPartName(pInstalled->m_wsFaceName, FontName)) {
570 for (i = 0; i < pInstalled->m_wsFamilyNames.size(); i++) {
571 if (IsPartName(pInstalled->m_wsFamilyNames[i], FontName))
574 if (i == pInstalled->m_wsFamilyNames.size())
593 if (nPenalty >= 0xFFFF)
598 ?
static_cast<uint16_t>(-1)
599 : FX_GetCodePageBit(wCodePage);
600 if (wBit !=
static_cast<uint16_t>(-1)) {
602 if ((pInstalled
->m_dwCsb[wBit / 32] & (1 << (wBit % 32))) == 0)
608 : FX_GetUnicodeBit(wcUnicode);
611 if ((pInstalled
->m_dwUsb[wBit / 32] & (1 << (wBit % 32))) == 0)
634 for (size_t i = 0; i < pFontMapper->GetFaceSize(); ++i) {
636 CreateFontStream(pFontMapper, i);
640 WideString wsFaceName =
642 RegisterFaces(pFontStream, wsFaceName);
645 return !m_InstalledFonts.empty();
649 return EnumFontsFromFontMapper();
654 uint32_t dwFontStyles,
655 const wchar_t* pszFontFamily,
659 if (!pdfium::Contains(m_Hash2CandidateList, dwHash)) {
660 m_Hash2CandidateList[dwHash] =
661 MatchFonts(wCodePage, dwFontStyles, pszFontFamily, wUnicode);
663 for (
const auto& info : m_Hash2CandidateList[dwHash]) {
664 CFGAS_FontDescriptor* pDesc = info.pFont;
665 if (!VerifyUnicodeForFontDescriptor(pDesc, wUnicode))
667 RetainPtr<CFGAS_GEFont> pFont =
668 LoadFontInternal(pDesc->m_wsFaceName, pDesc->m_nFaceIndex);
671 pFont->SetLogicalFontStyle(dwFontStyles);
672 m_Hash2Fonts[dwHash].push_back(pFont);
676 m_FailedUnicodesSet.insert(wUnicode);
681 const WideString& wsFaceName,
682 int32_t iFaceIndex) {
684 CreateFontStream(wsFaceName.ToUTF8());
689 if (!pInternalFont->LoadFile(
std::move(pFontStream), iFaceIndex))
692 return CFGAS_GEFont::LoadFont(
std::move(pInternalFont));
695std::vector<CFGAS_FontDescriptorInfo>
CFGAS_FontMgr::MatchFonts(
697 uint32_t dwFontStyles,
698 const WideString& FontName,
700 std::vector<CFGAS_FontDescriptorInfo> matched_fonts;
701 for (
const auto& pFont : m_InstalledFonts) {
703 CalcPenalty(pFont.get(), wCodePage, dwFontStyles, FontName, wcUnicode);
704 if (nPenalty >= 0xffff)
706 matched_fonts.push_back({pFont.get(), nPenalty});
707 if (matched_fonts.size() == 0xffff)
710 std::stable_sort(matched_fonts.begin(), matched_fonts.end());
711 return matched_fonts;
715 const WideString& wsFaceName) {
716 if (!pFace->IsScalable()) {
721 pFont->m_dwFontStyles |= GetFlags(pFace);
725 absl::optional<std::array<uint32_t, 4>> unicode_range =
726 pFace->GetOs2UnicodeRange();
727 auto usb_span = pdfium::make_span(pFont->m_dwUsb);
728 if (unicode_range.has_value()) {
729 fxcrt::spancpy(usb_span, pdfium::make_span(unicode_range.value()));
731 fxcrt::spanclr(usb_span);
734 absl::optional<std::array<uint32_t, 2>> code_page_range =
735 pFace->GetOs2CodePageRange();
736 auto csb_span = pdfium::make_span(pFont->m_dwCsb);
737 if (code_page_range.has_value()) {
738 fxcrt::spancpy(csb_span, pdfium::make_span(code_page_range.value()));
740 fxcrt::spanclr(csb_span);
743 static constexpr uint32_t kNameTag =
746 DataVector<uint8_t> table;
747 size_t table_size = pFace->GetSfntTable(kNameTag, table);
749 table.resize(table_size);
750 if (!pFace->GetSfntTable(kNameTag, table)) {
754 pFont->m_wsFamilyNames = GetNames(table);
755 pFont->m_wsFamilyNames.push_back(
757 pFont->m_wsFaceName = wsFaceName;
758 pFont->m_nFaceIndex =
759 pdfium::base::checked_cast<int32_t>(pFace->GetRec()->face_index);
760 m_InstalledFonts.push_back(std::move(pFont));
765 const WideString& wsFaceName) {
767 int32_t num_faces = 0;
769 RetainPtr<CFX_Face> pFace = LoadFace(pFontStream, index++);
773 if (num_faces == 0) {
775 pdfium::base::checked_cast<int32_t>(pFace->GetRec()->num_faces);
777 RegisterFace(pFace, wsFaceName);
778 pFace->ClearExternalStream();
779 }
while (index < num_faces);
786 uint32_t dwFontStyles,
787 const wchar_t* pszFontFamily) {
788 uint32_t dwHash = ShortFormHash(wCodePage, dwFontStyles, pszFontFamily);
789 auto* pFontVector = &m_Hash2Fonts[dwHash];
790 if (!pFontVector->empty()) {
791 for (
auto iter = pFontVector->begin(); iter != pFontVector->end(); ++iter) {
792 if (*iter !=
nullptr)
799 const FX_FONTDESCRIPTOR* pFD =
800 FindFont(pszFontFamily, dwFontStyles,
true, wCodePage,
801 FGAS_FONTUSB::kNoBitField, 0);
803 pFD = FindFont(
nullptr, dwFontStyles,
true, wCodePage,
804 FGAS_FONTUSB::kNoBitField, 0);
807 pFD = FindFont(
nullptr, dwFontStyles,
false, wCodePage,
808 FGAS_FONTUSB::kNoBitField, 0);
813 RetainPtr<CFGAS_GEFont> pFont =
814 CFGAS_GEFont::LoadFont(pFD->wsFontFace, dwFontStyles, wCodePage);
816 if (!pdfium::Contains(m_Hash2CandidateList, dwHash)) {
817 m_Hash2CandidateList[dwHash] =
818 MatchFonts(wCodePage, dwFontStyles, WideString(pszFontFamily), 0);
820 if (m_Hash2CandidateList[dwHash].empty())
825 LoadFontInternal(pDesc->m_wsFaceName, pDesc->m_nFaceIndex);
831 pFont->SetLogicalFontStyle(dwFontStyles);
832 pFontVector->push_back(pFont);
838 uint32_t dwFontStyles,
839 const wchar_t* pszFontFamily) {
840 if (pdfium::Contains(m_FailedUnicodesSet, wUnicode))
848 ? LongFormHash(wCodePage, wBitField, dwFontStyles, pszFontFamily)
849 : ShortFormHash(wCodePage, dwFontStyles, pszFontFamily);
850 for (
auto& pFont : m_Hash2Fonts[dwHash]) {
851 if (VerifyUnicode(pFont, wUnicode))
854 return GetFontByUnicodeImpl(wUnicode, dwFontStyles, pszFontFamily, dwHash,
855 wCodePage, wBitField);
859 uint32_t dwFontStyles,
862 uint32_t dwHash = ShortFormHash(wCodePage, dwFontStyles, pszFontFamily);
863 std::vector<RetainPtr<CFGAS_GEFont>>* pFontArray = &m_Hash2Fonts[dwHash];
864 if (!pFontArray->empty())
865 return pFontArray->front();
867 const FX_FONTDESCRIPTOR* pFD =
868 FindFont(pszFontFamily, dwFontStyles,
true, wCodePage,
869 FGAS_FONTUSB::kNoBitField, 0);
871 pFD = FindFont(pszFontFamily, dwFontStyles,
false, wCodePage,
872 FGAS_FONTUSB::kNoBitField, 0);
877 RetainPtr<CFGAS_GEFont> pFont =
878 CFGAS_GEFont::LoadFont(pFD->wsFontFace, dwFontStyles, wCodePage);
882 pFont->SetLogicalFontStyle(dwFontStyles);
883 pFontArray->push_back(pFont);
886 return GetFontByCodePage(wCodePage, dwFontStyles, pszFontFamily);
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
virtual bool ReadBlockAtOffset(pdfium::span< uint8_t > buffer, FX_FILESIZE offset)=0
static ByteString Format(const char *pFormat,...)
static WideString FromUTF8(ByteStringView str)
WideString & operator+=(wchar_t ch)
static WideString FromDefANSI(ByteStringView str)
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
static constexpr uint16_t kNoBitField