Add support for setting font features on Linux (#27808)
Fixes #15752. - Updated `cosmic_text` to 0.14.0 - Made a basic implementation for setting font features. #12176 is not fixed by this PR. Release Notes: - Added initial support for `font_features` on Linux
This commit is contained in:
parent
e13ecc07bc
commit
2b249f9e68
3 changed files with 47 additions and 15 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -3534,9 +3534,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cosmic-text"
|
||||
version = "0.13.2"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e418dd4f5128c3e93eab12246391c54a20c496811131f85754dc8152ee207892"
|
||||
checksum = "3e1ecbb5db9a4c2ee642df67bcfa8f044dd867dbbaa21bfab139cbc204ffbf67"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"fontdb 0.16.2",
|
||||
|
|
|
@ -161,7 +161,7 @@ blade-graphics = { workspace = true, optional = true }
|
|||
blade-macros = { workspace = true, optional = true }
|
||||
blade-util = { workspace = true, optional = true }
|
||||
bytemuck = { version = "1", optional = true }
|
||||
cosmic-text = { version = "0.13.2", optional = true }
|
||||
cosmic-text = { version = "0.14.0", optional = true }
|
||||
font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "5474cfad4b719a72ec8ed2cb7327b2b01fd10568", features = [
|
||||
"source-fontconfig-dlopen",
|
||||
], optional = true }
|
||||
|
|
|
@ -6,8 +6,8 @@ use crate::{
|
|||
use anyhow::{Context as _, Ok, Result, anyhow};
|
||||
use collections::HashMap;
|
||||
use cosmic_text::{
|
||||
Attrs, AttrsList, CacheKey, Family, Font as CosmicTextFont, FontSystem, ShapeBuffer, ShapeLine,
|
||||
SwashCache,
|
||||
Attrs, AttrsList, CacheKey, Family, Font as CosmicTextFont, FontFeatures as CosmicFontFeatures,
|
||||
FontSystem, ShapeBuffer, ShapeLine, SwashCache,
|
||||
};
|
||||
|
||||
use itertools::Itertools;
|
||||
|
@ -21,15 +21,29 @@ use std::{borrow::Cow, sync::Arc};
|
|||
|
||||
pub(crate) struct CosmicTextSystem(RwLock<CosmicTextSystemState>);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
struct FontKey {
|
||||
family: SharedString,
|
||||
features: FontFeatures,
|
||||
}
|
||||
|
||||
impl FontKey {
|
||||
fn new(family: SharedString, features: FontFeatures) -> Self {
|
||||
Self { family, features }
|
||||
}
|
||||
}
|
||||
|
||||
struct CosmicTextSystemState {
|
||||
swash_cache: SwashCache,
|
||||
font_system: FontSystem,
|
||||
scratch: ShapeBuffer,
|
||||
/// Contains all already loaded fonts, including all faces. Indexed by `FontId`.
|
||||
loaded_fonts_store: Vec<Arc<CosmicTextFont>>,
|
||||
/// Contains enabled font features for each loaded font.
|
||||
features_store: Vec<CosmicFontFeatures>,
|
||||
/// Caches the `FontId`s associated with a specific family to avoid iterating the font database
|
||||
/// for every font face in a family.
|
||||
font_ids_by_family_cache: HashMap<SharedString, SmallVec<[FontId; 4]>>,
|
||||
font_ids_by_family_cache: HashMap<FontKey, SmallVec<[FontId; 4]>>,
|
||||
/// The name of each font associated with the given font id
|
||||
postscript_names: HashMap<FontId, String>,
|
||||
}
|
||||
|
@ -44,6 +58,7 @@ impl CosmicTextSystem {
|
|||
swash_cache: SwashCache::new(),
|
||||
scratch: ShapeBuffer::default(),
|
||||
loaded_fonts_store: Vec::new(),
|
||||
features_store: Vec::new(),
|
||||
font_ids_by_family_cache: HashMap::default(),
|
||||
postscript_names: HashMap::default(),
|
||||
}))
|
||||
|
@ -78,15 +93,13 @@ impl PlatformTextSystem for CosmicTextSystem {
|
|||
fn font_id(&self, font: &Font) -> Result<FontId> {
|
||||
// todo(linux): Do we need to use CosmicText's Font APIs? Can we consolidate this to use font_kit?
|
||||
let mut state = self.0.write();
|
||||
|
||||
let candidates = if let Some(font_ids) = state.font_ids_by_family_cache.get(&font.family) {
|
||||
let key = FontKey::new(font.family.clone(), font.features.clone());
|
||||
let candidates = if let Some(font_ids) = state.font_ids_by_family_cache.get(&key) {
|
||||
font_ids.as_slice()
|
||||
} else {
|
||||
let font_ids = state.load_family(&font.family, &font.features)?;
|
||||
state
|
||||
.font_ids_by_family_cache
|
||||
.insert(font.family.clone(), font_ids);
|
||||
state.font_ids_by_family_cache[&font.family].as_ref()
|
||||
state.font_ids_by_family_cache.insert(key.clone(), font_ids);
|
||||
state.font_ids_by_family_cache[&key].as_ref()
|
||||
};
|
||||
|
||||
// todo(linux) ideally we would make fontdb's `find_best_match` pub instead of using font-kit here
|
||||
|
@ -229,9 +242,24 @@ impl CosmicTextSystemState {
|
|||
continue;
|
||||
};
|
||||
|
||||
// Convert features into cosmic_text struct.
|
||||
let mut font_features = CosmicFontFeatures::new();
|
||||
for feature in _features.0.iter() {
|
||||
let name_bytes: [u8; 4] = feature
|
||||
.0
|
||||
.as_bytes()
|
||||
.try_into()
|
||||
.map_err(|_| anyhow!("Incorrect feature flag format"))?;
|
||||
|
||||
let tag = cosmic_text::FeatureTag::new(&name_bytes);
|
||||
|
||||
font_features.set(tag, feature.1);
|
||||
}
|
||||
|
||||
let font_id = FontId(self.loaded_fonts_store.len());
|
||||
font_ids.push(font_id);
|
||||
self.loaded_fonts_store.push(font);
|
||||
self.features_store.push(font_features);
|
||||
self.postscript_names.insert(font_id, postscript_name);
|
||||
}
|
||||
|
||||
|
@ -361,18 +389,22 @@ impl CosmicTextSystemState {
|
|||
|
||||
#[profiling::function]
|
||||
fn layout_line(&mut self, text: &str, font_size: Pixels, font_runs: &[FontRun]) -> LineLayout {
|
||||
let mut attrs_list = AttrsList::new(Attrs::new());
|
||||
let mut attrs_list = AttrsList::new(&Attrs::new());
|
||||
let mut offs = 0;
|
||||
for run in font_runs {
|
||||
let font = &self.loaded_fonts_store[run.font_id.0];
|
||||
let font = self.font_system.db().face(font.id()).unwrap();
|
||||
|
||||
let features = self.features_store[run.font_id.0].clone();
|
||||
|
||||
attrs_list.add_span(
|
||||
offs..(offs + run.len),
|
||||
Attrs::new()
|
||||
&Attrs::new()
|
||||
.family(Family::Name(&font.families.first().unwrap().0))
|
||||
.stretch(font.stretch)
|
||||
.style(font.style)
|
||||
.weight(font.weight),
|
||||
.weight(font.weight)
|
||||
.font_features(features),
|
||||
);
|
||||
offs += run.len;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue