Use line height from attrs

This commit is contained in:
Jeremy Soller 2024-06-06 15:21:44 -06:00
parent 8638ec29bb
commit 37688747e1
6 changed files with 44 additions and 60 deletions

View file

@ -26,6 +26,7 @@ fn set_buffer_text<'a>(buffer: &mut BorrowedWithFontSystem<'a, Buffer>) {
let comic_attrs = attrs.family(Family::Name("Comic Neue")); let comic_attrs = attrs.family(Family::Name("Comic Neue"));
let spans: &[(&str, Attrs)] = &[ 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 8 ", attrs.metrics(Metrics::relative(8.0, 1.2))),
("Font size 20 ", attrs.metrics(Metrics::relative(20.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))), ("Font size 14 ", attrs.metrics(Metrics::relative(14.0, 1.2))),

View file

@ -26,6 +26,8 @@ pub struct LayoutRun<'a> {
pub line_y: f32, pub line_y: f32,
/// Y offset to top of line /// Y offset to top of line
pub line_top: f32, pub line_top: f32,
/// Y offset to next line
pub line_height: f32,
/// Width of line /// Width of line
pub line_w: f32, pub line_w: f32,
} }
@ -92,43 +94,18 @@ pub struct LayoutRunIter<'b> {
buffer: &'b Buffer, buffer: &'b Buffer,
line_i: usize, line_i: usize,
layout_i: usize, layout_i: usize,
remaining_len: usize,
total_layout: i32, total_layout: i32,
line_top: f32,
} }
impl<'b> LayoutRunIter<'b> { impl<'b> LayoutRunIter<'b> {
pub fn new(buffer: &'b Buffer) -> Self { 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 { Self {
buffer, buffer,
line_i: buffer.scroll.line, line_i: buffer.scroll.line,
layout_i: 0, layout_i: 0,
remaining_len: bottom_cropped_layout_lines,
total_layout: 0, total_layout: 0,
line_top: 0.0,
} }
} }
} }
@ -136,10 +113,6 @@ impl<'b> LayoutRunIter<'b> {
impl<'b> Iterator for LayoutRunIter<'b> { impl<'b> Iterator for LayoutRunIter<'b> {
type Item = LayoutRun<'b>; type Item = LayoutRun<'b>;
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining_len, Some(self.remaining_len))
}
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while let Some(line) = self.buffer.lines.get(self.line_i) { while let Some(line) = self.buffer.lines.get(self.line_i) {
let shape = line.shape_opt().as_ref()?; let shape = line.shape_opt().as_ref()?;
@ -153,30 +126,33 @@ impl<'b> Iterator for LayoutRunIter<'b> {
continue; continue;
} }
let line_top = self let mut line_height = self.buffer.metrics.line_height;
.total_layout for glyph in layout_line.glyphs.iter() {
.saturating_sub(self.buffer.scroll.layout) if let Some(glyph_line_height) = glyph.line_height_opt {
.saturating_sub(1) as f32 line_height = line_height.max(glyph_line_height);
* self.buffer.metrics.line_height; }
}
let line_top = self.line_top;
let glyph_height = layout_line.max_ascent + layout_line.max_descent; 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; let line_y = line_top + centering_offset + layout_line.max_ascent;
if line_top + centering_offset > self.buffer.height { if line_top + centering_offset > self.buffer.height {
return None; return None;
} }
return self.remaining_len.checked_sub(1).map(|num| { self.line_top += line_height;
self.remaining_len = num;
LayoutRun { return Some(LayoutRun {
line_i: self.line_i, line_i: self.line_i,
text: line.text(), text: line.text(),
rtl: shape.rtl, rtl: shape.rtl,
glyphs: &layout_line.glyphs, glyphs: &layout_line.glyphs,
line_y, line_y,
line_top, line_top,
line_w: layout_line.w, line_height,
} line_w: layout_line.w,
}); });
} }
self.line_i += 1; self.line_i += 1;
@ -187,8 +163,6 @@ impl<'b> Iterator for LayoutRunIter<'b> {
} }
} }
impl<'b> ExactSizeIterator for LayoutRunIter<'b> {}
/// Metrics of text /// Metrics of text
#[derive(Clone, Copy, Debug, Default, PartialEq)] #[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Metrics { pub struct Metrics {
@ -798,21 +772,19 @@ impl Buffer {
#[cfg(all(feature = "std", not(target_arch = "wasm32")))] #[cfg(all(feature = "std", not(target_arch = "wasm32")))]
let instant = std::time::Instant::now(); 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 new_cursor_opt = None;
let mut runs = self.layout_runs().peekable(); let mut runs = self.layout_runs().peekable();
let mut first_run = true; let mut first_run = true;
while let Some(run) = runs.next() { 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; first_run = false;
let new_cursor = Cursor::new(run.line_i, 0); let new_cursor = Cursor::new(run.line_i, 0);
new_cursor_opt = Some(new_cursor); 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_glyph = run.glyphs.len();
let mut new_cursor_char = 0; let mut new_cursor_char = 0;
let mut new_cursor_affinity = Affinity::After; let mut new_cursor_affinity = Affinity::After;
@ -1128,7 +1100,7 @@ impl Buffer {
)?; )?;
} }
Motion::Vertical(px) => { Motion::Vertical(px) => {
// TODO more efficient // TODO more efficient, use layout run line height
let lines = px / self.metrics().line_height as i32; let lines = px / self.metrics().line_height as i32;
match lines.cmp(&0) { match lines.cmp(&0) {
cmp::Ordering::Less => { cmp::Ordering::Less => {

View file

@ -57,11 +57,11 @@ impl<'buffer> Editor<'buffer> {
F: FnMut(i32, i32, u32, u32, Color), F: FnMut(i32, i32, u32, u32, Color),
{ {
self.with_buffer(|buffer| { self.with_buffer(|buffer| {
let line_height = buffer.metrics().line_height;
for run in buffer.layout_runs() { for run in buffer.layout_runs() {
let line_i = run.line_i; let line_i = run.line_i;
let line_y = run.line_y; let line_y = run.line_y;
let line_top = run.line_top; let line_top = run.line_top;
let line_height = run.line_height;
let cursor_glyph_opt = |cursor: &Cursor| -> Option<(usize, f32)> { let cursor_glyph_opt = |cursor: &Cursor| -> Option<(usize, f32)> {
if cursor.line == line_i { if cursor.line == line_i {

View file

@ -312,11 +312,11 @@ impl<'syntax_system, 'buffer> ViEditor<'syntax_system, 'buffer> {
let size = buffer.size(); let size = buffer.size();
f(0, 0, size.0 as u32, size.1 as u32, background_color); f(0, 0, size.0 as u32, size.1 as u32, background_color);
let font_size = buffer.metrics().font_size; let font_size = buffer.metrics().font_size;
let line_height = buffer.metrics().line_height;
for run in buffer.layout_runs() { for run in buffer.layout_runs() {
let line_i = run.line_i; let line_i = run.line_i;
let line_y = run.line_y; let line_y = run.line_y;
let line_top = run.line_top; let line_top = run.line_top;
let line_height = run.line_height;
let cursor_glyph_opt = |cursor: &Cursor| -> Option<(usize, f32, f32)> { let cursor_glyph_opt = |cursor: &Cursor| -> Option<(usize, f32, f32)> {
//TODO: better calculation of width //TODO: better calculation of width

View file

@ -16,6 +16,8 @@ pub struct LayoutGlyph {
pub end: usize, pub end: usize,
/// Font size of the glyph /// Font size of the glyph
pub font_size: f32, pub font_size: f32,
/// Line height of the glyph, will override buffer setting
pub line_height_opt: Option<f32>,
/// Font id of the glyph /// Font id of the glyph
pub font_id: fontdb::ID, pub font_id: fontdb::ID,
/// Font id of the glyph /// Font id of the glyph

View file

@ -494,6 +494,7 @@ impl ShapeGlyph {
fn layout( fn layout(
&self, &self,
font_size: f32, font_size: f32,
line_height_opt: Option<f32>,
x: f32, x: f32,
y: f32, y: f32,
w: f32, w: f32,
@ -503,6 +504,7 @@ impl ShapeGlyph {
start: self.start, start: self.start,
end: self.end, end: self.end,
font_size, font_size,
line_height_opt,
font_id: self.font_id, font_id: self.font_id,
glyph_id: self.glyph_id, glyph_id: self.glyph_id,
x, x,
@ -1418,7 +1420,14 @@ impl ShapeLine {
x -= x_advance; x -= x_advance;
} }
let y_advance = glyph_font_size * glyph.y_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 { if !self.rtl {
x += x_advance; x += x_advance;
} }