cosmic-text/src/buffer.rs

673 lines
21 KiB
Rust
Raw Normal View History

2022-10-24 08:56:48 -06:00
// SPDX-License-Identifier: MIT OR Apache-2.0
2022-11-08 08:43:27 -07:00
#[cfg(not(feature = "std"))]
use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::{
cmp,
2022-10-18 17:04:22 -06:00
fmt,
2022-10-18 12:42:37 -06:00
};
2022-10-24 14:18:40 -06:00
use unicode_segmentation::UnicodeSegmentation;
2022-10-18 12:07:22 -06:00
use crate::{Attrs, AttrsList, BufferLine, FontSystem, LayoutGlyph, LayoutLine, ShapeLine, Wrap};
2022-11-08 08:43:27 -07:00
#[cfg(feature = "swash")]
use crate::Color;
2022-10-18 12:07:22 -06:00
2022-10-18 17:13:48 -06:00
/// Current cursor location
2022-12-30 00:15:00 -08:00
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
2022-10-31 11:24:36 -06:00
pub struct Cursor {
/// Text line the cursor is on
pub line: usize,
/// Index of glyph at cursor (will insert behind this glyph)
pub index: usize,
2022-10-18 12:07:22 -06:00
}
2022-10-31 11:24:36 -06:00
impl Cursor {
2022-10-27 10:29:19 -06:00
/// Create a new cursor
pub const fn new(line: usize, index: usize) -> Self {
Self { line, index }
2022-10-18 12:07:22 -06:00
}
}
2022-10-31 11:24:36 -06:00
pub struct LayoutCursor {
pub line: usize,
pub layout: usize,
pub glyph: usize,
2022-10-22 11:42:08 -06:00
}
2022-10-31 11:24:36 -06:00
impl LayoutCursor {
pub fn new(line: usize, layout: usize, glyph: usize) -> Self {
2022-10-22 11:42:08 -06:00
Self { line, layout, glyph }
}
}
2022-10-27 10:29:19 -06:00
/// A line of visible text for rendering
2022-10-31 11:24:36 -06:00
pub struct LayoutRun<'a> {
2022-10-25 12:52:46 -06:00
/// The index of the original text line
pub line_i: usize,
2022-10-25 12:52:46 -06:00
/// The original text line
pub text: &'a str,
2022-10-25 13:15:52 -06:00
/// True if the original paragraph direction is RTL
2022-10-25 12:52:46 -06:00
pub rtl: bool,
/// The array of layout glyphs to draw
pub glyphs: &'a [LayoutGlyph],
/// Y offset of line
pub line_y: i32,
2022-12-15 04:59:31 +01:00
/// width of line
pub line_w: f32,
2022-10-25 12:52:46 -06:00
}
/// An iterator of visible text lines, see [`LayoutRun`]
2022-10-31 11:24:36 -06:00
pub struct LayoutRunIter<'a, 'b> {
buffer: &'b Buffer<'a>,
2022-10-25 12:52:46 -06:00
line_i: usize,
layout_i: usize,
remaining_len: usize,
2022-10-25 11:40:10 -06:00
line_y: i32,
2022-10-25 12:52:46 -06:00
total_layout: i32,
}
2022-10-31 11:24:36 -06:00
impl<'a, 'b> LayoutRunIter<'a, 'b> {
pub fn new(buffer: &'b Buffer<'a>) -> Self {
let total_layout_lines: usize = buffer.lines.iter().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.try_into().unwrap_or_default());
let maximum_lines = buffer.height.checked_div(buffer.metrics.line_height).unwrap_or_default();
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
};
2022-10-25 12:52:46 -06:00
Self {
buffer,
line_i: 0,
layout_i: 0,
remaining_len: bottom_cropped_layout_lines as usize,
2022-10-25 12:52:46 -06:00
line_y: buffer.metrics.font_size - buffer.metrics.line_height,
total_layout: 0,
}
}
}
2022-10-31 11:24:36 -06:00
impl<'a, 'b> Iterator for LayoutRunIter<'a, 'b> {
type Item = LayoutRun<'b>;
2022-10-25 12:52:46 -06:00
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining_len, Some(self.remaining_len))
}
2022-10-25 12:52:46 -06:00
fn next(&mut self) -> Option<Self::Item> {
while let Some(line) = self.buffer.lines.get(self.line_i) {
let shape = line.shape_opt().as_ref()?;
let layout = line.layout_opt().as_ref()?;
2022-10-25 12:52:46 -06:00
while let Some(layout_line) = layout.get(self.layout_i) {
self.layout_i += 1;
let scrolled = self.total_layout < self.buffer.scroll;
self.total_layout += 1;
if scrolled {
continue;
}
self.line_y += self.buffer.metrics.line_height;
if self.line_y > self.buffer.height {
return None;
}
self.remaining_len -= 1;
2022-10-31 11:24:36 -06:00
return Some(LayoutRun {
line_i: self.line_i,
text: line.text(),
2022-10-25 12:52:46 -06:00
rtl: shape.rtl,
glyphs: &layout_line.glyphs,
line_y: self.line_y,
2022-12-15 04:59:31 +01:00
line_w: layout_line.w,
2022-10-25 12:52:46 -06:00
});
}
self.line_i += 1;
self.layout_i = 0;
}
None
}
2022-10-25 11:40:10 -06:00
}
impl<'a, 'b> ExactSizeIterator for LayoutRunIter<'a, 'b> { }
2022-10-18 17:13:48 -06:00
/// Metrics of text
2022-10-18 17:04:22 -06:00
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
2022-10-31 11:24:36 -06:00
pub struct Metrics {
2022-10-18 17:13:48 -06:00
/// Font size in pixels
2022-10-18 17:04:22 -06:00
pub font_size: i32,
2022-10-18 17:13:48 -06:00
/// Line height in pixels
2022-10-18 17:04:22 -06:00
pub line_height: i32,
}
2022-10-31 11:24:36 -06:00
impl Metrics {
2022-10-18 17:04:22 -06:00
pub const fn new(font_size: i32, line_height: i32) -> Self {
Self { font_size, line_height }
}
pub const fn scale(self, scale: i32) -> Self {
Self {
font_size: self.font_size * scale,
line_height: self.line_height * scale,
}
}
}
2022-10-31 11:24:36 -06:00
impl fmt::Display for Metrics {
2022-10-18 17:04:22 -06:00
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}px / {}px", self.font_size, self.line_height)
}
}
2022-10-18 17:13:48 -06:00
/// A buffer of text that is shaped and laid out
2022-10-31 11:24:36 -06:00
pub struct Buffer<'a> {
font_system: &'a FontSystem,
/// [BufferLine]s (or paragraphs) of text in the buffer
2022-11-04 09:44:54 -06:00
pub lines: Vec<BufferLine>,
2022-10-31 11:24:36 -06:00
metrics: Metrics,
2022-10-18 12:42:37 -06:00
width: i32,
height: i32,
2022-10-18 13:20:13 -06:00
scroll: i32,
/// True if a redraw is requires. Set to false after processing
redraw: bool,
wrap: Wrap,
2022-10-18 12:07:22 -06:00
}
2022-10-31 11:24:36 -06:00
impl<'a> Buffer<'a> {
/// Create a new [`Buffer`] with the provided [`FontSystem`] and [`Metrics`]
2022-10-18 12:42:37 -06:00
pub fn new(
font_system: &'a FontSystem,
2022-10-31 11:24:36 -06:00
metrics: Metrics,
2022-10-18 12:42:37 -06:00
) -> Self {
let mut buffer = Self {
font_system,
lines: Vec::new(),
2022-10-18 17:04:22 -06:00
metrics,
width: 0,
height: 0,
scroll: 0,
2022-10-18 12:07:22 -06:00
redraw: false,
wrap: Wrap::Word,
};
buffer.set_text("", Attrs::new());
buffer
2022-10-18 12:07:22 -06:00
}
2022-10-31 11:24:36 -06:00
fn relayout(&mut self) {
2022-11-08 08:43:27 -07:00
#[cfg(feature = "std")]
let instant = std::time::Instant::now();
2022-10-31 11:24:36 -06:00
for line in &mut self.lines {
2022-10-31 11:24:36 -06:00
if line.shape_opt().is_some() {
line.reset_layout();
line.layout(
self.font_system,
self.metrics.font_size,
self.width,
self.wrap
2022-10-31 11:24:36 -06:00
);
}
}
self.redraw = true;
2022-11-08 08:43:27 -07:00
#[cfg(feature = "std")]
log::debug!("relayout: {:?}", instant.elapsed());
2022-10-31 11:24:36 -06:00
}
/// Pre-shape lines in the buffer, up to `lines`, return actual number of layout lines
pub fn shape_until(&mut self, lines: i32) -> i32 {
2022-11-08 08:43:27 -07:00
#[cfg(feature = "std")]
let instant = std::time::Instant::now();
2022-10-18 12:07:22 -06:00
let mut reshaped = 0;
let mut total_layout = 0;
for line in &mut self.lines {
if total_layout >= lines {
break;
}
if line.shape_opt().is_none() {
reshaped += 1;
}
let layout = line.layout(
2022-10-26 14:16:48 -06:00
self.font_system,
self.metrics.font_size,
self.width,
self.wrap
);
total_layout += layout.len() as i32;
2022-10-18 12:07:22 -06:00
}
if reshaped > 0 {
2022-11-08 08:43:27 -07:00
#[cfg(feature = "std")]
log::debug!("shape_until {}: {:?}", reshaped, instant.elapsed());
self.redraw = true;
2022-10-18 12:07:22 -06:00
}
total_layout
2022-10-18 12:07:22 -06:00
}
2022-10-25 11:13:22 -06:00
/// Shape lines until cursor, also scrolling to include cursor in view
2022-10-31 11:24:36 -06:00
pub fn shape_until_cursor(&mut self, cursor: Cursor) {
2022-11-08 08:43:27 -07:00
#[cfg(feature = "std")]
let instant = std::time::Instant::now();
let mut reshaped = 0;
let mut layout_i = 0;
for (line_i, line) in self.lines.iter_mut().enumerate() {
2022-10-31 11:24:36 -06:00
if line_i > cursor.line {
break;
}
if line.shape_opt().is_none() {
reshaped += 1;
}
let layout = line.layout(
2022-10-26 14:16:48 -06:00
self.font_system,
self.metrics.font_size,
self.width,
self.wrap
);
2022-10-31 11:24:36 -06:00
if line_i == cursor.line {
let layout_cursor = self.layout_cursor(&cursor);
2022-10-25 20:49:15 -06:00
layout_i += layout_cursor.layout as i32;
break;
} else {
layout_i += layout.len() as i32;
}
}
if reshaped > 0 {
2022-11-08 08:43:27 -07:00
#[cfg(feature = "std")]
log::debug!("shape_until_cursor {}: {:?}", reshaped, instant.elapsed());
self.redraw = true;
}
2022-10-31 11:24:36 -06:00
let lines = self.visible_lines();
2022-10-21 12:31:02 -06:00
if layout_i < self.scroll {
self.scroll = layout_i;
} else if layout_i >= self.scroll + lines {
self.scroll = layout_i - (lines - 1);
}
2022-10-21 12:31:02 -06:00
self.shape_until_scroll();
}
/// Shape lines until scroll
2022-10-25 15:33:48 -06:00
pub fn shape_until_scroll(&mut self) {
2022-10-31 11:24:36 -06:00
let lines = self.visible_lines();
2022-10-18 12:42:37 -06:00
let scroll_end = self.scroll + lines;
let total_layout = self.shape_until(scroll_end);
2022-10-18 12:42:37 -06:00
self.scroll = cmp::max(
0,
cmp::min(
total_layout - (lines - 1),
2022-10-18 12:42:37 -06:00
self.scroll,
),
);
}
2022-10-31 11:24:36 -06:00
pub fn layout_cursor(&self, cursor: &Cursor) -> LayoutCursor {
let line = &self.lines[cursor.line];
2022-10-22 11:42:08 -06:00
//TODO: ensure layout is done?
let layout = line.layout_opt().as_ref().expect("layout not found");
2022-10-22 11:42:08 -06:00
for (layout_i, layout_line) in layout.iter().enumerate() {
for (glyph_i, glyph) in layout_line.glyphs.iter().enumerate() {
if cursor.index == glyph.start {
2022-10-31 11:24:36 -06:00
return LayoutCursor::new(
2022-10-22 11:42:08 -06:00
cursor.line,
layout_i,
glyph_i
);
}
}
match layout_line.glyphs.last() {
Some(glyph) => {
if cursor.index == glyph.end {
2022-10-31 11:24:36 -06:00
return LayoutCursor::new(
2022-10-22 11:42:08 -06:00
cursor.line,
layout_i,
layout_line.glyphs.len()
);
}
},
None => {
2022-10-31 11:24:36 -06:00
return LayoutCursor::new(
2022-10-22 11:42:08 -06:00
cursor.line,
layout_i,
0
);
}
}
}
// Fall back to start of line
//TODO: should this be the end of the line?
2022-10-31 11:24:36 -06:00
LayoutCursor::new(
2022-10-22 11:42:08 -06:00
cursor.line,
0,
0
)
}
/// Get [`FontSystem`] used by this [`Buffer`]
pub fn font_system(&self) -> &'a FontSystem {
self.font_system
}
2022-10-31 11:36:54 -06:00
/// Shape the provided line index and return the result
2022-10-31 11:24:36 -06:00
pub fn line_shape(&mut self, line_i: usize) -> Option<&ShapeLine> {
let line = self.lines.get_mut(line_i)?;
Some(line.shape(self.font_system))
2022-10-22 11:42:08 -06:00
}
2022-10-31 11:36:54 -06:00
/// Lay out the provided line index and return the result
2022-10-31 11:24:36 -06:00
pub fn line_layout(&mut self, line_i: usize) -> Option<&[LayoutLine]> {
let line = self.lines.get_mut(line_i)?;
Some(line.layout(self.font_system, self.metrics.font_size, self.width, self.wrap))
2022-10-19 08:34:34 -06:00
}
/// Get the current [`Metrics`]
2022-10-31 11:24:36 -06:00
pub fn metrics(&self) -> Metrics {
2022-10-18 17:04:22 -06:00
self.metrics
2022-10-18 12:07:22 -06:00
}
/// Set the current [`Metrics`]
2022-10-31 11:24:36 -06:00
pub fn set_metrics(&mut self, metrics: Metrics) {
2022-10-18 17:04:22 -06:00
if metrics != self.metrics {
self.metrics = metrics;
2022-10-18 12:42:37 -06:00
self.relayout();
2022-10-18 13:20:13 -06:00
self.shape_until_scroll();
2022-10-18 12:42:37 -06:00
}
}
/// Get the current [`Wrap`]
pub fn wrap(&self) -> Wrap {
self.wrap
}
/// Set the current [`Wrap`]
pub fn set_wrap(&mut self, wrap: Wrap) {
if wrap != self.wrap {
self.wrap = wrap;
self.relayout();
self.shape_until_scroll();
}
}
2022-10-18 17:04:22 -06:00
/// Get the current buffer dimensions (width, height)
pub fn size(&self) -> (i32, i32) {
(self.width, self.height)
2022-10-18 13:05:36 -06:00
}
2022-10-18 17:04:22 -06:00
/// Set the current buffer dimensions
2022-10-18 12:42:37 -06:00
pub fn set_size(&mut self, width: i32, height: i32) {
if width != self.width || height != self.height {
2022-10-18 12:42:37 -06:00
self.width = width;
self.height = height;
self.relayout();
2022-10-18 12:42:37 -06:00
self.shape_until_scroll();
}
2022-10-18 12:07:22 -06:00
}
2022-10-18 17:04:22 -06:00
/// Get the current scroll location
pub fn scroll(&self) -> i32 {
self.scroll
}
2022-10-31 11:36:54 -06:00
/// Set the current scroll location
2022-10-31 11:24:36 -06:00
pub fn set_scroll(&mut self, scroll: i32) {
if scroll != self.scroll {
self.scroll = scroll;
self.redraw = true;
}
}
2022-10-18 17:04:22 -06:00
/// Get the number of lines that can be viewed in the buffer
2022-10-31 11:24:36 -06:00
pub fn visible_lines(&self) -> i32 {
2022-10-18 17:04:22 -06:00
self.height / self.metrics.line_height
}
/// Set text of buffer, using provided attributes for each line by default
pub fn set_text(&mut self, text: &str, attrs: Attrs<'a>) {
self.lines.clear();
for line in text.lines() {
2022-10-31 11:24:36 -06:00
self.lines.push(BufferLine::new(line.to_string(), AttrsList::new(attrs)));
}
// Make sure there is always one line
if self.lines.is_empty() {
2022-10-31 11:24:36 -06:00
self.lines.push(BufferLine::new(String::new(), AttrsList::new(attrs)));
2022-10-19 13:15:07 -06:00
}
2022-10-19 13:15:07 -06:00
self.scroll = 0;
2022-10-19 13:15:07 -06:00
self.shape_until_scroll();
}
/// True if a redraw is needed
pub fn redraw(&self) -> bool {
self.redraw
}
/// Set redraw needed flag
pub fn set_redraw(&mut self, redraw: bool) {
self.redraw = redraw;
}
2022-10-31 11:24:36 -06:00
/// Get the visible layout runs for rendering and other tasks
pub fn layout_runs<'b>(&'b self) -> LayoutRunIter<'a, 'b> {
LayoutRunIter::new(self)
2022-10-18 12:07:22 -06:00
}
2022-10-31 11:24:36 -06:00
/// Convert x, y position to Cursor (hit detection)
pub fn hit(&self, x: i32, y: i32) -> Option<Cursor> {
2022-11-08 08:43:27 -07:00
#[cfg(feature = "std")]
let instant = std::time::Instant::now();
let font_size = self.metrics.font_size;
let line_height = self.metrics.line_height;
2022-10-25 20:27:46 -06:00
let mut new_cursor_opt = None;
2022-10-25 13:13:13 -06:00
let mut runs = self.layout_runs().peekable();
let mut first_run = true;
while let Some(run) = runs.next() {
2022-10-25 13:13:13 -06:00
let line_y = run.line_y;
if first_run && y < line_y - font_size {
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
2022-10-25 13:13:13 -06:00
{
let mut new_cursor_glyph = run.glyphs.len();
let mut new_cursor_char = 0;
let mut first_glyph = true;
2022-10-25 13:13:13 -06:00
'hit: for (glyph_i, glyph) in run.glyphs.iter().enumerate() {
if first_glyph {
first_glyph = false;
if (run.rtl && x > glyph.x as i32) || (!run.rtl && x < 0) {
new_cursor_glyph = 0;
new_cursor_char = 0;
}
}
2022-10-25 20:27:46 -06:00
if x >= glyph.x as i32
&& x <= (glyph.x + glyph.w) as i32
2022-10-25 13:13:13 -06:00
{
new_cursor_glyph = glyph_i;
let cluster = &run.text[glyph.start..glyph.end];
let total = cluster.grapheme_indices(true).count();
let mut egc_x = glyph.x;
let egc_w = glyph.w / (total as f32);
for (egc_i, egc) in cluster.grapheme_indices(true) {
2022-10-25 20:27:46 -06:00
if x >= egc_x as i32
&& x <= (egc_x + egc_w) as i32
2022-10-25 13:13:13 -06:00
{
new_cursor_char = egc_i;
2022-10-25 20:27:46 -06:00
let right_half = x >= (egc_x + egc_w / 2.0) as i32;
2022-12-16 16:49:29 -07:00
if right_half != glyph.level.is_rtl() {
2022-10-25 13:13:13 -06:00
// If clicking on last half of glyph, move cursor past glyph
new_cursor_char += egc.len();
2022-10-24 14:18:40 -06:00
}
2022-10-25 13:13:13 -06:00
break 'hit;
2022-10-24 14:18:40 -06:00
}
2022-10-25 13:13:13 -06:00
egc_x += egc_w;
}
2022-10-24 14:18:40 -06:00
2022-10-25 20:27:46 -06:00
let right_half = x >= (glyph.x + glyph.w / 2.0) as i32;
2022-12-16 16:49:29 -07:00
if right_half != glyph.level.is_rtl() {
2022-10-25 13:13:13 -06:00
// If clicking on last half of glyph, move cursor past glyph
new_cursor_char = cluster.len();
}
2022-10-25 13:13:13 -06:00
break 'hit;
}
2022-10-25 13:13:13 -06:00
}
2022-10-31 11:24:36 -06:00
let mut new_cursor = Cursor::new(run.line_i, 0);
2022-10-25 13:13:13 -06:00
match run.glyphs.get(new_cursor_glyph) {
Some(glyph) => {
// Position at glyph
new_cursor.index = glyph.start + new_cursor_char;
},
None => if let Some(glyph) = run.glyphs.last() {
// Position at end of line
new_cursor.index = glyph.end;
},
}
2022-10-25 20:27:46 -06:00
new_cursor_opt = Some(new_cursor);
2022-10-25 13:13:13 -06:00
break;
} else if runs.peek().is_none() && y > run.line_y {
let mut new_cursor = Cursor::new(run.line_i, 0);
if let Some(glyph) = run.glyphs.last() {
new_cursor.index = glyph.end;
}
new_cursor_opt = Some(new_cursor);
}
}
2022-11-08 08:43:27 -07:00
#[cfg(feature = "std")]
log::trace!("click({}, {}): {:?}", x, y, instant.elapsed());
2022-10-25 20:27:46 -06:00
new_cursor_opt
}
2022-12-30 00:15:00 -08:00
pub fn highlight_blocks<'b>(&'b self, cursor_start: Cursor, cursor_end: Cursor) -> HighlightBlocksIter<'a, 'b> {
HighlightBlocksIter {
cursor_start,
cursor_end,
line: 0,
layout_line: 0,
run_line: 0,
buffer: self,
}
}
2022-10-25 11:40:10 -06:00
/// Draw the buffer
#[cfg(feature = "swash")]
2022-10-27 09:07:47 -06:00
pub fn draw<F>(&self, cache: &mut crate::SwashCache, color: Color, mut f: F)
where F: FnMut(i32, i32, u32, u32, Color)
2022-10-25 11:40:10 -06:00
{
2022-10-25 12:52:46 -06:00
for run in self.layout_runs() {
for glyph in run.glyphs.iter() {
2022-10-25 11:40:10 -06:00
let (cache_key, x_int, y_int) = (glyph.cache_key, glyph.x_int, glyph.y_int);
2022-10-26 14:16:48 -06:00
let glyph_color = match glyph.color_opt {
2022-10-27 09:07:47 -06:00
Some(some) => some,
2022-10-26 14:16:48 -06:00
None => color,
};
cache.with_pixels(cache_key, glyph_color, |x, y, color| {
f(x_int + x, run.line_y + y_int + y, 1, 1, color);
2022-10-25 11:40:10 -06:00
});
}
2022-10-25 12:52:46 -06:00
}
}
2022-10-18 12:07:22 -06:00
}
2022-12-30 00:15:00 -08:00
pub struct HighlightBlocksIter<'a, 'b> {
cursor_start: Cursor,
cursor_end: Cursor,
line: usize,
layout_line: usize,
run_line: usize,
buffer: &'b Buffer<'a>,
}
impl<'a, 'b> Iterator for HighlightBlocksIter<'a, 'b> {
type Item = (i32, i32, u32, u32);
fn next(&mut self) -> Option<Self::Item> {
while !self.is_done() {
if let Some(result) = self.peek() {
self.advance();
return Some(result);
}
self.advance();
}
None
}
}
impl<'a, 'b> HighlightBlocksIter<'a, 'b> {
pub fn peek(&self) -> Option<(i32, i32, u32, u32)> {
let Some(line) = self.buffer.lines.get(self.line) else { return None; };
let line: &BufferLine = line;
let run: &LayoutLine = line.layout_opt().as_ref().unwrap().get(self.run_line).unwrap();
let mut x_start = None;
let mut x_end = None;
for glyph in run.glyphs.iter() {
let cursor = Cursor::new(self.line, glyph.start);
if cursor >= self.cursor_start && cursor <= self.cursor_end {
if x_start.is_none() {
x_start = Some(glyph.x.round() as i32);
}
x_end = Some(glyph.x.round() as i32);
}
}
let cursor = Cursor::new(self.line, run.glyphs.last().map_or(0, |glyph| glyph.end));
if cursor >= self.cursor_start && cursor <= self.cursor_end {
if x_start.is_none() {
x_start = Some(run.glyphs.last().map_or(0, |glyph| (glyph.x + glyph.w).round() as i32));
}
x_end = Some(run.glyphs.last().map_or(0, |glyph| (glyph.x + glyph.w).round() as i32));
}
if let Some(x_start) = x_start {
let x_end = x_end.unwrap();
Some((x_start, self.layout_line as i32 * self.buffer.metrics.line_height, (x_end - x_start) as u32, self.buffer.metrics.line_height as u32))
} else {
None
}
}
pub fn advance(&mut self) {
let Some(line) = self.buffer.lines.get(self.line) else { return; };
let line: &BufferLine = line;
self.layout_line += 1;
self.run_line += 1;
if self.run_line >= line.layout_opt().as_ref().unwrap().len() {
self.run_line = 0;
self.line += 1;
}
}
pub fn is_done(&self) -> bool {
self.buffer.lines.get(self.line).is_none()
}
}