Decouple caching from Paragraph API

This commit is contained in:
Héctor Ramón Jiménez 2024-07-17 18:47:58 +02:00
parent 616689ca54
commit ffb520fb37
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
7 changed files with 128 additions and 95 deletions

View file

@ -1,8 +1,8 @@
//! Draw paragraphs.
use crate::core;
use crate::core::alignment;
use crate::core::text::{Hit, LineHeight, Shaping, Text};
use crate::core::{Font, Pixels, Point, Size};
use crate::core::text::{Hit, Shaping, Text};
use crate::core::{Font, Point, Size};
use crate::text;
use std::fmt;
@ -10,11 +10,11 @@ use std::sync::{self, Arc};
/// A bunch of text.
#[derive(Clone, PartialEq)]
pub struct Paragraph(Option<Arc<Internal>>);
pub struct Paragraph(Arc<Internal>);
#[derive(Clone)]
struct Internal {
buffer: cosmic_text::Buffer,
content: String, // TODO: Reuse from `buffer` (?)
font: Font,
shaping: Shaping,
horizontal_alignment: alignment::Horizontal,
@ -52,9 +52,7 @@ impl Paragraph {
}
fn internal(&self) -> &Arc<Internal> {
self.0
.as_ref()
.expect("paragraph should always be initialized")
&self.0
}
}
@ -90,9 +88,8 @@ impl core::text::Paragraph for Paragraph {
let min_bounds = text::measure(&buffer);
Self(Some(Arc::new(Internal {
Self(Arc::new(Internal {
buffer,
content: text.content.to_owned(),
font: text.font,
horizontal_alignment: text.horizontal_alignment,
vertical_alignment: text.vertical_alignment,
@ -100,59 +97,31 @@ impl core::text::Paragraph for Paragraph {
bounds: text.bounds,
min_bounds,
version: font_system.version(),
})))
}))
}
fn resize(&mut self, new_bounds: Size) {
let paragraph = self
.0
.take()
.expect("paragraph should always be initialized");
let paragraph = Arc::make_mut(&mut self.0);
match Arc::try_unwrap(paragraph) {
Ok(mut internal) => {
let mut font_system =
text::font_system().write().expect("Write font system");
let mut font_system =
text::font_system().write().expect("Write font system");
internal.buffer.set_size(
font_system.raw(),
Some(new_bounds.width),
Some(new_bounds.height),
);
paragraph.buffer.set_size(
font_system.raw(),
Some(new_bounds.width),
Some(new_bounds.height),
);
internal.bounds = new_bounds;
internal.min_bounds = text::measure(&internal.buffer);
self.0 = Some(Arc::new(internal));
}
Err(internal) => {
let metrics = internal.buffer.metrics();
// If there is a strong reference somewhere, we recompute the
// buffer from scratch
*self = Self::with_text(Text {
content: &internal.content,
bounds: internal.bounds,
size: Pixels(metrics.font_size),
line_height: LineHeight::Absolute(Pixels(
metrics.line_height,
)),
font: internal.font,
horizontal_alignment: internal.horizontal_alignment,
vertical_alignment: internal.vertical_alignment,
shaping: internal.shaping,
});
}
}
paragraph.bounds = new_bounds;
paragraph.min_bounds = text::measure(&paragraph.buffer);
}
fn compare(&self, text: Text<&str>) -> core::text::Difference {
fn compare(&self, text: Text<()>) -> core::text::Difference {
let font_system = text::font_system().read().expect("Read font system");
let paragraph = self.internal();
let metrics = paragraph.buffer.metrics();
if paragraph.version != font_system.version
|| paragraph.content != text.content
|| metrics.font_size != text.size.0
|| metrics.line_height != text.line_height.to_absolute(text.size).0
|| paragraph.font != text.font
@ -231,7 +200,7 @@ impl core::text::Paragraph for Paragraph {
impl Default for Paragraph {
fn default() -> Self {
Self(Some(Arc::new(Internal::default())))
Self(Arc::new(Internal::default()))
}
}
@ -240,7 +209,6 @@ impl fmt::Debug for Paragraph {
let paragraph = self.internal();
f.debug_struct("Paragraph")
.field("content", &paragraph.content)
.field("font", &paragraph.font)
.field("shaping", &paragraph.shaping)
.field("horizontal_alignment", &paragraph.horizontal_alignment)
@ -253,8 +221,7 @@ impl fmt::Debug for Paragraph {
impl PartialEq for Internal {
fn eq(&self, other: &Self) -> bool {
self.content == other.content
&& self.font == other.font
self.font == other.font
&& self.shaping == other.shaping
&& self.horizontal_alignment == other.horizontal_alignment
&& self.vertical_alignment == other.vertical_alignment
@ -271,7 +238,6 @@ impl Default for Internal {
font_size: 1.0,
line_height: 1.0,
}),
content: String::new(),
font: Font::default(),
shaping: Shaping::default(),
horizontal_alignment: alignment::Horizontal::Left,
@ -298,7 +264,7 @@ pub struct Weak {
impl Weak {
/// Tries to update the reference into a [`Paragraph`].
pub fn upgrade(&self) -> Option<Paragraph> {
self.raw.upgrade().map(Some).map(Paragraph)
self.raw.upgrade().map(Paragraph)
}
}