7#include "core/fxge/win32/cwin32_platform.h"
13#include "core/fxcrt/fx_codepage.h"
14#include "core/fxge/cfx_folderfontinfo.h"
15#include "core/fxge/cfx_gemodule.h"
16#include "third_party/base/check.h"
17#include "third_party/base/containers/span.h"
18#include "third_party/base/numerics/safe_conversions.h"
19#include "third_party/base/win/scoped_select_object.h"
20#include "third_party/base/win/win_util.h"
24using ScopedSelectObject = pdfium::base::win::ScopedSelectObject;
27 const char* m_pFaceName;
28 pdfium::span<
const char> m_pVariantName;
31constexpr Variant kVariantNames[] = {
32 {
"DFKai-SB", pdfium::make_span(
"\x19\x6A\x77\x69\xD4\x9A")},
37 const char* m_pWinName;
42constexpr Substs kBase14Substs[] = {
43 {
"Courier",
"Courier New",
false,
false},
44 {
"Courier-Bold",
"Courier New",
true,
false},
45 {
"Courier-BoldOblique",
"Courier New",
true,
true},
46 {
"Courier-Oblique",
"Courier New",
false,
true},
47 {
"Helvetica",
"Arial",
false,
false},
48 {
"Helvetica-Bold",
"Arial",
true,
false},
49 {
"Helvetica-BoldOblique",
"Arial",
true,
true},
50 {
"Helvetica-Oblique",
"Arial",
false,
true},
51 {
"Times-Roman",
"Times New Roman",
false,
false},
52 {
"Times-Bold",
"Times New Roman",
true,
false},
53 {
"Times-BoldItalic",
"Times New Roman",
true,
true},
54 {
"Times-Italic",
"Times New Roman",
false,
true},
58 const char* m_pSubFontName;
59 const char* m_pSrcFontName;
62constexpr FontNameMap kJpFontNameMap[] = {
63 {
"MS Mincho",
"Heiseimin-W3"},
64 {
"MS Gothic",
"Jun101-Light"},
67bool GetSubFontName(ByteString* name) {
68 for (size_t i = 0; i <
std::size(kJpFontNameMap); ++i) {
69 if (!FXSYS_stricmp(name
->c_str(), kJpFontNameMap[i].m_pSrcFontName)) {
70 *name = kJpFontNameMap[i].m_pSubFontName;
78HFONT Win32CreateFont(
int weight,
83 return ::CreateFontA(-10, 0, 0, 0, weight, italic, 0, 0,
84 static_cast<
int>(charset), OUT_TT_ONLY_PRECIS, 0, 0,
90 CFX_Win32FallbackFontInfo() =
default;
91 ~CFX_Win32FallbackFontInfo()
override =
default;
94 void* MapFont(
int weight,
98 const ByteString& face)
override;
104 ~CFX_Win32FontInfo()
override;
108 void* MapFont(
int weight,
112 const ByteString& face)
override;
113 void* GetFont(
const ByteString& face)
override {
return nullptr; }
114 size_t GetFontData(
void* hFont,
116 pdfium::span<uint8_t> buffer)
override;
117 bool GetFaceName(
void* hFont, ByteString* name)
override;
118 bool GetFontCharset(
void* hFont,
FX_Charset* charset)
override;
119 void DeleteFont(
void* hFont)
override;
121 void AddInstalledFont(
const LOGFONTA* plf, uint32_t font_type);
124 bool IsSupportedFont(
const LOGFONTA* plf);
125 void GetGBPreference(ByteString& face,
int weight,
int pitch_family);
126 void GetJapanesePreference(ByteString& face,
int weight,
int pitch_family);
127 ByteString FindFont(
const ByteString& name);
128 void* GetFontFromList(
int weight,
132 pdfium::span<
const char*
const> font_faces);
136 ByteString m_LastFamily;
138 ByteString m_FangSong;
141int CALLBACK FontEnumProc(
const LOGFONTA* plf,
142 const TEXTMETRICA* lpntme,
145 CFX_Win32FontInfo* pFontInfo =
reinterpret_cast<CFX_Win32FontInfo*>(lParam);
146 pFontInfo->AddInstalledFont(plf, font_type);
150CFX_Win32FontInfo::CFX_Win32FontInfo() : m_hDC(CreateCompatibleDC(
nullptr)) {}
152CFX_Win32FontInfo::~CFX_Win32FontInfo() {
156bool CFX_Win32FontInfo::IsSupportedFont(
const LOGFONTA* plf) {
157 HFONT hFont = CreateFontIndirectA(plf);
159 size_t font_size = GetFontData(hFont, 0, {});
160 if (font_size != GDI_ERROR && font_size >=
sizeof(uint32_t)) {
162 auto span = pdfium::as_writable_bytes(pdfium::span_from_ref(header));
163 GetFontData(hFont, 0, span);
164 header = FXSYS_UINT32_GET_MSBFIRST(span);
167 header ==
FXBSTR_ID('t', 'r', 'u', 'e') || header == 0x00010000 ||
168 header == 0x00020000 ||
176void CFX_Win32FontInfo::AddInstalledFont(
const LOGFONTA* plf,
177 uint32_t font_type) {
178 ByteString name(plf->lfFaceName);
179 if (name.GetLength() > 0 && name
[0
] ==
'@')
182 if (name == m_LastFamily) {
183 m_pMapper->AddInstalledFont(name, FX_GetCharsetFromInt(plf->lfCharSet));
186 if (!(font_type & TRUETYPE_FONTTYPE)) {
187 if (!(font_type & DEVICE_FONTTYPE) || !IsSupportedFont(plf))
191 m_pMapper->AddInstalledFont(name, FX_GetCharsetFromInt(plf->lfCharSet));
198 memset(&lf, 0,
sizeof(LOGFONTA));
200 lf.lfFaceName[0] = 0;
201 lf.lfPitchAndFamily = 0;
202 EnumFontFamiliesExA(m_hDC, &lf,
reinterpret_cast<FONTENUMPROCA>(FontEnumProc),
203 reinterpret_cast<uintptr_t>(
this), 0);
207ByteString CFX_Win32FontInfo::FindFont(
const ByteString& name) {
211 absl::optional<ByteString> maybe_installed =
212 m_pMapper->InstalledFontNameStartingWith(name);
213 if (maybe_installed.has_value())
214 return maybe_installed.value();
216 absl::optional<ByteString> maybe_localized =
217 m_pMapper->LocalizedFontNameStartingWith(name);
218 if (maybe_localized.has_value())
219 return maybe_localized.value();
224void* CFX_Win32FontInfo::GetFontFromList(
229 pdfium::span<
const char*
const> font_faces) {
230 DCHECK(!font_faces.empty());
235 for (
const char* face : font_faces) {
236 font = Win32CreateFont(weight, italic, charset, pitch_family, face);
237 ByteString actual_face;
238 if (GetFaceName(font, &actual_face) && actual_face.EqualNoCase(face))
244void* CFX_Win32FallbackFontInfo::MapFont(
int weight,
248 const ByteString& face) {
264 return FindFont(weight, bItalic, charset, pitch_family, face, !bCJK);
267void CFX_Win32FontInfo::GetGBPreference(ByteString& face,
270 if (face.Contains(
"KaiTi") || face.Contains(
"\xbf\xac")) {
271 if (m_KaiTi.IsEmpty()) {
272 m_KaiTi = FindFont(
"KaiTi");
273 if (m_KaiTi.IsEmpty()) {
278 }
else if (face.Contains(
"FangSong") || face.Contains(
"\xb7\xc2\xcb\xce")) {
279 if (m_FangSong.IsEmpty()) {
280 m_FangSong = FindFont(
"FangSong");
281 if (m_FangSong.IsEmpty()) {
282 m_FangSong =
"SimSun";
286 }
else if (face.Contains(
"SimSun") || face.Contains(
"\xcb\xce")) {
288 }
else if (face.Contains(
"SimHei") || face.Contains(
"\xba\xda")) {
290 }
else if (!(pitch_family & FF_ROMAN) && weight > 550) {
297void CFX_Win32FontInfo::GetJapanesePreference(ByteString& face,
300 if (face.Contains(
"Gothic") ||
301 face.Contains(
"\x83\x53\x83\x56\x83\x62\x83\x4e")) {
302 if (face.Contains(
"PGothic") ||
303 face.Contains(
"\x82\x6f\x83\x53\x83\x56\x83\x62\x83\x4e")) {
305 }
else if (face.Contains(
"UI Gothic")) {
306 face
= "MS UI Gothic";
308 if (face.Contains(
"HGSGothicM") || face.Contains(
"HGMaruGothicMPRO")) {
316 if (face.Contains(
"Mincho") || face.Contains(
"\x96\xbe\x92\xa9")) {
317 if (face.Contains(
"PMincho") || face.Contains(
"\x82\x6f\x96\xbe\x92\xa9")) {
324 if (GetSubFontName(&face))
327 if (!(pitch_family & FF_ROMAN) && weight > 400) {
334void* CFX_Win32FontInfo::MapFont(
int weight,
338 const ByteString& face) {
339 ByteString new_face = face;
340 for (
int iBaseFont = 0; iBaseFont < 12; iBaseFont++) {
341 if (new_face == ByteStringView(kBase14Substs[iBaseFont].m_pName)) {
342 new_face
= kBase14Substs[iBaseFont].m_pWinName;
343 weight = kBase14Substs[iBaseFont].m_bBold ? FW_BOLD : FW_NORMAL;
344 bItalic = kBase14Substs[iBaseFont].m_bItalic;
351 int subst_pitch_family;
353 case FX_Charset::kShiftJIS:
354 subst_pitch_family = FF_ROMAN;
359 subst_pitch_family = 0;
362 subst_pitch_family = pitch_family;
365 HFONT hFont = Win32CreateFont(weight, bItalic, charset, subst_pitch_family,
367 ByteString actual_new_face;
368 if (GetFaceName(hFont, &actual_new_face) &&
373 WideString wsFace = WideString
::FromDefANSI(actual_new_face.AsStringView()
);
374 for (
const Variant& variant : kVariantNames) {
375 if (new_face != variant.m_pFaceName)
379 WideString::FromUTF16LE(pdfium::as_bytes(variant.m_pVariantName));
380 if (wsFace == wsName)
383 ::DeleteObject(hFont);
389 GetJapanesePreference(new_face, weight, pitch_family);
392 GetGBPreference(new_face, weight, pitch_family);
398 static const char*
const kMonospaceFonts[] = {
"Microsoft YaHei",
400 static const char*
const kProportionalFonts[] = {
"Microsoft JHengHei",
402 pdfium::span<
const char*
const> candidate_fonts =
403 new_face.Contains(
"MSung") ? kMonospaceFonts : kProportionalFonts;
404 return GetFontFromList(weight, bItalic, charset, subst_pitch_family,
410 return Win32CreateFont(weight, bItalic, charset, subst_pitch_family,
414void CFX_Win32FontInfo::DeleteFont(
void* hFont) {
415 ::DeleteObject(hFont);
418size_t CFX_Win32FontInfo::GetFontData(
void* hFont,
420 pdfium::span<uint8_t> buffer) {
421 ScopedSelectObject select_object(m_hDC,
static_cast<HFONT>(hFont));
422 table = FXSYS_UINT32_GET_MSBFIRST(
reinterpret_cast<uint8_t*>(&table));
423 size_t size = ::GetFontData(m_hDC, table, 0, buffer.data(),
424 pdfium::base::checked_cast<DWORD>(buffer.size()));
425 return size != GDI_ERROR ? size : 0;
428bool CFX_Win32FontInfo::GetFaceName(
void* hFont, ByteString* name) {
429 ScopedSelectObject select_object(m_hDC,
static_cast<HFONT>(hFont));
431 if (::GetTextFaceA(m_hDC, std::size(facebuf), facebuf) == 0)
438bool CFX_Win32FontInfo::GetFontCharset(
void* hFont,
FX_Charset* charset) {
439 ScopedSelectObject select_object(m_hDC,
static_cast<HFONT>(hFont));
441 ::GetTextMetrics(m_hDC, &tm);
442 *charset = FX_GetCharsetFromInt(tm.tmCharSet);
453 if (pdfium::base::win::IsUser32AndGdi32Available())
461 auto font_info =
std::make_unique<CFX_Win32FallbackFontInfo>();
462 for (; *user_paths; user_paths++)
463 font_info->AddPath(*user_paths);
464 return std::move(font_info);
467 if (pdfium::base::win::IsUser32AndGdi32Available())
468 return std::make_unique<CFX_Win32FontInfo>();
471 auto fallback_info =
std::make_unique<CFX_Win32FallbackFontInfo>();
474 CHAR windows_path[MAX_PATH] = {};
475 DWORD path_len = ::GetWindowsDirectoryA(windows_path, MAX_PATH);
476 if (path_len > 0 && path_len < MAX_PATH) {
477 ByteString fonts_path(windows_path);
478 fonts_path
+= "\\Fonts";
479 fallback_info->AddPath(fonts_path);
481 return fallback_info;
485std::unique_ptr<CFX_GEModule::PlatformIface>
487 return std::make_unique<CWin32Platform>();
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)
const char * c_str() const
CharType operator[](const size_t index) const
static WideString FromDefANSI(ByteStringView str)
constexpr uint32_t FXBSTR_ID(uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4)