diff options
author | 2019-11-14 06:47:43 +0100 | |
---|---|---|
committer | 2019-11-14 06:47:43 +0100 | |
commit | a16dab9cf2e27cb933cc91383ca79ba8e188c4c2 (patch) | |
tree | db844c70cc8fbd2f48b175e97bde50866641a1b4 /wgpu/src/text.rs | |
parent | bc8d347736ec997ec0e0c401289e2bc09e212b8a (diff) | |
parent | 6857829dc3171fd68065498b6cd29f0ef02a8d43 (diff) | |
download | iced-a16dab9cf2e27cb933cc91383ca79ba8e188c4c2.tar.gz iced-a16dab9cf2e27cb933cc91383ca79ba8e188c4c2.tar.bz2 iced-a16dab9cf2e27cb933cc91383ca79ba8e188c4c2.zip |
Merge pull request #54 from hecrj/feature/external-fonts
Custom font support
Diffstat (limited to 'wgpu/src/text.rs')
-rw-r--r-- | wgpu/src/text.rs | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs new file mode 100644 index 00000000..3205fe55 --- /dev/null +++ b/wgpu/src/text.rs @@ -0,0 +1,158 @@ +mod font; + +use crate::Transformation; + +use std::cell::RefCell; +use std::collections::HashMap; + +pub struct Pipeline { + draw_brush: RefCell<wgpu_glyph::GlyphBrush<'static, ()>>, + draw_font_map: RefCell<HashMap<String, wgpu_glyph::FontId>>, + + measure_brush: RefCell<glyph_brush::GlyphBrush<'static, ()>>, +} + +impl Pipeline { + pub fn new(device: &mut wgpu::Device) -> Self { + // TODO: Font customization + let font_source = font::Source::new(); + + let default_font = font_source + .load(&[font::Family::SansSerif, font::Family::Serif]) + .expect("Find sans-serif or serif font"); + + let mono_font = font_source + .load(&[font::Family::Monospace]) + .expect("Find monospace font"); + + let draw_brush = + wgpu_glyph::GlyphBrushBuilder::using_fonts_bytes(vec![ + mono_font, + default_font.clone(), + ]) + .initial_cache_size((2048, 2048)) + .build(device, wgpu::TextureFormat::Bgra8UnormSrgb); + + let measure_brush = + glyph_brush::GlyphBrushBuilder::using_font_bytes(default_font) + .build(); + + Pipeline { + draw_brush: RefCell::new(draw_brush), + draw_font_map: RefCell::new(HashMap::new()), + + measure_brush: RefCell::new(measure_brush), + } + } + + pub fn overlay_font(&self) -> wgpu_glyph::FontId { + wgpu_glyph::FontId(0) + } + + pub fn queue(&mut self, section: wgpu_glyph::Section) { + self.draw_brush.borrow_mut().queue(section); + } + + pub fn draw_queued( + &mut self, + device: &mut wgpu::Device, + encoder: &mut wgpu::CommandEncoder, + target: &wgpu::TextureView, + transformation: Transformation, + region: wgpu_glyph::Region, + ) { + self.draw_brush + .borrow_mut() + .draw_queued_with_transform_and_scissoring( + device, + encoder, + target, + transformation.into(), + region, + ) + .expect("Draw text"); + } + + pub fn measure( + &self, + content: &str, + size: f32, + font: iced_native::Font, + bounds: iced_native::Size, + ) -> (f32, f32) { + use wgpu_glyph::GlyphCruncher; + + let wgpu_glyph::FontId(font_id) = self.find_font(font); + + let section = wgpu_glyph::Section { + text: content, + scale: wgpu_glyph::Scale { x: size, y: size }, + bounds: (bounds.width, bounds.height), + + // TODO: This is a bit hacky. We are loading the debug font as the + // first font in the `draw_brush`. The `measure_brush` does not + // contain this font. + // + // This should go away once we improve the debug view and integrate + // it as just another UI app. + font_id: wgpu_glyph::FontId(font_id - 1), + ..Default::default() + }; + + if let Some(bounds) = + self.measure_brush.borrow_mut().glyph_bounds(section) + { + (bounds.width().ceil(), bounds.height().ceil()) + } else { + (0.0, 0.0) + } + } + + pub fn space_width(&self, size: f32) -> f32 { + use wgpu_glyph::GlyphCruncher; + + let glyph_brush = self.measure_brush.borrow(); + + // TODO: Select appropriate font + let font = &glyph_brush.fonts()[0]; + + font.glyph(' ') + .scaled(wgpu_glyph::Scale { x: size, y: size }) + .h_metrics() + .advance_width + } + + pub fn clear_measurement_cache(&mut self) { + // TODO: We should probably use a `GlyphCalculator` for this. However, + // it uses a lifetimed `GlyphCalculatorGuard` with side-effects on drop. + // This makes stuff quite inconvenient. A manual method for trimming the + // cache would make our lives easier. + self.measure_brush + .borrow_mut() + .process_queued(|_, _| {}, |_| {}) + .expect("Trim text measurements"); + } + + pub fn find_font(&self, font: iced_native::Font) -> wgpu_glyph::FontId { + match font { + iced_native::Font::Default => wgpu_glyph::FontId(1), + iced_native::Font::External { name, bytes } => { + if let Some(font_id) = self.draw_font_map.borrow().get(name) { + return *font_id; + } + + // TODO: Find a way to share font data + let _ = self.measure_brush.borrow_mut().add_font_bytes(bytes); + + let font_id = + self.draw_brush.borrow_mut().add_font_bytes(bytes); + + self.draw_font_map + .borrow_mut() + .insert(String::from(name), font_id); + + font_id + } + } + } +} |