Start work on underlined text

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Max Brunsfeld
2021-09-06 15:36:09 -07:00
co-authored by Nathan Sobo
parent 8e5c709057
commit 9346aa300d
11 changed files with 317 additions and 152 deletions
+51 -43
View File
@@ -1,5 +1,4 @@
use crate::{
color::Color,
fonts::{FontId, GlyphId, Metrics, Properties},
geometry::{
rect::{RectF, RectI},
@@ -7,7 +6,7 @@ use crate::{
vector::{vec2f, vec2i, Vector2F},
},
platform,
text_layout::{Glyph, LineLayout, Run},
text_layout::{Glyph, LineLayout, Run, RunStyle},
};
use cocoa::appkit::{CGFloat, CGPoint};
use core_foundation::{
@@ -87,12 +86,7 @@ impl platform::FontSystem for FontSystem {
.rasterize_glyph(font_id, font_size, glyph_id, subpixel_shift, scale_factor)
}
fn layout_line(
&self,
text: &str,
font_size: f32,
runs: &[(usize, FontId, Color)],
) -> LineLayout {
fn layout_line(&self, text: &str, font_size: f32, runs: &[(usize, RunStyle)]) -> LineLayout {
self.0.read().layout_line(text, font_size, runs)
}
@@ -210,12 +204,7 @@ impl FontSystemState {
}
}
fn layout_line(
&self,
text: &str,
font_size: f32,
runs: &[(usize, FontId, Color)],
) -> LineLayout {
fn layout_line(&self, text: &str, font_size: f32, runs: &[(usize, RunStyle)]) -> LineLayout {
let font_id_attr_name = CFString::from_static_string("zed_font_id");
// Construct the attributed string, converting UTF8 ranges to UTF16 ranges.
@@ -227,20 +216,20 @@ impl FontSystemState {
let last_run: RefCell<Option<(usize, FontId)>> = Default::default();
let font_runs = runs
.iter()
.filter_map(|(len, font_id, _)| {
.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 font_id == last_font_id {
if style.font_id == *last_font_id {
*last_len += *len;
None
} else {
let result = (*last_len, *last_font_id);
*last_len = *len;
*last_font_id = *font_id;
*last_font_id = style.font_id;
Some(result)
}
} else {
*last_run = Some((*len, *font_id));
*last_run = Some((*len, style.font_id));
None
}
})
@@ -415,9 +404,8 @@ extern "C" {
#[cfg(test)]
mod tests {
use crate::MutableAppContext;
use super::*;
use crate::MutableAppContext;
use font_kit::properties::{Style, Weight};
use platform::FontSystem as _;
@@ -426,13 +414,25 @@ mod tests {
// This is failing intermittently on CI and we don't have time to figure it out
let fonts = FontSystem::new();
let menlo = fonts.load_family("Menlo").unwrap();
let menlo_regular = fonts.select_font(&menlo, &Properties::new()).unwrap();
let menlo_italic = fonts
.select_font(&menlo, &Properties::new().style(Style::Italic))
.unwrap();
let menlo_bold = fonts
.select_font(&menlo, &Properties::new().weight(Weight::BOLD))
.unwrap();
let menlo_regular = RunStyle {
font_id: fonts.select_font(&menlo, &Properties::new()).unwrap(),
color: Default::default(),
underline: false,
};
let menlo_italic = RunStyle {
font_id: fonts
.select_font(&menlo, &Properties::new().style(Style::Italic))
.unwrap(),
color: Default::default(),
underline: false,
};
let menlo_bold = RunStyle {
font_id: fonts
.select_font(&menlo, &Properties::new().weight(Weight::BOLD))
.unwrap(),
color: Default::default(),
underline: false,
};
assert_ne!(menlo_regular, menlo_italic);
assert_ne!(menlo_regular, menlo_bold);
assert_ne!(menlo_italic, menlo_bold);
@@ -440,18 +440,14 @@ mod tests {
let line = fonts.layout_line(
"hello world",
16.0,
&[
(2, menlo_bold, Default::default()),
(4, menlo_italic, Default::default()),
(5, menlo_regular, Default::default()),
],
&[(2, menlo_bold), (4, menlo_italic), (5, menlo_regular)],
);
assert_eq!(line.runs.len(), 3);
assert_eq!(line.runs[0].font_id, menlo_bold);
assert_eq!(line.runs[0].font_id, menlo_bold.font_id);
assert_eq!(line.runs[0].glyphs.len(), 2);
assert_eq!(line.runs[1].font_id, menlo_italic);
assert_eq!(line.runs[1].font_id, menlo_italic.font_id);
assert_eq!(line.runs[1].glyphs.len(), 4);
assert_eq!(line.runs[2].font_id, menlo_regular);
assert_eq!(line.runs[2].font_id, menlo_regular.font_id);
assert_eq!(line.runs[2].glyphs.len(), 5);
}
@@ -459,18 +455,26 @@ mod tests {
fn test_glyph_offsets() -> anyhow::Result<()> {
let fonts = FontSystem::new();
let zapfino = fonts.load_family("Zapfino")?;
let zapfino_regular = fonts.select_font(&zapfino, &Properties::new())?;
let zapfino_regular = RunStyle {
font_id: fonts.select_font(&zapfino, &Properties::new())?,
color: Default::default(),
underline: false,
};
let menlo = fonts.load_family("Menlo")?;
let menlo_regular = fonts.select_font(&menlo, &Properties::new())?;
let menlo_regular = RunStyle {
font_id: fonts.select_font(&menlo, &Properties::new())?,
color: Default::default(),
underline: false,
};
let text = "This is, m𐍈re 𐍈r less, Zapfino!𐍈";
let line = fonts.layout_line(
text,
16.0,
&[
(9, zapfino_regular, Color::default()),
(13, menlo_regular, Color::default()),
(text.len() - 22, zapfino_regular, Color::default()),
(9, zapfino_regular),
(13, menlo_regular),
(text.len() - 22, zapfino_regular),
],
);
assert_eq!(
@@ -536,15 +540,19 @@ mod tests {
fn test_layout_line_bom_char() {
let fonts = FontSystem::new();
let font_ids = fonts.load_family("Helvetica").unwrap();
let font_id = fonts.select_font(&font_ids, &Default::default()).unwrap();
let style = RunStyle {
font_id: fonts.select_font(&font_ids, &Default::default()).unwrap(),
color: Default::default(),
underline: false,
};
let line = "\u{feff}";
let layout = fonts.layout_line(line, 16., &[(line.len(), font_id, Default::default())]);
let layout = fonts.layout_line(line, 16., &[(line.len(), style)]);
assert_eq!(layout.len, line.len());
assert!(layout.runs.is_empty());
let line = "a\u{feff}b";
let layout = fonts.layout_line(line, 16., &[(line.len(), font_id, Default::default())]);
let layout = fonts.layout_line(line, 16., &[(line.len(), style)]);
assert_eq!(layout.len, line.len());
assert_eq!(layout.runs.len(), 1);
assert_eq!(layout.runs[0].glyphs.len(), 2);