diff --git a/Cargo.lock b/Cargo.lock index 939615fa..b8f5201f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -729,9 +729,9 @@ dependencies = [ [[package]] name = "font-types" -version = "0.5.5" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34fd7136aca682873d859ef34494ab1a7d3f57ecd485ed40eb6437ee8c85aa29" +checksum = "3cdb0bc47d40fdd11177c271c1bb3704b4230e7a945891d3cc184244c74d64b2" dependencies = [ "bytemuck", ] @@ -1885,9 +1885,9 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "read-fonts" -version = "0.19.3" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8b8af39d1f23869711ad4cea5e7835a20daa987f80232f7f2a2374d648ca64d" +checksum = "0f37de1c4e46fd22ef9e1242df0ffb52ea62b64a9e91d4df16cecc300f31dfd0" dependencies = [ "bytemuck", "font-types", @@ -2130,9 +2130,9 @@ dependencies = [ [[package]] name = "skrifa" -version = "0.19.3" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab45fb68b53576a43d4fc0e9ec8ea64e29a4d2cc7f44506964cb75f288222e9" +checksum = "a502599a3648f4fa3a5d0a532006d03a1f72fb9a8bc0c7aa97a74ab932f44ce3" dependencies = [ "bytemuck", "read-fonts", diff --git a/Cargo.toml b/Cargo.toml index bba03b50..bb67a00b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ vello = { version = "0.2.0", path = "vello" } vello_encoding = { version = "0.2.0", path = "vello_encoding" } vello_shaders = { version = "0.2.0", path = "vello_shaders" } bytemuck = { version = "1.16.0", features = ["derive"] } -skrifa = "0.19.3" +skrifa = "0.22.0" peniko = "0.2.0" futures-intrusive = "0.5.0" raw-window-handle = "0.6.2" diff --git a/examples/scenes/src/simple_text.rs b/examples/scenes/src/simple_text.rs index 8f235696..9fe417d4 100644 --- a/examples/scenes/src/simple_text.rs +++ b/examples/scenes/src/simple_text.rs @@ -3,12 +3,10 @@ use std::sync::Arc; -use vello::glyph::Glyph; use vello::kurbo::Affine; use vello::peniko::{Blob, Brush, BrushRef, Color, Font, StyleRef}; -use vello::skrifa::raw::FontRef; -use vello::skrifa::MetadataProvider; -use vello::Scene; +use vello::skrifa::{raw::FontRef, MetadataProvider}; +use vello::{Glyph, Scene}; // This is very much a hack to get things working. // On Windows, can set this to "c:\\Windows\\Fonts\\seguiemj.ttf" to get color emoji @@ -179,7 +177,7 @@ impl SimpleText { let x = pen_x; pen_x += advance; Some(Glyph { - id: gid.to_u16() as u32, + id: gid.to_u32(), x, y: pen_y, }) diff --git a/vello/src/glyph.rs b/vello/src/glyph.rs deleted file mode 100644 index 8d8a3627..00000000 --- a/vello/src/glyph.rs +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2022 the Vello Authors -// SPDX-License-Identifier: Apache-2.0 OR MIT - -//! Support for glyph rendering. - -use crate::scene::Scene; -use peniko::kurbo::Affine; -use peniko::{Brush, Color, Fill, Style}; -use skrifa::instance::{NormalizedCoord, Size}; -use skrifa::outline::OutlinePen; -use skrifa::raw::FontRef; -use skrifa::setting::Setting; -use skrifa::{GlyphId, OutlineGlyphCollection}; -use vello_encoding::Encoding; - -use peniko::kurbo::Shape; -pub use skrifa; -use skrifa::outline::DrawSettings; -use skrifa::MetadataProvider; -pub use vello_encoding::Glyph; - -/// General context for creating scene fragments for glyph outlines. -#[derive(Default)] -pub struct GlyphContext { - coords: Vec, -} - -impl GlyphContext { - /// Creates a new context. - pub fn new() -> Self { - Self::default() - } - - /// Creates a new provider for generating scene fragments for glyphs from - /// the specified font and settings. - pub fn new_provider<'a, V>( - &'a mut self, - font: &FontRef<'a>, - ppem: f32, - _hint: bool, - variations: V, - ) -> GlyphProvider<'a> - where - V: IntoIterator, - V::Item: Into>, - { - let outlines = font.outline_glyphs(); - let size = Size::new(ppem); - let axes = font.axes(); - let axis_count = axes.len(); - self.coords.clear(); - self.coords.resize(axis_count, Default::default()); - axes.location_to_slice(variations, &mut self.coords); - if self.coords.iter().all(|x| *x == NormalizedCoord::default()) { - self.coords.clear(); - } - GlyphProvider { - outlines, - size, - coords: &self.coords, - } - } -} - -/// Generator for scene fragments containing glyph outlines for a specific -/// font. -pub struct GlyphProvider<'a> { - outlines: OutlineGlyphCollection<'a>, - size: Size, - coords: &'a [NormalizedCoord], -} - -impl<'a> GlyphProvider<'a> { - /// Returns a scene fragment containing the commands to render the - /// specified glyph. - pub fn get(&mut self, gid: u16, brush: Option<&Brush>) -> Option { - let mut scene = Scene::new(); - let mut path = BezPathPen::default(); - let outline = self.outlines.get(GlyphId::new(gid))?; - let draw_settings = DrawSettings::unhinted(self.size, self.coords); - outline.draw(draw_settings, &mut path).ok()?; - scene.fill( - Fill::NonZero, - Affine::IDENTITY, - brush.unwrap_or(&Brush::Solid(Color::rgb8(255, 255, 255))), - None, - &path.0, - ); - Some(scene) - } - - pub fn encode_glyph(&mut self, gid: u16, style: &Style, encoding: &mut Encoding) -> Option<()> { - let fill = match style { - Style::Fill(fill) => *fill, - Style::Stroke(_) => Fill::NonZero, - }; - encoding.encode_fill_style(fill); - let mut path = encoding.encode_path(true); - let outline = self.outlines.get(GlyphId::new(gid))?; - let draw_settings = DrawSettings::unhinted(self.size, self.coords); - match style { - Style::Fill(_) => { - outline.draw(draw_settings, &mut path).ok()?; - } - Style::Stroke(stroke) => { - const STROKE_TOLERANCE: f64 = 0.01; - let mut pen = BezPathPen::default(); - outline.draw(draw_settings, &mut pen).ok()?; - let stroked = peniko::kurbo::stroke( - pen.0.path_elements(STROKE_TOLERANCE), - stroke, - &Default::default(), - STROKE_TOLERANCE, - ); - path.shape(&stroked); - } - } - if path.finish(false) != 0 { - Some(()) - } else { - None - } - } -} - -#[derive(Default)] -struct BezPathPen(peniko::kurbo::BezPath); - -impl OutlinePen for BezPathPen { - fn move_to(&mut self, x: f32, y: f32) { - self.0.move_to((x as f64, y as f64)); - } - - fn line_to(&mut self, x: f32, y: f32) { - self.0.line_to((x as f64, y as f64)); - } - - fn quad_to(&mut self, cx0: f32, cy0: f32, x: f32, y: f32) { - self.0 - .quad_to((cx0 as f64, cy0 as f64), (x as f64, y as f64)); - } - - fn curve_to(&mut self, cx0: f32, cy0: f32, cx1: f32, cy1: f32, x: f32, y: f32) { - self.0.curve_to( - (cx0 as f64, cy0 as f64), - (cx1 as f64, cy1 as f64), - (x as f64, y as f64), - ); - } - - fn close(&mut self) { - self.0.close_path(); - } -} diff --git a/vello/src/lib.rs b/vello/src/lib.rs index d8e7f116..fc6dbd72 100644 --- a/vello/src/lib.rs +++ b/vello/src/lib.rs @@ -97,10 +97,8 @@ pub use peniko; /// 2D geometry, with a focus on curves. pub use peniko::kurbo; -#[doc(hidden)] pub use skrifa; - -pub mod glyph; +pub use vello_encoding::Glyph; #[cfg(feature = "wgpu")] pub use wgpu; diff --git a/vello/src/scene.rs b/vello/src/scene.rs index 164d1e28..f9e79e21 100644 --- a/vello/src/scene.rs +++ b/vello/src/scene.rs @@ -464,7 +464,7 @@ impl<'a> DrawGlyphs<'a> { loop { let ppem = self.run.font_size; let outline_glyphs = (&mut glyphs).take_while(|glyph| { - let glyph_id = GlyphId::new(glyph.id.try_into().unwrap()); + let glyph_id = GlyphId::new(glyph.id); match colour_collection.get(glyph_id) { Some(color) => { final_glyph = Some((EmojiLikeGlyph::Colr(color), *glyph)); diff --git a/vello/src/scene/bitmap.rs b/vello/src/scene/bitmap.rs index 3795f550..d3af0b68 100644 --- a/vello/src/scene/bitmap.rs +++ b/vello/src/scene/bitmap.rs @@ -26,7 +26,7 @@ impl<'a> BitmapStrikes<'a> { /// This will prefer `sbix`, `CBDT`, and `CBLC` formats in that order. /// /// To select a specific format, use [`with_format`](Self::with_format). - pub fn new(font: &impl TableProvider<'a>) -> Self { + pub fn new(font: &(impl TableProvider<'a> + MetadataProvider<'a>)) -> Self { for format in [BitmapFormat::Sbix, BitmapFormat::Cbdt, BitmapFormat::Ebdt] { if let Some(strikes) = Self::with_format(font, format) { return strikes; @@ -38,7 +38,10 @@ impl<'a> BitmapStrikes<'a> { /// Creates a new `BitmapStrikes` for the given font and format. /// /// Returns `None` if the requested format is not available. - pub fn with_format(font: &impl TableProvider<'a>, format: BitmapFormat) -> Option { + pub fn with_format( + font: &(impl TableProvider<'a> + MetadataProvider<'a>), + format: BitmapFormat, + ) -> Option { let kind = match format { BitmapFormat::Sbix => StrikesKind::Sbix( font.sbix().ok()?, diff --git a/vello_encoding/src/glyph_cache.rs b/vello_encoding/src/glyph_cache.rs index ea0beeb7..31f290bd 100644 --- a/vello_encoding/src/glyph_cache.rs +++ b/vello_encoding/src/glyph_cache.rs @@ -8,7 +8,7 @@ use super::{Encoding, StreamOffsets}; use peniko::{Font, Style}; use skrifa::instance::{NormalizedCoord, Size}; -use skrifa::outline::{HintingInstance, HintingMode, LcdLayout, OutlineGlyphFormat}; +use skrifa::outline::{HintingInstance, HintingOptions, OutlineGlyphFormat}; use skrifa::{GlyphId, MetadataProvider, OutlineGlyphCollection}; #[derive(Default)] @@ -162,7 +162,7 @@ impl<'a> GlyphCacheSession<'a> { entry.serial = self.serial; return Some((entry.encoding.clone(), entry.stream_sizes)); } - let outline = self.outlines.get(GlyphId::new(key.glyph_id as u16))?; + let outline = self.outlines.get(GlyphId::new(key.glyph_id))?; let mut encoding = self.free_list.pop().unwrap_or_default(); let encoding_ptr = Arc::make_mut(&mut encoding); encoding_ptr.reset(); @@ -245,13 +245,19 @@ pub(crate) struct HintKey<'a> { impl<'a> HintKey<'a> { fn instance(&self) -> Option { - HintingInstance::new(self.outlines, self.size, self.coords, HINTING_MODE).ok() + HintingInstance::new(self.outlines, self.size, self.coords, HINTING_OPTIONS).ok() } } -const HINTING_MODE: HintingMode = HintingMode::Smooth { - lcd_subpixel: Some(LcdLayout::Horizontal), - preserve_linear_metrics: true, +// TODO: We might want to expose making these configurable in future. +// However, these options are probably fine for most users. +const HINTING_OPTIONS: HintingOptions = HintingOptions { + engine: skrifa::outline::Engine::AutoFallback, + target: skrifa::outline::Target::Smooth { + mode: skrifa::outline::SmoothMode::Lcd, + symmetric_rendering: false, + preserve_linear_metrics: true, + }, }; #[derive(Default)] @@ -278,7 +284,7 @@ impl HintCache { entry.font_index = key.font_index; entry .instance - .reconfigure(key.outlines, key.size, key.coords, HINTING_MODE) + .reconfigure(key.outlines, key.size, key.coords, HINTING_OPTIONS) .ok()?; } Some(&entry.instance)