Extract borrow of FontSystem from Buffer

This commit is contained in:
Edgar Geier 2023-03-12 10:30:03 +01:00
parent bff5aaaea3
commit 057b5b6fa9
No known key found for this signature in database
GPG key ID: DE2B55319457EB56
12 changed files with 381 additions and 216 deletions

View file

@ -10,7 +10,10 @@ use unicode_segmentation::UnicodeSegmentation;
#[cfg(feature = "swash")]
use crate::Color;
use crate::{Attrs, AttrsList, BufferLine, FontSystem, LayoutGlyph, LayoutLine, ShapeLine, Wrap};
use crate::{
Attrs, AttrsList, BorrowedWithFontSystem, BufferLine, FontSystem, LayoutGlyph, LayoutLine,
ShapeLine, Wrap,
};
/// Current cursor location
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
@ -169,8 +172,8 @@ impl<'a> LayoutRun<'a> {
}
/// An iterator of visible text lines, see [`LayoutRun`]
pub struct LayoutRunIter<'a, 'b> {
buffer: &'b Buffer<'a>,
pub struct LayoutRunIter<'b> {
buffer: &'b Buffer,
line_i: usize,
layout_i: usize,
remaining_len: usize,
@ -178,8 +181,8 @@ pub struct LayoutRunIter<'a, 'b> {
total_layout: i32,
}
impl<'a, 'b> LayoutRunIter<'a, 'b> {
pub fn new(buffer: &'b Buffer<'a>) -> Self {
impl<'b> LayoutRunIter<'b> {
pub fn new(buffer: &'b Buffer) -> Self {
let total_layout_lines: usize = buffer
.lines
.iter()
@ -215,7 +218,7 @@ impl<'a, 'b> LayoutRunIter<'a, 'b> {
}
}
impl<'a, 'b> Iterator for LayoutRunIter<'a, 'b> {
impl<'b> Iterator for LayoutRunIter<'b> {
type Item = LayoutRun<'b>;
fn size_hint(&self) -> (usize, Option<usize>) {
@ -258,7 +261,7 @@ impl<'a, 'b> Iterator for LayoutRunIter<'a, 'b> {
}
}
impl<'a, 'b> ExactSizeIterator for LayoutRunIter<'a, 'b> {}
impl<'b> ExactSizeIterator for LayoutRunIter<'b> {}
/// Metrics of text
#[derive(Clone, Copy, Debug, Default, PartialEq)]
@ -296,8 +299,7 @@ impl fmt::Display for Metrics {
}
/// A buffer of text that is shaped and laid out
pub struct Buffer<'a> {
font_system: &'a FontSystem,
pub struct Buffer {
/// [BufferLine]s (or paragraphs) of text in the buffer
pub lines: Vec<BufferLine>,
metrics: Metrics,
@ -309,17 +311,16 @@ pub struct Buffer<'a> {
wrap: Wrap,
}
impl<'a> Buffer<'a> {
impl Buffer {
/// Create a new [`Buffer`] with the provided [`FontSystem`] and [`Metrics`]
///
/// # Panics
///
/// Will panic if `metrics.line_height` is zero.
pub fn new(font_system: &'a FontSystem, metrics: Metrics) -> Self {
pub fn new(font_system: &FontSystem, metrics: Metrics) -> Self {
assert_ne!(metrics.line_height, 0.0, "line height cannot be 0");
let mut buffer = Self {
font_system,
lines: Vec::new(),
metrics,
width: 0.0,
@ -328,23 +329,28 @@ impl<'a> Buffer<'a> {
redraw: false,
wrap: Wrap::Word,
};
buffer.set_text("", Attrs::new());
buffer.set_text(font_system, "", Attrs::new());
buffer
}
fn relayout(&mut self) {
pub fn borrow_with<'a>(
&'a mut self,
font_system: &'a FontSystem,
) -> BorrowedWithFontSystem<'a, Buffer> {
BorrowedWithFontSystem {
inner: self,
font_system,
}
}
pub(crate) fn relayout(&mut self, font_system: &FontSystem) {
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
let instant = std::time::Instant::now();
for line in &mut self.lines {
if line.shape_opt().is_some() {
line.reset_layout();
line.layout(
self.font_system,
self.metrics.font_size,
self.width,
self.wrap,
);
line.layout(font_system, self.metrics.font_size, self.width, self.wrap);
}
}
@ -354,8 +360,7 @@ impl<'a> Buffer<'a> {
log::debug!("relayout: {:?}", instant.elapsed());
}
/// Pre-shape lines in the buffer, up to `lines`, return actual number of layout lines
pub fn shape_until(&mut self, lines: i32) -> i32 {
pub(crate) fn shape_until(&mut self, font_system: &FontSystem, lines: i32) -> i32 {
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
let instant = std::time::Instant::now();
@ -369,12 +374,7 @@ impl<'a> Buffer<'a> {
if line.shape_opt().is_none() {
reshaped += 1;
}
let layout = line.layout(
self.font_system,
self.metrics.font_size,
self.width,
self.wrap,
);
let layout = line.layout(font_system, self.metrics.font_size, self.width, self.wrap);
total_layout += layout.len() as i32;
}
@ -387,8 +387,7 @@ impl<'a> Buffer<'a> {
total_layout
}
/// Shape lines until cursor, also scrolling to include cursor in view
pub fn shape_until_cursor(&mut self, cursor: Cursor) {
pub(crate) fn shape_until_cursor(&mut self, font_system: &FontSystem, cursor: Cursor) {
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
let instant = std::time::Instant::now();
@ -402,12 +401,7 @@ impl<'a> Buffer<'a> {
if line.shape_opt().is_none() {
reshaped += 1;
}
let layout = line.layout(
self.font_system,
self.metrics.font_size,
self.width,
self.wrap,
);
let layout = line.layout(font_system, self.metrics.font_size, self.width, self.wrap);
if line_i == cursor.line {
let layout_cursor = self.layout_cursor(&cursor);
layout_i += layout_cursor.layout as i32;
@ -430,15 +424,14 @@ impl<'a> Buffer<'a> {
self.scroll = layout_i - (lines - 1);
}
self.shape_until_scroll();
self.shape_until_scroll(font_system);
}
/// Shape lines until scroll
pub fn shape_until_scroll(&mut self) {
pub(crate) fn shape_until_scroll(&mut self, font_system: &FontSystem) {
let lines = self.visible_lines();
let scroll_end = self.scroll + lines;
let total_layout = self.shape_until(scroll_end);
let total_layout = self.shape_until(font_system, scroll_end);
self.scroll = cmp::max(0, cmp::min(total_layout - (lines - 1), self.scroll));
}
@ -473,26 +466,22 @@ impl<'a> Buffer<'a> {
LayoutCursor::new(cursor.line, 0, 0)
}
/// Get [`FontSystem`] used by this [`Buffer`]
pub fn font_system(&self) -> &'a FontSystem {
self.font_system
pub(crate) fn line_shape(
&mut self,
font_system: &FontSystem,
line_i: usize,
) -> Option<&ShapeLine> {
let line = self.lines.get_mut(line_i)?;
Some(line.shape(font_system))
}
/// Shape the provided line index and return the result
pub fn line_shape(&mut self, line_i: usize) -> Option<&ShapeLine> {
pub(crate) fn line_layout(
&mut self,
font_system: &FontSystem,
line_i: usize,
) -> Option<&[LayoutLine]> {
let line = self.lines.get_mut(line_i)?;
Some(line.shape(self.font_system))
}
/// Lay out the provided line index and return the result
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,
))
Some(line.layout(font_system, self.metrics.font_size, self.width, self.wrap))
}
/// Get the current [`Metrics`]
@ -500,17 +489,12 @@ impl<'a> Buffer<'a> {
self.metrics
}
/// Set the current [`Metrics`]
///
/// # Panics
///
/// Will panic if `metrics.font_size` is zero.
pub fn set_metrics(&mut self, metrics: Metrics) {
fn set_metrics(&mut self, font_system: &FontSystem, metrics: Metrics) {
if metrics != self.metrics {
assert_ne!(metrics.font_size, 0.0, "font size cannot be 0");
self.metrics = metrics;
self.relayout();
self.shape_until_scroll();
self.relayout(font_system);
self.shape_until_scroll(font_system);
}
}
@ -519,12 +503,11 @@ impl<'a> Buffer<'a> {
self.wrap
}
/// Set the current [`Wrap`]
pub fn set_wrap(&mut self, wrap: Wrap) {
pub(crate) fn set_wrap(&mut self, font_system: &FontSystem, wrap: Wrap) {
if wrap != self.wrap {
self.wrap = wrap;
self.relayout();
self.shape_until_scroll();
self.relayout(font_system);
self.shape_until_scroll(font_system);
}
}
@ -533,16 +516,15 @@ impl<'a> Buffer<'a> {
(self.width, self.height)
}
/// Set the current buffer dimensions
pub fn set_size(&mut self, width: f32, height: f32) {
pub(crate) fn set_size(&mut self, font_system: &FontSystem, width: f32, height: f32) {
let clamped_width = width.max(0.0);
let clamped_height = height.max(0.0);
if clamped_width != self.width || clamped_height != self.height {
self.width = clamped_width;
self.height = clamped_height;
self.relayout();
self.shape_until_scroll();
self.relayout(font_system);
self.shape_until_scroll(font_system);
}
}
@ -564,8 +546,7 @@ impl<'a> Buffer<'a> {
(self.height / self.metrics.line_height) as i32
}
/// Set text of buffer, using provided attributes for each line by default
pub fn set_text(&mut self, text: &str, attrs: Attrs<'a>) {
pub(crate) fn set_text(&mut self, font_system: &FontSystem, text: &str, attrs: Attrs) {
self.lines.clear();
for line in text.lines() {
self.lines
@ -579,7 +560,7 @@ impl<'a> Buffer<'a> {
self.scroll = 0;
self.shape_until_scroll();
self.shape_until_scroll(font_system);
}
/// True if a redraw is needed
@ -593,7 +574,7 @@ impl<'a> Buffer<'a> {
}
/// Get the visible layout runs for rendering and other tasks
pub fn layout_runs<'b>(&'b self) -> LayoutRunIter<'a, 'b> {
pub fn layout_runs(&self) -> LayoutRunIter {
LayoutRunIter::new(self)
}
@ -698,10 +679,14 @@ impl<'a> Buffer<'a> {
new_cursor_opt
}
/// Draw the buffer
#[cfg(feature = "swash")]
pub fn draw<F>(&self, cache: &mut crate::SwashCache, color: Color, mut f: F)
where
pub(crate) fn draw<F>(
&self,
font_system: &FontSystem,
cache: &mut crate::SwashCache,
color: Color,
mut f: F,
) where
F: FnMut(i32, i32, u32, u32, Color),
{
for run in self.layout_runs() {
@ -713,10 +698,70 @@ impl<'a> Buffer<'a> {
None => color,
};
cache.with_pixels(self.font_system, cache_key, glyph_color, |x, y, color| {
cache.with_pixels(font_system, cache_key, glyph_color, |x, y, color| {
f(x_int + x, run.line_y as i32 + y_int + y, 1, 1, color);
});
}
}
}
}
impl<'a> BorrowedWithFontSystem<'a, Buffer> {
/// Pre-shape lines in the buffer, up to `lines`, return actual number of layout lines
pub fn shape_until(&mut self, lines: i32) -> i32 {
self.inner.shape_until(self.font_system, lines)
}
/// Shape lines until cursor, also scrolling to include cursor in view
pub fn shape_until_cursor(&mut self, cursor: Cursor) {
self.inner.shape_until_cursor(self.font_system, cursor);
}
/// Shape lines until scroll
pub fn shape_until_scroll(&mut self) {
self.inner.shape_until_scroll(self.font_system);
}
/// Shape the provided line index and return the result
pub fn line_shape(&mut self, line_i: usize) -> Option<&ShapeLine> {
self.inner.line_shape(self.font_system, line_i)
}
/// Lay out the provided line index and return the result
pub fn line_layout(&mut self, line_i: usize) -> Option<&[LayoutLine]> {
self.inner.line_layout(self.font_system, line_i)
}
/// Set the current [`Metrics`]
///
/// # Panics
///
/// Will panic if `metrics.font_size` is zero.
pub fn set_metrics(&mut self, metrics: Metrics) {
self.inner.set_metrics(self.font_system, metrics);
}
/// Set the current [`Wrap`]
pub fn set_wrap(&mut self, wrap: Wrap) {
self.inner.set_wrap(self.font_system, wrap);
}
/// Set the current buffer dimensions
pub fn set_size(&mut self, width: f32, height: f32) {
self.inner.set_size(self.font_system, width, height);
}
/// Set text of buffer, using provided attributes for each line by default
pub fn set_text(&mut self, text: &str, attrs: Attrs) {
self.inner.set_text(self.font_system, text, attrs);
}
/// Draw the buffer
#[cfg(feature = "swash")]
pub fn draw<F>(&self, cache: &mut crate::SwashCache, color: Color, f: F)
where
F: FnMut(i32, i32, u32, u32, Color),
{
self.inner.draw(self.font_system, cache, color, f);
}
}