Skip to content

Add font embolden #823

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 49 additions & 11 deletions vello/src/scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use peniko::{
BlendMode, Blob, Brush, BrushRef, Color, ColorStop, ColorStops, ColorStopsSource, Compose,
Extend, Fill, Font, Gradient, Image, Mix, StyleRef,
color::{AlphaColor, DynamicColor, Srgb, palette},
kurbo::{Affine, BezPath, Point, Rect, Shape, Stroke, StrokeOpts, Vec2},
kurbo::{Affine, BezPath, Join, Point, Rect, Shape, Stroke, StrokeOpts, Vec2},
};
use png::{BitDepth, ColorType, Transformations};
use skrifa::{
Expand All @@ -22,7 +22,7 @@ use skrifa::{
};
#[cfg(feature = "bump_estimate")]
use vello_encoding::BumpAllocatorMemory;
use vello_encoding::{Encoding, Glyph, GlyphRun, NormalizedCoord, Patch, Transform};
use vello_encoding::{EmboldenStyle, Encoding, Glyph, GlyphRun, NormalizedCoord, Patch, Transform};

// TODO - Document invariants and edge cases (#470)
// - What happens when we pass a transform matrix with NaN values to the Scene?
Expand Down Expand Up @@ -361,6 +361,7 @@ impl<'a> DrawGlyphs<'a> {
transform: Transform::IDENTITY,
glyph_transform: None,
font_size: 16.0,
embolden_style: EmboldenStyle::default(),
hint: false,
normalized_coords: coords_start..coords_start,
style: Fill::NonZero.into(),
Expand Down Expand Up @@ -411,6 +412,37 @@ impl<'a> DrawGlyphs<'a> {
self
}

/// Sets the amount of emboldening to apply.
///
/// The value represents the amount to embolden in em units.
/// A value of 0.0 means no emboldening (the default).
/// Typical values range from 0.01 to 0.1.
///
/// The default value is 0.0 (no emboldening).
#[must_use]
pub fn embolden(mut self, amount: f32) -> Self {
self.run.embolden_style.embolden = amount;
self
}

/// Sets the join to use when emboldening.
///
/// The default value is Miter.
#[must_use]
pub fn embolden_join(mut self, join: Join) -> Self {
self.run.embolden_style.join = join;
self
}

/// Sets the miter limit to use when emboldening with a miter join.
///
/// The default value is 4.0.
#[must_use]
pub fn embolden_miter_limit(mut self, miter_limit: f32) -> Self {
self.run.embolden_style.miter_limit = miter_limit;
self
}

/// Sets the normalized design space coordinates for a variable font instance.
#[must_use]
pub fn normalized_coords(mut self, coords: &[NormalizedCoord]) -> Self {
Expand Down Expand Up @@ -796,15 +828,18 @@ impl ColorPainter for DrawColorGlyphs<'_> {
return;
};

let mut path = BezPathOutline(BezPath::new());
let draw_settings = DrawSettings::unhinted(Size::unscaled(), self.location);

let Ok(_) = outline.draw(draw_settings, &mut path) else {
return;
let path = {
let mut path = BezPathOutline(BezPath::new());
let Ok(_) = outline.draw(draw_settings, &mut path) else {
return;
};
path.0
};

self.clip_depth += 1;
self.scene
.push_layer(Mix::Clip, 1.0, self.last_transform().to_kurbo(), &path.0);
.push_layer(Mix::Clip, 1.0, self.last_transform().to_kurbo(), &path);
}

fn push_clip_box(&mut self, clip_box: skrifa::raw::types::BoundingBox<f32>) {
Expand Down Expand Up @@ -878,11 +913,14 @@ impl ColorPainter for DrawColorGlyphs<'_> {
return;
};

let mut path = BezPathOutline(BezPath::new());
let draw_settings = DrawSettings::unhinted(Size::unscaled(), self.location);

let Ok(_) = outline.draw(draw_settings, &mut path) else {
return;
let path = {
let mut path = BezPathOutline(BezPath::new());
let Ok(_) = outline.draw(draw_settings, &mut path) else {
return;
};
path.0
};

let transform = self.last_transform();
Expand All @@ -893,7 +931,7 @@ impl ColorPainter for DrawColorGlyphs<'_> {
brush_transform
.map(conv_skrifa_transform)
.map(|it| it.to_kurbo()),
&path.0,
&path,
);
}
}
Expand Down
33 changes: 33 additions & 0 deletions vello_encoding/src/encoding.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright 2022 the Vello Authors
// SPDX-License-Identifier: Apache-2.0 OR MIT

use crate::path::{EmboldenStyle, WindingPathEncoder};

