Trim text measurements only before layout

This commit is contained in:
Héctor Ramón Jiménez 2023-06-29 18:23:11 +02:00
parent cdce03cf7f
commit d666e739cd
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
4 changed files with 30 additions and 28 deletions

View file

@ -12,6 +12,13 @@ use std::borrow::Cow;
pub trait Backend { pub trait Backend {
/// The custom kind of primitives this [`Backend`] supports. /// The custom kind of primitives this [`Backend`] supports.
type Primitive; type Primitive;
/// Trims the measurements cache.
///
/// This method is currently necessary to properly trim the text cache in
/// `iced_wgpu` and `iced_glow` because of limitations in the text rendering
/// pipeline. It will be removed in the future.
fn trim_measurements(&mut self) {}
} }
/// A graphics backend that supports text rendering. /// A graphics backend that supports text rendering.

View file

@ -93,6 +93,8 @@ impl<B: Backend, T> iced_core::Renderer for Renderer<B, T> {
element: &Element<'_, Message, Self>, element: &Element<'_, Message, Self>,
limits: &layout::Limits, limits: &layout::Limits,
) -> layout::Node { ) -> layout::Node {
self.backend.trim_measurements();
element.as_widget().layout(self, limits) element.as_widget().layout(self, limits)
} }

View file

@ -337,6 +337,10 @@ impl Backend {
impl crate::graphics::Backend for Backend { impl crate::graphics::Backend for Backend {
type Primitive = primitive::Custom; type Primitive = primitive::Custom;
fn trim_measurements(&mut self) {
self.text_pipeline.trim_measurements();
}
} }
impl backend::Text for Backend { impl backend::Text for Backend {

View file

@ -81,8 +81,7 @@ impl Pipeline {
let cache = self.cache.get_mut(); let cache = self.cache.get_mut();
if self.prepare_layer == 0 { if self.prepare_layer == 0 {
let _ = cache.switch(Mode::Drawing); cache.trim(Purpose::Drawing);
cache.trim();
} }
let keys: Vec<_> = sections let keys: Vec<_> = sections
@ -105,6 +104,7 @@ impl Pipeline {
}, },
shaping: section.shaping, shaping: section.shaping,
}, },
Purpose::Drawing,
); );
key key
@ -233,6 +233,10 @@ impl Pipeline {
self.prepare_layer = 0; self.prepare_layer = 0;
} }
pub fn trim_measurements(&mut self) {
self.cache.get_mut().trim(Purpose::Measuring);
}
pub fn measure( pub fn measure(
&self, &self,
content: &str, content: &str,
@ -246,10 +250,6 @@ impl Pipeline {
let line_height = f32::from(line_height.to_absolute(Pixels(size))); let line_height = f32::from(line_height.to_absolute(Pixels(size)));
if cache.switch(Mode::Measuring) {
cache.trim();
}
let (_, entry) = cache.allocate( let (_, entry) = cache.allocate(
&mut self.font_system.borrow_mut(), &mut self.font_system.borrow_mut(),
Key { Key {
@ -260,6 +260,7 @@ impl Pipeline {
bounds, bounds,
shaping, shaping,
}, },
Purpose::Measuring,
); );
entry.bounds entry.bounds
@ -280,10 +281,6 @@ impl Pipeline {
let line_height = f32::from(line_height.to_absolute(Pixels(size))); let line_height = f32::from(line_height.to_absolute(Pixels(size)));
if cache.switch(Mode::Measuring) {
cache.trim();
}
let (_, entry) = cache.allocate( let (_, entry) = cache.allocate(
&mut self.font_system.borrow_mut(), &mut self.font_system.borrow_mut(),
Key { Key {
@ -294,6 +291,7 @@ impl Pipeline {
bounds, bounds,
shaping, shaping,
}, },
Purpose::Measuring,
); );
let cursor = entry.buffer.hit(point.x, point.y)?; let cursor = entry.buffer.hit(point.x, point.y)?;
@ -364,7 +362,6 @@ struct Cache {
recently_measured: FxHashSet<KeyHash>, recently_measured: FxHashSet<KeyHash>,
recently_drawn: FxHashSet<KeyHash>, recently_drawn: FxHashSet<KeyHash>,
hasher: HashBuilder, hasher: HashBuilder,
mode: Mode,
} }
struct Entry { struct Entry {
@ -373,7 +370,7 @@ struct Entry {
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Mode { enum Purpose {
Measuring, Measuring,
Drawing, Drawing,
} }
@ -392,7 +389,6 @@ impl Cache {
recently_measured: FxHashSet::default(), recently_measured: FxHashSet::default(),
recently_drawn: FxHashSet::default(), recently_drawn: FxHashSet::default(),
hasher: HashBuilder::default(), hasher: HashBuilder::default(),
mode: Mode::Measuring,
} }
} }
@ -400,24 +396,17 @@ impl Cache {
self.entries.get(key) self.entries.get(key)
} }
fn switch(&mut self, mode: Mode) -> bool {
let has_changed = self.mode != mode;
self.mode = mode;
has_changed
}
fn allocate( fn allocate(
&mut self, &mut self,
font_system: &mut glyphon::FontSystem, font_system: &mut glyphon::FontSystem,
key: Key<'_>, key: Key<'_>,
purpose: Purpose,
) -> (KeyHash, &mut Entry) { ) -> (KeyHash, &mut Entry) {
let hash = key.hash(self.hasher.build_hasher()); let hash = key.hash(self.hasher.build_hasher());
let recently_used = match self.mode { let recently_used = match purpose {
Mode::Measuring => &mut self.recently_measured, Purpose::Measuring => &mut self.recently_measured,
Mode::Drawing => &mut self.recently_drawn, Purpose::Drawing => &mut self.recently_drawn,
}; };
if let Some(hash) = self.aliases.get(&hash) { if let Some(hash) = self.aliases.get(&hash) {
@ -469,7 +458,7 @@ impl Cache {
(hash, self.entries.get_mut(&hash).unwrap()) (hash, self.entries.get_mut(&hash).unwrap())
} }
fn trim(&mut self) { fn trim(&mut self, purpose: Purpose) {
self.entries.retain(|key, _| { self.entries.retain(|key, _| {
self.recently_measured.contains(key) self.recently_measured.contains(key)
|| self.recently_drawn.contains(key) || self.recently_drawn.contains(key)
@ -479,11 +468,11 @@ impl Cache {
|| self.recently_drawn.contains(value) || self.recently_drawn.contains(value)
}); });
match self.mode { match purpose {
Mode::Measuring => { Purpose::Measuring => {
self.recently_measured.clear(); self.recently_measured.clear();
} }
Mode::Drawing => { Purpose::Drawing => {
self.recently_drawn.clear(); self.recently_drawn.clear();
} }
} }