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.
This commit is contained in:
Chad Brokaw 2023-02-24 16:13:48 -05:00
parent 39e35ceba9
commit 82391534c0
9 changed files with 49 additions and 62 deletions

View file

@ -45,7 +45,7 @@ parking_lot = "0.12"
bytemuck = { version = "1.12.1", features = ["derive"] } bytemuck = { version = "1.12.1", features = ["derive"] }
smallvec = "1.8.0" smallvec = "1.8.0"
moscato = { git = "https://github.com/dfrg/pinot", rev = "59db153" } 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] [workspace.dependencies]
wgpu = "0.15" wgpu = "0.15"

View file

@ -17,14 +17,14 @@
use std::sync::Arc; use std::sync::Arc;
use vello::{ use vello::{
encoding::{Glyph, Transform}, encoding::Glyph,
glyph::{ glyph::{
pinot, pinot,
pinot::{FontRef, TableProvider}, pinot::{FontRef, TableProvider},
GlyphContext, GlyphContext,
}, },
kurbo::Affine, kurbo::Affine,
peniko::{Blob, Brush, BrushRef, Color, Fill, Font, Stroke}, peniko::{Blob, Brush, BrushRef, Font, StyleRef},
SceneBuilder, SceneBuilder,
}; };
@ -45,12 +45,14 @@ impl SimpleText {
} }
} }
pub fn add_run<'b>( pub fn add_run<'a>(
&mut self, &mut self,
builder: &mut SceneBuilder, builder: &mut SceneBuilder,
size: f32, size: f32,
brush: impl Into<BrushRef<'b>>, brush: impl Into<BrushRef<'a>>,
transform: Affine, transform: Affine,
glyph_transform: Option<Affine>,
style: impl Into<StyleRef<'a>>,
text: &str, text: &str,
) { ) {
let font = FontRef { let font = FontRef {
@ -58,6 +60,7 @@ impl SimpleText {
offset: 0, offset: 0,
}; };
let brush = brush.into(); let brush = brush.into();
let style = style.into();
if let Some(cmap) = font.cmap() { if let Some(cmap) = font.cmap() {
if let Some(hmtx) = font.hmtx() { if let Some(hmtx) = font.hmtx() {
let upem = font.head().map(|head| head.units_per_em()).unwrap_or(1000) as f64; let upem = font.head().map(|head| head.units_per_em()).unwrap_or(1000) as f64;
@ -69,22 +72,13 @@ impl SimpleText {
.unwrap_or(0); .unwrap_or(0);
let mut pen_x = 0f64; let mut pen_x = 0f64;
builder builder
.draw_glyphs(&self) .draw_glyphs(&self.font)
.font_size(size) .font_size(size)
.transform(transform) .transform(transform)
.glyph_transform(Some(Affine::new([ .glyph_transform(glyph_transform)
1.,
0.,
20f64.to_radians().tan(),
1.,
0.,
0.,
])))
.brush(brush) .brush(brush)
.stroke( .draw(
Stroke::new(1.), style,
// .fill(
// Fill::NonZero,
text.chars().map(|ch| { text.chars().map(|ch| {
let gid = cmap.map(ch as u32).unwrap_or(0); let gid = cmap.map(ch as u32).unwrap_or(0);
let advance = hmetrics let advance = hmetrics

View file

@ -128,6 +128,9 @@ fn animated_text(sb: &mut SceneBuilder, params: &mut SceneParams) {
text_size, text_size,
Color::WHITE, Color::WHITE,
Affine::translate((110.0, 700.0)), 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, s,
); );
let th = params.time as f64; let th = params.time as f64;

View file

@ -28,7 +28,7 @@ mod resolve;
pub use draw::{ pub use draw::{
DrawBeginClip, DrawColor, DrawImage, DrawLinearGradient, DrawMonoid, DrawRadialGradient, DrawBeginClip, DrawColor, DrawImage, DrawLinearGradient, DrawMonoid, DrawRadialGradient,
DrawStyle, DrawTag, DrawTag,
}; };
pub use encoding::{Encoding, StreamOffsets}; pub use encoding::{Encoding, StreamOffsets};
pub use glyph::{Glyph, GlyphRun}; pub use glyph::{Glyph, GlyphRun};

View file

@ -19,13 +19,6 @@ use peniko::{BlendMode, Color, Fill, Stroke};
use super::Monoid; use super::Monoid;
/// Fill or stroke style.
#[derive(Clone, Debug)]
pub enum DrawStyle {
Fill(Fill),
Stroke(Stroke),
}
/// Draw tag representation. /// Draw tag representation.
#[derive(Copy, Clone, PartialEq, Eq, Pod, Zeroable)] #[derive(Copy, Clone, PartialEq, Eq, Pod, Zeroable)]
#[repr(C)] #[repr(C)]

View file

@ -16,9 +16,9 @@
use std::ops::Range; use std::ops::Range;
use peniko::Font; use peniko::{Font, Style};
use super::{DrawStyle, StreamOffsets, Transform}; use super::{StreamOffsets, Transform};
/// Positioned glyph. /// Positioned glyph.
#[derive(Copy, Clone, Default, Debug)] #[derive(Copy, Clone, Default, Debug)]
@ -47,7 +47,7 @@ pub struct GlyphRun {
/// Range of normalized coordinates in the parent encoding. /// Range of normalized coordinates in the parent encoding.
pub normalized_coords: Range<usize>, pub normalized_coords: Range<usize>,
/// Fill or stroke style. /// Fill or stroke style.
pub style: DrawStyle, pub style: Style,
/// Range of glyphs in the parent encoding. /// Range of glyphs in the parent encoding.
pub glyphs: Range<usize>, pub glyphs: Range<usize>,
/// Stream offsets where this glyph run should be inserted. /// Stream offsets where this glyph run should be inserted.

View file

@ -16,9 +16,11 @@
use std::collections::HashMap; use std::collections::HashMap;
use super::{DrawStyle, Encoding, StreamOffsets}; use super::{Encoding, StreamOffsets};
use crate::glyph::GlyphProvider; use crate::glyph::GlyphProvider;
use peniko::{Fill, Style};
#[derive(Copy, Clone, PartialEq, Eq, Hash, Default, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Default, Debug)]
pub struct GlyphKey { pub struct GlyphKey {
pub font_id: u64, pub font_id: u64,
@ -43,17 +45,24 @@ impl GlyphCache {
pub fn get_or_insert( pub fn get_or_insert(
&mut self, &mut self,
key: GlyphKey, key: GlyphKey,
style: &DrawStyle, style: &Style,
scaler: &mut GlyphProvider, scaler: &mut GlyphProvider,
) -> Option<CachedRange> { ) -> Option<CachedRange> {
// 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) { if let Some(range) = self.glyphs.get(&key) {
return Some(*range); return Some(*range);
} }
}
let start = self.encoding.stream_offsets(); let start = self.encoding.stream_offsets();
scaler.encode_glyph(key.glyph_id as u16, style, &mut self.encoding)?; scaler.encode_glyph(key.glyph_id as u16, style, &mut self.encoding)?;
let end = self.encoding.stream_offsets(); let end = self.encoding.stream_offsets();
let range = CachedRange { start, end }; let range = CachedRange { start, end };
if is_nz_fill {
self.glyphs.insert(key, range); self.glyphs.insert(key, range);
}
Some(range) Some(range)
} }
} }

View file

@ -18,10 +18,10 @@
pub use moscato::pinot; pub use moscato::pinot;
use crate::encoding::{DrawStyle, Encoding}; use crate::encoding::Encoding;
use crate::scene::{SceneBuilder, SceneFragment}; use crate::scene::{SceneBuilder, SceneFragment};
use peniko::kurbo::{Affine, Rect}; use peniko::kurbo::{Affine, Rect};
use peniko::{Brush, Color, Fill, Mix}; use peniko::{Brush, Color, Fill, Mix, Style};
use moscato::{Context, Scaler}; use moscato::{Context, Scaler};
use pinot::{types::Tag, FontRef}; use pinot::{types::Tag, FontRef};
@ -104,20 +104,15 @@ impl<'a> GlyphProvider<'a> {
Some(fragment) Some(fragment)
} }
pub fn encode_glyph( pub fn encode_glyph(&mut self, gid: u16, style: &Style, encoding: &mut Encoding) -> Option<()> {
&mut self,
gid: u16,
style: &DrawStyle,
encoding: &mut Encoding,
) -> Option<()> {
let glyph = self.scaler.glyph(gid)?; let glyph = self.scaler.glyph(gid)?;
let path = glyph.path(0)?; let path = glyph.path(0)?;
match style { match style {
DrawStyle::Fill(Fill::NonZero) => encoding.encode_linewidth(-1.0), Style::Fill(Fill::NonZero) => encoding.encode_linewidth(-1.0),
DrawStyle::Fill(Fill::EvenOdd) => encoding.encode_linewidth(-2.0), Style::Fill(Fill::EvenOdd) => encoding.encode_linewidth(-2.0),
DrawStyle::Stroke(stroke) => encoding.encode_linewidth(stroke.width), 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() { for el in path.elements() {
use moscato::Element::*; use moscato::Element::*;
match el { match el {

View file

@ -15,9 +15,9 @@
// Also licensed under MIT license, at your choice. // Also licensed under MIT license, at your choice.
use peniko::kurbo::{Affine, Rect, Shape}; 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. /// Encoded definition of a scene and associated resources.
#[derive(Default)] #[derive(Default)]
@ -206,7 +206,7 @@ impl<'a> DrawGlyphs<'a> {
font_size: 16.0, font_size: 16.0,
hint: false, hint: false,
normalized_coords: coords_start..coords_start, normalized_coords: coords_start..coords_start,
style: DrawStyle::Fill(Fill::NonZero), style: Fill::NonZero.into(),
glyphs: glyphs_start..glyphs_start, glyphs: glyphs_start..glyphs_start,
stream_offsets, stream_offsets,
}, },
@ -276,19 +276,12 @@ impl<'a> DrawGlyphs<'a> {
self self
} }
/// Encodes a fill for the given sequence of glyphs and consumes the builder. /// Encodes a fill or stroke for for the given sequence of glyphs and consumes
pub fn fill(mut self, style: Fill, glyphs: impl Iterator<Item = Glyph>) { /// the builder.
self.run.style = DrawStyle::Fill(style); ///
self.finish(glyphs); /// The `style` parameter accepts either `Fill` or `&Stroke` types.
} pub fn draw(mut self, style: impl Into<StyleRef<'a>>, glyphs: impl Iterator<Item = Glyph>) {
self.run.style = style.into().to_owned();
/// Encodes a stroke for the given sequence of glyphs and consumes the builder.
pub fn stroke(mut self, style: Stroke, glyphs: impl Iterator<Item = Glyph>) {
self.run.style = DrawStyle::Stroke(style);
self.finish(glyphs);
}
fn finish(mut self, glyphs: impl Iterator<Item = Glyph>) {
self.encoding.glyphs.extend(glyphs); self.encoding.glyphs.extend(glyphs);
self.run.glyphs.end = self.encoding.glyphs.len(); self.run.glyphs.end = self.encoding.glyphs.len();
if self.run.glyphs.is_empty() { if self.run.glyphs.is_empty() {