7#include "core/fxge/win32/cwin32_platform.h"
15#include "core/fxcrt/byteorder.h"
16#include "core/fxcrt/check.h"
17#include "core/fxcrt/compiler_specific.h"
18#include "core/fxcrt/fx_codepage.h"
19#include "core/fxcrt/fx_system.h"
20#include "core/fxcrt/numerics/safe_conversions.h"
21#include "core/fxcrt/raw_span.h"
22#include "core/fxcrt/span.h"
23#include "core/fxcrt/stl_util.h"
24#include "core/fxcrt/win/scoped_select_object.h"
25#include "core/fxcrt/win/win_util.h"
26#include "core/fxge/cfx_folderfontinfo.h"
27#include "core/fxge/cfx_gemodule.h"
32 const char* m_pFaceName;
33 const wchar_t* m_pVariantName;
36constexpr Variant kVariantNames[] = {
37 {
"DFKai-SB", L"\x6A19\x6977\x9AD4"},
42 const char* m_pWinName;
47constexpr auto kBase14Substs =
fxcrt::ToArray<
const Substs>({
48 {
"Courier",
"Courier New",
false,
false},
49 {
"Courier-Bold",
"Courier New",
true,
false},
50 {
"Courier-BoldOblique",
"Courier New",
true,
true},
51 {
"Courier-Oblique",
"Courier New",
false,
true},
52 {
"Helvetica",
"Arial",
false,
false},
53 {
"Helvetica-Bold",
"Arial",
true,
false},
54 {
"Helvetica-BoldOblique",
"Arial",
true,
true},
55 {
"Helvetica-Oblique",
"Arial",
false,
true},
56 {
"Times-Roman",
"Times New Roman",
false,
false},
57 {
"Times-Bold",
"Times New Roman",
true,
false},
58 {
"Times-BoldItalic",
"Times New Roman",
true,
true},
59 {
"Times-Italic",
"Times New Roman",
false,
true},
63 const char* m_pSubFontName;
64 const char* m_pSrcFontName;
67constexpr FontNameMap kJpFontNameMap[] = {
68 {
"MS Mincho",
"Heiseimin-W3"},
69 {
"MS Gothic",
"Jun101-Light"},
74 for (size_t i = 0; i <
std::size(kJpFontNameMap); ++i) {
75 if (!FXSYS_stricmp(name->c_str(), kJpFontNameMap[i].m_pSrcFontName)) {
76 *name = kJpFontNameMap[i].m_pSubFontName;
85HFONT Win32CreateFont(
int weight,
90 return ::CreateFontA(-10, 0, 0, 0, weight, italic, 0, 0,
91 static_cast<
int>(charset), OUT_TT_ONLY_PRECIS, 0, 0,
97 CFX_Win32FallbackFontInfo() =
default;
98 ~CFX_Win32FallbackFontInfo()
override =
default;
101 void* MapFont(
int weight,
111 ~CFX_Win32FontInfo()
override;
115 void* MapFont(
int weight,
120 void* GetFont(
const ByteString& face)
override {
return nullptr; }
121 size_t GetFontData(
void* hFont,
123 pdfium::span<uint8_t> buffer)
override;
124 bool GetFaceName(
void* hFont,
ByteString* name)
override;
125 bool GetFontCharset(
void* hFont,
FX_Charset* charset)
override;
126 void DeleteFont(
void* hFont)
override;
128 void AddInstalledFont(
const LOGFONTA* plf, uint32_t font_type);
131 bool IsSupportedFont(
const LOGFONTA* plf);
132 void GetGBPreference(
ByteString& face,
int weight,
int pitch_family);
133 void GetJapanesePreference(
ByteString& face,
int weight,
int pitch_family);
135 void* GetFontFromList(
int weight,
139 pdfium::span<
const char*
const> font_faces);
148int CALLBACK FontEnumProc(
const LOGFONTA* plf,
149 const TEXTMETRICA* lpntme,
152 CFX_Win32FontInfo* pFontInfo =
reinterpret_cast<CFX_Win32FontInfo*>(lParam);
153 pFontInfo->AddInstalledFont(plf, font_type);
157CFX_Win32FontInfo::CFX_Win32FontInfo() : m_hDC(CreateCompatibleDC(
nullptr)) {}
159CFX_Win32FontInfo::~CFX_Win32FontInfo() {
163bool CFX_Win32FontInfo::IsSupportedFont(
const LOGFONTA* plf) {
164 HFONT hFont = CreateFontIndirectA(plf);
166 size_t font_size = GetFontData(hFont, 0, {});
167 if (font_size != GDI_ERROR && font_size >=
sizeof(uint32_t)) {
169 auto span =
pdfium::as_writable_bytes(
pdfium::span_from_ref(header));
170 GetFontData(hFont, 0, span);
171 header = fxcrt::GetUInt32MSBFirst(span);
174 header ==
FXBSTR_ID('t', 'r', 'u', 'e') || header == 0x00010000 ||
175 header == 0x00020000 ||
183void CFX_Win32FontInfo::AddInstalledFont(
const LOGFONTA* plf,
184 uint32_t font_type) {
186 if (name.GetLength() > 0 && name[0] ==
'@')
189 if (name == m_LastFamily) {
190 m_pMapper->AddInstalledFont(name, FX_GetCharsetFromInt(plf->lfCharSet));
193 if (!(font_type & TRUETYPE_FONTTYPE)) {
194 if (!(font_type & DEVICE_FONTTYPE) || !IsSupportedFont(plf))
198 m_pMapper->AddInstalledFont(name, FX_GetCharsetFromInt(plf->lfCharSet));
205 static_assert(std::is_aggregate_v<
decltype(lf)>);
207 lf.lfFaceName[0] = 0;
208 lf.lfPitchAndFamily = 0;
209 EnumFontFamiliesExA(m_hDC, &lf,
reinterpret_cast<FONTENUMPROCA>(FontEnumProc),
210 reinterpret_cast<uintptr_t>(
this), 0);
219 m_pMapper->InstalledFontNameStartingWith(name);
220 if (maybe_installed.has_value())
221 return maybe_installed.value();
224 m_pMapper->LocalizedFontNameStartingWith(name);
225 if (maybe_localized.has_value())
226 return maybe_localized.value();
231void* CFX_Win32FontInfo::GetFontFromList(
236 pdfium::span<
const char*
const> font_faces) {
237 DCHECK(!font_faces.empty());
242 for (
const char* face : font_faces) {
243 font = Win32CreateFont(weight, italic, charset, pitch_family, face);
244 ByteString actual_face;
245 if (GetFaceName(font, &actual_face) && actual_face.EqualNoCase(face))
251void* CFX_Win32FallbackFontInfo::MapFont(
int weight,
271 return FindFont(weight, bItalic, charset, pitch_family, face, !bCJK);
274void CFX_Win32FontInfo::GetGBPreference(
ByteString& face,
277 if (face.Contains(
"KaiTi") || face.Contains(
"\xbf\xac")) {
278 if (m_KaiTi.IsEmpty()) {
279 m_KaiTi = FindFont(
"KaiTi");
280 if (m_KaiTi.IsEmpty()) {
285 }
else if (face.Contains(
"FangSong") || face.Contains(
"\xb7\xc2\xcb\xce")) {
286 if (m_FangSong.IsEmpty()) {
287 m_FangSong = FindFont(
"FangSong");
288 if (m_FangSong.IsEmpty()) {
289 m_FangSong =
"SimSun";
293 }
else if (face.Contains(
"SimSun") || face.Contains(
"\xcb\xce")) {
295 }
else if (face.Contains(
"SimHei") || face.Contains(
"\xba\xda")) {
297 }
else if (!(pitch_family & FF_ROMAN) && weight > 550) {
304void CFX_Win32FontInfo::GetJapanesePreference(
ByteString& face,
307 if (face.Contains(
"Gothic") ||
308 face.Contains(
"\x83\x53\x83\x56\x83\x62\x83\x4e")) {
309 if (face.Contains(
"PGothic") ||
310 face.Contains(
"\x82\x6f\x83\x53\x83\x56\x83\x62\x83\x4e")) {
312 }
else if (face.Contains(
"UI Gothic")) {
313 face
= "MS UI Gothic";
315 if (face.Contains(
"HGSGothicM") || face.Contains(
"HGMaruGothicMPRO")) {
323 if (face.Contains(
"Mincho") || face.Contains(
"\x96\xbe\x92\xa9")) {
324 if (face.Contains(
"PMincho") || face.Contains(
"\x82\x6f\x96\xbe\x92\xa9")) {
331 if (GetSubFontName(&face))
334 if (!(pitch_family & FF_ROMAN) && weight > 400) {
341void* CFX_Win32FontInfo::MapFont(
int weight,
347 for (
int iBaseFont = 0; iBaseFont < 12; iBaseFont++) {
348 if (new_face ==
ByteStringView(kBase14Substs[iBaseFont].m_pName)) {
349 new_face = kBase14Substs[iBaseFont].m_pWinName;
350 weight = kBase14Substs[iBaseFont].m_bBold ? FW_BOLD : FW_NORMAL;
351 bItalic = kBase14Substs[iBaseFont].m_bItalic;
358 int subst_pitch_family;
360 case FX_Charset::kShiftJIS:
361 subst_pitch_family = FF_ROMAN;
366 subst_pitch_family = 0;
369 subst_pitch_family = pitch_family;
372 HFONT hFont = Win32CreateFont(weight, bItalic, charset, subst_pitch_family,
375 if (GetFaceName(hFont, &actual_new_face) &&
381 for (
const Variant& variant : kVariantNames) {
382 if (new_face
!= variant.m_pFaceName)
386 if (wsFace
== wsName)
389 ::DeleteObject(hFont);
395 GetJapanesePreference(new_face, weight, pitch_family);
398 GetGBPreference(new_face, weight, pitch_family);
404 static const char*
const kMonospaceFonts[] = {
"Microsoft YaHei",
406 static const char*
const kProportionalFonts[] = {
"Microsoft JHengHei",
408 pdfium::span<
const char*
const> candidate_fonts =
409 new_face.Contains(
"MSung") ? kMonospaceFonts : kProportionalFonts;
410 return GetFontFromList(weight, bItalic, charset, subst_pitch_family,
416 return Win32CreateFont(weight, bItalic, charset, subst_pitch_family,
420void CFX_Win32FontInfo::DeleteFont(
void* hFont) {
421 ::DeleteObject(hFont);
424size_t CFX_Win32FontInfo::GetFontData(
void* hFont,
426 pdfium::span<uint8_t> buffer) {
429 size_t size = ::GetFontData(m_hDC, table, 0, buffer.data(),
430 pdfium::checked_cast<DWORD>(buffer.size()));
431 return size != GDI_ERROR ? size : 0;
434bool CFX_Win32FontInfo::GetFaceName(
void* hFont,
ByteString* name) {
437 if (::GetTextFaceA(m_hDC, std::size(facebuf), facebuf) == 0)
444bool CFX_Win32FontInfo::GetFontCharset(
void* hFont,
FX_Charset* charset) {
447 ::GetTextMetrics(m_hDC, &tm);
448 *charset = FX_GetCharsetFromInt(tm.tmCharSet);
468 auto font_info =
std::make_unique<CFX_Win32FallbackFontInfo>();
470 for (; *user_paths; user_paths++) {
471 font_info->AddPath(*user_paths);
478 return std::make_unique<CFX_Win32FontInfo>();
482 auto fallback_info =
std::make_unique<CFX_Win32FallbackFontInfo>();
485 CHAR windows_path[MAX_PATH] = {};
486 DWORD path_len = ::GetWindowsDirectoryA(windows_path, MAX_PATH);
487 if (path_len > 0 && path_len < MAX_PATH) {
489 fonts_path
+= "\\Fonts";
490 fallback_info->AddPath(fonts_path);
492 return fallback_info;
496std::unique_ptr<CFX_GEModule::PlatformIface>
498 return std::make_unique<CWin32Platform>();
fxcrt::ByteString ByteString
void * GetSubstFont(const ByteString &face)
void * FindFont(int weight, bool bItalic, FX_Charset charset, int pitch_family, const ByteString &family, bool bMatchName)
static CFX_GEModule * Get()
const char ** GetUserFontPaths() const
bool EqualNoCase(ByteStringView str) const
ByteString & operator+=(const char *str)
ByteString & operator=(const char *str)
bool operator!=(const char *ptr) const
bool operator==(const WideString &other) const
static WideString FromDefANSI(ByteStringView str)
WideString(const wchar_t *ptr)
constexpr uint32_t FXBSTR_ID(uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4)
uint32_t FromBE32(uint32_t x)
bool IsUser32AndGdi32Available()
fxcrt::ByteStringView ByteStringView
fxcrt::WideString WideString