diff --git a/Cargo.lock b/Cargo.lock index 41ebb69519156ada3721321706ac99957ede6161..84731880fe6462ea79fc39540ad3685652afb240 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3243,6 +3243,7 @@ dependencies = [ "async-task", "backtrace", "bindgen 0.65.1", + "bitflags 2.4.0", "block", "bytemuck", "cbindgen", diff --git a/crates/gpui3/Cargo.toml b/crates/gpui3/Cargo.toml index 2c567f20478a1f4ae90554d76efc55a231253d89..965ee5371dd9ca3be7ef13073732eba63fbda83c 100644 --- a/crates/gpui3/Cargo.toml +++ b/crates/gpui3/Cargo.toml @@ -58,6 +58,7 @@ slotmap = "1.0.6" bytemuck = { version = "1.14.0", features = ["derive"] } schemars.workspace = true plane-split = "0.18.0" +bitflags = "2.4.0" [dev-dependencies] backtrace = "0.3" diff --git a/crates/gpui3/src/app.rs b/crates/gpui3/src/app.rs index de5c4274dd9009775be8f6adf9f27ac175ca478a..7cbaf51dbfd15a0895fc889395cb5e811b82d2d5 100644 --- a/crates/gpui3/src/app.rs +++ b/crates/gpui3/src/app.rs @@ -13,6 +13,7 @@ use std::{ marker::PhantomData, sync::{Arc, Weak}, }; +use util::ResultExt; #[derive(Clone)] pub struct App(Arc>); @@ -173,7 +174,9 @@ impl AppContext { .collect::>(); for dirty_window_id in dirty_window_ids { - self.update_window(dirty_window_id, |cx| cx.draw()); + self.update_window(dirty_window_id, |cx| cx.draw()) + .unwrap() // We know we have the window. + .log_err(); } } diff --git a/crates/gpui3/src/gpui3.rs b/crates/gpui3/src/gpui3.rs index 562c7fcbfef036396a2deea8fb8a1483b8bf6c36..1010812953bb670cfe184ca2773062c542fb3b6c 100644 --- a/crates/gpui3/src/gpui3.rs +++ b/crates/gpui3/src/gpui3.rs @@ -77,7 +77,7 @@ impl Flatten for Result { } } -#[derive(Clone, Eq, PartialEq)] +#[derive(Clone, Eq, PartialEq, Hash)] pub struct SharedString(ArcCow<'static, str>); impl Default for SharedString { diff --git a/crates/gpui3/src/platform.rs b/crates/gpui3/src/platform.rs index acbd8f99a760676ae3108c691904a05763bfcf8c..f8650e3d28d0fb09e00764a214f5252ec736d522 100644 --- a/crates/gpui3/src/platform.rs +++ b/crates/gpui3/src/platform.rs @@ -6,8 +6,8 @@ mod mac; mod test; use crate::{ - AnyWindowHandle, Bounds, FontFeatures, FontId, FontMetrics, FontStyle, FontWeight, GlyphId, - LineLayout, Pixels, Point, Result, RunStyle, Scene, SharedString, Size, + AnyWindowHandle, Bounds, FontFeatures, FontId, FontStyle, FontWeight, GlyphId, LineLayout, + Pixels, Point, Result, RunStyle, Scene, SharedString, Size, }; use anyhow::anyhow; use async_task::Runnable; @@ -25,7 +25,6 @@ use std::{ str::FromStr, sync::Arc, }; -pub use time::UtcOffset; use uuid::Uuid; pub use events::*; @@ -34,6 +33,7 @@ pub use keystroke::*; pub use mac::*; #[cfg(any(test, feature = "test"))] pub use test::*; +pub use time::UtcOffset; #[cfg(target_os = "macos")] pub(crate) fn current_platform() -> Arc { @@ -154,19 +154,12 @@ pub trait PlatformDispatcher: Send + Sync { } pub trait PlatformTextSystem: Send + Sync { - fn add_fonts(&self, fonts: &[Arc>]) -> anyhow::Result<()>; - fn all_families(&self) -> Vec; - fn load_family(&self, name: &str, features: &FontFeatures) -> anyhow::Result>; - fn select_font( - &self, - font_ids: &[FontId], - weight: FontWeight, - style: FontStyle, - ) -> anyhow::Result; + fn add_fonts(&self, fonts: &[Arc>]) -> Result<()>; + fn all_font_families(&self) -> Vec; + fn select_font(&self, descriptor: FontDescriptor) -> Result; fn font_metrics(&self, font_id: FontId) -> FontMetrics; - fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) - -> anyhow::Result>; - fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> anyhow::Result>; + fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result>; + fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> Result>; fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option; fn rasterize_glyph( &self, @@ -404,3 +397,24 @@ impl ClipboardItem { hasher.finish() } } + +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub struct FontDescriptor { + family: SharedString, + features: FontFeatures, + weight: FontWeight, + style: FontStyle, +} + +#[derive(Clone, Copy, Debug)] +pub struct FontMetrics { + pub units_per_em: u32, + pub ascent: f32, + pub descent: f32, + pub line_gap: f32, + pub underline_position: f32, + pub underline_thickness: f32, + pub cap_height: f32, + pub x_height: f32, + pub bounding_box: Bounds, +} diff --git a/crates/gpui3/src/platform/mac/open_type.rs b/crates/gpui3/src/platform/mac/open_type.rs index 9da38a28ac0eb1275f366d8b075951c492adc014..50e93a866db6c569926b791e5c89d82be7f8199b 100644 --- a/crates/gpui3/src/platform/mac/open_type.rs +++ b/crates/gpui3/src/platform/mac/open_type.rs @@ -1,7 +1,5 @@ #![allow(unused, non_upper_case_globals)] -use std::ptr; - use crate::FontFeatures; use cocoa::appkit::CGFloat; use core_foundation::{base::TCFType, number::CFNumber}; @@ -13,6 +11,7 @@ use core_text::{ }, }; use font_kit::font::Font; +use std::ptr; const kCaseSensitiveLayoutOffSelector: i32 = 1; const kCaseSensitiveLayoutOnSelector: i32 = 0; @@ -108,243 +107,243 @@ const kTypographicExtrasType: i32 = 14; const kVerticalFractionsSelector: i32 = 1; const kVerticalPositionType: i32 = 10; -pub fn apply_features(font: &mut Font, features: &FontFeatures) { +pub fn apply_features(font: &mut Font, features: FontFeatures) { // See https://chromium.googlesource.com/chromium/src/+/66.0.3359.158/third_party/harfbuzz-ng/src/hb-coretext.cc // for a reference implementation. toggle_open_type_feature( font, - features.calt, + features.calt(), kContextualAlternatesType, kContextualAlternatesOnSelector, kContextualAlternatesOffSelector, ); toggle_open_type_feature( font, - features.case, + features.case(), kCaseSensitiveLayoutType, kCaseSensitiveLayoutOnSelector, kCaseSensitiveLayoutOffSelector, ); toggle_open_type_feature( font, - features.cpsp, + features.cpsp(), kCaseSensitiveLayoutType, kCaseSensitiveSpacingOnSelector, kCaseSensitiveSpacingOffSelector, ); toggle_open_type_feature( font, - features.frac, + features.frac(), kFractionsType, kDiagonalFractionsSelector, kNoFractionsSelector, ); toggle_open_type_feature( font, - features.liga, + features.liga(), kLigaturesType, kCommonLigaturesOnSelector, kCommonLigaturesOffSelector, ); toggle_open_type_feature( font, - features.onum, + features.onum(), kNumberCaseType, kLowerCaseNumbersSelector, 2, ); toggle_open_type_feature( font, - features.ordn, + features.ordn(), kVerticalPositionType, kOrdinalsSelector, kNormalPositionSelector, ); toggle_open_type_feature( font, - features.pnum, + features.pnum(), kNumberSpacingType, kProportionalNumbersSelector, 4, ); toggle_open_type_feature( font, - features.ss01, + features.ss01(), kStylisticAlternativesType, kStylisticAltOneOnSelector, kStylisticAltOneOffSelector, ); toggle_open_type_feature( font, - features.ss02, + features.ss02(), kStylisticAlternativesType, kStylisticAltTwoOnSelector, kStylisticAltTwoOffSelector, ); toggle_open_type_feature( font, - features.ss03, + features.ss03(), kStylisticAlternativesType, kStylisticAltThreeOnSelector, kStylisticAltThreeOffSelector, ); toggle_open_type_feature( font, - features.ss04, + features.ss04(), kStylisticAlternativesType, kStylisticAltFourOnSelector, kStylisticAltFourOffSelector, ); toggle_open_type_feature( font, - features.ss05, + features.ss05(), kStylisticAlternativesType, kStylisticAltFiveOnSelector, kStylisticAltFiveOffSelector, ); toggle_open_type_feature( font, - features.ss06, + features.ss06(), kStylisticAlternativesType, kStylisticAltSixOnSelector, kStylisticAltSixOffSelector, ); toggle_open_type_feature( font, - features.ss07, + features.ss07(), kStylisticAlternativesType, kStylisticAltSevenOnSelector, kStylisticAltSevenOffSelector, ); toggle_open_type_feature( font, - features.ss08, + features.ss08(), kStylisticAlternativesType, kStylisticAltEightOnSelector, kStylisticAltEightOffSelector, ); toggle_open_type_feature( font, - features.ss09, + features.ss09(), kStylisticAlternativesType, kStylisticAltNineOnSelector, kStylisticAltNineOffSelector, ); toggle_open_type_feature( font, - features.ss10, + features.ss10(), kStylisticAlternativesType, kStylisticAltTenOnSelector, kStylisticAltTenOffSelector, ); toggle_open_type_feature( font, - features.ss11, + features.ss11(), kStylisticAlternativesType, kStylisticAltElevenOnSelector, kStylisticAltElevenOffSelector, ); toggle_open_type_feature( font, - features.ss12, + features.ss12(), kStylisticAlternativesType, kStylisticAltTwelveOnSelector, kStylisticAltTwelveOffSelector, ); toggle_open_type_feature( font, - features.ss13, + features.ss13(), kStylisticAlternativesType, kStylisticAltThirteenOnSelector, kStylisticAltThirteenOffSelector, ); toggle_open_type_feature( font, - features.ss14, + features.ss14(), kStylisticAlternativesType, kStylisticAltFourteenOnSelector, kStylisticAltFourteenOffSelector, ); toggle_open_type_feature( font, - features.ss15, + features.ss15(), kStylisticAlternativesType, kStylisticAltFifteenOnSelector, kStylisticAltFifteenOffSelector, ); toggle_open_type_feature( font, - features.ss16, + features.ss16(), kStylisticAlternativesType, kStylisticAltSixteenOnSelector, kStylisticAltSixteenOffSelector, ); toggle_open_type_feature( font, - features.ss17, + features.ss17(), kStylisticAlternativesType, kStylisticAltSeventeenOnSelector, kStylisticAltSeventeenOffSelector, ); toggle_open_type_feature( font, - features.ss18, + features.ss18(), kStylisticAlternativesType, kStylisticAltEighteenOnSelector, kStylisticAltEighteenOffSelector, ); toggle_open_type_feature( font, - features.ss19, + features.ss19(), kStylisticAlternativesType, kStylisticAltNineteenOnSelector, kStylisticAltNineteenOffSelector, ); toggle_open_type_feature( font, - features.ss20, + features.ss20(), kStylisticAlternativesType, kStylisticAltTwentyOnSelector, kStylisticAltTwentyOffSelector, ); toggle_open_type_feature( font, - features.subs, + features.subs(), kVerticalPositionType, kInferiorsSelector, kNormalPositionSelector, ); toggle_open_type_feature( font, - features.sups, + features.sups(), kVerticalPositionType, kSuperiorsSelector, kNormalPositionSelector, ); toggle_open_type_feature( font, - features.swsh, + features.swsh(), kContextualAlternatesType, kSwashAlternatesOnSelector, kSwashAlternatesOffSelector, ); toggle_open_type_feature( font, - features.titl, + features.titl(), kStyleOptionsType, kTitlingCapsSelector, kNoStyleOptionsSelector, ); toggle_open_type_feature( font, - features.tnum, + features.tnum(), kNumberSpacingType, kMonospacedNumbersSelector, 4, ); toggle_open_type_feature( font, - features.zero, + features.zero(), kTypographicExtrasType, kSlashedZeroOnSelector, kSlashedZeroOffSelector, diff --git a/crates/gpui3/src/platform/mac/screen.rs b/crates/gpui3/src/platform/mac/screen.rs index 352a36c5a1852fd39440cfb3fb7296ac7fd9d62d..048b9dd6fd45b0a2cbf86f7c9a789d9cfef25d45 100644 --- a/crates/gpui3/src/platform/mac/screen.rs +++ b/crates/gpui3/src/platform/mac/screen.rs @@ -1,7 +1,5 @@ use super::ns_string; -use crate::{ - platform, point, px, size, Bounds, Pixels, PlatformScreen, PlatformScreenHandle, ScreenId, -}; +use crate::{point, px, size, Bounds, Pixels, PlatformScreen, PlatformScreenHandle, ScreenId}; use cocoa::{ appkit::NSScreen, base::{id, nil}, diff --git a/crates/gpui3/src/platform/mac/text_system.rs b/crates/gpui3/src/platform/mac/text_system.rs index 5d87b77a6bc300b220ab2fc6d539d5f587f58d85..50b389c23a96ea71d103aab66c1a955189d172cb 100644 --- a/crates/gpui3/src/platform/mac/text_system.rs +++ b/crates/gpui3/src/platform/mac/text_system.rs @@ -1,7 +1,7 @@ use crate::{ - point, px, size, Bounds, FontFeatures, FontId, FontMetrics, FontStyle, FontWeight, Glyph, - GlyphId, LineLayout, Pixels, PlatformTextSystem, Point, RasterizationOptions, Run, RunStyle, - Size, + platform::FontDescriptor, point, px, size, Bounds, FontFeatures, FontId, FontMetrics, + FontStyle, FontWeight, Glyph, GlyphId, LineLayout, Pixels, PlatformTextSystem, Point, + RasterizationOptions, Result, Run, RunStyle, SharedString, Size, }; use cocoa::appkit::{CGFloat, CGPoint}; use collections::HashMap; @@ -31,6 +31,7 @@ use pathfinder_geometry::{ transform2d::Transform2F, vector::{Vector2F, Vector2I}, }; +use smallvec::SmallVec; use std::{cell::RefCell, char, cmp, convert::TryFrom, ffi::c_void, sync::Arc}; use super::open_type; @@ -44,7 +45,9 @@ struct TextSystemState { memory_source: MemSource, system_source: SystemSource, fonts: Vec, + font_selections: HashMap, font_ids_by_postscript_name: HashMap, + font_ids_by_family_name: HashMap>, postscript_names_by_font_id: HashMap, } @@ -54,8 +57,10 @@ impl MacTextSystem { memory_source: MemSource::empty(), system_source: SystemSource::new(), fonts: Vec::new(), - font_ids_by_postscript_name: Default::default(), - postscript_names_by_font_id: Default::default(), + font_selections: HashMap::default(), + font_ids_by_postscript_name: HashMap::default(), + font_ids_by_family_name: HashMap::default(), + postscript_names_by_font_id: HashMap::default(), })) } } @@ -67,11 +72,11 @@ impl Default for MacTextSystem { } impl PlatformTextSystem for MacTextSystem { - fn add_fonts(&self, fonts: &[Arc>]) -> anyhow::Result<()> { + fn add_fonts(&self, fonts: &[Arc>]) -> Result<()> { self.0.write().add_fonts(fonts) } - fn all_families(&self) -> Vec { + fn all_font_families(&self) -> Vec { self.0 .read() .system_source @@ -79,32 +84,49 @@ impl PlatformTextSystem for MacTextSystem { .expect("core text should never return an error") } - fn load_family(&self, name: &str, features: &FontFeatures) -> anyhow::Result> { - self.0.write().load_family(name, features) - } - - fn select_font( - &self, - font_ids: &[FontId], - weight: FontWeight, - style: FontStyle, - ) -> anyhow::Result { - self.0.read().select_font(font_ids, weight, style) + fn select_font(&self, descriptor: FontDescriptor) -> Result { + let lock = self.0.upgradable_read(); + if let Some(font_id) = lock.font_selections.get(&descriptor) { + Ok(*font_id) + } else { + let mut lock = parking_lot::RwLockUpgradableReadGuard::upgrade(lock); + let candidates = + if let Some(font_ids) = lock.font_ids_by_family_name.get(&descriptor.family) { + font_ids.as_slice() + } else { + let font_ids = lock.load_family(&descriptor.family, descriptor.features)?; + lock.font_ids_by_family_name + .insert(descriptor.family.clone(), font_ids); + lock.font_ids_by_family_name[&descriptor.family].as_ref() + }; + + let candidate_properties = candidates + .iter() + .map(|font_id| lock.fonts[font_id.0].properties()) + .collect::>(); + + let ix = font_kit::matching::find_best_match( + &candidate_properties, + &font_kit::properties::Properties { + style: descriptor.style.into(), + weight: descriptor.weight.into(), + stretch: Default::default(), + }, + )?; + + Ok(candidates[ix]) + } } fn font_metrics(&self, font_id: FontId) -> FontMetrics { self.0.read().font_metrics(font_id) } - fn typographic_bounds( - &self, - font_id: FontId, - glyph_id: GlyphId, - ) -> anyhow::Result> { + fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result> { self.0.read().typographic_bounds(font_id, glyph_id) } - fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> anyhow::Result> { + fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> Result> { self.0.read().advance(font_id, glyph_id) } @@ -147,7 +169,7 @@ impl PlatformTextSystem for MacTextSystem { } impl TextSystemState { - fn add_fonts(&mut self, fonts: &[Arc>]) -> anyhow::Result<()> { + fn add_fonts(&mut self, fonts: &[Arc>]) -> Result<()> { self.memory_source.add_fonts( fonts .iter() @@ -156,13 +178,16 @@ impl TextSystemState { Ok(()) } - fn load_family(&mut self, name: &str, features: &FontFeatures) -> anyhow::Result> { - let mut font_ids = Vec::new(); - + fn load_family( + &mut self, + name: &SharedString, + features: FontFeatures, + ) -> Result> { + let mut font_ids = SmallVec::new(); let family = self .memory_source - .select_family_by_name(name) - .or_else(|_| self.system_source.select_family_by_name(name))?; + .select_family_by_name(name.as_ref()) + .or_else(|_| self.system_source.select_family_by_name(name.as_ref()))?; for font in family.fonts() { let mut font = font.load()?; open_type::apply_features(&mut font, features); @@ -178,42 +203,53 @@ impl TextSystemState { Ok(font_ids) } - fn select_font( - &self, - font_ids: &[FontId], - weight: FontWeight, - style: FontStyle, - ) -> anyhow::Result { - let candidates = font_ids - .iter() - .map(|font_id| self.fonts[font_id.0].properties()) - .collect::>(); - let idx = font_kit::matching::find_best_match( - &candidates, - &font_kit::properties::Properties { - style: style.into(), - weight: weight.into(), - stretch: Default::default(), - }, - )?; - Ok(font_ids[idx]) - } + // fn select_font( + // &mut self, + // family: &SharedString, + // weight: FontWeight, + // style: FontStyle, + // features: FontFeatures, + // ) -> Result { + // let candidates = if let Some(font_ids) = self.font_ids_by_family_name.get(family) { + // font_ids + // } else { + // let font_ids = if let Some(font_ids) = self.font_ids_by_family_name.get(family) { + // font_ids.as_slice() + // } else { + // self.font_ids_by_family_name + // .insert(family.clone()) + // .or_insert(font_ids).as_slice() + // }; + + // }; + + // let font_properties = candidates + // .iter() + // .map(|font_id| self.fonts[font_id.0].properties()) + // .collect::>(); + + // // let idx = font_kit::matching::find_best_match( + // // &candidates, + // // &font_kit::properties::Properties { + // // style: style.into(), + // // weight: weight.into(), + // // stretch: Default::default(), + // // }, + // // )?; + // // Ok(font_ids[idx]) + // } fn font_metrics(&self, font_id: FontId) -> FontMetrics { self.fonts[font_id.0].metrics().into() } - fn typographic_bounds( - &self, - font_id: FontId, - glyph_id: GlyphId, - ) -> anyhow::Result> { + fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result> { Ok(self.fonts[font_id.0] .typographic_bounds(glyph_id.into())? .into()) } - fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> anyhow::Result> { + fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> Result> { Ok(self.fonts[font_id.0].advance(glyph_id.into())?.into()) } @@ -659,7 +695,7 @@ impl From for FontkitStyle { // } // #[test] -// fn test_glyph_offsets() -> anyhow::Result<()> { +// fn test_glyph_offsets() -> crate::Result<()> { // let fonts = FontSystem::new(); // let zapfino = fonts.load_family("Zapfino", &Default::default())?; // let zapfino_regular = RunStyle { diff --git a/crates/gpui3/src/text_system.rs b/crates/gpui3/src/text_system.rs index c7935801ccce13bfc6568a48d967fdc3917833a0..0ec0fac7ceb8f88c74ecf65e0410013245b2aa46 100644 --- a/crates/gpui3/src/text_system.rs +++ b/crates/gpui3/src/text_system.rs @@ -1,11 +1,9 @@ -mod font_cache; +mod font_features; mod line_wrapper; mod text_layout_cache; -pub use font_cache::*; +pub use font_features::*; use line_wrapper::*; -use schemars::JsonSchema; -use serde_derive::{Deserialize, Serialize}; pub use text_layout_cache::*; use crate::{Hsla, Pixels, PlatformTextSystem, Point, Result, Size, UnderlineStyle}; @@ -19,8 +17,13 @@ use std::{ sync::Arc, }; +#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)] +pub struct FontId(pub usize); + +#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)] +pub struct FontFamilyId(pub usize); + pub struct TextSystem { - font_cache: Arc, text_layout_cache: Arc, platform_text_system: Arc, wrapper_pool: Mutex>>, @@ -29,7 +32,7 @@ pub struct TextSystem { impl TextSystem { pub fn new(platform_text_system: Arc) -> Self { TextSystem { - font_cache: Arc::new(FontCache::new(platform_text_system.clone())), + // font_cache: Arc::new(FontCache::new(platform_text_system.clone())), text_layout_cache: Arc::new(TextLayoutCache::new(platform_text_system.clone())), platform_text_system, wrapper_pool: Mutex::new(HashMap::default()), @@ -37,7 +40,8 @@ impl TextSystem { } pub fn font_family_name(&self, family_id: FontFamilyId) -> Result> { - self.font_cache.family_name(family_id) + todo!() + // self.font_cache.family_name(family_id) } pub fn load_font_family( @@ -45,16 +49,19 @@ impl TextSystem { names: &[&str], features: &FontFeatures, ) -> Result { - self.font_cache.load_family(names, features) + todo!() + // self.font_cache.load_family(names, features) } /// Returns an arbitrary font family that is available on the system. pub fn known_existing_font_family(&self) -> FontFamilyId { - self.font_cache.known_existing_family() + todo!() + // self.font_cache.known_existing_family() } pub fn default_font(&self, family_id: FontFamilyId) -> FontId { - self.font_cache.default_font(family_id) + todo!() + // self.font_cache.default_font(family_id) } pub fn select_font( @@ -63,55 +70,67 @@ impl TextSystem { weight: FontWeight, style: FontStyle, ) -> Result { - self.font_cache.select_font(family_id, weight, style) + todo!() + // self.font_cache.select_font(family_id, weight, style) } - pub fn read_font_metric(&self, font_id: FontId, f: F) -> T - where - F: FnOnce(&FontMetrics) -> T, - T: 'static, - { - self.font_cache.read_metric(font_id, f) - } + // pub fn read_font_metric(&self, font_id: FontId, f: F) -> T + // where + // F: FnOnce(&FontMetrics) -> T, + // T: 'static, + // { + // todo!() + // // self.font_cache.read_metric(font_id, f) + // } pub fn bounding_box(&self, font_id: FontId, font_size: Pixels) -> Size { - self.font_cache.bounding_box(font_id, font_size) + todo!() + // self.font_cache.bounding_box(font_id, font_size) } pub fn em_width(&self, font_id: FontId, font_size: Pixels) -> Pixels { - self.font_cache.em_width(font_id, font_size) + todo!() + // self.font_cache.em_width(font_id, font_size) } pub fn em_advance(&self, font_id: FontId, font_size: Pixels) -> Pixels { - self.font_cache.em_advance(font_id, font_size) + todo!() + // self.font_cache.em_advance(font_id, font_size) } pub fn line_height(&self, font_size: Pixels) -> Pixels { - self.font_cache.line_height(font_size) + todo!() + // self.font_cache.line_height(font_size) } pub fn cap_height(&self, font_id: FontId, font_size: Pixels) -> Pixels { - self.font_cache.cap_height(font_id, font_size) + todo!() + // self.font_cache.cap_height(font_id, font_size) } pub fn x_height(&self, font_id: FontId, font_size: Pixels) -> Pixels { - self.font_cache.x_height(font_id, font_size) + todo!() + // self.font_cache.x_height(font_id, font_size) } pub fn ascent(&self, font_id: FontId, font_size: Pixels) -> Pixels { - self.font_cache.ascent(font_id, font_size) + todo!() + // self.font_cache.ascent(font_id, font_size) } pub fn descent(&self, font_id: FontId, font_size: Pixels) -> Pixels { - self.font_cache.descent(font_id, font_size) + todo!() + // self.font_cache.descent(font_id, font_size) } pub fn em_size(&self, font_id: FontId, font_size: Pixels) -> Pixels { - self.font_cache.em_size(font_id, font_size) + todo!() + // self.font_cache.em_size(font_id, font_size) } pub fn baseline_offset(&self, font_id: FontId, font_size: Pixels) -> Pixels { - self.font_cache.baseline_offset(font_id, font_size) + todo!() + // self.font_cache.baseline_offset(font_id, font_size) } pub fn layout_str<'a>( @@ -235,44 +254,6 @@ impl Display for FontStyle { } } -#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, JsonSchema)] -pub struct FontFeatures { - pub calt: Option, - pub case: Option, - pub cpsp: Option, - pub frac: Option, - pub liga: Option, - pub onum: Option, - pub ordn: Option, - pub pnum: Option, - pub ss01: Option, - pub ss02: Option, - pub ss03: Option, - pub ss04: Option, - pub ss05: Option, - pub ss06: Option, - pub ss07: Option, - pub ss08: Option, - pub ss09: Option, - pub ss10: Option, - pub ss11: Option, - pub ss12: Option, - pub ss13: Option, - pub ss14: Option, - pub ss15: Option, - pub ss16: Option, - pub ss17: Option, - pub ss18: Option, - pub ss19: Option, - pub ss20: Option, - pub subs: Option, - pub sups: Option, - pub swsh: Option, - pub titl: Option, - pub tnum: Option, - pub zero: Option, -} - #[derive(Clone, Debug, PartialEq, Eq)] pub struct RunStyle { pub color: Hsla, diff --git a/crates/gpui3/src/text_system/font_features.rs b/crates/gpui3/src/text_system/font_features.rs new file mode 100644 index 0000000000000000000000000000000000000000..ce93fd5bc93fe59c5d7c113c29cc9bf91f69d42e --- /dev/null +++ b/crates/gpui3/src/text_system/font_features.rs @@ -0,0 +1,162 @@ +use schemars::{ + schema::{InstanceType, Schema, SchemaObject, SingleOrVec}, + JsonSchema, +}; + +macro_rules! create_definitions { + ($($(#[$meta:meta])* ($name:ident, $idx:expr)),* $(,)?) => { + #[derive(Default, Copy, Clone, Eq, PartialEq, Hash)] + pub struct FontFeatures { + enabled: u64, + disabled: u64, + } + + impl FontFeatures { + $( + pub fn $name(&self) -> Option { + if (self.enabled & (1 << $idx)) != 0 { + Some(true) + } else if (self.disabled & (1 << $idx)) != 0 { + Some(false) + } else { + None + } + } + )* + } + + impl std::fmt::Debug for FontFeatures { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut debug = f.debug_struct("FontFeatures"); + $( + if let Some(value) = self.$name() { + debug.field(stringify!($name), &value); + }; + )* + debug.finish() + } + } + + impl<'de> serde::Deserialize<'de> for FontFeatures { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + use serde::de::{MapAccess, Visitor}; + use std::fmt; + + struct FontFeaturesVisitor; + + impl<'de> Visitor<'de> for FontFeaturesVisitor { + type Value = FontFeatures; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a map of font features") + } + + fn visit_map(self, mut access: M) -> Result + where + M: MapAccess<'de>, + { + let mut enabled: u64 = 0; + let mut disabled: u64 = 0; + + while let Some((key, value)) = access.next_entry::>()? { + let idx = match key.as_str() { + $(stringify!($name) => $idx,)* + _ => continue, + }; + match value { + Some(true) => enabled |= 1 << idx, + Some(false) => disabled |= 1 << idx, + None => {} + }; + } + Ok(FontFeatures { enabled, disabled }) + } + } + + let features = deserializer.deserialize_map(FontFeaturesVisitor)?; + Ok(features) + } + } + + impl serde::Serialize for FontFeatures { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeMap; + + let mut map = serializer.serialize_map(None)?; + + $( + let feature = stringify!($name); + if let Some(value) = self.$name() { + map.serialize_entry(feature, &value)?; + } + )* + + map.end() + } + } + + impl JsonSchema for FontFeatures { + fn schema_name() -> String { + "FontFeatures".into() + } + + fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> Schema { + let mut schema = SchemaObject::default(); + let properties = &mut schema.object().properties; + let feature_schema = Schema::Object(SchemaObject { + instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Boolean))), + ..Default::default() + }); + + $( + properties.insert(stringify!($name).to_owned(), feature_schema.clone()); + )* + + schema.into() + } + } + }; +} + +create_definitions!( + (calt, 0), + (case, 1), + (cpsp, 2), + (frac, 3), + (liga, 4), + (onum, 5), + (ordn, 6), + (pnum, 7), + (ss01, 8), + (ss02, 9), + (ss03, 10), + (ss04, 11), + (ss05, 12), + (ss06, 13), + (ss07, 14), + (ss08, 15), + (ss09, 16), + (ss10, 17), + (ss11, 18), + (ss12, 19), + (ss13, 20), + (ss14, 21), + (ss15, 22), + (ss16, 23), + (ss17, 24), + (ss18, 25), + (ss19, 26), + (ss20, 27), + (subs, 28), + (sups, 29), + (swsh, 30), + (titl, 31), + (tnum, 32), + (zero, 33) +); diff --git a/crates/gpui3/src/text_system/line_wrapper.rs b/crates/gpui3/src/text_system/line_wrapper.rs index 4cca331da7b2affa37d2484868136738864b4619..3770fdf96731d5f3d57c22a385ed8ce736823157 100644 --- a/crates/gpui3/src/text_system/line_wrapper.rs +++ b/crates/gpui3/src/text_system/line_wrapper.rs @@ -215,7 +215,7 @@ impl Boundary { #[cfg(test)] mod tests { use super::*; - use crate::{App, FontWeight}; + use crate::{App, FontFeatures, FontWeight}; #[test] fn test_wrap_line() { @@ -291,7 +291,7 @@ mod tests { let text_system = cx.text_system().clone(); let family = text_system - .load_font_family(&["Helvetica"], &Default::default()) + .load_font_family(&["Helvetica"], &FontFeatures::default()) .unwrap(); let font_id = text_system .select_font(family, Default::default(), Default::default())