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 <iterator>
10#include <memory>
11#include <utility>
12
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"
21
22namespace {
23
24using ScopedSelectObject = pdfium::base::win::ScopedSelectObject;
25
26struct Variant {
27 const char* m_pFaceName;
28 pdfium::span<const char> m_pVariantName;
29};
30
31constexpr Variant kVariantNames[] = {
32 {"DFKai-SB", pdfium::make_span("\x19\x6A\x77\x69\xD4\x9A")},
33};
34
35struct Substs {
36 const char* m_pName;
37 const char* m_pWinName;
38 bool m_bBold;
39 bool m_bItalic;
40};
41
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},
55};
56
57struct FontNameMap {
58 const char* m_pSubFontName;
59 const char* m_pSrcFontName;
60};
61
62constexpr FontNameMap kJpFontNameMap[] = {
63 {"MS Mincho", "Heiseimin-W3"},
64 {"MS Gothic", "Jun101-Light"},
65};
66
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;
71 return true;
72 }
73 }
74 return false;
75}
76
77// Wraps CreateFontA() so callers don't have to specify all the arguments.
78HFONT Win32CreateFont(int weight,
79 bool italic,
80 FX_Charset charset,
81 int pitch_family,
82 const char* face) {
83 return ::CreateFontA(-10, 0, 0, 0, weight, italic, 0, 0,
84 static_cast<int>(charset), OUT_TT_ONLY_PRECIS, 0, 0,
85 pitch_family, face);
86}
87
88class CFX_Win32FallbackFontInfo final : public CFX_FolderFontInfo {
89 public:
90 CFX_Win32FallbackFontInfo() = default;
91 ~CFX_Win32FallbackFontInfo() override = default;
92
93 // CFX_FolderFontInfo:
94 void* MapFont(int weight,
95 bool bItalic,
96 FX_Charset charset,
97 int pitch_family,
98 const ByteString& face) override;
99};
100
101class CFX_Win32FontInfo final : public SystemFontInfoIface {
102 public:
103 CFX_Win32FontInfo();
104 ~CFX_Win32FontInfo() override;
105
106 // SystemFontInfoIface:
107 bool EnumFontList(CFX_FontMapper* pMapper) override;
108 void* MapFont(int weight,
109 bool bItalic,
110 FX_Charset charset,
111 int pitch_family,
112 const ByteString& face) override;
113 void* GetFont(const ByteString& face) override { return nullptr; }
114 size_t GetFontData(void* hFont,
115 uint32_t table,
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;
120
121 void AddInstalledFont(const LOGFONTA* plf, uint32_t font_type);
122
123 private:
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,
129 bool italic,
130 FX_Charset charset,
131 int pitch_family,
132 pdfium::span<const char* const> font_faces);
133
134 const HDC m_hDC;
135 UnownedPtr<CFX_FontMapper> m_pMapper;
136 ByteString m_LastFamily;
137 ByteString m_KaiTi;
138 ByteString m_FangSong;
139};
140
141int CALLBACK FontEnumProc(const LOGFONTA* plf,
142 const TEXTMETRICA* lpntme,
143 uint32_t font_type,
144 LPARAM lParam) {
145 CFX_Win32FontInfo* pFontInfo = reinterpret_cast<CFX_Win32FontInfo*>(lParam);
146 pFontInfo->AddInstalledFont(plf, font_type);
147 return 1;
148}
149
150CFX_Win32FontInfo::CFX_Win32FontInfo() : m_hDC(CreateCompatibleDC(nullptr)) {}
151
152CFX_Win32FontInfo::~CFX_Win32FontInfo() {
153 DeleteDC(m_hDC);
154}
155
156bool CFX_Win32FontInfo::IsSupportedFont(const LOGFONTA* plf) {
157 HFONT hFont = CreateFontIndirectA(plf);
158 bool ret = false;
159 size_t font_size = GetFontData(hFont, 0, {});
160 if (font_size != GDI_ERROR && font_size >= sizeof(uint32_t)) {
161 uint32_t header;
162 auto span = pdfium::as_writable_bytes(pdfium::span_from_ref(header));
163 GetFontData(hFont, 0, span);
164 header = FXSYS_UINT32_GET_MSBFIRST(span);
165 ret = header == FXBSTR_ID('O', 'T', 'T', 'O') ||
166 header == FXBSTR_ID('t', 't', 'c', 'f') ||
167 header == FXBSTR_ID('t', 'r', 'u', 'e') || header == 0x00010000 ||
168 header == 0x00020000 ||
169 (header & 0xFFFF0000) == FXBSTR_ID(0x80, 0x01, 0x00, 0x00) ||
170 (header & 0xFFFF0000) == FXBSTR_ID('%', '!', 0, 0);
171 }
172 DeleteFont(hFont);
173 return ret;
174}
175
176void CFX_Win32FontInfo::AddInstalledFont(const LOGFONTA* plf,
177 uint32_t font_type) {
178 ByteString name(plf->lfFaceName);
179 if (name.GetLength() > 0 && name[0] == '@')
180 return;
181
182 if (name == m_LastFamily) {
183 m_pMapper->AddInstalledFont(name, FX_GetCharsetFromInt(plf->lfCharSet));
184 return;
185 }
186 if (!(font_type & TRUETYPE_FONTTYPE)) {
187 if (!(font_type & DEVICE_FONTTYPE) || !IsSupportedFont(plf))
188 return;
189 }
190
191 m_pMapper->AddInstalledFont(name, FX_GetCharsetFromInt(plf->lfCharSet));
192 m_LastFamily = name;
193}
194
195bool CFX_Win32FontInfo::EnumFontList(CFX_FontMapper* pMapper) {
196 m_pMapper = pMapper;
197 LOGFONTA lf;
198 memset(&lf, 0, sizeof(LOGFONTA));
199 lf.lfCharSet = static_cast<int>(FX_Charset::kDefault);
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);
204 return true;
205}
206
207ByteString CFX_Win32FontInfo::FindFont(const ByteString& name) {
208 if (!m_pMapper)
209 return name;
210
211 absl::optional<ByteString> maybe_installed =
212 m_pMapper->InstalledFontNameStartingWith(name);
213 if (maybe_installed.has_value())
214 return maybe_installed.value();
215
216 absl::optional<ByteString> maybe_localized =
217 m_pMapper->LocalizedFontNameStartingWith(name);
218 if (maybe_localized.has_value())
219 return maybe_localized.value();
220
221 return ByteString();
222}
223
224void* CFX_Win32FontInfo::GetFontFromList(
225 int weight,
226 bool italic,
227 FX_Charset charset,
228 int pitch_family,
229 pdfium::span<const char* const> font_faces) {
230 DCHECK(!font_faces.empty());
231
232 // Initialization not needed because of DCHECK() above and the assignment in
233 // the for-loop below.
234 HFONT font;
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))
239 break;
240 }
241 return font;
242}
243
244void* CFX_Win32FallbackFontInfo::MapFont(int weight,
245 bool bItalic,
246 FX_Charset charset,
247 int pitch_family,
248 const ByteString& face) {
249 void* font = GetSubstFont(face);
250 if (font)
251 return font;
252
253 bool bCJK = true;
254 switch (charset) {
259 break;
260 default:
261 bCJK = false;
262 break;
263 }
264 return FindFont(weight, bItalic, charset, pitch_family, face, !bCJK);
265}
266
267void CFX_Win32FontInfo::GetGBPreference(ByteString& face,
268 int weight,
269 int pitch_family) {
270 if (face.Contains("KaiTi") || face.Contains("\xbf\xac")) {
271 if (m_KaiTi.IsEmpty()) {
272 m_KaiTi = FindFont("KaiTi");
273 if (m_KaiTi.IsEmpty()) {
274 m_KaiTi = "SimSun";
275 }
276 }
277 face = m_KaiTi;
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";
283 }
284 }
285 face = m_FangSong;
286 } else if (face.Contains("SimSun") || face.Contains("\xcb\xce")) {
287 face = "SimSun";
288 } else if (face.Contains("SimHei") || face.Contains("\xba\xda")) {
289 face = "SimHei";
290 } else if (!(pitch_family & FF_ROMAN) && weight > 550) {
291 face = "SimHei";
292 } else {
293 face = "SimSun";
294 }
295}
296
297void CFX_Win32FontInfo::GetJapanesePreference(ByteString& face,
298 int weight,
299 int pitch_family) {
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")) {
304 face = "MS PGothic";
305 } else if (face.Contains("UI Gothic")) {
306 face = "MS UI Gothic";
307 } else {
308 if (face.Contains("HGSGothicM") || face.Contains("HGMaruGothicMPRO")) {
309 face = "MS PGothic";
310 } else {
311 face = "MS Gothic";
312 }
313 }
314 return;
315 }
316 if (face.Contains("Mincho") || face.Contains("\x96\xbe\x92\xa9")) {
317 if (face.Contains("PMincho") || face.Contains("\x82\x6f\x96\xbe\x92\xa9")) {
318 face = "MS PMincho";
319 } else {
320 face = "MS Mincho";
321 }
322 return;
323 }
324 if (GetSubFontName(&face))
325 return;
326
327 if (!(pitch_family & FF_ROMAN) && weight > 400) {
328 face = "MS PGothic";
329 } else {
330 face = "MS PMincho";
331 }
332}
333
334void* CFX_Win32FontInfo::MapFont(int weight,
335 bool bItalic,
336 FX_Charset charset,
337 int pitch_family,
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;
345 break;
346 }
347 }
348 if (charset == FX_Charset::kANSI || charset == FX_Charset::kSymbol)
349 charset = FX_Charset::kDefault;
350
351 int subst_pitch_family;
352 switch (charset) {
353 case FX_Charset::kShiftJIS:
354 subst_pitch_family = FF_ROMAN;
355 break;
359 subst_pitch_family = 0;
360 break;
361 default:
362 subst_pitch_family = pitch_family;
363 break;
364 }
365 HFONT hFont = Win32CreateFont(weight, bItalic, charset, subst_pitch_family,
366 new_face.c_str());
367 ByteString actual_new_face;
368 if (GetFaceName(hFont, &actual_new_face) &&
369 new_face.EqualNoCase(actual_new_face.AsStringView())) {
370 return hFont;
371 }
372
373 WideString wsFace = WideString::FromDefANSI(actual_new_face.AsStringView());
374 for (const Variant& variant : kVariantNames) {
375 if (new_face != variant.m_pFaceName)
376 continue;
377
378 WideString wsName =
379 WideString::FromUTF16LE(pdfium::as_bytes(variant.m_pVariantName));
380 if (wsFace == wsName)
381 return hFont;
382 }
383 ::DeleteObject(hFont);
384 if (charset == FX_Charset::kDefault)
385 return nullptr;
386
387 switch (charset) {
389 GetJapanesePreference(new_face, weight, pitch_family);
390 break;
392 GetGBPreference(new_face, weight, pitch_family);
393 break;
395 new_face = "Gulim";
396 break;
398 static const char* const kMonospaceFonts[] = {"Microsoft YaHei",
399 "MingLiU"};
400 static const char* const kProportionalFonts[] = {"Microsoft JHengHei",
401 "PMingLiU"};
402 pdfium::span<const char* const> candidate_fonts =
403 new_face.Contains("MSung") ? kMonospaceFonts : kProportionalFonts;
404 return GetFontFromList(weight, bItalic, charset, subst_pitch_family,
405 candidate_fonts);
406 }
407 default:
408 break;
409 }
410 return Win32CreateFont(weight, bItalic, charset, subst_pitch_family,
411 new_face.c_str());
412}
413
414void CFX_Win32FontInfo::DeleteFont(void* hFont) {
415 ::DeleteObject(hFont);
416}
417
418size_t CFX_Win32FontInfo::GetFontData(void* hFont,
419 uint32_t table,
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;
426}
427
428bool CFX_Win32FontInfo::GetFaceName(void* hFont, ByteString* name) {
429 ScopedSelectObject select_object(m_hDC, static_cast<HFONT>(hFont));
430 char facebuf[100];
431 if (::GetTextFaceA(m_hDC, std::size(facebuf), facebuf) == 0)
432 return false;
433
434 *name = facebuf;
435 return true;
436}
437
438bool CFX_Win32FontInfo::GetFontCharset(void* hFont, FX_Charset* charset) {
439 ScopedSelectObject select_object(m_hDC, static_cast<HFONT>(hFont));
440 TEXTMETRIC tm;
441 ::GetTextMetrics(m_hDC, &tm);
442 *charset = FX_GetCharsetFromInt(tm.tmCharSet);
443 return true;
444}
445
446} // namespace
447
448CWin32Platform::CWin32Platform() = default;
449
450CWin32Platform::~CWin32Platform() = default;
451
452void CWin32Platform::Init() {
453 if (pdfium::base::win::IsUser32AndGdi32Available())
454 m_GdiplusExt.Load();
455}
456
459 auto** user_paths = CFX_GEModule::Get()->GetUserFontPaths();
460 if (user_paths) {
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);
465 }
466
467 if (pdfium::base::win::IsUser32AndGdi32Available())
468 return std::make_unique<CFX_Win32FontInfo>();
469
470 // Select the fallback font information class if GDI is disabled.
471 auto fallback_info = std::make_unique<CFX_Win32FallbackFontInfo>();
472 // Construct the font path manually, SHGetKnownFolderPath won't work under
473 // a restrictive sandbox.
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);
480 }
481 return fallback_info;
482}
483
484// static
485std::unique_ptr<CFX_GEModule::PlatformIface>
486CFX_GEModule::PlatformIface::Create() {
487 return std::make_unique<CWin32Platform>();
488}
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 & operator+=(const char *str)
ByteString & operator=(const char *str)
const char * c_str() const
Definition bytestring.h:76
CharType operator[](const size_t index) const
Definition bytestring.h:150
static WideString FromDefANSI(ByteStringView str)
FX_Charset
Definition fx_codepage.h:70
@ kChineseTraditional
@ kChineseSimplified
constexpr uint32_t FXBSTR_ID(uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4)
Definition fx_string.h:19