Update wgpu_glyph and glyph_brush

This commit is contained in:
Héctor Ramón Jiménez 2020-05-25 21:49:16 +02:00
parent 5324eb1024
commit f5ee6d0e51
4 changed files with 111 additions and 117 deletions

View File

@ -13,9 +13,9 @@ canvas = ["lyon"]
[dependencies] [dependencies]
wgpu = "0.5" 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" zerocopy = "0.3"
glyph_brush = "0.6" glyph_brush = "0.7"
raw-window-handle = "0.3" raw-window-handle = "0.3"
glam = "0.8" glam = "0.8"
font-kit = "0.6" font-kit = "0.6"

View File

@ -7,7 +7,8 @@ use crate::{
use crate::image::{self, Image}; use crate::image::{self, Image};
use iced_native::{ 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; mod widget;
@ -29,12 +30,23 @@ struct Layer<'a> {
bounds: Rectangle<u32>, bounds: Rectangle<u32>,
quads: Vec<Quad>, quads: Vec<Quad>,
meshes: Vec<(Vector, Rectangle<u32>, &'a triangle::Mesh2D)>, meshes: Vec<(Vector, Rectangle<u32>, &'a triangle::Mesh2D)>,
text: Vec<wgpu_glyph::Section<'a>>, text: Vec<Text<'a>>,
#[cfg(any(feature = "image", feature = "svg"))] #[cfg(any(feature = "image", feature = "svg"))]
images: Vec<Image>, images: Vec<Image>,
} }
#[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> { impl<'a> Layer<'a> {
pub fn new(bounds: Rectangle<u32>) -> Self { pub fn new(bounds: Rectangle<u32>) -> Self {
Self { Self {
@ -159,41 +171,15 @@ impl Renderer {
} => { } => {
let layer = layers.last_mut().unwrap(); let layer = layers.last_mut().unwrap();
layer.text.push(wgpu_glyph::Section { layer.text.push(Text {
text: &content, content,
screen_position: ( bounds: *bounds + translation,
bounds.x + translation.x, size: *size,
bounds.y + translation.y,
),
bounds: (bounds.width, bounds.height),
scale: wgpu_glyph::Scale { x: *size, y: *size },
color: color.into_linear(), color: color.into_linear(),
font_id: self.text_pipeline.find_font(*font), font: *font,
layout: wgpu_glyph::Layout::default() horizontal_alignment: *horizontal_alignment,
.h_align(match horizontal_alignment { vertical_alignment: *vertical_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()
})
} }
Primitive::Quad { Primitive::Quad {
bounds, bounds,
@ -315,26 +301,26 @@ impl Renderer {
let first = layers.first().unwrap(); let first = layers.first().unwrap();
let mut overlay = Layer::new(first.bounds); 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() { for (i, line) in lines.iter().enumerate() {
overlay.text.push(wgpu_glyph::Section { let text = Text {
text: line.as_ref(), content: line.as_ref(),
screen_position: (11.0, 11.0 + 25.0 * i as f32), 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], color: [0.9, 0.9, 0.9, 1.0],
scale, size: 20.0,
font_id, font: Font::Default,
..wgpu_glyph::Section::default() horizontal_alignment: HorizontalAlignment::Left,
}); vertical_alignment: VerticalAlignment::Top,
};
overlay.text.push(wgpu_glyph::Section { overlay.text.push(text);
text: line.as_ref(),
screen_position: (10.0, 10.0 + 25.0 * i as f32), overlay.text.push(Text {
bounds: text.bounds + Vector::new(-1.0, -1.0),
color: [0.0, 0.0, 0.0, 1.0], color: [0.0, 0.0, 0.0, 1.0],
scale, ..text
font_id,
..wgpu_glyph::Section::default()
}); });
} }
@ -409,8 +395,8 @@ impl Renderer {
// bit "jumpy". We may be able to do better once we improve // bit "jumpy". We may be able to do better once we improve
// our text rendering/caching pipeline. // our text rendering/caching pipeline.
screen_position: ( screen_position: (
(text.screen_position.0 * scale_factor).round(), (text.bounds.x * scale_factor).round(),
(text.screen_position.1 * scale_factor).round(), (text.bounds.y * scale_factor).round(),
), ),
// TODO: Fix precision issues with some scale factors. // TODO: Fix precision issues with some scale factors.
// //
@ -422,14 +408,45 @@ impl Renderer {
// scaling when rendering. This would ensure that both // scaling when rendering. This would ensure that both
// measuring and rendering follow the same layout rules. // measuring and rendering follow the same layout rules.
bounds: ( bounds: (
(text.bounds.0 * scale_factor).ceil(), (text.bounds.width * scale_factor).ceil(),
(text.bounds.1 * scale_factor).ceil(), (text.bounds.height * scale_factor).ceil(),
), ),
scale: wgpu_glyph::Scale { text: vec![wgpu_glyph::Text {
x: text.scale.x * scale_factor, text: text.content,
y: text.scale.y * scale_factor, scale: wgpu_glyph::ab_glyph::PxScale {
}, x: text.size * scale_factor,
..*text 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); self.text_pipeline.queue(text);

View File

@ -17,20 +17,13 @@ impl text_input::Renderer for Renderer {
} }
fn measure_value(&self, value: &str, size: u16, font: Font) -> f32 { 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, value,
f32::from(size), f32::from(size),
font, font,
Size::INFINITY, 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 width
} }

View File

@ -3,6 +3,7 @@ mod font;
use crate::Transformation; use crate::Transformation;
use std::{cell::RefCell, collections::HashMap}; use std::{cell::RefCell, collections::HashMap};
use wgpu_glyph::ab_glyph;
pub const BUILTIN_ICONS: iced_native::Font = iced_native::Font::External { pub const BUILTIN_ICONS: iced_native::Font = iced_native::Font::External {
name: "iced_wgpu icons", name: "iced_wgpu icons",
@ -15,10 +16,10 @@ const FALLBACK_FONT: &[u8] = include_bytes!("../fonts/Lato-Regular.ttf");
#[derive(Debug)] #[derive(Debug)]
pub struct Pipeline { pub struct Pipeline {
draw_brush: RefCell<wgpu_glyph::GlyphBrush<'static, ()>>, draw_brush: RefCell<wgpu_glyph::GlyphBrush<()>>,
draw_font_map: RefCell<HashMap<String, wgpu_glyph::FontId>>, draw_font_map: RefCell<HashMap<String, wgpu_glyph::FontId>>,
measure_brush: RefCell<glyph_brush::GlyphBrush<'static, ()>>, measure_brush: RefCell<glyph_brush::GlyphBrush<()>>,
} }
impl Pipeline { impl Pipeline {
@ -37,28 +38,25 @@ impl Pipeline {
.unwrap_or_else(|_| FALLBACK_FONT.to_vec()) .unwrap_or_else(|_| FALLBACK_FONT.to_vec())
}); });
let load_glyph_brush = |font: Vec<u8>| { let font = ab_glyph::FontArc::try_from_vec(default_font)
let builder = .unwrap_or_else(|_| {
wgpu_glyph::GlyphBrushBuilder::using_fonts_bytes(vec![ log::warn!(
font.clone() "System font failed to load. Falling back to \
])?; embedded font..."
);
Ok(( ab_glyph::FontArc::try_from_slice(FALLBACK_FONT)
builder, .expect("Load fallback font")
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")
}); });
let draw_brush = brush_builder let draw_brush =
.initial_cache_size((2048, 2048)) wgpu_glyph::GlyphBrushBuilder::using_font(font.clone())
.build(device, format); .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 { Pipeline {
draw_brush: RefCell::new(draw_brush), 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<'_>) { pub fn queue(&mut self, section: wgpu_glyph::Section<'_>) {
self.draw_brush.borrow_mut().queue(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 wgpu_glyph::FontId(font_id) = self.find_font(font);
let section = wgpu_glyph::Section { let section = wgpu_glyph::Section {
text: content,
scale: wgpu_glyph::Scale { x: size, y: size },
bounds: (bounds.width, bounds.height), 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() ..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) { pub fn clear_measurement_cache(&mut self) {
// TODO: We should probably use a `GlyphCalculator` for this. However, // TODO: We should probably use a `GlyphCalculator` for this. However,
// it uses a lifetimed `GlyphCalculatorGuard` with side-effects on drop. // it uses a lifetimed `GlyphCalculatorGuard` with side-effects on drop.
@ -170,11 +153,12 @@ impl Pipeline {
return *font_id; return *font_id;
} }
// TODO: Find a way to share font data let font = ab_glyph::FontArc::try_from_slice(bytes)
let _ = self.measure_brush.borrow_mut().add_font_bytes(bytes); .expect("Load font");
let font_id = let _ = self.measure_brush.borrow_mut().add_font(font.clone());
self.draw_brush.borrow_mut().add_font_bytes(bytes);
let font_id = self.draw_brush.borrow_mut().add_font(font);
let _ = self let _ = self
.draw_font_map .draw_font_map