iced_graphics/text/
cache.rs
1use 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 = cosmic_text::Metrics::new(
44 key.size,
45 key.line_height.max(f32::MIN_POSITIVE),
46 );
47 let mut buffer = cosmic_text::Buffer::new(font_system, metrics);
48
49 buffer.set_size(
50 font_system,
51 Some(key.bounds.width),
52 Some(key.bounds.height.max(key.line_height)),
53 );
54 buffer.set_text(
55 font_system,
56 key.content,
57 text::to_attributes(key.font),
58 text::to_shaping(key.shaping),
59 );
60
61 let (bounds, has_rtl) = text::measure(&buffer);
62
63 if has_rtl {
64 buffer.set_size(
65 font_system,
66 Some(bounds.width),
67 Some(bounds.height),
68 );
69 }
70
71 let _ = entry.insert(Entry {
72 buffer,
73 min_bounds: bounds,
74 });
75
76 for bounds in [
77 bounds,
78 Size {
79 width: key.bounds.width,
80 ..bounds
81 },
82 ] {
83 if key.bounds != bounds {
84 let _ = self.aliases.insert(
85 Key { bounds, ..key }.hash(FxHasher::default()),
86 hash,
87 );
88 }
89 }
90 }
91
92 let _ = self.recently_used.insert(hash);
93
94 (hash, self.entries.get_mut(&hash).unwrap())
95 }
96
97 pub fn trim(&mut self) {
101 self.entries
102 .retain(|key, _| self.recently_used.contains(key));
103
104 self.aliases
105 .retain(|_, value| self.recently_used.contains(value));
106
107 self.recently_used.clear();
108 }
109}
110
111#[derive(Debug, Clone, Copy)]
113pub struct Key<'a> {
114 pub content: &'a str,
116 pub size: f32,
118 pub line_height: f32,
120 pub font: Font,
122 pub bounds: Size,
124 pub shaping: text::Shaping,
126}
127
128impl Key<'_> {
129 fn hash<H: Hasher>(self, mut hasher: H) -> KeyHash {
130 self.content.hash(&mut hasher);
131 self.size.to_bits().hash(&mut hasher);
132 self.line_height.to_bits().hash(&mut hasher);
133 self.font.hash(&mut hasher);
134 self.bounds.width.to_bits().hash(&mut hasher);
135 self.bounds.height.to_bits().hash(&mut hasher);
136 self.shaping.hash(&mut hasher);
137
138 hasher.finish()
139 }
140}
141
142pub type KeyHash = u64;
144
145#[derive(Debug)]
147pub struct Entry {
148 pub buffer: cosmic_text::Buffer,
150 pub min_bounds: Size,
152}