windows: Support all OpenType font features (#10756)

Release Notes:

- Added support for all `OpenType` font features to DirectWrite.



https://github.com/zed-industries/zed/assets/14981363/cb2848cd-9178-4d87-881a-54dc646b2b61

---------

Co-authored-by: Mikayla Maki <mikayla@zed.dev>
This commit is contained in:
张小白 2024-04-27 04:58:12 +08:00 committed by GitHub
parent 268cb948a7
commit 11dc3c2582
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 114 additions and 25 deletions

View file

@ -1,3 +1,7 @@
#[cfg(target_os = "windows")]
use crate::SharedString;
#[cfg(target_os = "windows")]
use itertools::Itertools;
use schemars::{
schema::{InstanceType, Schema, SchemaObject, SingleOrVec},
JsonSchema,
@ -7,10 +11,14 @@ macro_rules! create_definitions {
($($(#[$meta:meta])* ($name:ident, $idx:expr)),* $(,)?) => {
/// The OpenType features that can be configured for a given font.
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
#[derive(Default, Clone, Eq, PartialEq, Hash)]
pub struct FontFeatures {
enabled: u64,
disabled: u64,
#[cfg(target_os = "windows")]
other_enabled: SharedString,
#[cfg(target_os = "windows")]
other_disabled: SharedString,
}
impl FontFeatures {
@ -47,6 +55,14 @@ macro_rules! create_definitions {
}
}
)*
{
for name in self.other_enabled.as_ref().chars().chunks(4).into_iter() {
result.push((name.collect::<String>(), true));
}
for name in self.other_disabled.as_ref().chars().chunks(4).into_iter() {
result.push((name.collect::<String>(), false));
}
}
result
}
}
@ -59,6 +75,15 @@ macro_rules! create_definitions {
debug.field(stringify!($name), &value);
};
)*
#[cfg(target_os = "windows")]
{
for name in self.other_enabled.as_ref().chars().chunks(4).into_iter() {
debug.field(name.collect::<String>().as_str(), &true);
}
for name in self.other_disabled.as_ref().chars().chunks(4).into_iter() {
debug.field(name.collect::<String>().as_str(), &false);
}
}
debug.finish()
}
}
@ -80,6 +105,7 @@ macro_rules! create_definitions {
formatter.write_str("a map of font features")
}
#[cfg(not(target_os = "windows"))]
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
@ -100,6 +126,54 @@ macro_rules! create_definitions {
}
Ok(FontFeatures { enabled, disabled })
}
#[cfg(target_os = "windows")]
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut enabled: u64 = 0;
let mut disabled: u64 = 0;
let mut other_enabled = "".to_owned();
let mut other_disabled = "".to_owned();
while let Some((key, value)) = access.next_entry::<String, Option<bool>>()? {
let idx = match key.as_str() {
$(stringify!($name) => Some($idx),)*
other_feature => {
if other_feature.len() != 4 || !other_feature.is_ascii() {
log::error!("Incorrect feature name: {}", other_feature);
continue;
}
None
},
};
if let Some(idx) = idx {
match value {
Some(true) => enabled |= 1 << idx,
Some(false) => disabled |= 1 << idx,
None => {}
};
} else {
match value {
Some(true) => other_enabled.push_str(key.as_str()),
Some(false) => other_disabled.push_str(key.as_str()),
None => {}
};
}
}
let other_enabled = if other_enabled.is_empty() {
"".into()
} else {
other_enabled.into()
};
let other_disabled = if other_disabled.is_empty() {
"".into()
} else {
other_disabled.into()
};
Ok(FontFeatures { enabled, disabled, other_enabled, other_disabled })
}
}
let features = deserializer.deserialize_map(FontFeaturesVisitor)?;
@ -125,6 +199,16 @@ macro_rules! create_definitions {
}
)*
#[cfg(target_os = "windows")]
{
for name in self.other_enabled.as_ref().chars().chunks(4).into_iter() {
map.serialize_entry(name.collect::<String>().as_str(), &true)?;
}
for name in self.other_disabled.as_ref().chars().chunks(4).into_iter() {
map.serialize_entry(name.collect::<String>().as_str(), &false)?;
}
}
map.end()
}
}