Set *_font_fallbacks default to None (#16941)
Some checks are pending
CI / Check formatting and spelling (push) Waiting to run
CI / (macOS) Run Clippy and tests (push) Waiting to run
CI / (Linux) Run Clippy and tests (push) Waiting to run
CI / (Windows) Run Clippy and tests (push) Waiting to run
CI / Create a macOS bundle (push) Blocked by required conditions
CI / Create a Linux bundle (push) Blocked by required conditions
CI / Create arm64 Linux bundle (push) Blocked by required conditions
Deploy Docs / Deploy Docs (push) Waiting to run
Docs / Check formatting (push) Waiting to run

In the current `default.json`, `*_font_fallbacks=[]`, which results in
the `fallbacks` value in the `Font` struct always being `Some(...)`.

This PR introduces the following improvements:
1. Changed `*_font_fallbacks = []` to `*_font_fallbacks = null` in
`default.json`.
2. Enhanced the macOS and Windows implementations.

Release Notes:

- N/A
This commit is contained in:
张小白 2024-08-29 13:30:46 +08:00 committed by GitHub
parent 6c8836ec21
commit 64fa7a5234
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 89 additions and 83 deletions

View file

@ -28,7 +28,7 @@
"buffer_font_family": "Zed Plex Mono",
// Set the buffer text's font fallbacks, this will be merged with
// the platform's default fallbacks.
"buffer_font_fallbacks": [],
"buffer_font_fallbacks": null,
// The OpenType features to enable for text in the editor.
"buffer_font_features": {
// Disable ligatures:
@ -54,7 +54,7 @@
"ui_font_family": "Zed Plex Sans",
// Set the UI's font fallbacks, this will be merged with the platform's
// default font fallbacks.
"ui_font_fallbacks": [],
"ui_font_fallbacks": null,
// The OpenType features to enable for text in the UI
"ui_font_features": {
// Disable ligatures:

View file

@ -35,50 +35,25 @@ pub fn apply_features_and_fallbacks(
fallbacks: Option<&FontFallbacks>,
) -> anyhow::Result<()> {
unsafe {
let fallback_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
let mut keys = vec![kCTFontFeatureSettingsAttribute];
let mut values = vec![generate_feature_array(features)];
if let Some(fallbacks) = fallbacks {
for user_fallback in fallbacks.fallback_list() {
let name = CFString::from(user_fallback.as_str());
let fallback_desc =
CTFontDescriptorCreateWithNameAndSize(name.as_concrete_TypeRef(), 0.0);
CFArrayAppendValue(fallback_array, fallback_desc as _);
CFRelease(fallback_desc as _);
if !fallbacks.fallback_list().is_empty() {
keys.push(kCTFontCascadeListAttribute);
values.push(generate_fallback_array(
fallbacks,
font.native_font().as_concrete_TypeRef(),
));
}
}
{
let preferred_languages: CFArray<CFString> =
CFArray::wrap_under_create_rule(CFLocaleCopyPreferredLanguages());
let default_fallbacks = CTFontCopyDefaultCascadeListForLanguages(
font.native_font().as_concrete_TypeRef(),
preferred_languages.as_concrete_TypeRef(),
);
let default_fallbacks: CFArray<CTFontDescriptor> =
CFArray::wrap_under_create_rule(default_fallbacks);
default_fallbacks
.iter()
.filter(|desc| desc.font_path().is_some())
.map(|desc| {
CFArrayAppendValue(fallback_array, desc.as_concrete_TypeRef() as _);
});
}
let feature_array = generate_feature_array(features);
let keys = [kCTFontFeatureSettingsAttribute, kCTFontCascadeListAttribute];
let values = [feature_array, fallback_array];
let attrs = CFDictionaryCreate(
kCFAllocatorDefault,
keys.as_ptr() as _,
values.as_ptr() as _,
2,
keys.len() as isize,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks,
);
CFRelease(feature_array as *const _ as _);
CFRelease(fallback_array as *const _ as _);
let new_descriptor = CTFontDescriptorCreateWithAttributes(attrs);
CFRelease(attrs as _);
let new_descriptor = CTFontDescriptor::wrap_under_create_rule(new_descriptor);
@ -97,8 +72,7 @@ pub fn apply_features_and_fallbacks(
fn generate_feature_array(features: &FontFeatures) -> CFMutableArrayRef {
unsafe {
let mut feature_array =
CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
let feature_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
for (tag, value) in features.tag_value_list() {
let keys = [kCTFontOpenTypeFeatureTag, kCTFontOpenTypeFeatureValue];
let values = [
@ -121,6 +95,42 @@ fn generate_feature_array(features: &FontFeatures) -> CFMutableArrayRef {
}
}
fn generate_fallback_array(fallbacks: &FontFallbacks, font_ref: CTFontRef) -> CFMutableArrayRef {
unsafe {
let fallback_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
for user_fallback in fallbacks.fallback_list() {
let name = CFString::from(user_fallback.as_str());
let fallback_desc =
CTFontDescriptorCreateWithNameAndSize(name.as_concrete_TypeRef(), 0.0);
CFArrayAppendValue(fallback_array, fallback_desc as _);
CFRelease(fallback_desc as _);
}
append_system_fallbacks(fallback_array, font_ref);
fallback_array
}
}
fn append_system_fallbacks(fallback_array: CFMutableArrayRef, font_ref: CTFontRef) {
unsafe {
let preferred_languages: CFArray<CFString> =
CFArray::wrap_under_create_rule(CFLocaleCopyPreferredLanguages());
let default_fallbacks = CTFontCopyDefaultCascadeListForLanguages(
font_ref,
preferred_languages.as_concrete_TypeRef(),
);
let default_fallbacks: CFArray<CTFontDescriptor> =
CFArray::wrap_under_create_rule(default_fallbacks);
default_fallbacks
.iter()
.filter(|desc| desc.font_path().is_some())
.map(|desc| {
CFArrayAppendValue(fallback_array, desc.as_concrete_TypeRef() as _);
});
}
}
#[link(name = "CoreText", kind = "framework")]
extern "C" {
static kCTFontOpenTypeFeatureTag: CFStringRef;

View file

@ -275,54 +275,52 @@ impl DirectWriteState {
fn generate_font_fallbacks(
&self,
fallbacks: Option<&FontFallbacks>,
fallbacks: &FontFallbacks,
) -> Result<Option<IDWriteFontFallback>> {
if fallbacks.is_some_and(|fallbacks| fallbacks.fallback_list().is_empty()) {
if fallbacks.fallback_list().is_empty() {
return Ok(None);
}
unsafe {
let builder = self.components.factory.CreateFontFallbackBuilder()?;
let font_set = &self.system_font_collection.GetFontSet()?;
if let Some(fallbacks) = fallbacks {
for family_name in fallbacks.fallback_list() {
let Some(fonts) = font_set
.GetMatchingFonts(
&HSTRING::from(family_name),
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
)
.log_err()
else {
continue;
};
if fonts.GetFontCount() == 0 {
log::error!("No matching font found for {}", family_name);
continue;
}
let font = fonts.GetFontFaceReference(0)?.CreateFontFace()?;
let mut count = 0;
font.GetUnicodeRanges(None, &mut count).ok();
if count == 0 {
continue;
}
let mut unicode_ranges = vec![DWRITE_UNICODE_RANGE::default(); count as usize];
let Some(_) = font
.GetUnicodeRanges(Some(&mut unicode_ranges), &mut count)
.log_err()
else {
continue;
};
let target_family_name = HSTRING::from(family_name);
builder.AddMapping(
&unicode_ranges,
&[target_family_name.as_ptr()],
None,
None,
None,
1.0,
)?;
for family_name in fallbacks.fallback_list() {
let Some(fonts) = font_set
.GetMatchingFonts(
&HSTRING::from(family_name),
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
)
.log_err()
else {
continue;
};
if fonts.GetFontCount() == 0 {
log::error!("No matching font found for {}", family_name);
continue;
}
let font = fonts.GetFontFaceReference(0)?.CreateFontFace()?;
let mut count = 0;
font.GetUnicodeRanges(None, &mut count).ok();
if count == 0 {
continue;
}
let mut unicode_ranges = vec![DWRITE_UNICODE_RANGE::default(); count as usize];
let Some(_) = font
.GetUnicodeRanges(Some(&mut unicode_ranges), &mut count)
.log_err()
else {
continue;
};
let target_family_name = HSTRING::from(family_name);
builder.AddMapping(
&unicode_ranges,
&[target_family_name.as_ptr()],
None,
None,
None,
1.0,
)?;
}
let system_fallbacks = self.components.factory.GetSystemFontFallback()?;
builder.AddMappings(&system_fallbacks)?;
@ -378,10 +376,8 @@ impl DirectWriteState {
else {
continue;
};
let fallbacks = self
.generate_font_fallbacks(font_fallbacks)
.log_err()
.unwrap_or_default();
let fallbacks = font_fallbacks
.and_then(|fallbacks| self.generate_font_fallbacks(fallbacks).log_err().flatten());
let font_info = FontInfo {
font_family: family_name.to_owned(),
font_face,