From 82391534c0ca18616e09cdfc7b618cef7664c8b0 Mon Sep 17 00:00:00 2001 From: Chad Brokaw Date: Fri, 24 Feb 2023 16:13:48 -0500 Subject: [PATCH] small fixes * make SimpleText::add_run accept glyph_transform and style parameters so it doesn't unconditionally do oblique strokes * replace fill/stroke methods on DrawGlyphs with a single draw method that accepts either fill or stroke styles * update peniko rev to access the new style types used above * for now, change glyph cache to only cache non-zero fills. Prior to this, style was ignored in the key which could lead to incorrect rendering. --- Cargo.toml | 2 +- examples/scenes/src/simple_text.rs | 28 +++++++++++----------------- examples/scenes/src/test_scenes.rs | 3 +++ src/encoding.rs | 2 +- src/encoding/draw.rs | 7 ------- src/encoding/glyph.rs | 6 +++--- src/encoding/glyph_cache.rs | 19 ++++++++++++++----- src/glyph.rs | 19 +++++++------------ src/scene.rs | 25 +++++++++---------------- 9 files changed, 49 insertions(+), 62 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bf92017..5bf7c6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ parking_lot = "0.12" bytemuck = { version = "1.12.1", features = ["derive"] } smallvec = "1.8.0" moscato = { git = "https://github.com/dfrg/pinot", rev = "59db153" } -peniko = { git = "https://github.com/linebender/peniko", rev = "8cb710f" } +peniko = { git = "https://github.com/linebender/peniko", rev = "882882c" } [workspace.dependencies] wgpu = "0.15" diff --git a/examples/scenes/src/simple_text.rs b/examples/scenes/src/simple_text.rs index 821905d..1d3dc47 100644 --- a/examples/scenes/src/simple_text.rs +++ b/examples/scenes/src/simple_text.rs @@ -17,14 +17,14 @@ use std::sync::Arc; use vello::{ - encoding::{Glyph, Transform}, + encoding::Glyph, glyph::{ pinot, pinot::{FontRef, TableProvider}, GlyphContext, }, kurbo::Affine, - peniko::{Blob, Brush, BrushRef, Color, Fill, Font, Stroke}, + peniko::{Blob, Brush, BrushRef, Font, StyleRef}, SceneBuilder, }; @@ -45,12 +45,14 @@ impl SimpleText { } } - pub fn add_run<'b>( + pub fn add_run<'a>( &mut self, builder: &mut SceneBuilder, size: f32, - brush: impl Into>, + brush: impl Into>, transform: Affine, + glyph_transform: Option, + style: impl Into>, text: &str, ) { let font = FontRef { @@ -58,6 +60,7 @@ impl SimpleText { offset: 0, }; let brush = brush.into(); + let style = style.into(); if let Some(cmap) = font.cmap() { if let Some(hmtx) = font.hmtx() { let upem = font.head().map(|head| head.units_per_em()).unwrap_or(1000) as f64; @@ -69,22 +72,13 @@ impl SimpleText { .unwrap_or(0); let mut pen_x = 0f64; builder - .draw_glyphs(&self) + .draw_glyphs(&self.font) .font_size(size) .transform(transform) - .glyph_transform(Some(Affine::new([ - 1., - 0., - 20f64.to_radians().tan(), - 1., - 0., - 0., - ]))) + .glyph_transform(glyph_transform) .brush(brush) - .stroke( - Stroke::new(1.), - // .fill( - // Fill::NonZero, + .draw( + style, text.chars().map(|ch| { let gid = cmap.map(ch as u32).unwrap_or(0); let advance = hmetrics diff --git a/examples/scenes/src/test_scenes.rs b/examples/scenes/src/test_scenes.rs index 1bf1493..3df9cfa 100644 --- a/examples/scenes/src/test_scenes.rs +++ b/examples/scenes/src/test_scenes.rs @@ -128,6 +128,9 @@ fn animated_text(sb: &mut SceneBuilder, params: &mut SceneParams) { text_size, Color::WHITE, Affine::translate((110.0, 700.0)), + // Add a skew to simulate an oblique font. + Some(Affine::new([1., 0., 20f64.to_radians().tan(), 1., 0., 0.])), + &Stroke::new(1.0), s, ); let th = params.time as f64; diff --git a/src/encoding.rs b/src/encoding.rs index f2278d3..239bd54 100644 --- a/src/encoding.rs +++ b/src/encoding.rs @@ -28,7 +28,7 @@ mod resolve; pub use draw::{ DrawBeginClip, DrawColor, DrawImage, DrawLinearGradient, DrawMonoid, DrawRadialGradient, - DrawStyle, DrawTag, + DrawTag, }; pub use encoding::{Encoding, StreamOffsets}; pub use glyph::{Glyph, GlyphRun}; diff --git a/src/encoding/draw.rs b/src/encoding/draw.rs index 1456807..d19e281 100644 --- a/src/encoding/draw.rs +++ b/src/encoding/draw.rs @@ -19,13 +19,6 @@ use peniko::{BlendMode, Color, Fill, Stroke}; use super::Monoid; -/// Fill or stroke style. -#[derive(Clone, Debug)] -pub enum DrawStyle { - Fill(Fill), - Stroke(Stroke), -} - /// Draw tag representation. #[derive(Copy, Clone, PartialEq, Eq, Pod, Zeroable)] #[repr(C)] diff --git a/src/encoding/glyph.rs b/src/encoding/glyph.rs index 62c87e9..6fe900e 100644 --- a/src/encoding/glyph.rs +++ b/src/encoding/glyph.rs @@ -16,9 +16,9 @@ use std::ops::Range; -use peniko::Font; +use peniko::{Font, Style}; -use super::{DrawStyle, StreamOffsets, Transform}; +use super::{StreamOffsets, Transform}; /// Positioned glyph. #[derive(Copy, Clone, Default, Debug)] @@ -47,7 +47,7 @@ pub struct GlyphRun { /// Range of normalized coordinates in the parent encoding. pub normalized_coords: Range, /// Fill or stroke style. - pub style: DrawStyle, + pub style: Style, /// Range of glyphs in the parent encoding. pub glyphs: Range, /// Stream offsets where this glyph run should be inserted. diff --git a/src/encoding/glyph_cache.rs b/src/encoding/glyph_cache.rs index 6dd144f..6cb0ba8 100644 --- a/src/encoding/glyph_cache.rs +++ b/src/encoding/glyph_cache.rs @@ -16,9 +16,11 @@ use std::collections::HashMap; -use super::{DrawStyle, Encoding, StreamOffsets}; +use super::{Encoding, StreamOffsets}; use crate::glyph::GlyphProvider; +use peniko::{Fill, Style}; + #[derive(Copy, Clone, PartialEq, Eq, Hash, Default, Debug)] pub struct GlyphKey { pub font_id: u64, @@ -43,17 +45,24 @@ impl GlyphCache { pub fn get_or_insert( &mut self, key: GlyphKey, - style: &DrawStyle, + style: &Style, scaler: &mut GlyphProvider, ) -> Option { - if let Some(range) = self.glyphs.get(&key) { - return Some(*range); + // For now, only cache non-zero filled glyphs so we don't need to keep style + // as part of the key. + let is_nz_fill = matches!(style, Style::Fill(Fill::NonZero)); + if is_nz_fill { + if let Some(range) = self.glyphs.get(&key) { + return Some(*range); + } } let start = self.encoding.stream_offsets(); scaler.encode_glyph(key.glyph_id as u16, style, &mut self.encoding)?; let end = self.encoding.stream_offsets(); let range = CachedRange { start, end }; - self.glyphs.insert(key, range); + if is_nz_fill { + self.glyphs.insert(key, range); + } Some(range) } } diff --git a/src/glyph.rs b/src/glyph.rs index a7498d9..7f825f2 100644 --- a/src/glyph.rs +++ b/src/glyph.rs @@ -18,10 +18,10 @@ pub use moscato::pinot; -use crate::encoding::{DrawStyle, Encoding}; +use crate::encoding::Encoding; use crate::scene::{SceneBuilder, SceneFragment}; use peniko::kurbo::{Affine, Rect}; -use peniko::{Brush, Color, Fill, Mix}; +use peniko::{Brush, Color, Fill, Mix, Style}; use moscato::{Context, Scaler}; use pinot::{types::Tag, FontRef}; @@ -104,20 +104,15 @@ impl<'a> GlyphProvider<'a> { Some(fragment) } - pub fn encode_glyph( - &mut self, - gid: u16, - style: &DrawStyle, - encoding: &mut Encoding, - ) -> Option<()> { + pub fn encode_glyph(&mut self, gid: u16, style: &Style, encoding: &mut Encoding) -> Option<()> { let glyph = self.scaler.glyph(gid)?; let path = glyph.path(0)?; match style { - DrawStyle::Fill(Fill::NonZero) => encoding.encode_linewidth(-1.0), - DrawStyle::Fill(Fill::EvenOdd) => encoding.encode_linewidth(-2.0), - DrawStyle::Stroke(stroke) => encoding.encode_linewidth(stroke.width), + Style::Fill(Fill::NonZero) => encoding.encode_linewidth(-1.0), + Style::Fill(Fill::EvenOdd) => encoding.encode_linewidth(-2.0), + Style::Stroke(stroke) => encoding.encode_linewidth(stroke.width), } - let mut path_encoder = encoding.encode_path(matches!(style, DrawStyle::Fill(_))); + let mut path_encoder = encoding.encode_path(matches!(style, Style::Fill(_))); for el in path.elements() { use moscato::Element::*; match el { diff --git a/src/scene.rs b/src/scene.rs index 51346ce..bf73906 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -15,9 +15,9 @@ // Also licensed under MIT license, at your choice. use peniko::kurbo::{Affine, Rect, Shape}; -use peniko::{BlendMode, Brush, BrushRef, Color, Fill, Font, Stroke}; +use peniko::{BlendMode, BrushRef, Color, Fill, Font, Stroke, StyleRef}; -use crate::encoding::{DrawStyle, Encoding, Glyph, GlyphRun, Patch, Transform}; +use crate::encoding::{Encoding, Glyph, GlyphRun, Patch, Transform}; /// Encoded definition of a scene and associated resources. #[derive(Default)] @@ -206,7 +206,7 @@ impl<'a> DrawGlyphs<'a> { font_size: 16.0, hint: false, normalized_coords: coords_start..coords_start, - style: DrawStyle::Fill(Fill::NonZero), + style: Fill::NonZero.into(), glyphs: glyphs_start..glyphs_start, stream_offsets, }, @@ -276,19 +276,12 @@ impl<'a> DrawGlyphs<'a> { self } - /// Encodes a fill for the given sequence of glyphs and consumes the builder. - pub fn fill(mut self, style: Fill, glyphs: impl Iterator) { - self.run.style = DrawStyle::Fill(style); - self.finish(glyphs); - } - - /// Encodes a stroke for the given sequence of glyphs and consumes the builder. - pub fn stroke(mut self, style: Stroke, glyphs: impl Iterator) { - self.run.style = DrawStyle::Stroke(style); - self.finish(glyphs); - } - - fn finish(mut self, glyphs: impl Iterator) { + /// Encodes a fill or stroke for for the given sequence of glyphs and consumes + /// the builder. + /// + /// The `style` parameter accepts either `Fill` or `&Stroke` types. + pub fn draw(mut self, style: impl Into>, glyphs: impl Iterator) { + self.run.style = style.into().to_owned(); self.encoding.glyphs.extend(glyphs); self.run.glyphs.end = self.encoding.glyphs.len(); if self.run.glyphs.is_empty() {