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"] }
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"

View file

@ -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<BrushRef<'b>>,
brush: impl Into<BrushRef<'a>>,
transform: Affine,
glyph_transform: Option<Affine>,
style: impl Into<StyleRef<'a>>,
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

View file

@ -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;

View file

@ -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};

View file

@ -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)]

View file

@ -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<usize>,
/// Fill or stroke style.
pub style: DrawStyle,
pub style: Style,
/// Range of glyphs in the parent encoding.
pub glyphs: Range<usize>,
/// Stream offsets where this glyph run should be inserted.

View file

@ -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<CachedRange> {
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)
}
}

View file

@ -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 {

View file

@ -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<Item = Glyph>) {
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<Item = Glyph>) {
self.run.style = DrawStyle::Stroke(style);
self.finish(glyphs);
}
fn finish(mut self, glyphs: impl Iterator<Item = Glyph>) {
/// 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<StyleRef<'a>>, glyphs: impl Iterator<Item = Glyph>) {
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() {