use super::{
DrawBlurRoundedRect, DrawColor, DrawImage, DrawLinearGradient, DrawRadialGradient,
DrawSweepGradient, DrawTag, Glyph, GlyphRun, NormalizedCoord, Patch, PathEncoder, PathTag,
Expand Down Expand Up @@ -33,6 +35,8 @@ pub struct Encoding {
pub transforms: Vec<Transform>,
/// The style stream
pub styles: Vec<Style>,
/// Winding information for subpaths of filled shapes
pub path_windings: Vec<f32>,
/// Late bound resource data.
pub resources: Resources,
/// Number of encoded paths.
Expand Down Expand Up @@ -77,6 +81,7 @@ impl Encoding {
self.styles.clear();
self.draw_data.clear();
self.draw_tags.clear();
self.path_windings.clear();
self.n_paths = 0;
self.n_path_segments = 0;
self.n_clips = 0;
Expand Down Expand Up @@ -112,6 +117,7 @@ impl Encoding {
run.stream_offsets.draw_data += offsets.draw_data;
run.stream_offsets.transforms += offsets.transforms;
run.stream_offsets.styles += offsets.styles;
run.stream_offsets.path_windings += offsets.path_windings;
run
}));
self.resources
Expand Down Expand Up @@ -149,6 +155,7 @@ impl Encoding {
self.path_data.extend_from_slice(&other.path_data);
self.draw_tags.extend_from_slice(&other.draw_tags);
self.draw_data.extend_from_slice(&other.draw_data);
self.path_windings.extend_from_slice(&other.path_windings);
self.n_paths += other.n_paths;
self.n_path_segments += other.n_path_segments;
self.n_clips += other.n_clips;
Expand All @@ -175,6 +182,7 @@ impl Encoding {
draw_data: self.draw_data.len(),
transforms: self.transforms.len(),
styles: self.styles.len(),
path_windings: self.path_windings.len(),
}
}

Expand All @@ -188,6 +196,16 @@ impl Encoding {
self.encode_style(Style::from_stroke(stroke));
}

/// Encodes a fill style with embolden.
pub fn encode_fill_style_embolden(&mut self, fill: Fill, embolden_fill: EmboldenStyle) {
self.encode_style(Style::from_embolden_fill(fill, embolden_fill));
}

/// Encodes a stroke style with embolden.
pub fn encode_stroke_style_embolden(&mut self, stroke: &Stroke, embolden: f32) {
self.encode_style(Style::from_stroke(stroke).with_embolden(embolden));
}

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);
Expand Down Expand Up @@ -225,6 +243,18 @@ impl Encoding {
)
}

/// Returns an encoder for encoding a filled path with winding data for expansion.
pub fn encode_winding_path(&mut self, is_fill: bool) -> WindingPathEncoder<'_> {
WindingPathEncoder::new(
&mut self.path_tags,
&mut self.path_data,
&mut self.n_path_segments,
&mut self.n_paths,
&mut self.path_windings,
is_fill,
)
}

