diff --git a/crates/gpui3/src/elements/div.rs b/crates/gpui3/src/elements/div.rs index 1daef0f7c8..7ed37f883c 100644 --- a/crates/gpui3/src/elements/div.rs +++ b/crates/gpui3/src/elements/div.rs @@ -35,7 +35,7 @@ impl Element for Div { let style = self.computed_style(); let pop_text_style = style .text_style(cx) - .map(|style| cx.push_text_style(style)) + .map(|style| cx.push_text_style(style.clone())) .is_some(); let children = self @@ -63,7 +63,7 @@ impl Element for Div { let style = self.computed_style(); let pop_text_style = style .text_style(cx) - .map(|style| cx.push_text_style(style)) + .map(|style| cx.push_text_style(style.clone())) .is_some(); style.paint_background(bounds, cx); // self.interaction_handlers().paint(order, bounds, cx); diff --git a/crates/gpui3/src/platform.rs b/crates/gpui3/src/platform.rs index f8650e3d28..3782d259ab 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, FontStyle, FontWeight, GlyphId, LineLayout, - Pixels, Point, Result, RunStyle, Scene, SharedString, Size, + AnyWindowHandle, Bounds, Font, FontId, FontMetrics, GlyphId, LineLayout, Pixels, Point, Result, + RunStyle, Scene, SharedString, Size, }; use anyhow::anyhow; use async_task::Runnable; @@ -156,8 +156,8 @@ pub trait PlatformDispatcher: Send + Sync { pub trait PlatformTextSystem: Send + Sync { 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 select_font(&self, descriptor: Font) -> Result; + fn font_metrics(&self, font_id: FontId) -> Arc; 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; @@ -397,24 +397,3 @@ 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/text_system.rs b/crates/gpui3/src/platform/mac/text_system.rs index 50b389c23a..6c3cd7bf27 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::{ - platform::FontDescriptor, point, px, size, Bounds, FontFeatures, FontId, FontMetrics, - FontStyle, FontWeight, Glyph, GlyphId, LineLayout, Pixels, PlatformTextSystem, Point, - RasterizationOptions, Result, Run, RunStyle, SharedString, Size, + point, px, size, Bounds, Font, 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; @@ -18,6 +18,7 @@ use core_graphics::{ }; use core_text::{font::CTFont, line::CTLine, string_attributes::kCTFontAttributeName}; use font_kit::{ + font::Font as FontKitFont, handle::Handle, hinting::HintingOptions, metrics::Metrics, @@ -44,8 +45,9 @@ pub struct MacTextSystem(RwLock); struct TextSystemState { memory_source: MemSource, system_source: SystemSource, - fonts: Vec, - font_selections: HashMap, + fonts: Vec, + font_selections: HashMap, + font_metrics: HashMap>, font_ids_by_postscript_name: HashMap, font_ids_by_family_name: HashMap>, postscript_names_by_font_id: HashMap, @@ -58,6 +60,7 @@ impl MacTextSystem { system_source: SystemSource::new(), fonts: Vec::new(), font_selections: HashMap::default(), + font_metrics: HashMap::default(), font_ids_by_postscript_name: HashMap::default(), font_ids_by_family_name: HashMap::default(), postscript_names_by_font_id: HashMap::default(), @@ -84,21 +87,21 @@ impl PlatformTextSystem for MacTextSystem { .expect("core text should never return an error") } - fn select_font(&self, descriptor: FontDescriptor) -> Result { + fn select_font(&self, font: Font) -> Result { let lock = self.0.upgradable_read(); - if let Some(font_id) = lock.font_selections.get(&descriptor) { + if let Some(font_id) = lock.font_selections.get(&font) { 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 candidates = if let Some(font_ids) = lock.font_ids_by_family_name.get(&font.family) + { + font_ids.as_slice() + } else { + let font_ids = lock.load_family(&font.family, font.features)?; + lock.font_ids_by_family_name + .insert(font.family.clone(), font_ids); + lock.font_ids_by_family_name[&font.family].as_ref() + }; let candidate_properties = candidates .iter() @@ -108,8 +111,8 @@ impl PlatformTextSystem for MacTextSystem { let ix = font_kit::matching::find_best_match( &candidate_properties, &font_kit::properties::Properties { - style: descriptor.style.into(), - weight: descriptor.weight.into(), + style: font.style.into(), + weight: font.weight.into(), stretch: Default::default(), }, )?; @@ -118,8 +121,16 @@ impl PlatformTextSystem for MacTextSystem { } } - fn font_metrics(&self, font_id: FontId) -> FontMetrics { - self.0.read().font_metrics(font_id) + fn font_metrics(&self, font_id: FontId) -> Arc { + let lock = self.0.upgradable_read(); + if let Some(metrics) = lock.font_metrics.get(&font_id) { + metrics.clone() + } else { + let mut lock = parking_lot::RwLockUpgradableReadGuard::upgrade(lock); + let metrics: Arc = Arc::new(lock.fonts[font_id.0].metrics().into()); + lock.font_metrics.insert(font_id, metrics.clone()); + metrics + } } fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result> { @@ -203,46 +214,6 @@ impl TextSystemState { Ok(font_ids) } - // 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) -> Result> { Ok(self.fonts[font_id.0] .typographic_bounds(glyph_id.into())? @@ -393,30 +364,30 @@ impl TextSystemState { string.replace_str(&CFString::new(text), CFRange::init(0, 0)); let utf16_line_len = string.char_len() as usize; - let last_run: RefCell> = Default::default(); + let last_run: RefCell> = Default::default(); let font_runs = runs .iter() .filter_map(|(len, style)| { let mut last_run = last_run.borrow_mut(); - if let Some((last_len, last_font_id)) = last_run.as_mut() { - if style.font_id == *last_font_id { + if let Some((last_len, last_font)) = last_run.as_mut() { + if style.font == *last_font { *last_len += *len; None } else { - let result = (*last_len, *last_font_id); + let result = (*last_len, last_font.clone()); *last_len = *len; - *last_font_id = style.font_id; + *last_font = style.font.clone(); Some(result) } } else { - *last_run = Some((*len, style.font_id)); + *last_run = Some((*len, style.font.clone())); None } }) .chain(std::iter::from_fn(|| last_run.borrow_mut().take())); let mut ix_converter = StringIndexConverter::new(text); - for (run_len, font_id) in font_runs { + for (run_len, font_descriptor) in font_runs { let utf8_end = ix_converter.utf8_ix + run_len; let utf16_start = ix_converter.utf16_ix; @@ -429,7 +400,9 @@ impl TextSystemState { let cf_range = CFRange::init(utf16_start as isize, (utf16_end - utf16_start) as isize); - let font = &self.fonts[font_id.0]; + + let font_id = self.font_selections[&font_descriptor]; + let font: &FontKitFont = &self.fonts[font_id.0]; unsafe { string.set_attribute( cf_range, diff --git a/crates/gpui3/src/style.rs b/crates/gpui3/src/style.rs index 1114b224f4..2d1467d6a7 100644 --- a/crates/gpui3/src/style.rs +++ b/crates/gpui3/src/style.rs @@ -1,7 +1,8 @@ use crate::{ rems, AbsoluteLength, Bounds, Corners, CornersRefinement, DefiniteLength, Edges, - EdgesRefinement, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rems, - Result, RunStyle, SharedString, Size, SizeRefinement, ViewContext, WindowContext, + EdgesRefinement, Font, FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, + PointRefinement, Rems, Result, RunStyle, SharedString, Size, SizeRefinement, ViewContext, + WindowContext, }; use refineable::Refineable; pub use taffy::style::{ @@ -88,17 +89,8 @@ pub struct Style { #[refineable] pub corner_radii: Corners, - /// The color of text within this element. Cascades to children unless overridden. - pub text_color: Option, - - /// The font size in rems. - pub font_size: Option, - - pub font_family: Option, - - pub font_weight: Option, - - pub font_style: Option, + /// TEXT + pub text: TextStyleRefinement, } #[derive(Refineable, Clone, Debug)] @@ -106,6 +98,7 @@ pub struct Style { pub struct TextStyle { pub color: Hsla, pub font_family: SharedString, + pub font_features: FontFeatures, pub font_size: Rems, pub font_weight: FontWeight, pub font_style: FontStyle, @@ -117,6 +110,7 @@ impl Default for TextStyle { TextStyle { color: Hsla::default(), font_family: SharedString::default(), + font_features: FontFeatures::default(), font_size: rems(1.), font_weight: FontWeight::default(), font_style: FontStyle::default(), @@ -151,7 +145,12 @@ impl TextStyle { pub fn to_run(&self) -> RunStyle { RunStyle { - font_id: todo!(), + font: Font { + family: self.font_family.clone(), + features: Default::default(), + weight: self.font_weight, + style: self.font_style, + }, color: self.color, underline: self.underline.clone(), } @@ -170,24 +169,12 @@ pub struct HighlightStyle { impl Eq for HighlightStyle {} impl Style { - pub fn text_style(&self, _cx: &WindowContext) -> Option { - if self.text_color.is_none() - && self.font_size.is_none() - && self.font_family.is_none() - && self.font_weight.is_none() - && self.font_style.is_none() - { - return None; + pub fn text_style(&self, _cx: &WindowContext) -> Option<&TextStyleRefinement> { + if self.text.is_some() { + Some(&self.text) + } else { + None } - - Some(TextStyleRefinement { - color: self.text_color, - font_family: self.font_family.clone(), - font_size: self.font_size, - font_weight: self.font_weight, - font_style: self.font_style, - underline: None, - }) } /// Paints the background of an element styled with this style. @@ -244,11 +231,7 @@ impl Default for Style { fill: None, border_color: None, corner_radii: Corners::default(), - text_color: None, - font_size: Some(rems(1.)), - font_family: None, - font_weight: None, - font_style: None, + text: TextStyleRefinement::default(), } } } diff --git a/crates/gpui3/src/style_helpers.rs b/crates/gpui3/src/style_helpers.rs index a545eedd09..12d9eade05 100644 --- a/crates/gpui3/src/style_helpers.rs +++ b/crates/gpui3/src/style_helpers.rs @@ -1,6 +1,6 @@ use crate::{ self as gpui3, relative, rems, AlignItems, Display, Fill, FlexDirection, Hsla, JustifyContent, - Length, Position, SharedString, Style, Styled, + Length, Position, SharedString, Style, StyleRefinement, Styled, TextStyleRefinement, }; pub trait StyleHelpers: Styled