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
This commit is contained in:
张小白 2024-04-25 04:00:25 +08:00 committed by GitHub
parent 9e88155a48
commit 06d2d9da5f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -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<FontInfo>,
@ -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,
)
.unwrap()
} else {
self.find_font_id(
target_font.family.as_ref(),
target_font.weight,
target_font.style,
&target_font.features,
)
.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<FontId> {
// 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(|| {
self.update_system_font_collection();
self.get_font_id_from_font_collection(
family_name,
target_font.weight,
target_font.style,
&target_font.features,
true,
)
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,
)
})
.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::<LOGFONTW>() 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,