/// Encodes a shape. If `is_fill` is true, all subpaths will be automatically closed.
/// Returns true if a non-zero number of segments were encoded.
pub fn encode_shape(&mut self, shape: &impl Shape, is_fill: bool) -> bool {
Expand Down Expand Up @@ -572,6 +602,8 @@ pub struct StreamOffsets {
pub transforms: usize,
/// Current length of style stream.
pub styles: usize,
/// Current length of path winding stream.
pub path_windings: usize,
}

impl StreamOffsets {
Expand All @@ -582,6 +614,7 @@ impl StreamOffsets {
self.draw_data += other.draw_data;
self.transforms += other.transforms;
self.styles += other.styles;
self.path_windings += other.path_windings;
}
}

Expand Down
5 changes: 4 additions & 1 deletion vello_encoding/src/glyph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@

use std::ops::Range;

use peniko::{Font, Style};
use crate::path::EmboldenStyle;

use super::{StreamOffsets, Transform};
use peniko::{Font, Style};

/// Positioned glyph.
#[derive(Copy, Clone, Default, Debug)]
Expand All @@ -29,6 +30,8 @@ pub struct GlyphRun {
pub glyph_transform: Option<Transform>,
/// Size of the font in pixels per em.
pub font_size: f32,
/// The style to use when emboldening with embolden in em.
pub embolden_style: EmboldenStyle,
/// True if hinting is enabled.
pub hint: bool,
/// Range of normalized coordinates in the parent encoding.
Expand Down
62 changes: 46 additions & 16 deletions vello_encoding/src/glyph_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
use std::collections::HashMap;
use std::sync::Arc;

use crate::path::EmboldenStyle;

use super::{Encoding, StreamOffsets};

use peniko::{Font, Style};
Expand All @@ -30,6 +32,7 @@ impl GlyphCache {
size: f32,
hint: bool,
style: &'a Style,
embolden_fill: EmboldenStyle,
) -> Option<GlyphCacheSession<'a>> {
let font_id = font.data.id();
let font_index = font.index;
Expand Down Expand Up @@ -64,10 +67,12 @@ impl GlyphCache {
};
// TODO: we're ignoring dashing for now
let style_bits = match style {
Style::Fill(fill) => super::path::Style::from_fill(*fill),
Style::Stroke(stroke) => super::path::Style::from_stroke(stroke),
Style::Fill(fill) => super::path::Style::from_embolden_fill(*fill, embolden_fill),
Style::Stroke(stroke) => {
super::path::Style::from_stroke(stroke).with_embolden(embolden_fill.embolden)
}
};
let style_bits: [u32; 2] = bytemuck::cast(style_bits);
let style_bits: [u32; 3] = bytemuck::cast(style_bits);
Some(GlyphCacheSession {
free_list: &mut self.free_list,
map,
Expand All @@ -82,6 +87,7 @@ impl GlyphCache {
hinter,
serial: self.serial,
cached_count: &mut self.cached_count,
embolden_fill_style: embolden_fill,
})
}

Expand Down Expand Up @@ -141,11 +147,12 @@ pub(crate) struct GlyphCacheSession<'a> {
size: Size,
size_bits: u32,
style: &'a Style,
style_bits: [u32; 2],
style_bits: [u32; 3],
outlines: OutlineGlyphCollection<'a>,
hinter: Option<&'a HintingInstance>,
serial: u64,
cached_count: &'a mut usize,
embolden_fill_style: EmboldenStyle,
}

impl GlyphCacheSession<'_> {
Expand All @@ -171,30 +178,53 @@ impl GlyphCacheSession<'_> {
encoding_ptr.reset();
let is_fill = match &self.style {
Style::Fill(fill) => {
encoding_ptr.encode_fill_style(*fill);
encoding_ptr.encode_fill_style_embolden(*fill, self.embolden_fill_style);
true
}
Style::Stroke(stroke) => {
encoding_ptr.encode_stroke_style(stroke);
encoding_ptr
.encode_stroke_style_embolden(stroke, self.embolden_fill_style.embolden);
false
}
};
use skrifa::outline::DrawSettings;
let mut path = encoding_ptr.encode_path(is_fill);
let draw_settings = if key.hint {
if let Some(hinter) = self.hinter {
DrawSettings::hinted(hinter, false)
let fill_style = self.embolden_fill_style;
if fill_style.embolden != 0. {
let mut path = encoding_ptr.encode_winding_path(is_fill);
let draw_settings = if key.hint {
if let Some(hinter) = self.hinter {
DrawSettings::hinted(hinter, false)
} else {
DrawSettings::unhinted(self.size, self.coords)
}
} else {
DrawSettings::unhinted(self.size, self.coords)
};

outline.draw(draw_settings, &mut path).ok()?;
if path.finish(false) == 0 {
encoding_ptr.reset();
}
} else {
DrawSettings::unhinted(self.size, self.coords)
};
outline.draw(draw_settings, &mut path).ok()?;
if path.finish(false) == 0 {
encoding_ptr.reset();
let mut path = encoding_ptr.encode_path(is_fill);
let draw_settings = if key.hint {
if let Some(hinter) = self.hinter {
DrawSettings::hinted(hinter, false)
} else {
DrawSettings::unhinted(self.size, self.coords)
}
} else {
DrawSettings::unhinted(self.size, self.coords)
};

outline.draw(draw_settings, &mut path).ok()?;
if path.finish(false) == 0 {
encoding_ptr.reset();
}
}

let stream_sizes = encoding_ptr.stream_offsets();

self.map.insert(
key,
GlyphEntry {
Expand All @@ -214,7 +244,7 @@ struct GlyphKey {
font_index: u32,
glyph_id: u32,
font_size_bits: u32,
style_bits: [u32; 2],
style_bits: [u32; 3],
hint: bool,
}

Expand Down
4 changes: 2 additions & 2 deletions vello_encoding/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ pub use mask::{make_mask_lut, make_mask_lut_16};
pub use math::Transform;
pub use monoid::Monoid;
pub use path::{
Cubic, LineSoup, Path, PathBbox, PathEncoder, PathMonoid, PathSegment, PathSegmentType,
PathTag, SegmentCount, Style, Tile,
Cubic, EmboldenStyle, LineSoup, Path, PathBbox, PathEncoder, PathMonoid, PathSegment,
PathSegmentType, PathTag, SegmentCount, Style, Tile,
};
pub use ramp_cache::Ramps;
pub use resolve::{Layout, Patch, Resolver, resolve_solid_paths_only};
Expand Down
Loading