#include "xfa/fgas/font/cfgas_fontmgr.h"
#include <stdint.h>
#include <algorithm>
#include <array>
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>
#include "build/build_config.h"
#include "core/fxcrt/byteorder.h"
#include "core/fxcrt/cfx_read_only_vector_stream.h"
#include "core/fxcrt/check.h"
#include "core/fxcrt/compiler_specific.h"
#include "core/fxcrt/containers/contains.h"
#include "core/fxcrt/data_vector.h"
#include "core/fxcrt/fixed_size_data_vector.h"
#include "core/fxcrt/fx_codepage.h"
#include "core/fxcrt/fx_extension.h"
#include "core/fxcrt/fx_memcpy_wrappers.h"
#include "core/fxcrt/fx_system.h"
#include "core/fxcrt/numerics/safe_conversions.h"
#include "core/fxcrt/span.h"
#include "core/fxcrt/stl_util.h"
#include "core/fxge/cfx_font.h"
#include "core/fxge/cfx_fontmapper.h"
#include "core/fxge/cfx_fontmgr.h"
#include "core/fxge/cfx_gemodule.h"
#include "core/fxge/fx_font.h"
#include "core/fxge/fx_fontencoding.h"
#include "xfa/fgas/font/cfgas_gefont.h"
#include "xfa/fgas/font/fgas_fontutils.h"
#if BUILDFLAG(IS_WIN)
#include "core/fxcrt/win/win_util.h"
#endif
namespace {
bool VerifyUnicode(const RetainPtr<CFGAS_GEFont>& pFont, wchar_t wcUnicode) { … }
uint32_t ShortFormHash(FX_CodePage wCodePage,
uint32_t dwFontStyles,
WideStringView wsFontFamily) { … }
uint32_t LongFormHash(FX_CodePage wCodePage,
uint16_t wBitField,
uint32_t dwFontStyles,
WideStringView wsFontFamily) { … }
}
#if BUILDFLAG(IS_WIN)
namespace {
struct FX_FONTMATCHPARAMS {
const wchar_t* pwsFamily;
uint32_t dwFontStyles;
uint32_t dwUSB;
bool matchParagraphStyle;
wchar_t wUnicode;
FX_CodePage wCodePage;
};
int32_t GetSimilarityScore(FX_FONTDESCRIPTOR const* pFont,
uint32_t dwFontStyles) {
int32_t iValue = 0;
if (FontStyleIsSymbolic(dwFontStyles) ==
FontStyleIsSymbolic(pFont->dwFontStyles)) {
iValue += 64;
}
if (FontStyleIsFixedPitch(dwFontStyles) ==
FontStyleIsFixedPitch(pFont->dwFontStyles)) {
iValue += 32;
}
if (FontStyleIsSerif(dwFontStyles) == FontStyleIsSerif(pFont->dwFontStyles))
iValue += 16;
if (FontStyleIsScript(dwFontStyles) == FontStyleIsScript(pFont->dwFontStyles))
iValue += 8;
return iValue;
}
const FX_FONTDESCRIPTOR* MatchDefaultFont(
FX_FONTMATCHPARAMS* pParams,
const std::deque<FX_FONTDESCRIPTOR>& fonts) {
const FX_FONTDESCRIPTOR* pBestFont = nullptr;
int32_t iBestSimilar = 0;
for (const auto& font : fonts) {
if (FontStyleIsForceBold(font.dwFontStyles) &&
FontStyleIsItalic(font.dwFontStyles)) {
continue;
}
if (pParams->pwsFamily) {
if (FXSYS_wcsicmp(pParams->pwsFamily, font.wsFontFace))
continue;
if (font.uCharSet == FX_Charset::kSymbol)
return &font;
}
if (font.uCharSet == FX_Charset::kSymbol)
continue;
if (pParams->wCodePage != FX_CodePage::kFailure) {
if (FX_GetCodePageFromCharset(font.uCharSet) != pParams->wCodePage)
continue;
} else {
if (pParams->dwUSB < 128) {
uint32_t dwByte = pParams->dwUSB / 32;
uint32_t dwUSB = 1 << (pParams->dwUSB % 32);
if ((font.FontSignature.fsUsb[dwByte] & dwUSB) == 0)
continue;
}
}
if (pParams->matchParagraphStyle) {
if ((font.dwFontStyles & 0x0F) == (pParams->dwFontStyles & 0x0F))
return &font;
continue;
}
if (pParams->pwsFamily) {
if (FXSYS_wcsicmp(pParams->pwsFamily, font.wsFontFace) == 0)
return &font;
}
int32_t iSimilarValue = GetSimilarityScore(&font, pParams->dwFontStyles);
if (iBestSimilar < iSimilarValue) {
iBestSimilar = iSimilarValue;
pBestFont = &font;
}
}
return iBestSimilar < 1 ? nullptr : pBestFont;
}
uint32_t GetGdiFontStyles(const LOGFONTW& lf) {
uint32_t dwStyles = 0;
if ((lf.lfPitchAndFamily & 0x03) == FIXED_PITCH)
dwStyles |= FXFONT_FIXED_PITCH;
uint8_t nFamilies = lf.lfPitchAndFamily & 0xF0;
if (nFamilies == FF_ROMAN)
dwStyles |= FXFONT_SERIF;
if (nFamilies == FF_SCRIPT)
dwStyles |= FXFONT_SCRIPT;
if (lf.lfCharSet == SYMBOL_CHARSET)
dwStyles |= FXFONT_SYMBOLIC;
return dwStyles;
}
int32_t CALLBACK GdiFontEnumProc(ENUMLOGFONTEX* lpelfe,
NEWTEXTMETRICEX* lpntme,
DWORD dwFontType,
LPARAM lParam) {
if (dwFontType != TRUETYPE_FONTTYPE)
return 1;
const LOGFONTW& lf = ((LPENUMLOGFONTEXW)lpelfe)->elfLogFont;
if (lf.lfFaceName[0] == L'@')
return 1;
FX_FONTDESCRIPTOR font = {};
static_assert(std::is_aggregate_v<decltype(font)>);
font.uCharSet = FX_GetCharsetFromInt(lf.lfCharSet);
font.dwFontStyles = GetGdiFontStyles(lf);
UNSAFE_TODO({
FXSYS_wcsncpy(font.wsFontFace, (const wchar_t*)lf.lfFaceName, 31);
font.wsFontFace[31] = 0;
FXSYS_memcpy(&font.FontSignature, &lpntme->ntmFontSig,
sizeof(lpntme->ntmFontSig));
});
reinterpret_cast<std::deque<FX_FONTDESCRIPTOR>*>(lParam)->push_back(font);
return 1;
}
std::deque<FX_FONTDESCRIPTOR> EnumGdiFonts(const wchar_t* pwsFaceName,
wchar_t wUnicode) {
std::deque<FX_FONTDESCRIPTOR> fonts;
if (!pdfium::IsUser32AndGdi32Available()) {
return fonts;
}
LOGFONTW lfFind = {};
static_assert(std::is_aggregate_v<decltype(lfFind)>);
lfFind.lfCharSet = DEFAULT_CHARSET;
if (pwsFaceName) {
UNSAFE_TODO({
FXSYS_wcsncpy(lfFind.lfFaceName, pwsFaceName, 31);
lfFind.lfFaceName[31] = 0;
});
}
HDC hDC = ::GetDC(nullptr);
EnumFontFamiliesExW(hDC, (LPLOGFONTW)&lfFind, (FONTENUMPROCW)GdiFontEnumProc,
(LPARAM)&fonts, 0);
::ReleaseDC(nullptr, hDC);
return fonts;
}
}
CFGAS_FontMgr::CFGAS_FontMgr() : m_FontFaces(EnumGdiFonts(nullptr, 0xFEFF)) {}
CFGAS_FontMgr::~CFGAS_FontMgr() = default;
bool CFGAS_FontMgr::EnumFonts() {
return true;
}
RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByUnicodeImpl(
wchar_t wUnicode,
uint32_t dwFontStyles,
const wchar_t* pszFontFamily,
uint32_t dwHash,
FX_CodePage wCodePage,
uint16_t wBitField) {
const FX_FONTDESCRIPTOR* pFD = FindFont(pszFontFamily, dwFontStyles, false,
wCodePage, wBitField, wUnicode);
if (!pFD && pszFontFamily) {
pFD =
FindFont(nullptr, dwFontStyles, false, wCodePage, wBitField, wUnicode);
}
if (!pFD)
return nullptr;
FX_CodePage newCodePage = FX_GetCodePageFromCharset(pFD->uCharSet);
RetainPtr<CFGAS_GEFont> pFont =
CFGAS_GEFont::LoadFont(pFD->wsFontFace, dwFontStyles, newCodePage);
if (!pFont)
return nullptr;
pFont->SetLogicalFontStyle(dwFontStyles);
if (!VerifyUnicode(pFont, wUnicode)) {
m_FailedUnicodesSet.insert(wUnicode);
return nullptr;
}
m_Hash2Fonts[dwHash].push_back(pFont);
return pFont;
}
const FX_FONTDESCRIPTOR* CFGAS_FontMgr::FindFont(const wchar_t* pszFontFamily,
uint32_t dwFontStyles,
bool matchParagraphStyle,
FX_CodePage wCodePage,
uint32_t dwUSB,
wchar_t wUnicode) {
FX_FONTMATCHPARAMS params = {};
static_assert(std::is_aggregate_v<decltype(params)>);
params.dwUSB = dwUSB;
params.wUnicode = wUnicode;
params.wCodePage = wCodePage;
params.pwsFamily = pszFontFamily;
params.dwFontStyles = dwFontStyles;
params.matchParagraphStyle = matchParagraphStyle;
const FX_FONTDESCRIPTOR* pDesc = MatchDefaultFont(¶ms, m_FontFaces);
if (pDesc)
return pDesc;
if (!pszFontFamily)
return nullptr;
std::deque<FX_FONTDESCRIPTOR> namedFonts =
EnumGdiFonts(pszFontFamily, wUnicode);
params.pwsFamily = nullptr;
pDesc = MatchDefaultFont(¶ms, namedFonts);
if (!pDesc)
return nullptr;
auto it = std::find(m_FontFaces.rbegin(), m_FontFaces.rend(), *pDesc);
if (it != m_FontFaces.rend())
return &*it;
m_FontFaces.push_back(*pDesc);
return &m_FontFaces.back();
}
#else
namespace {
constexpr auto kCodePages = …;
uint16_t FX_GetCodePageBit(FX_CodePage wCodePage) { … }
uint16_t FX_GetUnicodeBit(wchar_t wcUnicode) { … }
uint16_t ReadUInt16FromSpanAtOffset(pdfium::span<const uint8_t> data,
size_t offset) { … }
extern "C" {
unsigned long ftStreamRead(FXFT_StreamRec* stream,
unsigned long offset,
unsigned char* buffer,
unsigned long count) { … }
void ftStreamClose(FXFT_StreamRec* stream) { … }
}
std::vector<WideString> GetNames(pdfium::span<const uint8_t> name_table) { … }
uint32_t GetFlags(const RetainPtr<CFX_Face>& face) { … }
RetainPtr<IFX_SeekableReadStream> CreateFontStream(CFX_FontMapper* pFontMapper,
size_t index) { … }
RetainPtr<IFX_SeekableReadStream> CreateFontStream(
const ByteString& bsFaceName) { … }
RetainPtr<CFX_Face> LoadFace(
const RetainPtr<IFX_SeekableReadStream>& pFontStream,
int32_t iFaceIndex) { … }
bool VerifyUnicodeForFontDescriptor(CFGAS_FontDescriptor* pDesc,
wchar_t wcUnicode) { … }
bool IsPartName(const WideString& name1, const WideString& name2) { … }
int32_t CalcPenalty(CFGAS_FontDescriptor* pInstalled,
FX_CodePage wCodePage,
uint32_t dwFontStyles,
const WideString& FontName,
wchar_t wcUnicode) { … }
}
CFGAS_FontDescriptor::CFGAS_FontDescriptor() = default;
CFGAS_FontDescriptor::~CFGAS_FontDescriptor() = default;
CFGAS_FontMgr::CFGAS_FontMgr() = default;
CFGAS_FontMgr::~CFGAS_FontMgr() = default;
bool CFGAS_FontMgr::EnumFontsFromFontMapper() { … }
bool CFGAS_FontMgr::EnumFonts() { … }
RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByUnicodeImpl(
wchar_t wUnicode,
uint32_t dwFontStyles,
const wchar_t* pszFontFamily,
uint32_t dwHash,
FX_CodePage wCodePage,
uint16_t ) { … }
RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::LoadFontInternal(
const WideString& wsFaceName,
int32_t iFaceIndex) { … }
std::vector<CFGAS_FontDescriptorInfo> CFGAS_FontMgr::MatchFonts(
FX_CodePage wCodePage,
uint32_t dwFontStyles,
const WideString& FontName,
wchar_t wcUnicode) { … }
void CFGAS_FontMgr::RegisterFace(RetainPtr<CFX_Face> pFace,
const WideString& wsFaceName) { … }
void CFGAS_FontMgr::RegisterFaces(
const RetainPtr<IFX_SeekableReadStream>& pFontStream,
const WideString& wsFaceName) { … }
#endif
RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByCodePage(
FX_CodePage wCodePage,
uint32_t dwFontStyles,
const wchar_t* pszFontFamily) { … }
RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByUnicode(
wchar_t wUnicode,
uint32_t dwFontStyles,
const wchar_t* pszFontFamily) { … }
RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::LoadFont(const wchar_t* pszFontFamily,
uint32_t dwFontStyles,
FX_CodePage wCodePage) { … }