forma_render/cpu/buffer/
mod.rs1use std::{
16 cell::RefCell,
17 rc::{Rc, Weak},
18};
19
20use crate::{styling::Color, utils::SmallBitSet};
21
22use super::painter::CachedTile;
23
24pub mod layout;
25
26use self::layout::{Flusher, Layout};
27
28#[derive(Debug)]
44pub struct Buffer<'b, 'l, L: Layout> {
45 pub(crate) buffer: &'b mut [u8],
46 pub(crate) layout: &'l mut L,
47 pub(crate) layer_cache: Option<BufferLayerCache>,
48 pub(crate) flusher: Option<Box<dyn Flusher>>,
49}
50
51#[derive(Debug)]
64pub struct BufferBuilder<'b, 'l, L: Layout> {
65 buffer: Buffer<'b, 'l, L>,
66}
67
68impl<'b, 'l, L: Layout> BufferBuilder<'b, 'l, L> {
69 #[inline]
70 pub fn new(buffer: &'b mut [u8], layout: &'l mut L) -> Self {
71 Self {
72 buffer: Buffer {
73 buffer,
74 layout,
75 layer_cache: None,
76 flusher: None,
77 },
78 }
79 }
80
81 #[inline]
82 pub fn layer_cache(mut self, layer_cache: BufferLayerCache) -> Self {
83 self.buffer.layer_cache = Some(layer_cache);
84 self
85 }
86
87 #[inline]
88 pub fn flusher(mut self, flusher: Box<dyn Flusher>) -> Self {
89 self.buffer.flusher = Some(flusher);
90 self
91 }
92
93 #[inline]
94 pub fn build(self) -> Buffer<'b, 'l, L> {
95 self.buffer
96 }
97}
98
99#[derive(Debug)]
100struct IdDropper {
101 id: u8,
102 buffers_with_caches: Weak<RefCell<SmallBitSet>>,
103}
104
105impl Drop for IdDropper {
106 fn drop(&mut self) {
107 if let Some(buffers_with_caches) = Weak::upgrade(&self.buffers_with_caches) {
108 buffers_with_caches.borrow_mut().remove(self.id);
109 }
110 }
111}
112
113#[derive(Debug)]
114pub(crate) struct CacheInner {
115 pub clear_color: Option<Color>,
116 pub tiles: Vec<CachedTile>,
117 pub width: Option<usize>,
118 pub height: Option<usize>,
119 _id_dropper: IdDropper,
120}
121
122#[derive(Clone, Debug)]
168pub struct BufferLayerCache {
169 pub(crate) id: u8,
170 pub(crate) cache: Rc<RefCell<CacheInner>>,
171}
172
173impl BufferLayerCache {
174 pub(crate) fn new(id: u8, buffers_with_caches: Weak<RefCell<SmallBitSet>>) -> Self {
175 Self {
176 id,
177 cache: Rc::new(RefCell::new(CacheInner {
178 clear_color: None,
179 tiles: Vec::new(),
180 width: None,
181 height: None,
182 _id_dropper: IdDropper {
183 id,
184 buffers_with_caches,
185 },
186 })),
187 }
188 }
189
190 #[inline]
191 pub fn clear(&self) {
192 let mut cache = self.cache.borrow_mut();
193
194 cache.clear_color = None;
195 cache.tiles.fill(CachedTile::default());
196 }
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202
203 use std::mem;
204
205 fn new_cache(bit_set: &Rc<RefCell<SmallBitSet>>) -> BufferLayerCache {
206 bit_set
207 .borrow_mut()
208 .first_empty_slot()
209 .map(|id| BufferLayerCache::new(id, Rc::downgrade(bit_set)))
210 .unwrap()
211 }
212
213 #[test]
214 fn clone_and_drop() {
215 let bit_set = Rc::new(RefCell::new(SmallBitSet::default()));
216
217 let cache0 = new_cache(&bit_set);
218 let cache1 = new_cache(&bit_set);
219 let cache2 = new_cache(&bit_set);
220
221 assert!(bit_set.borrow().contains(&0));
222 assert!(bit_set.borrow().contains(&1));
223 assert!(bit_set.borrow().contains(&2));
224
225 mem::drop(cache0.clone());
226 mem::drop(cache1.clone());
227 mem::drop(cache2.clone());
228
229 assert!(bit_set.borrow().contains(&0));
230 assert!(bit_set.borrow().contains(&1));
231 assert!(bit_set.borrow().contains(&2));
232
233 mem::drop(cache1);
234
235 assert!(bit_set.borrow().contains(&0));
236 assert!(!bit_set.borrow().contains(&1));
237 assert!(bit_set.borrow().contains(&2));
238
239 let cache1 = new_cache(&bit_set);
240
241 assert!(bit_set.borrow().contains(&0));
242 assert!(bit_set.borrow().contains(&1));
243 assert!(bit_set.borrow().contains(&2));
244
245 mem::drop(cache0);
246 mem::drop(cache1);
247 mem::drop(cache2);
248
249 assert!(!bit_set.borrow().contains(&0));
250 assert!(!bit_set.borrow().contains(&1));
251 assert!(!bit_set.borrow().contains(&2));
252 }
253}