From 37688747e176e61118425c9ce25fea62e7af91c7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 6 Jun 2024 15:21:44 -0600 Subject: [PATCH] Use line height from attrs --- examples/rich-text/src/main.rs | 1 + src/buffer.rs | 86 ++++++++++++---------------------- src/edit/editor.rs | 2 +- src/edit/vi.rs | 2 +- src/layout.rs | 2 + src/shape.rs | 11 ++++- 6 files changed, 44 insertions(+), 60 deletions(-) diff --git a/examples/rich-text/src/main.rs b/examples/rich-text/src/main.rs index 4762e43..2c42b73 100644 --- a/examples/rich-text/src/main.rs +++ b/examples/rich-text/src/main.rs @@ -26,6 +26,7 @@ fn set_buffer_text<'a>(buffer: &mut BorrowedWithFontSystem<'a, Buffer>) { let comic_attrs = attrs.family(Family::Name("Comic Neue")); let spans: &[(&str, Attrs)] = &[ + ("Font size 64 ", attrs.metrics(Metrics::relative(64.0, 1.2))), ("Font size 8 ", attrs.metrics(Metrics::relative(8.0, 1.2))), ("Font size 20 ", attrs.metrics(Metrics::relative(20.0, 1.2))), ("Font size 14 ", attrs.metrics(Metrics::relative(14.0, 1.2))), diff --git a/src/buffer.rs b/src/buffer.rs index 8da5942..46f70a5 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -26,6 +26,8 @@ pub struct LayoutRun<'a> { pub line_y: f32, /// Y offset to top of line pub line_top: f32, + /// Y offset to next line + pub line_height: f32, /// Width of line pub line_w: f32, } @@ -92,43 +94,18 @@ pub struct LayoutRunIter<'b> { buffer: &'b Buffer, line_i: usize, layout_i: usize, - remaining_len: usize, total_layout: i32, + line_top: f32, } impl<'b> LayoutRunIter<'b> { pub fn new(buffer: &'b Buffer) -> Self { - let total_layout_lines: usize = buffer - .lines - .iter() - .skip(buffer.scroll.line) - .map(|line| { - line.layout_opt() - .as_ref() - .map(|layout| layout.len()) - .unwrap_or_default() - }) - .sum(); - let top_cropped_layout_lines = - total_layout_lines.saturating_sub(buffer.scroll.layout.try_into().unwrap_or_default()); - let maximum_lines = if buffer.metrics.line_height == 0.0 { - 0 - } else { - (buffer.height / buffer.metrics.line_height) as i32 - }; - let bottom_cropped_layout_lines = - if top_cropped_layout_lines > maximum_lines.try_into().unwrap_or_default() { - maximum_lines.try_into().unwrap_or_default() - } else { - top_cropped_layout_lines - }; - Self { buffer, line_i: buffer.scroll.line, layout_i: 0, - remaining_len: bottom_cropped_layout_lines, total_layout: 0, + line_top: 0.0, } } } @@ -136,10 +113,6 @@ impl<'b> LayoutRunIter<'b> { impl<'b> Iterator for LayoutRunIter<'b> { type Item = LayoutRun<'b>; - fn size_hint(&self) -> (usize, Option) { - (self.remaining_len, Some(self.remaining_len)) - } - fn next(&mut self) -> Option { while let Some(line) = self.buffer.lines.get(self.line_i) { let shape = line.shape_opt().as_ref()?; @@ -153,30 +126,33 @@ impl<'b> Iterator for LayoutRunIter<'b> { continue; } - let line_top = self - .total_layout - .saturating_sub(self.buffer.scroll.layout) - .saturating_sub(1) as f32 - * self.buffer.metrics.line_height; + let mut line_height = self.buffer.metrics.line_height; + for glyph in layout_line.glyphs.iter() { + if let Some(glyph_line_height) = glyph.line_height_opt { + line_height = line_height.max(glyph_line_height); + } + } + + let line_top = self.line_top; let glyph_height = layout_line.max_ascent + layout_line.max_descent; - let centering_offset = (self.buffer.metrics.line_height - glyph_height) / 2.0; + let centering_offset = (line_height - glyph_height) / 2.0; let line_y = line_top + centering_offset + layout_line.max_ascent; if line_top + centering_offset > self.buffer.height { return None; } - return self.remaining_len.checked_sub(1).map(|num| { - self.remaining_len = num; - LayoutRun { - line_i: self.line_i, - text: line.text(), - rtl: shape.rtl, - glyphs: &layout_line.glyphs, - line_y, - line_top, - line_w: layout_line.w, - } + self.line_top += line_height; + + return Some(LayoutRun { + line_i: self.line_i, + text: line.text(), + rtl: shape.rtl, + glyphs: &layout_line.glyphs, + line_y, + line_top, + line_height, + line_w: layout_line.w, }); } self.line_i += 1; @@ -187,8 +163,6 @@ impl<'b> Iterator for LayoutRunIter<'b> { } } -impl<'b> ExactSizeIterator for LayoutRunIter<'b> {} - /// Metrics of text #[derive(Clone, Copy, Debug, Default, PartialEq)] pub struct Metrics { @@ -798,21 +772,19 @@ impl Buffer { #[cfg(all(feature = "std", not(target_arch = "wasm32")))] let instant = std::time::Instant::now(); - let font_size = self.metrics.font_size; - let line_height = self.metrics.line_height; - let mut new_cursor_opt = None; let mut runs = self.layout_runs().peekable(); let mut first_run = true; while let Some(run) = runs.next() { - let line_y = run.line_y; + let line_top = run.line_top; + let line_height = run.line_height; - if first_run && y < line_y - font_size { + if first_run && y < line_top { first_run = false; let new_cursor = Cursor::new(run.line_i, 0); new_cursor_opt = Some(new_cursor); - } else if y >= line_y - font_size && y < line_y - font_size + line_height { + } else if y >= line_top && y < line_top + line_height { let mut new_cursor_glyph = run.glyphs.len(); let mut new_cursor_char = 0; let mut new_cursor_affinity = Affinity::After; @@ -1128,7 +1100,7 @@ impl Buffer { )?; } Motion::Vertical(px) => { - // TODO more efficient + // TODO more efficient, use layout run line height let lines = px / self.metrics().line_height as i32; match lines.cmp(&0) { cmp::Ordering::Less => { diff --git a/src/edit/editor.rs b/src/edit/editor.rs index cf76901..c7784d9 100644 --- a/src/edit/editor.rs +++ b/src/edit/editor.rs @@ -57,11 +57,11 @@ impl<'buffer> Editor<'buffer> { F: FnMut(i32, i32, u32, u32, Color), { self.with_buffer(|buffer| { - let line_height = buffer.metrics().line_height; for run in buffer.layout_runs() { let line_i = run.line_i; let line_y = run.line_y; let line_top = run.line_top; + let line_height = run.line_height; let cursor_glyph_opt = |cursor: &Cursor| -> Option<(usize, f32)> { if cursor.line == line_i { diff --git a/src/edit/vi.rs b/src/edit/vi.rs index e1913cc..92b0480 100644 --- a/src/edit/vi.rs +++ b/src/edit/vi.rs @@ -312,11 +312,11 @@ impl<'syntax_system, 'buffer> ViEditor<'syntax_system, 'buffer> { let size = buffer.size(); f(0, 0, size.0 as u32, size.1 as u32, background_color); let font_size = buffer.metrics().font_size; - let line_height = buffer.metrics().line_height; for run in buffer.layout_runs() { let line_i = run.line_i; let line_y = run.line_y; let line_top = run.line_top; + let line_height = run.line_height; let cursor_glyph_opt = |cursor: &Cursor| -> Option<(usize, f32, f32)> { //TODO: better calculation of width diff --git a/src/layout.rs b/src/layout.rs index 99a78de..64226b5 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -16,6 +16,8 @@ pub struct LayoutGlyph { pub end: usize, /// Font size of the glyph pub font_size: f32, + /// Line height of the glyph, will override buffer setting + pub line_height_opt: Option, /// Font id of the glyph pub font_id: fontdb::ID, /// Font id of the glyph diff --git a/src/shape.rs b/src/shape.rs index 75ab7f0..ef834d8 100644 --- a/src/shape.rs +++ b/src/shape.rs @@ -494,6 +494,7 @@ impl ShapeGlyph { fn layout( &self, font_size: f32, + line_height_opt: Option, x: f32, y: f32, w: f32, @@ -503,6 +504,7 @@ impl ShapeGlyph { start: self.start, end: self.end, font_size, + line_height_opt, font_id: self.font_id, glyph_id: self.glyph_id, x, @@ -1418,7 +1420,14 @@ impl ShapeLine { x -= x_advance; } let y_advance = glyph_font_size * glyph.y_advance; - glyphs.push(glyph.layout(glyph_font_size, x, y, x_advance, span.level)); + glyphs.push(glyph.layout( + glyph_font_size, + glyph.metrics_opt.map(|x| x.line_height), + x, + y, + x_advance, + span.level, + )); if !self.rtl { x += x_advance; }