From 06d2d9da5fbf7fe2f0dff4d5b4a9de48049729db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=B0=8F=E7=99=BD?= <364772080@qq.com> Date: Thu, 25 Apr 2024 04:00:25 +0800 Subject: [PATCH] windows: Let the OS decide which font to use as the UI font (#10877) On my computer, I get `Yahei UI`, which makes sense since I'm using a Chinese operating system, and `Yahei UI` includes Chinese codepoints. On an English operating system, `Segoe UI` should be used instead. Edit: I also choose to use the UI font selected by the system as the fallback font, rather than hard-coding the `Arial` font. Release Notes: - N/A --- .../gpui/src/platform/windows/direct_write.rs | 100 ++++++++++++------ 1 file changed, 65 insertions(+), 35 deletions(-) diff --git a/crates/gpui/src/platform/windows/direct_write.rs b/crates/gpui/src/platform/windows/direct_write.rs index d536a6c4d007669752730cc5d106962a27c9151a..96b95114c67671199ef9ecf2cdcfebdc323f0668 100644 --- a/crates/gpui/src/platform/windows/direct_write.rs +++ b/crates/gpui/src/platform/windows/direct_write.rs @@ -16,9 +16,11 @@ use windows::{ Direct2D::{Common::*, *}, DirectWrite::*, Dxgi::Common::*, + Gdi::LOGFONTW, Imaging::{D2D::IWICImagingFactory2, *}, }, System::{Com::*, SystemServices::LOCALE_NAME_MAX_LENGTH}, + UI::WindowsAndMessaging::*, }, }; @@ -51,6 +53,7 @@ unsafe impl Send for DirectWriteComponent {} struct DirectWriteState { components: DirectWriteComponent, + system_ui_font_name: SharedString, system_font_collection: IDWriteFontCollection1, custom_font_collection: IDWriteFontCollection1, fonts: Vec, @@ -106,9 +109,11 @@ impl DirectWriteTextSystem { .factory .CreateFontCollectionFromFontSet(&custom_font_set)? }; + let system_ui_font_name = get_system_ui_font_name(); Ok(Self(RwLock::new(DirectWriteState { components, + system_ui_font_name, system_font_collection, custom_font_collection, fonts: Vec::new(), @@ -309,53 +314,55 @@ impl DirectWriteState { } fn select_font(&mut self, target_font: &Font) -> FontId { - let family_name = if target_font.family == ".SystemUIFont" { - // https://learn.microsoft.com/en-us/windows/win32/uxguide/vis-fonts - // Segoe UI is the Windows font intended for user interface text strings. - "Segoe UI" - } else { - target_font.family.as_ref() - }; unsafe { - // try to find target font in custom font collection first - self.get_font_id_from_font_collection( - family_name, - target_font.weight, - target_font.style, - &target_font.features, - false, - ) - .or_else(|| { - self.get_font_id_from_font_collection( - family_name, + if target_font.family == ".SystemUIFont" { + let family = self.system_ui_font_name.clone(); + self.find_font_id( + family.as_ref(), target_font.weight, target_font.style, &target_font.features, - true, ) - }) - .or_else(|| { - self.update_system_font_collection(); - self.get_font_id_from_font_collection( - family_name, + .unwrap() + } else { + self.find_font_id( + target_font.family.as_ref(), target_font.weight, target_font.style, &target_font.features, - true, ) + .unwrap_or_else(|| { + let family = self.system_ui_font_name.clone(); + log::error!("{} not found, use {} instead.", target_font.family, family); + self.get_font_id_from_font_collection( + family.as_ref(), + target_font.weight, + target_font.style, + &target_font.features, + true, + ) + .unwrap() + }) + } + } + } + + unsafe fn find_font_id( + &mut self, + family_name: &str, + weight: FontWeight, + style: FontStyle, + features: &FontFeatures, + ) -> Option { + // try to find target font in custom font collection first + self.get_font_id_from_font_collection(family_name, weight, style, features, false) + .or_else(|| { + self.get_font_id_from_font_collection(family_name, weight, style, features, true) }) .or_else(|| { - log::error!("{} not found, use Arial instead.", family_name); - self.get_font_id_from_font_collection( - "Arial", - target_font.weight, - target_font.style, - &target_font.features, - false, - ) + self.update_system_font_collection(); + self.get_font_id_from_font_collection(family_name, weight, style, features, true) }) - .unwrap() - } } fn layout_line(&mut self, text: &str, font_size: Pixels, font_runs: &[FontRun]) -> LineLayout { @@ -1271,6 +1278,29 @@ fn translate_color(color: &DWRITE_COLOR_F) -> D2D1_COLOR_F { } } +fn get_system_ui_font_name() -> SharedString { + unsafe { + let mut info: LOGFONTW = std::mem::zeroed(); + let font_family = if SystemParametersInfoW( + SPI_GETICONTITLELOGFONT, + std::mem::size_of::() as u32, + Some(&mut info as *mut _ as _), + SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS(0), + ) + .log_err() + .is_none() + { + // https://learn.microsoft.com/en-us/windows/win32/uxguide/vis-fonts + // Segoe UI is the Windows font intended for user interface text strings. + "Segoe UI".into() + } else { + String::from_utf16_lossy(&info.lfFaceName).into() + }; + log::info!("Use {} as UI font.", font_family); + font_family + } +} + const DEFAULT_LOCALE_NAME: PCWSTR = windows::core::w!("en-US"); const BRUSH_COLOR: D2D1_COLOR_F = D2D1_COLOR_F { r: 1.0,