diff options
-rw-r--r-- | tiny_skia/Cargo.toml | 5 | ||||
-rw-r--r-- | tiny_skia/src/text.rs | 280 | ||||
-rw-r--r-- | wgpu/Cargo.toml | 3 | ||||
-rw-r--r-- | wgpu/src/text.rs | 372 |
4 files changed, 289 insertions, 371 deletions
diff --git a/tiny_skia/Cargo.toml b/tiny_skia/Cargo.toml index 69197589..31f5cb6b 100644 --- a/tiny_skia/Cargo.toml +++ b/tiny_skia/Cargo.toml @@ -14,7 +14,6 @@ softbuffer = "0.2" tiny-skia = "0.8" bytemuck = "1" rustc-hash = "1.1" -ouroboros = "0.15" kurbo = "0.9" [dependencies.iced_graphics] @@ -24,8 +23,8 @@ features = ["tiny-skia"] [dependencies.cosmic-text] features = ["std", "swash"] -git = "https://github.com/hecrj/cosmic-text" -rev = "81080c1b9498933b43c1889601a7ea6a3d16e161" +git = "https://github.com/pop-os/cosmic-text" +rev = "e788c175ec31094b04dcacbc0537dba4433afcfc" [dependencies.twox-hash] version = "1.6" diff --git a/tiny_skia/src/text.rs b/tiny_skia/src/text.rs index 714695b9..8391571c 100644 --- a/tiny_skia/src/text.rs +++ b/tiny_skia/src/text.rs @@ -11,62 +11,31 @@ use std::sync::Arc; #[allow(missing_debug_implementations)] pub struct Pipeline { - system: Option<System>, + font_system: RefCell<cosmic_text::FontSystem>, glyph_cache: GlyphCache, -} - -#[ouroboros::self_referencing] -struct System { - fonts: cosmic_text::FontSystem, - - #[borrows(fonts)] - #[not_covariant] - measurement_cache: RefCell<Cache<'this>>, - - #[borrows(fonts)] - #[not_covariant] - render_cache: Cache<'this>, + measurement_cache: RefCell<Cache>, + render_cache: Cache, } impl Pipeline { pub fn new() -> Self { Pipeline { - system: Some( - SystemBuilder { - fonts: cosmic_text::FontSystem::new_with_fonts( - [cosmic_text::fontdb::Source::Binary(Arc::new( - include_bytes!("../../wgpu/fonts/Iced-Icons.ttf") - .as_slice(), - ))] - .into_iter(), - ), - measurement_cache_builder: |_| RefCell::new(Cache::new()), - render_cache_builder: |_| Cache::new(), - } - .build(), - ), + font_system: RefCell::new(cosmic_text::FontSystem::new_with_fonts( + [cosmic_text::fontdb::Source::Binary(Arc::new( + include_bytes!("../../wgpu/fonts/Iced-Icons.ttf") + .as_slice(), + ))] + .into_iter(), + )), glyph_cache: GlyphCache::new(), + measurement_cache: RefCell::new(Cache::new()), + render_cache: Cache::new(), } } pub fn load_font(&mut self, bytes: Cow<'static, [u8]>) { - let heads = self.system.take().unwrap().into_heads(); - - let (locale, mut db) = heads.fonts.into_locale_and_db(); - - db.load_font_source(cosmic_text::fontdb::Source::Binary(Arc::new( - bytes.into_owned(), - ))); - - self.system = Some( - SystemBuilder { - fonts: cosmic_text::FontSystem::new_with_locale_and_db( - locale, db, - ), - measurement_cache_builder: |_| RefCell::new(Cache::new()), - render_cache_builder: |_| Cache::new(), - } - .build(), + self.font_system.get_mut().db_mut().load_font_source( + cosmic_text::fontdb::Source::Binary(Arc::new(bytes.into_owned())), ); } @@ -82,78 +51,75 @@ impl Pipeline { pixels: &mut tiny_skia::PixmapMut<'_>, clip_mask: Option<&tiny_skia::ClipMask>, ) { - self.system.as_mut().unwrap().with_mut(|fields| { - let key = Key { - bounds: { - let size = bounds.size(); - - // TODO: Reuse buffers from layouting - Size::new(size.width.ceil(), size.height.ceil()) - }, - content, - font, - size, - }; - - let (_, buffer) = fields.render_cache.allocate(fields.fonts, key); - - let (total_lines, max_width) = buffer - .layout_runs() - .enumerate() - .fold((0, 0.0), |(_, max), (i, buffer)| { - (i + 1, buffer.line_w.max(max)) - }); - - let total_height = total_lines as f32 * size * 1.2; - - let x = match horizontal_alignment { - alignment::Horizontal::Left => bounds.x, - alignment::Horizontal::Center => bounds.x - max_width / 2.0, - alignment::Horizontal::Right => bounds.x - max_width, - }; - - let y = match vertical_alignment { - alignment::Vertical::Top => bounds.y, - alignment::Vertical::Center => bounds.y - total_height / 2.0, - alignment::Vertical::Bottom => bounds.y - total_height, - }; - - let mut swash = cosmic_text::SwashCache::new(fields.fonts); - - for run in buffer.layout_runs() { - for glyph in run.glyphs { - if let Some((buffer, placement)) = self - .glyph_cache - .allocate(glyph.cache_key, color, &mut swash) - { - let pixmap = tiny_skia::PixmapRef::from_bytes( - buffer, - placement.width, - placement.height, - ) - .expect("Create glyph pixel map"); - - pixels.draw_pixmap( - x as i32 + glyph.x_int + placement.left, - y as i32 - glyph.y_int - placement.top - + run.line_y as i32, - pixmap, - &tiny_skia::PixmapPaint::default(), - tiny_skia::Transform::identity(), - clip_mask, - ); - } + let font_system = self.font_system.get_mut(); + let key = Key { + bounds: { + let size = bounds.size(); + + // TODO: Reuse buffers from layouting + Size::new(size.width.ceil(), size.height.ceil()) + }, + content, + font, + size, + }; + + let (_, buffer) = self.render_cache.allocate(font_system, key); + + let (total_lines, max_width) = buffer + .layout_runs() + .enumerate() + .fold((0, 0.0), |(_, max), (i, buffer)| { + (i + 1, buffer.line_w.max(max)) + }); + + let total_height = total_lines as f32 * size * 1.2; + + let x = match horizontal_alignment { + alignment::Horizontal::Left => bounds.x, + alignment::Horizontal::Center => bounds.x - max_width / 2.0, + alignment::Horizontal::Right => bounds.x - max_width, + }; + + let y = match vertical_alignment { + alignment::Vertical::Top => bounds.y, + alignment::Vertical::Center => bounds.y - total_height / 2.0, + alignment::Vertical::Bottom => bounds.y - total_height, + }; + + let mut swash = cosmic_text::SwashCache::new(); + + for run in buffer.layout_runs() { + for glyph in run.glyphs { + if let Some((buffer, placement)) = self.glyph_cache.allocate( + glyph.cache_key, + color, + font_system, + &mut swash, + ) { + let pixmap = tiny_skia::PixmapRef::from_bytes( + buffer, + placement.width, + placement.height, + ) + .expect("Create glyph pixel map"); + + pixels.draw_pixmap( + x as i32 + glyph.x_int + placement.left, + y as i32 - glyph.y_int - placement.top + + run.line_y as i32, + pixmap, + &tiny_skia::PixmapPaint::default(), + tiny_skia::Transform::identity(), + clip_mask, + ); } } - }); + } } pub fn trim_cache(&mut self) { - self.system - .as_mut() - .unwrap() - .with_render_cache_mut(|cache| cache.trim()); - + self.render_cache.trim(); self.glyph_cache.trim(); } @@ -164,28 +130,26 @@ impl Pipeline { font: Font, bounds: Size, ) -> (f32, f32) { - self.system.as_ref().unwrap().with(|fields| { - let mut measurement_cache = fields.measurement_cache.borrow_mut(); - - let (_, paragraph) = measurement_cache.allocate( - fields.fonts, - Key { - content, - size, - font, - bounds, - }, - ); + let mut measurement_cache = self.measurement_cache.borrow_mut(); - let (total_lines, max_width) = paragraph - .layout_runs() - .enumerate() - .fold((0, 0.0), |(_, max), (i, buffer)| { - (i + 1, buffer.line_w.max(max)) - }); + let (_, paragraph) = measurement_cache.allocate( + &mut self.font_system.borrow_mut(), + Key { + content, + size, + font, + bounds, + }, + ); - (max_width, size * 1.2 * total_lines as f32) - }) + let (total_lines, max_width) = paragraph + .layout_runs() + .enumerate() + .fold((0, 0.0), |(_, max), (i, buffer)| { + (i + 1, buffer.line_w.max(max)) + }); + + (max_width, size * 1.2 * total_lines as f32) } pub fn hit_test( @@ -197,30 +161,25 @@ impl Pipeline { point: Point, _nearest_only: bool, ) -> Option<Hit> { - self.system.as_ref().unwrap().with(|fields| { - let mut measurement_cache = fields.measurement_cache.borrow_mut(); - - let (_, paragraph) = measurement_cache.allocate( - fields.fonts, - Key { - content, - size, - font, - bounds, - }, - ); + let mut measurement_cache = self.measurement_cache.borrow_mut(); - let cursor = paragraph.hit(point.x, point.y)?; + let (_, paragraph) = measurement_cache.allocate( + &mut self.font_system.borrow_mut(), + Key { + content, + size, + font, + bounds, + }, + ); - Some(Hit::CharOffset(cursor.index)) - }) + let cursor = paragraph.hit(point.x, point.y)?; + + Some(Hit::CharOffset(cursor.index)) } pub fn trim_measurement_cache(&mut self) { - self.system - .as_mut() - .unwrap() - .with_measurement_cache_mut(|cache| cache.borrow_mut().trim()); + self.measurement_cache.borrow_mut().trim(); } } @@ -256,14 +215,15 @@ impl GlyphCache { &mut self, cache_key: cosmic_text::CacheKey, color: Color, - swash: &mut cosmic_text::SwashCache<'_>, + font_system: &mut cosmic_text::FontSystem, + swash: &mut cosmic_text::SwashCache, ) -> Option<(&[u8], cosmic_text::Placement)> { let [r, g, b, _a] = color.into_rgba8(); let key = (cache_key, [r, g, b]); if let hash_map::Entry::Vacant(entry) = self.entries.entry(key) { // TODO: Outline support - let image = swash.get_image_uncached(cache_key)?; + let image = swash.get_image_uncached(font_system, cache_key)?; let glyph_size = image.placement.width as usize * image.placement.height as usize; @@ -343,8 +303,8 @@ impl GlyphCache { } } -struct Cache<'a> { - entries: FxHashMap<KeyHash, cosmic_text::Buffer<'a>>, +struct Cache { + entries: FxHashMap<KeyHash, cosmic_text::Buffer>, recently_used: FxHashSet<KeyHash>, hasher: HashBuilder, } @@ -355,7 +315,7 @@ type HashBuilder = twox_hash::RandomXxHashBuilder64; #[cfg(target_arch = "wasm32")] type HashBuilder = std::hash::BuildHasherDefault<twox_hash::XxHash64>; -impl<'a> Cache<'a> { +impl Cache { fn new() -> Self { Self { entries: FxHashMap::default(), @@ -366,9 +326,9 @@ impl<'a> Cache<'a> { fn allocate( &mut self, - fonts: &'a cosmic_text::FontSystem, + font_system: &mut cosmic_text::FontSystem, key: Key<'_>, - ) -> (KeyHash, &mut cosmic_text::Buffer<'a>) { + ) -> (KeyHash, &mut cosmic_text::Buffer) { let hash = { let mut hasher = self.hasher.build_hasher(); @@ -383,13 +343,15 @@ impl<'a> Cache<'a> { if let hash_map::Entry::Vacant(entry) = self.entries.entry(hash) { let metrics = cosmic_text::Metrics::new(key.size, key.size * 1.2); - let mut buffer = cosmic_text::Buffer::new(fonts, metrics); + let mut buffer = cosmic_text::Buffer::new(font_system, metrics); buffer.set_size( + font_system, key.bounds.width, key.bounds.height.max(key.size * 1.2), ); buffer.set_text( + font_system, key.content, cosmic_text::Attrs::new() .family(to_family(key.font)) diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 6a313d4f..3aef4ff4 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -21,7 +21,6 @@ futures = "0.3" bitflags = "1.2" once_cell = "1.0" rustc-hash = "1.1" -ouroboros = "0.15" [target.'cfg(target_arch = "wasm32")'.dependencies] wgpu = { version = "0.14", features = ["webgl"] } @@ -45,7 +44,7 @@ path = "../graphics" [dependencies.glyphon] version = "0.2" git = "https://github.com/hecrj/glyphon.git" -rev = "edd23695ad53db5f89d455c3c130172fd107d6a2" +rev = "47050174841a4f58fc8d85c943a2117f72f19e8e" [dependencies.encase] version = "0.3.0" diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 35f24cd9..ac116f69 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -12,23 +12,12 @@ use std::sync::Arc; #[allow(missing_debug_implementations)] pub struct Pipeline { - system: Option<System>, + font_system: RefCell<glyphon::FontSystem>, renderers: Vec<glyphon::TextRenderer>, atlas: glyphon::TextAtlas, prepare_layer: usize, -} - -#[ouroboros::self_referencing] -struct System { - fonts: glyphon::FontSystem, - - #[borrows(fonts)] - #[not_covariant] - measurement_cache: RefCell<Cache<'this>>, - - #[borrows(fonts)] - #[not_covariant] - render_cache: Cache<'this>, + measurement_cache: RefCell<Cache>, + render_cache: Cache, } impl Pipeline { @@ -38,42 +27,23 @@ impl Pipeline { format: wgpu::TextureFormat, ) -> Self { Pipeline { - system: Some( - SystemBuilder { - fonts: glyphon::FontSystem::new_with_fonts( - [glyphon::fontdb::Source::Binary(Arc::new( - include_bytes!("../fonts/Iced-Icons.ttf") - .as_slice(), - ))] - .into_iter(), - ), - measurement_cache_builder: |_| RefCell::new(Cache::new()), - render_cache_builder: |_| Cache::new(), - } - .build(), - ), + font_system: RefCell::new(glyphon::FontSystem::new_with_fonts( + [glyphon::fontdb::Source::Binary(Arc::new( + include_bytes!("../fonts/Iced-Icons.ttf").as_slice(), + ))] + .into_iter(), + )), renderers: Vec::new(), atlas: glyphon::TextAtlas::new(device, queue, format), prepare_layer: 0, + measurement_cache: RefCell::new(Cache::new()), + render_cache: Cache::new(), } } pub fn load_font(&mut self, bytes: Cow<'static, [u8]>) { - let heads = self.system.take().unwrap().into_heads(); - - let (locale, mut db) = heads.fonts.into_locale_and_db(); - - db.load_font_source(glyphon::fontdb::Source::Binary(Arc::new( - bytes.into_owned(), - ))); - - self.system = Some( - SystemBuilder { - fonts: glyphon::FontSystem::new_with_locale_and_db(locale, db), - measurement_cache_builder: |_| RefCell::new(Cache::new()), - render_cache_builder: |_| Cache::new(), - } - .build(), + self.font_system.get_mut().db_mut().load_font_source( + glyphon::fontdb::Source::Binary(Arc::new(bytes.into_owned())), ); } @@ -86,126 +56,123 @@ impl Pipeline { scale_factor: f32, target_size: Size<u32>, ) -> bool { - self.system.as_mut().unwrap().with_mut(|fields| { - if self.renderers.len() <= self.prepare_layer { - self.renderers - .push(glyphon::TextRenderer::new(device, queue)); - } + if self.renderers.len() <= self.prepare_layer { + self.renderers + .push(glyphon::TextRenderer::new(device, queue)); + } - let renderer = &mut self.renderers[self.prepare_layer]; - - let keys: Vec<_> = sections - .iter() - .map(|section| { - let (key, _) = fields.render_cache.allocate( - fields.fonts, - Key { - content: section.content, - size: section.size * scale_factor, - font: section.font, - bounds: Size { - width: (section.bounds.width * scale_factor) - .ceil(), - height: (section.bounds.height * scale_factor) - .ceil(), - }, + let font_system = self.font_system.get_mut(); + let renderer = &mut self.renderers[self.prepare_layer]; + + let keys: Vec<_> = sections + .iter() + .map(|section| { + let (key, _) = self.render_cache.allocate( + font_system, + Key { + content: section.content, + size: section.size * scale_factor, + font: section.font, + bounds: Size { + width: (section.bounds.width * scale_factor).ceil(), + height: (section.bounds.height * scale_factor) + .ceil(), }, - ); - - key - }) - .collect(); - - let bounds = glyphon::TextBounds { - left: (bounds.x * scale_factor) as i32, - top: (bounds.y * scale_factor) as i32, - right: ((bounds.x + bounds.width) * scale_factor) as i32, - bottom: ((bounds.y + bounds.height) * scale_factor) as i32, - }; - - let text_areas = - sections.iter().zip(keys.iter()).map(|(section, key)| { - let buffer = fields - .render_cache - .get(key) - .expect("Get cached buffer"); - - let x = section.bounds.x * scale_factor; - let y = section.bounds.y * scale_factor; - - let (total_lines, max_width) = buffer - .layout_runs() - .enumerate() - .fold((0, 0.0), |(_, max), (i, buffer)| { - (i + 1, buffer.line_w.max(max)) - }); - - let total_height = - total_lines as f32 * section.size * 1.2 * scale_factor; - - let left = match section.horizontal_alignment { - alignment::Horizontal::Left => x, - alignment::Horizontal::Center => x - max_width / 2.0, - alignment::Horizontal::Right => x - max_width, - }; - - let top = match section.vertical_alignment { - alignment::Vertical::Top => y, - alignment::Vertical::Center => y - total_height / 2.0, - alignment::Vertical::Bottom => y - total_height, - }; - - glyphon::TextArea { - buffer, - left: left as i32, - top: top as i32, - bounds, - default_color: { - let [r, g, b, a] = section.color.into_linear(); - - glyphon::Color::rgba( - (r * 255.0) as u8, - (g * 255.0) as u8, - (b * 255.0) as u8, - (a * 255.0) as u8, - ) - }, - } - }); - - let result = renderer.prepare( - device, - queue, - &mut self.atlas, - glyphon::Resolution { - width: target_size.width, - height: target_size.height, - }, - text_areas, - &mut glyphon::SwashCache::new(fields.fonts), - ); + }, + ); + + key + }) + .collect(); + + let bounds = glyphon::TextBounds { + left: (bounds.x * scale_factor) as i32, + top: (bounds.y * scale_factor) as i32, + right: ((bounds.x + bounds.width) * scale_factor) as i32, + bottom: ((bounds.y + bounds.height) * scale_factor) as i32, + }; - match result { - Ok(()) => { - self.prepare_layer += 1; + let text_areas = + sections.iter().zip(keys.iter()).map(|(section, key)| { + let buffer = + self.render_cache.get(key).expect("Get cached buffer"); + + let x = section.bounds.x * scale_factor; + let y = section.bounds.y * scale_factor; + + let (total_lines, max_width) = buffer + .layout_runs() + .enumerate() + .fold((0, 0.0), |(_, max), (i, buffer)| { + (i + 1, buffer.line_w.max(max)) + }); + + let total_height = + total_lines as f32 * section.size * 1.2 * scale_factor; + + let left = match section.horizontal_alignment { + alignment::Horizontal::Left => x, + alignment::Horizontal::Center => x - max_width / 2.0, + alignment::Horizontal::Right => x - max_width, + }; + + let top = match section.vertical_alignment { + alignment::Vertical::Top => y, + alignment::Vertical::Center => y - total_height / 2.0, + alignment::Vertical::Bottom => y - total_height, + }; + + glyphon::TextArea { + buffer, + left: left as i32, + top: top as i32, + bounds, + default_color: { + let [r, g, b, a] = section.color.into_linear(); + + glyphon::Color::rgba( + (r * 255.0) as u8, + (g * 255.0) as u8, + (b * 255.0) as u8, + (a * 255.0) as u8, + ) + }, + } + }); + + let result = renderer.prepare( + device, + queue, + font_system, + &mut self.atlas, + glyphon::Resolution { + width: target_size.width, + height: target_size.height, + }, + text_areas, + &mut glyphon::SwashCache::new(), + ); + + match result { + Ok(()) => { + self.prepare_layer += 1; + true + } + Err(glyphon::PrepareError::AtlasFull(content_type)) => { + self.prepare_layer = 0; + + #[allow(clippy::needless_bool)] + if self.atlas.grow(device, content_type) { + false + } else { + // If the atlas cannot grow, then all bets are off. + // Instead of panicking, we will just pray that the result + // will be somewhat readable... true } - Err(glyphon::PrepareError::AtlasFull(content_type)) => { - self.prepare_layer = 0; - - #[allow(clippy::needless_bool)] - if self.atlas.grow(device, content_type) { - false - } else { - // If the atlas cannot grow, then all bets are off. - // Instead of panicking, we will just pray that the result - // will be somewhat readable... - true - } - } } - }) + } } pub fn render<'a>( @@ -230,11 +197,7 @@ impl Pipeline { pub fn end_frame(&mut self) { self.atlas.trim(); - - self.system - .as_mut() - .unwrap() - .with_render_cache_mut(|cache| cache.trim()); + self.render_cache.trim(); self.prepare_layer = 0; } @@ -246,28 +209,26 @@ impl Pipeline { font: Font, bounds: Size, ) -> (f32, f32) { - self.system.as_ref().unwrap().with(|fields| { - let mut measurement_cache = fields.measurement_cache.borrow_mut(); - - let (_, paragraph) = measurement_cache.allocate( - fields.fonts, - Key { - content, - size, - font, - bounds, - }, - ); + let mut measurement_cache = self.measurement_cache.borrow_mut(); + + let (_, paragraph) = measurement_cache.allocate( + &mut self.font_system.borrow_mut(), + Key { + content, + size, + font, + bounds, + }, + ); - let (total_lines, max_width) = paragraph - .layout_runs() - .enumerate() - .fold((0, 0.0), |(_, max), (i, buffer)| { - (i + 1, buffer.line_w.max(max)) - }); + let (total_lines, max_width) = paragraph + .layout_runs() + .enumerate() + .fold((0, 0.0), |(_, max), (i, buffer)| { + (i + 1, buffer.line_w.max(max)) + }); - (max_width, size * 1.2 * total_lines as f32) - }) + (max_width, size * 1.2 * total_lines as f32) } pub fn hit_test( @@ -279,30 +240,25 @@ impl Pipeline { point: Point, _nearest_only: bool, ) -> Option<Hit> { - self.system.as_ref().unwrap().with(|fields| { - let mut measurement_cache = fields.measurement_cache.borrow_mut(); - - let (_, paragraph) = measurement_cache.allocate( - fields.fonts, - Key { - content, - size, - font, - bounds, - }, - ); + let mut measurement_cache = self.measurement_cache.borrow_mut(); + + let (_, paragraph) = measurement_cache.allocate( + &mut self.font_system.borrow_mut(), + Key { + content, + size, + font, + bounds, + }, + ); - let cursor = paragraph.hit(point.x, point.y)?; + let cursor = paragraph.hit(point.x, point.y)?; - Some(Hit::CharOffset(cursor.index)) - }) + Some(Hit::CharOffset(cursor.index)) } pub fn trim_measurement_cache(&mut self) { - self.system - .as_mut() - .unwrap() - .with_measurement_cache_mut(|cache| cache.borrow_mut().trim()); + self.measurement_cache.borrow_mut().trim(); } } @@ -317,8 +273,8 @@ fn to_family(font: Font) -> glyphon::Family<'static> { } } -struct Cache<'a> { - entries: FxHashMap<KeyHash, glyphon::Buffer<'a>>, +struct Cache { + entries: FxHashMap<KeyHash, glyphon::Buffer>, recently_used: FxHashSet<KeyHash>, hasher: HashBuilder, } @@ -329,7 +285,7 @@ type HashBuilder = twox_hash::RandomXxHashBuilder64; #[cfg(target_arch = "wasm32")] type HashBuilder = std::hash::BuildHasherDefault<twox_hash::XxHash64>; -impl<'a> Cache<'a> { +impl Cache { fn new() -> Self { Self { entries: FxHashMap::default(), @@ -338,15 +294,15 @@ impl<'a> Cache<'a> { } } - fn get(&self, key: &KeyHash) -> Option<&glyphon::Buffer<'a>> { + fn get(&self, key: &KeyHash) -> Option<&glyphon::Buffer> { self.entries.get(key) } fn allocate( &mut self, - fonts: &'a glyphon::FontSystem, + font_system: &mut glyphon::FontSystem, key: Key<'_>, - ) -> (KeyHash, &mut glyphon::Buffer<'a>) { + ) -> (KeyHash, &mut glyphon::Buffer) { let hash = { let mut hasher = self.hasher.build_hasher(); @@ -361,13 +317,15 @@ impl<'a> Cache<'a> { if let hash_map::Entry::Vacant(entry) = self.entries.entry(hash) { let metrics = glyphon::Metrics::new(key.size, key.size * 1.2); - let mut buffer = glyphon::Buffer::new(fonts, metrics); + let mut buffer = glyphon::Buffer::new(font_system, metrics); buffer.set_size( + font_system, key.bounds.width, key.bounds.height.max(key.size * 1.2), ); buffer.set_text( + font_system, key.content, glyphon::Attrs::new() .family(to_family(key.font)) |