summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón <hector0193@gmail.com>2023-06-30 19:10:41 +0200
committerLibravatar GitHub <noreply@github.com>2023-06-30 19:10:41 +0200
commita057f8811bfc47afc4271f05b92263a19122d888 (patch)
tree3adab32cf4901ad985cc6844f970019df75f20a2
parent949eca3eb814bce04f0c658ea0c9da9ecbbdfe12 (diff)
parentd666e739cdcc2084c14593888867d40066c232fe (diff)
downloadiced-a057f8811bfc47afc4271f05b92263a19122d888.tar.gz
iced-a057f8811bfc47afc4271f05b92263a19122d888.tar.bz2
iced-a057f8811bfc47afc4271f05b92263a19122d888.zip
Merge pull request #1938 from iced-rs/text-cache-modes
Text cache modes
-rw-r--r--core/src/renderer.rs15
-rw-r--r--graphics/src/backend.rs7
-rw-r--r--graphics/src/renderer.rs15
-rw-r--r--runtime/src/user_interface.rs13
-rw-r--r--wgpu/src/backend.rs4
-rw-r--r--wgpu/src/text.rs73
6 files changed, 99 insertions, 28 deletions
diff --git a/core/src/renderer.rs b/core/src/renderer.rs
index 1b327e56..7c73d2e4 100644
--- a/core/src/renderer.rs
+++ b/core/src/renderer.rs
@@ -5,13 +5,26 @@ mod null;
#[cfg(debug_assertions)]
pub use null::Null;
-use crate::{Background, BorderRadius, Color, Rectangle, Vector};
+use crate::layout;
+use crate::{Background, BorderRadius, Color, Element, Rectangle, Vector};
/// A component that can be used by widgets to draw themselves on a screen.
pub trait Renderer: Sized {
/// The supported theme of the [`Renderer`].
type Theme;
+ /// Lays out the elements of a user interface.
+ ///
+ /// You should override this if you need to perform any operations before or
+ /// after layouting. For instance, trimming the measurements cache.
+ fn layout<Message>(
+ &mut self,
+ element: &Element<'_, Message, Self>,
+ limits: &layout::Limits,
+ ) -> layout::Node {
+ element.as_widget().layout(self, limits)
+ }
+
/// Draws the primitives recorded in the given closure in a new layer.
///
/// The layer will clip its contents to the provided `bounds`.
diff --git a/graphics/src/backend.rs b/graphics/src/backend.rs
index 77bb650b..59e95bf8 100644
--- a/graphics/src/backend.rs
+++ b/graphics/src/backend.rs
@@ -12,6 +12,13 @@ use std::borrow::Cow;
pub trait Backend {
/// The custom kind of primitives this [`Backend`] supports.
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.
diff --git a/graphics/src/renderer.rs b/graphics/src/renderer.rs
index d80dea34..c0cec60a 100644
--- a/graphics/src/renderer.rs
+++ b/graphics/src/renderer.rs
@@ -3,10 +3,13 @@ use crate::backend::{self, Backend};
use crate::Primitive;
use iced_core::image;
+use iced_core::layout;
use iced_core::renderer;
use iced_core::svg;
use iced_core::text::{self, Text};
-use iced_core::{Background, Color, Font, Point, Rectangle, Size, Vector};
+use iced_core::{
+ Background, Color, Element, Font, Point, Rectangle, Size, Vector,
+};
use std::borrow::Cow;
use std::marker::PhantomData;
@@ -85,6 +88,16 @@ impl<B: Backend, T> Renderer<B, T> {
impl<B: Backend, T> iced_core::Renderer for Renderer<B, T> {
type Theme = T;
+ fn layout<Message>(
+ &mut self,
+ element: &Element<'_, Message, Self>,
+ limits: &layout::Limits,
+ ) -> layout::Node {
+ self.backend.trim_measurements();
+
+ element.as_widget().layout(self, limits)
+ }
+
fn with_layer(&mut self, bounds: Rectangle, f: impl FnOnce(&mut Self)) {
let current = self.start_layer();
diff --git a/runtime/src/user_interface.rs b/runtime/src/user_interface.rs
index 34b2ada0..619423fd 100644
--- a/runtime/src/user_interface.rs
+++ b/runtime/src/user_interface.rs
@@ -95,9 +95,8 @@ where
let Cache { mut state } = cache;
state.diff(root.as_widget());
- let base = root
- .as_widget()
- .layout(renderer, &layout::Limits::new(Size::ZERO, bounds));
+ let base =
+ renderer.layout(&root, &layout::Limits::new(Size::ZERO, bounds));
UserInterface {
root,
@@ -227,8 +226,8 @@ where
if shell.is_layout_invalid() {
let _ = ManuallyDrop::into_inner(manual_overlay);
- self.base = self.root.as_widget().layout(
- renderer,
+ self.base = renderer.layout(
+ &self.root,
&layout::Limits::new(Size::ZERO, self.bounds),
);
@@ -323,8 +322,8 @@ where
}
shell.revalidate_layout(|| {
- self.base = self.root.as_widget().layout(
- renderer,
+ self.base = renderer.layout(
+ &self.root,
&layout::Limits::new(Size::ZERO, self.bounds),
);
diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs
index 596d43c5..4a0c54f0 100644
--- a/wgpu/src/backend.rs
+++ b/wgpu/src/backend.rs
@@ -337,6 +337,10 @@ impl Backend {
impl crate::graphics::Backend for Backend {
type Primitive = primitive::Custom;
+
+ fn trim_measurements(&mut self) {
+ self.text_pipeline.trim_measurements();
+ }
}
impl backend::Text for Backend {
diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs
index 1b94edf6..65d3b818 100644
--- a/wgpu/src/text.rs
+++ b/wgpu/src/text.rs
@@ -80,6 +80,10 @@ impl Pipeline {
let renderer = &mut self.renderers[self.prepare_layer];
let cache = self.cache.get_mut();
+ if self.prepare_layer == 0 {
+ cache.trim(Purpose::Drawing);
+ }
+
let keys: Vec<_> = sections
.iter()
.map(|section| {
@@ -100,6 +104,7 @@ impl Pipeline {
},
shaping: section.shaping,
},
+ Purpose::Drawing,
);
key
@@ -224,11 +229,14 @@ impl Pipeline {
pub fn end_frame(&mut self) {
self.atlas.trim();
- self.cache.get_mut().trim();
self.prepare_layer = 0;
}
+ pub fn trim_measurements(&mut self) {
+ self.cache.get_mut().trim(Purpose::Measuring);
+ }
+
pub fn measure(
&self,
content: &str,
@@ -238,11 +246,11 @@ impl Pipeline {
bounds: Size,
shaping: Shaping,
) -> Size {
- let mut measurement_cache = self.cache.borrow_mut();
+ let mut cache = self.cache.borrow_mut();
let line_height = f32::from(line_height.to_absolute(Pixels(size)));
- let (_, entry) = measurement_cache.allocate(
+ let (_, entry) = cache.allocate(
&mut self.font_system.borrow_mut(),
Key {
content,
@@ -252,6 +260,7 @@ impl Pipeline {
bounds,
shaping,
},
+ Purpose::Measuring,
);
entry.bounds
@@ -268,11 +277,11 @@ impl Pipeline {
point: Point,
_nearest_only: bool,
) -> Option<Hit> {
- let mut measurement_cache = self.cache.borrow_mut();
+ let mut cache = self.cache.borrow_mut();
let line_height = f32::from(line_height.to_absolute(Pixels(size)));
- let (_, entry) = measurement_cache.allocate(
+ let (_, entry) = cache.allocate(
&mut self.font_system.borrow_mut(),
Key {
content,
@@ -282,6 +291,7 @@ impl Pipeline {
bounds,
shaping,
},
+ Purpose::Measuring,
);
let cursor = entry.buffer.hit(point.x, point.y)?;
@@ -348,8 +358,9 @@ fn to_shaping(shaping: Shaping) -> glyphon::Shaping {
struct Cache {
entries: FxHashMap<KeyHash, Entry>,
- measurements: FxHashMap<KeyHash, KeyHash>,
- recently_used: FxHashSet<KeyHash>,
+ aliases: FxHashMap<KeyHash, KeyHash>,
+ recently_measured: FxHashSet<KeyHash>,
+ recently_drawn: FxHashSet<KeyHash>,
hasher: HashBuilder,
}
@@ -358,6 +369,12 @@ struct Entry {
bounds: Size,
}
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum Purpose {
+ Measuring,
+ Drawing,
+}
+
#[cfg(not(target_arch = "wasm32"))]
type HashBuilder = twox_hash::RandomXxHashBuilder64;
@@ -368,8 +385,9 @@ impl Cache {
fn new() -> Self {
Self {
entries: FxHashMap::default(),
- measurements: FxHashMap::default(),
- recently_used: FxHashSet::default(),
+ aliases: FxHashMap::default(),
+ recently_measured: FxHashSet::default(),
+ recently_drawn: FxHashSet::default(),
hasher: HashBuilder::default(),
}
}
@@ -382,11 +400,17 @@ impl Cache {
&mut self,
font_system: &mut glyphon::FontSystem,
key: Key<'_>,
+ purpose: Purpose,
) -> (KeyHash, &mut Entry) {
let hash = key.hash(self.hasher.build_hasher());
- if let Some(hash) = self.measurements.get(&hash) {
- let _ = self.recently_used.insert(*hash);
+ let recently_used = match purpose {
+ Purpose::Measuring => &mut self.recently_measured,
+ Purpose::Drawing => &mut self.recently_drawn,
+ };
+
+ if let Some(hash) = self.aliases.get(&hash) {
+ let _ = recently_used.insert(*hash);
return (*hash, self.entries.get_mut(hash).unwrap());
}
@@ -421,7 +445,7 @@ impl Cache {
},
] {
if key.bounds != bounds {
- let _ = self.measurements.insert(
+ let _ = self.aliases.insert(
Key { bounds, ..key }.hash(self.hasher.build_hasher()),
hash,
);
@@ -429,18 +453,29 @@ impl Cache {
}
}
- let _ = self.recently_used.insert(hash);
+ let _ = recently_used.insert(hash);
(hash, self.entries.get_mut(&hash).unwrap())
}
- fn trim(&mut self) {
- self.entries
- .retain(|key, _| self.recently_used.contains(key));
- self.measurements
- .retain(|_, value| self.recently_used.contains(value));
+ fn trim(&mut self, purpose: Purpose) {
+ self.entries.retain(|key, _| {
+ self.recently_measured.contains(key)
+ || self.recently_drawn.contains(key)
+ });
+ self.aliases.retain(|_, value| {
+ self.recently_measured.contains(value)
+ || self.recently_drawn.contains(value)
+ });
- self.recently_used.clear();
+ match purpose {
+ Purpose::Measuring => {
+ self.recently_measured.clear();
+ }
+ Purpose::Drawing => {
+ self.recently_drawn.clear();
+ }
+ }
}
}