Add tracking to font function

This commit is contained in:
Martin Haug 2021-11-20 12:36:03 +01:00
parent 63c274e7f6
commit c020707ebc
5 changed files with 36 additions and 1 deletions

View File

@ -3,7 +3,7 @@ use super::*;
/// A length that is relative to the font size. /// A length that is relative to the font size.
/// ///
/// `1em` is the same as the font size. /// `1em` is the same as the font size.
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Em(N64); pub struct Em(N64);

View File

@ -163,6 +163,7 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let fallback = args.named("fallback")?; let fallback = args.named("fallback")?;
let style = args.named("style")?; let style = args.named("style")?;
let weight = args.named("weight")?; let weight = args.named("weight")?;
let tracking = args.named::<f64>("tracking")?;
let stretch = args.named("stretch")?; let stretch = args.named("stretch")?;
let size = args.named::<Linear>("size")?.or_else(|| args.find()); let size = args.named::<Linear>("size")?.or_else(|| args.find());
let top_edge = args.named("top-edge")?; let top_edge = args.named("top-edge")?;
@ -203,6 +204,10 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
text.fill = Paint::Color(fill); text.fill = Paint::Color(fill);
} }
if let Some(tracking) = tracking {
text.tracking = Em::new(tracking);
}
set!(text.variant.style => style); set!(text.variant.style => style);
set!(text.variant.weight => weight); set!(text.variant.weight => weight);
set!(text.variant.stretch => stretch); set!(text.variant.stretch => stretch);
@ -259,6 +264,8 @@ pub fn shape<'a>(
); );
} }
track_segment(&mut glyphs, style.tracking);
let (size, baseline) = measure(ctx, &glyphs, style); let (size, baseline) = measure(ctx, &glyphs, style);
ShapedText { ShapedText {
text, text,
@ -555,6 +562,23 @@ fn shape_segment<'a>(
} }
} }
/// Apply tracking to a slice of shaped glyphs.
fn track_segment(glyphs: &mut [ShapedGlyph], tracking: Em) {
if tracking.is_zero() {
return;
}
let mut glyphs = glyphs.iter_mut().peekable();
while let Some(glyph) = glyphs.next() {
if glyphs
.peek()
.map_or(false, |next| glyph.text_index != next.text_index)
{
glyph.x_advance += tracking;
}
}
}
/// Measure the size and baseline of a run of shaped glyphs with the given /// Measure the size and baseline of a run of shaped glyphs with the given
/// properties. /// properties.
fn measure( fn measure(

View File

@ -140,6 +140,8 @@ pub struct TextStyle {
pub families: Rc<FamilyStyle>, pub families: Rc<FamilyStyle>,
/// OpenType features. /// OpenType features.
pub features: Rc<FontFeatures>, pub features: Rc<FontFeatures>,
/// The amount of space that should be added between character.
pub tracking: Em,
/// Whether 300 extra font weight should be added to what is defined by the /// Whether 300 extra font weight should be added to what is defined by the
/// `variant`. /// `variant`.
pub strong: bool, pub strong: bool,
@ -222,6 +224,7 @@ impl Default for TextStyle {
fill: Paint::Color(Color::Rgba(RgbaColor::BLACK)), fill: Paint::Color(Color::Rgba(RgbaColor::BLACK)),
families: Rc::new(FamilyStyle::default()), families: Rc::new(FamilyStyle::default()),
features: Rc::new(FontFeatures::default()), features: Rc::new(FontFeatures::default()),
tracking: Em::zero(),
strong: false, strong: false,
emph: false, emph: false,
monospace: false, monospace: false,

BIN
tests/ref/text/tracking.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,8 @@
// Test tracking characters apart or together.
---
#font(tracking: -0.01)
I saw Zoe yӛsterday, on the tram.
---
I'm in#font(tracking: 0.3)[ spaace]!