@@ -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:
@@ -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;
@@ -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,