Checkpoint
This commit is contained in:
parent
e9a84a21e4
commit
96f9c67e77
8 changed files with 171 additions and 230 deletions
|
@ -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);
|
||||||
|
|
|
@ -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>,
|
|
||||||
}
|
|
||||||
|
|
|
@ -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,21 +87,21 @@ 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
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -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,
|
||||||
|
|
|
@ -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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>,
|
||||||
|
}
|
||||||
|
|
|
@ -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.))
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue