Checkpoint

This commit is contained in:
Nathan Sobo 2023-09-27 17:17:30 -06:00
parent e9a84a21e4
commit 96f9c67e77
8 changed files with 171 additions and 230 deletions

View file

@ -35,7 +35,7 @@ impl<S: 'static> Element for Div<S> {
let style = self.computed_style(); let style = self.computed_style();
let pop_text_style = style let pop_text_style = style
.text_style(cx) .text_style(cx)
.map(|style| cx.push_text_style(style)) .map(|style| cx.push_text_style(style.clone()))
.is_some(); .is_some();
let children = self let children = self
@ -63,7 +63,7 @@ impl<S: 'static> Element for Div<S> {
let style = self.computed_style(); let style = self.computed_style();
let pop_text_style = style let pop_text_style = style
.text_style(cx) .text_style(cx)
.map(|style| cx.push_text_style(style)) .map(|style| cx.push_text_style(style.clone()))
.is_some(); .is_some();
style.paint_background(bounds, cx); style.paint_background(bounds, cx);
// self.interaction_handlers().paint(order, bounds, cx); // self.interaction_handlers().paint(order, bounds, cx);

View file

@ -6,8 +6,8 @@ mod mac;
mod test; mod test;
use crate::{ use crate::{
AnyWindowHandle, Bounds, FontFeatures, FontId, FontStyle, FontWeight, GlyphId, LineLayout, AnyWindowHandle, Bounds, Font, FontId, FontMetrics, GlyphId, LineLayout, Pixels, Point, Result,
Pixels, Point, Result, RunStyle, Scene, SharedString, Size, RunStyle, Scene, SharedString, Size,
}; };
use anyhow::anyhow; use anyhow::anyhow;
use async_task::Runnable; use async_task::Runnable;
@ -156,8 +156,8 @@ pub trait PlatformDispatcher: Send + Sync {
pub trait PlatformTextSystem: Send + Sync { pub trait PlatformTextSystem: Send + Sync {
fn add_fonts(&self, fonts: &[Arc<Vec<u8>>]) -> Result<()>; fn add_fonts(&self, fonts: &[Arc<Vec<u8>>]) -> Result<()>;
fn all_font_families(&self) -> Vec<String>; fn all_font_families(&self) -> Vec<String>;
fn select_font(&self, descriptor: FontDescriptor) -> Result<FontId>; fn select_font(&self, descriptor: Font) -> Result<FontId>;
fn font_metrics(&self, font_id: FontId) -> FontMetrics; fn font_metrics(&self, font_id: FontId) -> Arc<FontMetrics>;
fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>>; fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>>;
fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Size<f32>>; fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Size<f32>>;
fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId>; fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId>;
@ -397,24 +397,3 @@ impl ClipboardItem {
hasher.finish() 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<f32>,
}

View file

@ -1,7 +1,7 @@
use crate::{ use crate::{
platform::FontDescriptor, point, px, size, Bounds, FontFeatures, FontId, FontMetrics, point, px, size, Bounds, Font, FontFeatures, FontId, FontMetrics, FontStyle, FontWeight, Glyph,
FontStyle, FontWeight, Glyph, GlyphId, LineLayout, Pixels, PlatformTextSystem, Point, GlyphId, LineLayout, Pixels, PlatformTextSystem, Point, RasterizationOptions, Result, Run,
RasterizationOptions, Result, Run, RunStyle, SharedString, Size, RunStyle, SharedString, Size,
}; };
use cocoa::appkit::{CGFloat, CGPoint}; use cocoa::appkit::{CGFloat, CGPoint};
use collections::HashMap; use collections::HashMap;
@ -18,6 +18,7 @@ use core_graphics::{
}; };
use core_text::{font::CTFont, line::CTLine, string_attributes::kCTFontAttributeName}; use core_text::{font::CTFont, line::CTLine, string_attributes::kCTFontAttributeName};
use font_kit::{ use font_kit::{
font::Font as FontKitFont,
handle::Handle, handle::Handle,
hinting::HintingOptions, hinting::HintingOptions,
metrics::Metrics, metrics::Metrics,
@ -44,8 +45,9 @@ pub struct MacTextSystem(RwLock<TextSystemState>);
struct TextSystemState { struct TextSystemState {
memory_source: MemSource, memory_source: MemSource,
system_source: SystemSource, system_source: SystemSource,
fonts: Vec<font_kit::font::Font>, fonts: Vec<FontKitFont>,
font_selections: HashMap<FontDescriptor, FontId>, font_selections: HashMap<Font, FontId>,
font_metrics: HashMap<FontId, Arc<FontMetrics>>,
font_ids_by_postscript_name: HashMap<String, FontId>, font_ids_by_postscript_name: HashMap<String, FontId>,
font_ids_by_family_name: HashMap<SharedString, SmallVec<[FontId; 4]>>, font_ids_by_family_name: HashMap<SharedString, SmallVec<[FontId; 4]>>,
postscript_names_by_font_id: HashMap<FontId, String>, postscript_names_by_font_id: HashMap<FontId, String>,
@ -58,6 +60,7 @@ impl MacTextSystem {
system_source: SystemSource::new(), system_source: SystemSource::new(),
fonts: Vec::new(), fonts: Vec::new(),
font_selections: HashMap::default(), font_selections: HashMap::default(),
font_metrics: HashMap::default(),
font_ids_by_postscript_name: HashMap::default(), font_ids_by_postscript_name: HashMap::default(),
font_ids_by_family_name: HashMap::default(), font_ids_by_family_name: HashMap::default(),
postscript_names_by_font_id: HashMap::default(), postscript_names_by_font_id: HashMap::default(),
@ -84,20 +87,20 @@ impl PlatformTextSystem for MacTextSystem {
.expect("core text should never return an error") .expect("core text should never return an error")
} }
fn select_font(&self, descriptor: FontDescriptor) -> Result<FontId> { fn select_font(&self, font: Font) -> Result<FontId> {
let lock = self.0.upgradable_read(); 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) Ok(*font_id)
} else { } else {
let mut lock = parking_lot::RwLockUpgradableReadGuard::upgrade(lock); let mut lock = parking_lot::RwLockUpgradableReadGuard::upgrade(lock);
let candidates = let candidates = if let Some(font_ids) = lock.font_ids_by_family_name.get(&font.family)
if let Some(font_ids) = lock.font_ids_by_family_name.get(&descriptor.family) { {
font_ids.as_slice() font_ids.as_slice()
} else { } else {
let font_ids = lock.load_family(&descriptor.family, descriptor.features)?; let font_ids = lock.load_family(&font.family, font.features)?;
lock.font_ids_by_family_name lock.font_ids_by_family_name
.insert(descriptor.family.clone(), font_ids); .insert(font.family.clone(), font_ids);
lock.font_ids_by_family_name[&descriptor.family].as_ref() lock.font_ids_by_family_name[&font.family].as_ref()
}; };
let candidate_properties = candidates let candidate_properties = candidates
@ -108,8 +111,8 @@ impl PlatformTextSystem for MacTextSystem {
let ix = font_kit::matching::find_best_match( let ix = font_kit::matching::find_best_match(
&candidate_properties, &candidate_properties,
&font_kit::properties::Properties { &font_kit::properties::Properties {
style: descriptor.style.into(), style: font.style.into(),
weight: descriptor.weight.into(), weight: font.weight.into(),
stretch: Default::default(), stretch: Default::default(),
}, },
)?; )?;
@ -118,8 +121,16 @@ impl PlatformTextSystem for MacTextSystem {
} }
} }
fn font_metrics(&self, font_id: FontId) -> FontMetrics { fn font_metrics(&self, font_id: FontId) -> Arc<FontMetrics> {
self.0.read().font_metrics(font_id) 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<FontMetrics> = 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<Bounds<f32>> { fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>> {
@ -203,46 +214,6 @@ impl TextSystemState {
Ok(font_ids) Ok(font_ids)
} }
// fn select_font(
// &mut self,
// family: &SharedString,
// weight: FontWeight,
// style: FontStyle,
// features: FontFeatures,
// ) -> Result<FontId> {
// 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::<SmallVec<[_; 4]>>();
// // 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<Bounds<f32>> { fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>> {
Ok(self.fonts[font_id.0] Ok(self.fonts[font_id.0]
.typographic_bounds(glyph_id.into())? .typographic_bounds(glyph_id.into())?
@ -393,30 +364,30 @@ impl TextSystemState {
string.replace_str(&CFString::new(text), CFRange::init(0, 0)); string.replace_str(&CFString::new(text), CFRange::init(0, 0));
let utf16_line_len = string.char_len() as usize; let utf16_line_len = string.char_len() as usize;
let last_run: RefCell<Option<(usize, FontId)>> = Default::default(); let last_run: RefCell<Option<(usize, Font)>> = Default::default();
let font_runs = runs let font_runs = runs
.iter() .iter()
.filter_map(|(len, style)| { .filter_map(|(len, style)| {
let mut last_run = last_run.borrow_mut(); let mut last_run = last_run.borrow_mut();
if let Some((last_len, last_font_id)) = last_run.as_mut() { if let Some((last_len, last_font)) = last_run.as_mut() {
if style.font_id == *last_font_id { if style.font == *last_font {
*last_len += *len; *last_len += *len;
None None
} else { } else {
let result = (*last_len, *last_font_id); let result = (*last_len, last_font.clone());
*last_len = *len; *last_len = *len;
*last_font_id = style.font_id; *last_font = style.font.clone();
Some(result) Some(result)
} }
} else { } else {
*last_run = Some((*len, style.font_id)); *last_run = Some((*len, style.font.clone()));
None None
} }
}) })
.chain(std::iter::from_fn(|| last_run.borrow_mut().take())); .chain(std::iter::from_fn(|| last_run.borrow_mut().take()));
let mut ix_converter = StringIndexConverter::new(text); 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 utf8_end = ix_converter.utf8_ix + run_len;
let utf16_start = ix_converter.utf16_ix; let utf16_start = ix_converter.utf16_ix;
@ -429,7 +400,9 @@ impl TextSystemState {
let cf_range = let cf_range =
CFRange::init(utf16_start as isize, (utf16_end - utf16_start) as isize); 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 { unsafe {
string.set_attribute( string.set_attribute(
cf_range, cf_range,

View file

@ -1,7 +1,8 @@
use crate::{ use crate::{
rems, AbsoluteLength, Bounds, Corners, CornersRefinement, DefiniteLength, Edges, rems, AbsoluteLength, Bounds, Corners, CornersRefinement, DefiniteLength, Edges,
EdgesRefinement, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rems, EdgesRefinement, Font, FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point,
Result, RunStyle, SharedString, Size, SizeRefinement, ViewContext, WindowContext, PointRefinement, Rems, Result, RunStyle, SharedString, Size, SizeRefinement, ViewContext,
WindowContext,
}; };
use refineable::Refineable; use refineable::Refineable;
pub use taffy::style::{ pub use taffy::style::{
@ -88,17 +89,8 @@ pub struct Style {
#[refineable] #[refineable]
pub corner_radii: Corners<AbsoluteLength>, pub corner_radii: Corners<AbsoluteLength>,
/// The color of text within this element. Cascades to children unless overridden. /// TEXT
pub text_color: Option<Hsla>, pub text: TextStyleRefinement,
/// The font size in rems.
pub font_size: Option<Rems>,
pub font_family: Option<SharedString>,
pub font_weight: Option<FontWeight>,
pub font_style: Option<FontStyle>,
} }
#[derive(Refineable, Clone, Debug)] #[derive(Refineable, Clone, Debug)]
@ -106,6 +98,7 @@ pub struct Style {
pub struct TextStyle { pub struct TextStyle {
pub color: Hsla, pub color: Hsla,
pub font_family: SharedString, pub font_family: SharedString,
pub font_features: FontFeatures,
pub font_size: Rems, pub font_size: Rems,
pub font_weight: FontWeight, pub font_weight: FontWeight,
pub font_style: FontStyle, pub font_style: FontStyle,
@ -117,6 +110,7 @@ impl Default for TextStyle {
TextStyle { TextStyle {
color: Hsla::default(), color: Hsla::default(),
font_family: SharedString::default(), font_family: SharedString::default(),
font_features: FontFeatures::default(),
font_size: rems(1.), font_size: rems(1.),
font_weight: FontWeight::default(), font_weight: FontWeight::default(),
font_style: FontStyle::default(), font_style: FontStyle::default(),
@ -151,7 +145,12 @@ impl TextStyle {
pub fn to_run(&self) -> RunStyle { pub fn to_run(&self) -> RunStyle {
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, color: self.color,
underline: self.underline.clone(), underline: self.underline.clone(),
} }
@ -170,24 +169,12 @@ pub struct HighlightStyle {
impl Eq for HighlightStyle {} impl Eq for HighlightStyle {}
impl Style { impl Style {
pub fn text_style(&self, _cx: &WindowContext) -> Option<TextStyleRefinement> { pub fn text_style(&self, _cx: &WindowContext) -> Option<&TextStyleRefinement> {
if self.text_color.is_none() if self.text.is_some() {
&& self.font_size.is_none() Some(&self.text)
&& self.font_family.is_none() } else {
&& self.font_weight.is_none() None
&& self.font_style.is_none()
{
return 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. /// Paints the background of an element styled with this style.
@ -244,11 +231,7 @@ impl Default for Style {
fill: None, fill: None,
border_color: None, border_color: None,
corner_radii: Corners::default(), corner_radii: Corners::default(),
text_color: None, text: TextStyleRefinement::default(),
font_size: Some(rems(1.)),
font_family: None,
font_weight: None,
font_style: None,
} }
} }
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
self as gpui3, relative, rems, AlignItems, Display, Fill, FlexDirection, Hsla, JustifyContent, 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<Style = Style> { pub trait StyleHelpers: Styled<Style = Style> {
@ -213,12 +213,16 @@ pub trait StyleHelpers: Styled<Style = Style> {
self self
} }
fn text_color<C>(mut self, color: C) -> Self fn text_style(&mut self) -> &mut Option<TextStyleRefinement> {
let style: &mut StyleRefinement = self.declared_style();
&mut style.text
}
fn text_color(mut self, color: impl Into<Hsla>) -> Self
where where
C: Into<Hsla>,
Self: Sized, Self: Sized,
{ {
self.declared_style().text_color = Some(color.into()); self.text_style().get_or_insert_with(Default::default).color = Some(color.into());
self self
} }
@ -226,7 +230,9 @@ pub trait StyleHelpers: Styled<Style = Style> {
where where
Self: Sized, Self: Sized,
{ {
self.declared_style().font_size = Some(rems(0.75)); self.text_style()
.get_or_insert_with(Default::default)
.font_size = Some(rems(0.75));
self self
} }
@ -234,7 +240,9 @@ pub trait StyleHelpers: Styled<Style = Style> {
where where
Self: Sized, Self: Sized,
{ {
self.declared_style().font_size = Some(rems(0.875)); self.text_style()
.get_or_insert_with(Default::default)
.font_size = Some(rems(0.875));
self self
} }
@ -242,7 +250,9 @@ pub trait StyleHelpers: Styled<Style = Style> {
where where
Self: Sized, Self: Sized,
{ {
self.declared_style().font_size = Some(rems(1.0)); self.text_style()
.get_or_insert_with(Default::default)
.font_size = Some(rems(1.0));
self self
} }
@ -250,7 +260,9 @@ pub trait StyleHelpers: Styled<Style = Style> {
where where
Self: Sized, Self: Sized,
{ {
self.declared_style().font_size = Some(rems(1.125)); self.text_style()
.get_or_insert_with(Default::default)
.font_size = Some(rems(1.125));
self self
} }
@ -258,7 +270,9 @@ pub trait StyleHelpers: Styled<Style = Style> {
where where
Self: Sized, Self: Sized,
{ {
self.declared_style().font_size = Some(rems(1.25)); self.text_style()
.get_or_insert_with(Default::default)
.font_size = Some(rems(1.25));
self self
} }
@ -266,7 +280,9 @@ pub trait StyleHelpers: Styled<Style = Style> {
where where
Self: Sized, Self: Sized,
{ {
self.declared_style().font_size = Some(rems(1.5)); self.text_style()
.get_or_insert_with(Default::default)
.font_size = Some(rems(1.5));
self self
} }
@ -274,7 +290,9 @@ pub trait StyleHelpers: Styled<Style = Style> {
where where
Self: Sized, Self: Sized,
{ {
self.declared_style().font_size = Some(rems(1.875)); self.text_style()
.get_or_insert_with(Default::default)
.font_size = Some(rems(1.875));
self self
} }
@ -282,7 +300,9 @@ pub trait StyleHelpers: Styled<Style = Style> {
where where
Self: Sized, Self: Sized,
{ {
self.declared_style().font_family = Some(family_name.into()); self.text_style()
.get_or_insert_with(Default::default)
.font_family = Some(family_name.into());
self self
} }
} }

View file

@ -6,7 +6,9 @@ pub use font_features::*;
use line_wrapper::*; use line_wrapper::*;
pub use text_layout_cache::*; pub use text_layout_cache::*;
use crate::{Hsla, Pixels, PlatformTextSystem, Point, Result, Size, UnderlineStyle}; use crate::{
Bounds, Hsla, Pixels, PlatformTextSystem, Point, Result, SharedString, Size, UnderlineStyle,
};
use collections::HashMap; use collections::HashMap;
use core::fmt; use core::fmt;
use parking_lot::Mutex; use parking_lot::Mutex;
@ -26,64 +28,25 @@ pub struct FontFamilyId(pub usize);
pub struct TextSystem { pub struct TextSystem {
text_layout_cache: Arc<TextLayoutCache>, text_layout_cache: Arc<TextLayoutCache>,
platform_text_system: Arc<dyn PlatformTextSystem>, platform_text_system: Arc<dyn PlatformTextSystem>,
wrapper_pool: Mutex<HashMap<(FontId, Pixels), Vec<LineWrapper>>>, wrapper_pool: Mutex<HashMap<(Font, Pixels), Vec<LineWrapper>>>,
} }
impl TextSystem { impl TextSystem {
pub fn new(platform_text_system: Arc<dyn PlatformTextSystem>) -> Self { pub fn new(platform_text_system: Arc<dyn PlatformTextSystem>) -> Self {
TextSystem { TextSystem {
// font_cache: Arc::new(FontCache::new(platform_text_system.clone())),
text_layout_cache: Arc::new(TextLayoutCache::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()), wrapper_pool: Mutex::new(HashMap::default()),
platform_text_system,
} }
} }
pub fn font_family_name(&self, family_id: FontFamilyId) -> Result<Arc<str>> { pub fn select_font(&self, descriptor: impl Into<Font>) -> Result<FontId> {
todo!() self.platform_text_system.select_font(descriptor.into())
// self.font_cache.family_name(family_id)
} }
pub fn load_font_family(
&self,
names: &[&str],
features: &FontFeatures,
) -> Result<FontFamilyId> {
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 {
todo!()
// self.font_cache.known_existing_family()
}
pub fn default_font(&self, family_id: FontFamilyId) -> FontId {
todo!()
// self.font_cache.default_font(family_id)
}
pub fn select_font(
&self,
family_id: FontFamilyId,
weight: FontWeight,
style: FontStyle,
) -> Result<FontId> {
todo!()
// self.font_cache.select_font(family_id, weight, style)
}
// pub fn read_font_metric<F, T>(&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<Pixels> { pub fn bounding_box(&self, font_id: FontId, font_size: Pixels) -> Size<Pixels> {
let metrics = self.platform_text_system.font_metrics(font_id);
todo!() todo!()
// self.font_cache.bounding_box(font_id, font_size) // self.font_cache.bounding_box(font_id, font_size)
} }
@ -146,11 +109,11 @@ impl TextSystem {
self.text_layout_cache.finish_frame() self.text_layout_cache.finish_frame()
} }
pub fn line_wrapper(self: &Arc<Self>, font_id: FontId, font_size: Pixels) -> LineWrapperHandle { pub fn line_wrapper(self: &Arc<Self>, font: Font, font_size: Pixels) -> LineWrapperHandle {
let lock = &mut self.wrapper_pool.lock(); let lock = &mut self.wrapper_pool.lock();
let wrappers = lock.entry((font_id, font_size)).or_default(); let wrappers = lock.entry((font.clone(), font_size)).or_default();
let wrapper = wrappers.pop().unwrap_or_else(|| { let wrapper = wrappers.pop().unwrap_or_else(|| {
LineWrapper::new(font_id, font_size, self.platform_text_system.clone()) LineWrapper::new(font, font_size, self.platform_text_system.clone())
}); });
LineWrapperHandle { LineWrapperHandle {
@ -170,7 +133,7 @@ impl Drop for LineWrapperHandle {
let mut state = self.text_system.wrapper_pool.lock(); let mut state = self.text_system.wrapper_pool.lock();
let wrapper = self.wrapper.take().unwrap(); let wrapper = self.wrapper.take().unwrap();
state state
.get_mut(&(wrapper.font_id, wrapper.font_size)) .get_mut(&(wrapper.font.clone(), wrapper.font_size))
.unwrap() .unwrap()
.push(wrapper); .push(wrapper);
} }
@ -256,8 +219,8 @@ impl Display for FontStyle {
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct RunStyle { pub struct RunStyle {
pub font: Font,
pub color: Hsla, pub color: Hsla,
pub font_id: FontId,
pub underline: Option<UnderlineStyle>, pub underline: Option<UnderlineStyle>,
} }
@ -305,3 +268,40 @@ pub struct Run {
pub font_id: FontId, pub font_id: FontId,
pub glyphs: Vec<Glyph>, pub glyphs: Vec<Glyph>,
} }
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Font {
pub family: SharedString,
pub features: FontFeatures,
pub weight: FontWeight,
pub style: FontStyle,
}
pub fn font(family: impl Into<SharedString>) -> Font {
Font {
family: family.into(),
features: FontFeatures::default(),
weight: FontWeight::default(),
style: FontStyle::default(),
}
}
impl Font {
pub fn bold(mut self) -> Self {
self.weight = FontWeight::BOLD;
self
}
}
#[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<f32>,
}

View file

@ -1,11 +1,10 @@
use super::FontId; use crate::{px, Font, Line, Pixels, PlatformTextSystem, RunStyle, ShapedBoundary};
use crate::{px, Line, Pixels, PlatformTextSystem, RunStyle, ShapedBoundary};
use collections::HashMap; use collections::HashMap;
use std::{iter, sync::Arc}; use std::{iter, sync::Arc};
pub struct LineWrapper { pub struct LineWrapper {
text_system: Arc<dyn PlatformTextSystem>, text_system: Arc<dyn PlatformTextSystem>,
pub(crate) font_id: FontId, pub(crate) font: Font,
pub(crate) font_size: Pixels, pub(crate) font_size: Pixels,
cached_ascii_char_widths: [Option<Pixels>; 128], cached_ascii_char_widths: [Option<Pixels>; 128],
cached_other_char_widths: HashMap<char, Pixels>, cached_other_char_widths: HashMap<char, Pixels>,
@ -14,14 +13,10 @@ pub struct LineWrapper {
impl LineWrapper { impl LineWrapper {
pub const MAX_INDENT: u32 = 256; pub const MAX_INDENT: u32 = 256;
pub fn new( pub fn new(font: Font, font_size: Pixels, text_system: Arc<dyn PlatformTextSystem>) -> Self {
font_id: FontId,
font_size: Pixels,
text_system: Arc<dyn PlatformTextSystem>,
) -> Self {
Self { Self {
text_system, text_system,
font_id, font,
font_size, font_size,
cached_ascii_char_widths: [None; 128], cached_ascii_char_widths: [None; 128],
cached_other_char_widths: HashMap::default(), cached_other_char_widths: HashMap::default(),
@ -190,7 +185,7 @@ impl LineWrapper {
&[( &[(
1, 1,
RunStyle { RunStyle {
font_id: self.font_id, font: self.font.clone(),
color: Default::default(), color: Default::default(),
underline: Default::default(), underline: Default::default(),
}, },
@ -215,21 +210,17 @@ impl Boundary {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::{App, FontFeatures, FontWeight}; use crate::{font, App};
#[test] #[test]
fn test_wrap_line() { fn test_wrap_line() {
App::test().run(|cx| { App::test().run(|cx| {
let text_system = cx.text_system().clone(); let text_system = cx.text_system().clone();
let family = text_system let mut wrapper = LineWrapper::new(
.load_font_family(&["Courier"], &Default::default()) font("Courier"),
.unwrap(); px(16.),
let font_id = text_system text_system.platform_text_system.clone(),
.select_font(family, Default::default(), Default::default()) );
.unwrap();
let mut wrapper =
LineWrapper::new(font_id, px(16.), text_system.platform_text_system.clone());
assert_eq!( assert_eq!(
wrapper wrapper
.wrap_line("aa bbb cccc ddddd eeee", px(72.)) .wrap_line("aa bbb cccc ddddd eeee", px(72.))
@ -290,21 +281,13 @@ mod tests {
App::test().run(|cx| { App::test().run(|cx| {
let text_system = cx.text_system().clone(); let text_system = cx.text_system().clone();
let family = text_system
.load_font_family(&["Helvetica"], &FontFeatures::default())
.unwrap();
let font_id = text_system
.select_font(family, Default::default(), Default::default())
.unwrap();
let normal = RunStyle { let normal = RunStyle {
font_id, font: font("Helvetica"),
color: Default::default(), color: Default::default(),
underline: Default::default(), underline: Default::default(),
}; };
let bold = RunStyle { let bold = RunStyle {
font_id: text_system font: font("Helvetica").bold(),
.select_font(family, FontWeight::BOLD, Default::default())
.unwrap(),
color: Default::default(), color: Default::default(),
underline: Default::default(), underline: Default::default(),
}; };
@ -317,13 +300,16 @@ mod tests {
(4, normal.clone()), (4, normal.clone()),
(5, bold.clone()), (5, bold.clone()),
(6, normal.clone()), (6, normal.clone()),
(1, bold), (1, bold.clone()),
(7, normal), (7, normal.clone()),
], ],
); );
let mut wrapper = let mut wrapper = LineWrapper::new(
LineWrapper::new(font_id, px(16.), text_system.platform_text_system.clone()); normal.font,
px(16.),
text_system.platform_text_system.clone(),
);
assert_eq!( assert_eq!(
wrapper wrapper
.wrap_shaped_line(text, &line, px(72.)) .wrap_shaped_line(text, &line, px(72.))

View file

@ -139,7 +139,7 @@ impl<'a> PartialEq for CacheKeyRef<'a> {
&& self.runs.len() == other.runs.len() && self.runs.len() == other.runs.len()
&& self.runs.iter().zip(other.runs.iter()).all( && self.runs.iter().zip(other.runs.iter()).all(
|((len_a, style_a), (len_b, style_b))| { |((len_a, style_a), (len_b, style_b))| {
len_a == len_b && style_a.font_id == style_b.font_id len_a == len_b && style_a.font == style_b.font
}, },
) )
} }
@ -151,7 +151,7 @@ impl<'a> Hash for CacheKeyRef<'a> {
self.font_size.hash(state); self.font_size.hash(state);
for (len, style_id) in self.runs { for (len, style_id) in self.runs {
len.hash(state); len.hash(state);
style_id.font_id.hash(state); style_id.font.hash(state);
} }
} }
} }