Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cwin32_platform.cpp
Go to the documentation of this file.
1// Copyright 2020 The PDFium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "core/fxge/win32/cwin32_platform.h"
8
9#include <array>
10#include <iterator>
11#include <memory>
12#include <type_traits>
13#include <utility>
14
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"
28
29namespace {
30
31struct Variant {
32 const char* m_pFaceName;
33 const wchar_t* m_pVariantName;
34};
35
36constexpr Variant kVariantNames[] = {
37 {"DFKai-SB", L"\x6A19\x6977\x9AD4"},
38};
39
40struct Substs {
41 const char* m_pName;
42 const char* m_pWinName;
43 bool m_bBold;
44 bool m_bItalic;
45};
46
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},
60});
61
62struct FontNameMap {
63 const char* m_pSubFontName;
64 const char* m_pSrcFontName;
65};
66
67constexpr FontNameMap kJpFontNameMap[] = {
68 {"MS Mincho", "Heiseimin-W3"},
69 {"MS Gothic", "Jun101-Light"},
70};
71
72bool GetSubFontName(ByteString* name) {
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;
77 return true;
78 }
79 }
80 });
81 return false;
82}
83
84// Wraps CreateFontA() so callers don't have to specify all the arguments.
85HFONT Win32CreateFont(int weight,
86 bool italic,
87 FX_Charset charset,
88 int pitch_family,
89 const char* face) {
90 return ::CreateFontA(-10, 0, 0, 0, weight, italic, 0, 0,
91 static_cast<int>(charset), OUT_TT_ONLY_PRECIS, 0, 0,
92 pitch_family, face);
93}
94
95class CFX_Win32FallbackFontInfo final : public CFX_FolderFontInfo {
96 public:
97 CFX_Win32FallbackFontInfo() = default;
98 ~CFX_Win32FallbackFontInfo() override = default;
99
100 // CFX_FolderFontInfo:
101 void* MapFont(int weight,
102 bool bItalic,
103 FX_Charset charset,
104 int pitch_family,
105 const ByteString& face) override;
106};
107
108class CFX_Win32FontInfo final : public SystemFontInfoIface {
109 public:
110 CFX_Win32FontInfo();
111 ~CFX_Win32FontInfo() override;
112
113 // SystemFontInfoIface:
114 bool EnumFontList(CFX_FontMapper* pMapper) override;
115 void* MapFont(int weight,
116 bool bItalic,
117 FX_Charset charset,
118 int pitch_family,
119 const ByteString& face) override;
120 void* GetFont(const ByteString& face) override { return nullptr; }
121 size_t GetFontData(void* hFont,
122 uint32_t table,
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;
127
128 void AddInstalledFont(const LOGFONTA* plf, uint32_t font_type);
129
130 private:
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);
134 ByteString FindFont(const ByteString& name);
135 void* GetFontFromList(int weight,
136 bool italic,
137 FX_Charset charset,
138 int pitch_family,
139 pdfium::span<const char* const> font_faces);
140
141 const HDC m_hDC;
142 UnownedPtr<CFX_FontMapper> m_pMapper;
143 ByteString m_LastFamily;
144 ByteString m_KaiTi;
145 ByteString m_FangSong;
146};
147
148int CALLBACK FontEnumProc(const LOGFONTA* plf,
149 const TEXTMETRICA* lpntme,
150 uint32_t font_type,
151 LPARAM lParam) {
152 CFX_Win32FontInfo* pFontInfo = reinterpret_cast<CFX_Win32FontInfo*>(lParam);
153 pFontInfo->AddInstalledFont(plf, font_type);
154 return 1;
155}
156
157CFX_Win32FontInfo::CFX_Win32FontInfo() : m_hDC(CreateCompatibleDC(nullptr)) {}
158
159CFX_Win32FontInfo::~CFX_Win32FontInfo() {
160 DeleteDC(m_hDC);
161}
162
163bool CFX_Win32FontInfo::IsSupportedFont(const LOGFONTA* plf) {
164 HFONT hFont = CreateFontIndirectA(plf);
165 bool ret = false;
166 size_t font_size = GetFontData(hFont, 0, {});
167 if (font_size != GDI_ERROR && font_size >= sizeof(uint32_t)) {
168 uint32_t header;
169 auto span = pdfium::as_writable_bytes(pdfium::span_from_ref(header));
170 GetFontData(hFont, 0, span);
171 header = fxcrt::GetUInt32MSBFirst(span);
172 ret = header == FXBSTR_ID('O', 'T', 'T', 'O') ||
173 header == FXBSTR_ID('t', 't', 'c', 'f') ||
174 header == FXBSTR_ID('t', 'r', 'u', 'e') || header == 0x00010000 ||
175 header == 0x00020000 ||
176 (header & 0xFFFF0000) == FXBSTR_ID(0x80, 0x01, 0x00, 0x00) ||
177 (header & 0xFFFF0000) == FXBSTR_ID('%', '!', 0, 0);
178 }
179 DeleteFont(hFont);
180 return ret;
181}
182
183void CFX_Win32FontInfo::AddInstalledFont(const LOGFONTA* plf,
184 uint32_t font_type) {
185 ByteString name(plf->lfFaceName);
186 if (name.GetLength() > 0 && name[0] == '@')
187 return;
188
189 if (name == m_LastFamily) {
190 m_pMapper->AddInstalledFont(name, FX_GetCharsetFromInt(plf->lfCharSet));
191 return;
192 }
193 if (!(font_type & TRUETYPE_FONTTYPE)) {
194 if (!(font_type & DEVICE_FONTTYPE) || !IsSupportedFont(plf))
195 return;
196 }
197
198 m_pMapper->AddInstalledFont(name, FX_GetCharsetFromInt(plf->lfCharSet));
199 m_LastFamily = name;
200}
201
202bool CFX_Win32FontInfo::EnumFontList(CFX_FontMapper* pMapper) {
203 m_pMapper = pMapper;
204 LOGFONTA lf = {}; // Aggregate initialization.
205 static_assert(std::is_aggregate_v<decltype(lf)>);
206 lf.lfCharSet = static_cast<int>(FX_Charset::kDefault);
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);
211 return true;
212}
213
214ByteString CFX_Win32FontInfo::FindFont(const ByteString& name) {
215 if (!m_pMapper)
216 return name;
217
218 std::optional<ByteString> maybe_installed =
219 m_pMapper->InstalledFontNameStartingWith(name);
220 if (maybe_installed.has_value())
221 return maybe_installed.value();
222
223 std::optional<ByteString> maybe_localized =
224 m_pMapper->LocalizedFontNameStartingWith(name);
225 if (maybe_localized.has_value())
226 return maybe_localized.value();
227
228 return ByteString();
229}
230
231void* CFX_Win32FontInfo::GetFontFromList(
232 int weight,
233 bool italic,
234 FX_Charset charset,
235 int pitch_family,
236 pdfium::span<const char* const> font_faces) {
237 DCHECK(!font_faces.empty());
238
239 // Initialization not needed because of DCHECK() above and the assignment in
240 // the for-loop below.
241 HFONT font;
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))
246 break;
247 }
248 return font;
249}
250
251void* CFX_Win32FallbackFontInfo::MapFont(int weight,
252 bool bItalic,
253 FX_Charset charset,
254 int pitch_family,
255 const ByteString& face) {
256 void* font = GetSubstFont(face);
257 if (font)
258 return font;
259
260 bool bCJK = true;
261 switch (charset) {
266 break;
267 default:
268 bCJK = false;
269 break;
270 }
271 return FindFont(weight, bItalic, charset, pitch_family, face, !bCJK);
272}
273
274void CFX_Win32FontInfo::GetGBPreference(ByteString& face,
275 int weight,
276 int pitch_family) {
277 if (face.Contains("KaiTi") || face.Contains("\xbf\xac")) {
278 if (m_KaiTi.IsEmpty()) {
279 m_KaiTi = FindFont("KaiTi");
280 if (m_KaiTi.IsEmpty()) {
281 m_KaiTi = "SimSun";
282 }
283 }
284 face = m_KaiTi;
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";
290 }
291 }
292 face = m_FangSong;
293 } else if (face.Contains("SimSun") || face.Contains("\xcb\xce")) {
294 face = "SimSun";
295 } else if (face.Contains("SimHei") || face.Contains("\xba\xda")) {
296 face = "SimHei";
297 } else if (!(pitch_family & FF_ROMAN) && weight > 550) {
298 face = "SimHei";
299 } else {
300 face = "SimSun";
301 }
302}
303
304void CFX_Win32FontInfo::GetJapanesePreference(ByteString& face,
305 int weight,
306 int pitch_family) {
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")) {
311 face = "MS PGothic";
312 } else if (face.Contains("UI Gothic")) {
313 face = "MS UI Gothic";
314 } else {
315 if (face.Contains("HGSGothicM") || face.Contains("HGMaruGothicMPRO")) {
316 face = "MS PGothic";
317 } else {
318 face = "MS Gothic";
319 }
320 }
321 return;
322 }
323 if (face.Contains("Mincho") || face.Contains("\x96\xbe\x92\xa9")) {
324 if (face.Contains("PMincho") || face.Contains("\x82\x6f\x96\xbe\x92\xa9")) {
325 face = "MS PMincho";
326 } else {
327 face = "MS Mincho";
328 }
329 return;
330 }
331 if (GetSubFontName(&face))
332 return;
333
334 if (!(pitch_family & FF_ROMAN) && weight > 400) {
335 face = "MS PGothic";
336 } else {
337 face = "MS PMincho";
338 }
339}
340
341void* CFX_Win32FontInfo::MapFont(int weight,
342 bool bItalic,
343 FX_Charset charset,
344 int pitch_family,
345 const ByteString& face) {
346 ByteString new_face = face;
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;
352 break;
353 }
354 }
355 if (charset == FX_Charset::kANSI || charset == FX_Charset::kSymbol)
356 charset = FX_Charset::kDefault;
357
358 int subst_pitch_family;
359 switch (charset) {
360 case FX_Charset::kShiftJIS:
361 subst_pitch_family = FF_ROMAN;
362 break;
366 subst_pitch_family = 0;
367 break;
368 default:
369 subst_pitch_family = pitch_family;
370 break;
371 }
372 HFONT hFont = Win32CreateFont(weight, bItalic, charset, subst_pitch_family,
373 new_face.c_str());
374 ByteString actual_new_face;
375 if (GetFaceName(hFont, &actual_new_face) &&
376 new_face.EqualNoCase(actual_new_face.AsStringView())) {
377 return hFont;
378 }
379
380 WideString wsFace = WideString::FromDefANSI(actual_new_face.AsStringView());
381 for (const Variant& variant : kVariantNames) {
382 if (new_face != variant.m_pFaceName)
383 continue;
384
385 WideString wsName(variant.m_pVariantName);
386 if (wsFace == wsName)
387 return hFont;
388 }
389 ::DeleteObject(hFont);
390 if (charset == FX_Charset::kDefault)
391 return nullptr;
392
393 switch (charset) {
395 GetJapanesePreference(new_face, weight, pitch_family);
396 break;
398 GetGBPreference(new_face, weight, pitch_family);
399 break;
401 new_face = "Gulim";
402 break;
404 static const char* const kMonospaceFonts[] = {"Microsoft YaHei",
405 "MingLiU"};
406 static const char* const kProportionalFonts[] = {"Microsoft JHengHei",
407 "PMingLiU"};
408 pdfium::span<const char* const> candidate_fonts =
409 new_face.Contains("MSung") ? kMonospaceFonts : kProportionalFonts;
410 return GetFontFromList(weight, bItalic, charset, subst_pitch_family,
411 candidate_fonts);
412 }
413 default:
414 break;
415 }
416 return Win32CreateFont(weight, bItalic, charset, subst_pitch_family,
417 new_face.c_str());
418}
419
420void CFX_Win32FontInfo::DeleteFont(void* hFont) {
421 ::DeleteObject(hFont);
422}
423
424size_t CFX_Win32FontInfo::GetFontData(void* hFont,
425 uint32_t table,
426 pdfium::span<uint8_t> buffer) {
427 pdfium::ScopedSelectObject select_object(m_hDC, static_cast<HFONT>(hFont));
428 table = fxcrt::FromBE32(table);
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;
432}
433
434bool CFX_Win32FontInfo::GetFaceName(void* hFont, ByteString* name) {
435 pdfium::ScopedSelectObject select_object(m_hDC, static_cast<HFONT>(hFont));
436 char facebuf[100];
437 if (::GetTextFaceA(m_hDC, std::size(facebuf), facebuf) == 0)
438 return false;
439
440 *name = facebuf;
441 return true;
442}
443
444bool CFX_Win32FontInfo::GetFontCharset(void* hFont, FX_Charset* charset) {
445 pdfium::ScopedSelectObject select_object(m_hDC, static_cast<HFONT>(hFont));
446 TEXTMETRIC tm;
447 ::GetTextMetrics(m_hDC, &tm);
448 *charset = FX_GetCharsetFromInt(tm.tmCharSet);
449 return true;
450}
451
452} // namespace
453
454CWin32Platform::CWin32Platform() = default;
455
456CWin32Platform::~CWin32Platform() = default;
457
458void CWin32Platform::Init() {
460 m_GdiplusExt.Load();
461 }
462}
463
466 auto** user_paths = CFX_GEModule::Get()->GetUserFontPaths();
467 if (user_paths) {
468 auto font_info = std::make_unique<CFX_Win32FallbackFontInfo>();
470 for (; *user_paths; user_paths++) {
471 font_info->AddPath(*user_paths);
472 }
473 });
474 return font_info;
475 }
476
478 return std::make_unique<CFX_Win32FontInfo>();
479 }
480
481 // Select the fallback font information class if GDI is disabled.
482 auto fallback_info = std::make_unique<CFX_Win32FallbackFontInfo>();
483 // Construct the font path manually, SHGetKnownFolderPath won't work under
484 // a restrictive sandbox.
485 CHAR windows_path[MAX_PATH] = {};
486 DWORD path_len = ::GetWindowsDirectoryA(windows_path, MAX_PATH);
487 if (path_len > 0 && path_len < MAX_PATH) {
488 ByteString fonts_path(windows_path);
489 fonts_path += "\\Fonts";
490 fallback_info->AddPath(fonts_path);
491 }
492 return fallback_info;
493}
494
495// static
496std::unique_ptr<CFX_GEModule::PlatformIface>
497CFX_GEModule::PlatformIface::Create() {
498 return std::make_unique<CWin32Platform>();
499}
fxcrt::ByteString ByteString
Definition bytestring.h:180
#define DCHECK
Definition check.h:33
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
std::unique_ptr< SystemFontInfoIface > CreateDefaultSystemFontInfo() override
void Init() override
~CWin32Platform() override
bool EqualNoCase(ByteStringView str) const
ByteString()=default
ByteString & operator+=(const char *str)
ByteString & operator=(const char *str)
bool operator!=(const char *ptr) const
Definition bytestring.h:65
bool operator==(const WideString &other) const
static WideString FromDefANSI(ByteStringView str)
WideString(const wchar_t *ptr)
#define UNSAFE_TODO(...)
FX_Charset
Definition fx_codepage.h:71
@ kChineseTraditional
Definition fx_codepage.h:91
@ kChineseSimplified
Definition fx_codepage.h:90
constexpr uint32_t FXBSTR_ID(uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4)
Definition fx_string.h:19
uint32_t FromBE32(uint32_t x)
Definition byteorder.h:82
bool IsUser32AndGdi32Available()
Definition win_util.cc:12
fxcrt::ByteStringView ByteStringView
fxcrt::WideString WideString
Definition widestring.h:207