iced_graphics/text/
cache.rs1use crate::core::{Font, Size};
3use crate::text;
4
5use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
6use std::collections::hash_map;
7use std::hash::{Hash, Hasher};
8
9#[derive(Debug, Default)]
11pub struct Cache {
12 entries: FxHashMap<KeyHash, Entry>,
13 aliases: FxHashMap<KeyHash, KeyHash>,
14 recently_used: FxHashSet<KeyHash>,
15}
16
17impl Cache {
18 pub fn new() -> Self {
20 Self::default()
21 }
22
23 pub fn get(&self, key: &KeyHash) -> Option<&Entry> {
25 self.entries.get(key)
26 }
27
28 pub fn allocate(
30 &mut self,
31 font_system: &mut cosmic_text::FontSystem,
32 key: Key<'_>,
33 ) -> (KeyHash, &mut Entry) {
34 let hash = key.hash(FxHasher::default());
35
36 if let Some(hash) = self.aliases.get(&hash) {
37 let _ = self.recently_used.insert(*hash);
38
39 return (*hash, self.entries.get_mut(hash).unwrap());
40 }
41
42 if let hash_map::Entry::Vacant(entry) = self.entries.entry(hash) {
43 let metrics =
44 cosmic_text::Metrics::new(key.size, key.line_height.max(f32::MIN_POSITIVE));
45 let mut buffer = cosmic_text::Buffer::new(font_system, metrics);
46
47 buffer.set_size(
48 font_system,
49 Some(key.bounds.width),
50 Some(key.bounds.height.max(key.line_height)),
51 );
52 buffer.set_text(
53 font_system,
54 key.content,
55 &text::to_attributes(key.font),
56 text::to_shaping(key.shaping, key.content),
57 None,
58 );
59
60 let bounds = text::align(&mut buffer, font_system, key.align_x);
61
62 let _ = entry.insert(Entry {
63 buffer,
64 min_bounds: bounds,
65 });
66
67 for bounds in [
68 bounds,
69 Size {
70 width: key.bounds.width,
71 ..bounds
72 },
73 ] {
74 if key.bounds != bounds {
75 let _ = self
76 .aliases
77 .insert(Key { bounds, ..key }.hash(FxHasher::default()), hash);
78 }
79 }
80 }
81
82 let _ = self.recently_used.insert(hash);
83
84 (hash, self.entries.get_mut(&hash).unwrap())
85 }
86
87 pub fn trim(&mut self) {
91 self.entries
92 .retain(|key, _| self.recently_used.contains(key));
93
94 self.aliases
95 .retain(|_, value| self.recently_used.contains(value));
96
97 self.recently_used.clear();
98 }
99}
100
101#[derive(Debug, Clone, Copy)]
103pub struct Key<'a> {
104 pub content: &'a str,
106 pub size: f32,
108 pub line_height: f32,
110 pub font: Font,
112 pub bounds: Size,
114 pub shaping: text::Shaping,
116 pub align_x: text::Alignment,
118}
119
120impl Key<'_> {
121 fn hash<H: Hasher>(self, mut hasher: H) -> KeyHash {
122 self.content.hash(&mut hasher);
123 self.size.to_bits().hash(&mut hasher);
124 self.line_height.to_bits().hash(&mut hasher);
125 self.font.hash(&mut hasher);
126 self.bounds.width.to_bits().hash(&mut hasher);
127 self.bounds.height.to_bits().hash(&mut hasher);
128 self.shaping.hash(&mut hasher);
129 self.align_x.hash(&mut hasher);
130
131 hasher.finish()
132 }
133}
134
135pub type KeyHash = u64;
137
138#[derive(Debug)]
140pub struct Entry {
141 pub buffer: cosmic_text::Buffer,
143 pub min_bounds: Size,
145}