diff --git a/Cargo.toml b/Cargo.toml index 246c3e33..1e0efd6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,7 +58,7 @@ kurbo = "0.10.4" [workspace.dependencies] bytemuck = { version = "1.12.1", features = ["derive"] } skrifa = "0.15.4" -peniko = { git = "https://github.com/linebender/peniko", rev = "629fc3325b016a8c98b1cd6204cb4ddf1c6b3daa" } +peniko = { git = "https://github.com/linebender/peniko", rev = "8717635681dedfab3e9f3741fcbc7f3318a82ff0" } # NOTE: Make sure to keep this in sync with the version badge in README.md wgpu = { version = "0.18" } diff --git a/crates/encoding/src/encoding.rs b/crates/encoding/src/encoding.rs index 019de237..a9eee83a 100644 --- a/crates/encoding/src/encoding.rs +++ b/crates/encoding/src/encoding.rs @@ -41,9 +41,19 @@ pub struct Encoding { pub n_clips: u32, /// Number of unclosed clips/layers. pub n_open_clips: u32, + /// Flags that capture the current state of the encoding. + pub flags: u32, } impl Encoding { + /// Forces encoding of the next transform even if it matches + /// the current transform in the stream. + pub const FORCE_NEXT_TRANSFORM: u32 = 1; + + /// Forces encoding of the next style even if it matches + /// the current style in the stream. + pub const FORCE_NEXT_STYLE: u32 = 2; + /// Creates a new encoding. pub fn new() -> Self { Self::default() @@ -66,6 +76,7 @@ impl Encoding { self.n_path_segments = 0; self.n_clips = 0; self.n_open_clips = 0; + self.flags = 0; #[cfg(feature = "full")] self.resources.reset(); if !is_fragment { @@ -93,6 +104,7 @@ impl Encoding { .glyph_runs .extend(other.resources.glyph_runs.iter().cloned().map(|mut run| { run.glyphs.start += glyphs_base; + run.glyphs.end += glyphs_base; run.normalized_coords.start += coords_base; run.stream_offsets.path_tags += offsets.path_tags; run.stream_offsets.path_data += offsets.path_data; @@ -141,6 +153,7 @@ impl Encoding { self.n_path_segments += other.n_path_segments; self.n_clips += other.n_clips; self.n_open_clips += other.n_open_clips; + self.flags = other.flags; if let Some(transform) = *transform { self.transforms .extend(other.transforms.iter().map(|x| transform * *x)); @@ -168,19 +181,19 @@ impl Encoding { /// Encodes a fill style. pub fn encode_fill_style(&mut self, fill: Fill) { - let style = Style::from_fill(fill); - if self.styles.last() != Some(&style) { - self.path_tags.push(PathTag::STYLE); - self.styles.push(style); - } + self.encode_style(Style::from_fill(fill)); } /// Encodes a stroke style. pub fn encode_stroke_style(&mut self, stroke: &Stroke) { - let style = Style::from_stroke(stroke); - if self.styles.last() != Some(&style) { + self.encode_style(Style::from_stroke(stroke)); + } + + fn encode_style(&mut self, style: Style) { + if self.flags & Self::FORCE_NEXT_STYLE != 0 || self.styles.last() != Some(&style) { self.path_tags.push(PathTag::STYLE); self.styles.push(style); + self.flags &= !Self::FORCE_NEXT_STYLE; } } @@ -189,9 +202,12 @@ impl Encoding { /// If the given transform is different from the current one, encodes it and /// returns true. Otherwise, encodes nothing and returns false. pub fn encode_transform(&mut self, transform: Transform) -> bool { - if self.transforms.last() != Some(&transform) { + if self.flags & Self::FORCE_NEXT_TRANSFORM != 0 + || self.transforms.last() != Some(&transform) + { self.path_tags.push(PathTag::TRANSFORM); self.transforms.push(transform); + self.flags &= !Self::FORCE_NEXT_TRANSFORM; true } else { false @@ -381,6 +397,12 @@ impl Encoding { } } + /// Forces the next transform and style to be encoded even if they match + /// the current state. + pub fn force_next_transform_and_style(&mut self) { + self.flags |= Self::FORCE_NEXT_TRANSFORM | Self::FORCE_NEXT_STYLE; + } + // Swap the last two tags in the path tag stream; used for transformed // gradients. pub fn swap_last_path_tags(&mut self) { diff --git a/examples/scenes/src/simple_text.rs b/examples/scenes/src/simple_text.rs index 060a015d..a79d3b64 100644 --- a/examples/scenes/src/simple_text.rs +++ b/examples/scenes/src/simple_text.rs @@ -17,7 +17,7 @@ use std::sync::Arc; use vello::{ - glyph::{Glyph, GlyphContext}, + glyph::Glyph, kurbo::Affine, peniko::{Blob, Brush, BrushRef, Font, StyleRef}, skrifa::{raw::FontRef, MetadataProvider}, @@ -136,35 +136,18 @@ impl SimpleText { transform: Affine, text: &str, ) { - let default_font = FontRef::new(ROBOTO_FONT).unwrap(); - let font = font.and_then(to_font_ref).unwrap_or(default_font); - let font_size = vello::skrifa::instance::Size::new(size); - let var_loc = vello::skrifa::instance::LocationRef::default(); - let charmap = font.charmap(); - let metrics = font.metrics(font_size, var_loc); - let line_height = metrics.ascent - metrics.descent + metrics.leading; - let glyph_metrics = font.glyph_metrics(font_size, var_loc); - let mut pen_x = 0f64; - let mut pen_y = 0f64; - let vars: [(&str, f32); 0] = []; - let mut gcx = GlyphContext::new(); - let mut provider = gcx.new_provider(&font, size, false, &vars); - for ch in text.chars() { - if ch == '\n' { - pen_y += line_height as f64; - pen_x = 0.0; - continue; - } - let gid = charmap.map(ch).unwrap_or_default(); - let advance = glyph_metrics.advance_width(gid).unwrap_or_default() as f64; - if let Some(glyph) = provider.get(gid.to_u16(), brush) { - let xform = transform - * Affine::translate((pen_x, pen_y)) - * Affine::scale_non_uniform(1.0, -1.0); - builder.append(&glyph, Some(xform)); - } - pen_x += advance; - } + use vello::peniko::{Color, Fill}; + let brush = brush.unwrap_or(&Brush::Solid(Color::WHITE)); + self.add_run( + builder, + font, + size, + brush, + transform, + None, + Fill::NonZero, + text, + ); } } diff --git a/src/scene.rs b/src/scene.rs index 084bd24f..86ebe975 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -346,5 +346,9 @@ impl<'a> DrawGlyphs<'a> { resources.glyph_runs.push(self.run); resources.patches.push(Patch::GlyphRun { index }); self.encoding.encode_brush(self.brush, self.brush_alpha); + // Glyph run resolve step affects transform and style state in a way + // that is opaque to the current encoding. + // See + self.encoding.force_next_transform_and_style(); } }