From f5ee6d0e51d18bcd30a0bbcd28fa992d995bdf3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 25 May 2020 21:49:16 +0200 Subject: [PATCH] Update `wgpu_glyph` and `glyph_brush` --- wgpu/Cargo.toml | 4 +- wgpu/src/renderer.rs | 139 ++++++++++++++----------- wgpu/src/renderer/widget/text_input.rs | 9 +- wgpu/src/text.rs | 76 ++++++-------- 4 files changed, 111 insertions(+), 117 deletions(-) diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 612af1ed..28f7181f 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -13,9 +13,9 @@ canvas = ["lyon"] [dependencies] wgpu = "0.5" -wgpu_glyph = "0.8" +wgpu_glyph = { git = "https://github.com/hecrj/wgpu_glyph.git", branch = "feature/update-glyph-brush" } zerocopy = "0.3" -glyph_brush = "0.6" +glyph_brush = "0.7" raw-window-handle = "0.3" glam = "0.8" font-kit = "0.6" diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 71b4af38..f3a7c288 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -7,7 +7,8 @@ use crate::{ use crate::image::{self, Image}; use iced_native::{ - layout, mouse, Background, Color, Layout, Point, Rectangle, Vector, Widget, + layout, mouse, Background, Color, Font, HorizontalAlignment, Layout, Point, + Rectangle, Size, Vector, VerticalAlignment, Widget, }; mod widget; @@ -29,12 +30,23 @@ struct Layer<'a> { bounds: Rectangle, quads: Vec, meshes: Vec<(Vector, Rectangle, &'a triangle::Mesh2D)>, - text: Vec>, + text: Vec>, #[cfg(any(feature = "image", feature = "svg"))] images: Vec, } +#[derive(Debug, Clone, Copy)] +pub struct Text<'a> { + pub content: &'a str, + pub bounds: Rectangle, + pub color: [f32; 4], + pub size: f32, + pub font: Font, + pub horizontal_alignment: HorizontalAlignment, + pub vertical_alignment: VerticalAlignment, +} + impl<'a> Layer<'a> { pub fn new(bounds: Rectangle) -> Self { Self { @@ -159,41 +171,15 @@ impl Renderer { } => { let layer = layers.last_mut().unwrap(); - layer.text.push(wgpu_glyph::Section { - text: &content, - screen_position: ( - bounds.x + translation.x, - bounds.y + translation.y, - ), - bounds: (bounds.width, bounds.height), - scale: wgpu_glyph::Scale { x: *size, y: *size }, + layer.text.push(Text { + content, + bounds: *bounds + translation, + size: *size, color: color.into_linear(), - font_id: self.text_pipeline.find_font(*font), - layout: wgpu_glyph::Layout::default() - .h_align(match horizontal_alignment { - iced_native::HorizontalAlignment::Left => { - wgpu_glyph::HorizontalAlign::Left - } - iced_native::HorizontalAlignment::Center => { - wgpu_glyph::HorizontalAlign::Center - } - iced_native::HorizontalAlignment::Right => { - wgpu_glyph::HorizontalAlign::Right - } - }) - .v_align(match vertical_alignment { - iced_native::VerticalAlignment::Top => { - wgpu_glyph::VerticalAlign::Top - } - iced_native::VerticalAlignment::Center => { - wgpu_glyph::VerticalAlign::Center - } - iced_native::VerticalAlignment::Bottom => { - wgpu_glyph::VerticalAlign::Bottom - } - }), - ..Default::default() - }) + font: *font, + horizontal_alignment: *horizontal_alignment, + vertical_alignment: *vertical_alignment, + }); } Primitive::Quad { bounds, @@ -315,26 +301,26 @@ impl Renderer { let first = layers.first().unwrap(); let mut overlay = Layer::new(first.bounds); - let font_id = self.text_pipeline.overlay_font(); - let scale = wgpu_glyph::Scale { x: 20.0, y: 20.0 }; - for (i, line) in lines.iter().enumerate() { - overlay.text.push(wgpu_glyph::Section { - text: line.as_ref(), - screen_position: (11.0, 11.0 + 25.0 * i as f32), + let text = Text { + content: line.as_ref(), + bounds: Rectangle::new( + Point::new(11.0, 11.0 + 25.0 * i as f32), + Size::INFINITY, + ), color: [0.9, 0.9, 0.9, 1.0], - scale, - font_id, - ..wgpu_glyph::Section::default() - }); + size: 20.0, + font: Font::Default, + horizontal_alignment: HorizontalAlignment::Left, + vertical_alignment: VerticalAlignment::Top, + }; - overlay.text.push(wgpu_glyph::Section { - text: line.as_ref(), - screen_position: (10.0, 10.0 + 25.0 * i as f32), + overlay.text.push(text); + + overlay.text.push(Text { + bounds: text.bounds + Vector::new(-1.0, -1.0), color: [0.0, 0.0, 0.0, 1.0], - scale, - font_id, - ..wgpu_glyph::Section::default() + ..text }); } @@ -409,8 +395,8 @@ impl Renderer { // bit "jumpy". We may be able to do better once we improve // our text rendering/caching pipeline. screen_position: ( - (text.screen_position.0 * scale_factor).round(), - (text.screen_position.1 * scale_factor).round(), + (text.bounds.x * scale_factor).round(), + (text.bounds.y * scale_factor).round(), ), // TODO: Fix precision issues with some scale factors. // @@ -422,14 +408,45 @@ impl Renderer { // scaling when rendering. This would ensure that both // measuring and rendering follow the same layout rules. bounds: ( - (text.bounds.0 * scale_factor).ceil(), - (text.bounds.1 * scale_factor).ceil(), + (text.bounds.width * scale_factor).ceil(), + (text.bounds.height * scale_factor).ceil(), ), - scale: wgpu_glyph::Scale { - x: text.scale.x * scale_factor, - y: text.scale.y * scale_factor, - }, - ..*text + text: vec![wgpu_glyph::Text { + text: text.content, + scale: wgpu_glyph::ab_glyph::PxScale { + x: text.size * scale_factor, + y: text.size * scale_factor, + }, + font_id: self.text_pipeline.find_font(text.font), + extra: wgpu_glyph::Extra { + color: text.color, + z: 0.0, + }, + }], + layout: wgpu_glyph::Layout::default() + .h_align(match text.horizontal_alignment { + HorizontalAlignment::Left => { + wgpu_glyph::HorizontalAlign::Left + } + HorizontalAlignment::Center => { + wgpu_glyph::HorizontalAlign::Center + } + HorizontalAlignment::Right => { + wgpu_glyph::HorizontalAlign::Right + } + }) + .v_align(match text.vertical_alignment { + VerticalAlignment::Top => { + wgpu_glyph::VerticalAlign::Top + } + VerticalAlignment::Center => { + wgpu_glyph::VerticalAlign::Center + } + VerticalAlignment::Bottom => { + wgpu_glyph::VerticalAlign::Bottom + } + }), + ..Default::default() }; self.text_pipeline.queue(text); diff --git a/wgpu/src/renderer/widget/text_input.rs b/wgpu/src/renderer/widget/text_input.rs index 57be6692..5799dba7 100644 --- a/wgpu/src/renderer/widget/text_input.rs +++ b/wgpu/src/renderer/widget/text_input.rs @@ -17,20 +17,13 @@ impl text_input::Renderer for Renderer { } fn measure_value(&self, value: &str, size: u16, font: Font) -> f32 { - let (mut width, _) = self.text_pipeline.measure( + let (width, _) = self.text_pipeline.measure( value, f32::from(size), font, Size::INFINITY, ); - let spaces_around = value.len() - value.trim().len(); - - if spaces_around > 0 { - let space_width = self.text_pipeline.space_width(size as f32); - width += spaces_around as f32 * space_width; - } - width } diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index f4521e72..7b6bef6c 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -3,6 +3,7 @@ mod font; use crate::Transformation; use std::{cell::RefCell, collections::HashMap}; +use wgpu_glyph::ab_glyph; pub const BUILTIN_ICONS: iced_native::Font = iced_native::Font::External { name: "iced_wgpu icons", @@ -15,10 +16,10 @@ const FALLBACK_FONT: &[u8] = include_bytes!("../fonts/Lato-Regular.ttf"); #[derive(Debug)] pub struct Pipeline { - draw_brush: RefCell>, + draw_brush: RefCell>, draw_font_map: RefCell>, - measure_brush: RefCell>, + measure_brush: RefCell>, } impl Pipeline { @@ -37,28 +38,25 @@ impl Pipeline { .unwrap_or_else(|_| FALLBACK_FONT.to_vec()) }); - let load_glyph_brush = |font: Vec| { - let builder = - wgpu_glyph::GlyphBrushBuilder::using_fonts_bytes(vec![ - font.clone() - ])?; + let font = ab_glyph::FontArc::try_from_vec(default_font) + .unwrap_or_else(|_| { + log::warn!( + "System font failed to load. Falling back to \ + embedded font..." + ); - Ok(( - builder, - glyph_brush::GlyphBrushBuilder::using_font_bytes(font).build(), - )) - }; - - let (brush_builder, measure_brush) = load_glyph_brush(default_font) - .unwrap_or_else(|_: wgpu_glyph::rusttype::Error| { - log::warn!("System font failed to load. Falling back to embedded font..."); - - load_glyph_brush(FALLBACK_FONT.to_vec()).expect("Load fallback font") + ab_glyph::FontArc::try_from_slice(FALLBACK_FONT) + .expect("Load fallback font") }); - let draw_brush = brush_builder - .initial_cache_size((2048, 2048)) - .build(device, format); + let draw_brush = + wgpu_glyph::GlyphBrushBuilder::using_font(font.clone()) + .initial_cache_size((2048, 2048)) + .draw_cache_multithread(false) // TODO: Expose as a configuration flag + .build(device, format); + + let measure_brush = + glyph_brush::GlyphBrushBuilder::using_font(font).build(); Pipeline { draw_brush: RefCell::new(draw_brush), @@ -68,10 +66,6 @@ impl Pipeline { } } - 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); } @@ -108,10 +102,13 @@ impl Pipeline { 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), - font_id: wgpu_glyph::FontId(font_id), + text: vec![wgpu_glyph::Text { + text: content, + scale: size.into(), + font_id: wgpu_glyph::FontId(font_id), + extra: wgpu_glyph::Extra::default(), + }], ..Default::default() }; @@ -124,20 +121,6 @@ impl Pipeline { } } - 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. @@ -170,11 +153,12 @@ impl Pipeline { return *font_id; } - // TODO: Find a way to share font data - let _ = self.measure_brush.borrow_mut().add_font_bytes(bytes); + let font = ab_glyph::FontArc::try_from_slice(bytes) + .expect("Load font"); - let font_id = - self.draw_brush.borrow_mut().add_font_bytes(bytes); + let _ = self.measure_brush.borrow_mut().add_font(font.clone()); + + let font_id = self.draw_brush.borrow_mut().add_font(font); let _ = self .draw_font_map