add letter spacing
This commit is contained in:
parent
500a8fc6d1
commit
08822cac2e
2 changed files with 53 additions and 6 deletions
45
src/attrs.rs
45
src/attrs.rs
|
|
@ -5,6 +5,7 @@ use alloc::vec::Vec;
|
|||
use core::ops::Range;
|
||||
use rangemap::RangeMap;
|
||||
use smol_str::SmolStr;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use crate::{CacheKeyFlags, Metrics};
|
||||
|
||||
|
|
@ -125,6 +126,37 @@ impl From<CacheMetrics> for Metrics {
|
|||
}
|
||||
}
|
||||
|
||||
/// A wrapper for letter spacing to get around that f32 doesn't implement Eq and Hash
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct LetterSpacing(pub f32);
|
||||
|
||||
impl PartialEq for LetterSpacing {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if self.0.is_nan() {
|
||||
other.0.is_nan()
|
||||
} else {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for LetterSpacing {}
|
||||
|
||||
impl Hash for LetterSpacing {
|
||||
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||
const CANONICAL_NAN_BITS: u32 = 0x7fc0_0000;
|
||||
|
||||
let bits = if self.0.is_nan() {
|
||||
CANONICAL_NAN_BITS
|
||||
} else {
|
||||
// Add +0.0 to canonicalize -0.0 to +0.0
|
||||
(self.0 + 0.0).to_bits()
|
||||
};
|
||||
|
||||
bits.hash(hasher);
|
||||
}
|
||||
}
|
||||
|
||||
/// Text attributes
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct Attrs<'a> {
|
||||
|
|
@ -137,6 +169,8 @@ pub struct Attrs<'a> {
|
|||
pub metadata: usize,
|
||||
pub cache_key_flags: CacheKeyFlags,
|
||||
pub metrics_opt: Option<CacheMetrics>,
|
||||
/// Letter spacing (tracking) in pixels
|
||||
pub letter_spacing_opt: Option<LetterSpacing>,
|
||||
}
|
||||
|
||||
impl<'a> Attrs<'a> {
|
||||
|
|
@ -153,6 +187,7 @@ impl<'a> Attrs<'a> {
|
|||
metadata: 0,
|
||||
cache_key_flags: CacheKeyFlags::empty(),
|
||||
metrics_opt: None,
|
||||
letter_spacing_opt: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -204,6 +239,12 @@ impl<'a> Attrs<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set letter spacing (tracking) in EM
|
||||
pub fn letter_spacing(mut self, letter_spacing: f32) -> Self {
|
||||
self.letter_spacing_opt = Some(LetterSpacing(letter_spacing));
|
||||
self
|
||||
}
|
||||
|
||||
/// Check if font matches
|
||||
pub fn matches(&self, face: &fontdb::FaceInfo) -> bool {
|
||||
//TODO: smarter way of including emoji
|
||||
|
|
@ -252,6 +293,8 @@ pub struct AttrsOwned {
|
|||
pub metadata: usize,
|
||||
pub cache_key_flags: CacheKeyFlags,
|
||||
pub metrics_opt: Option<CacheMetrics>,
|
||||
/// Letter spacing (tracking) in EM
|
||||
pub letter_spacing_opt: Option<LetterSpacing>,
|
||||
}
|
||||
|
||||
impl AttrsOwned {
|
||||
|
|
@ -265,6 +308,7 @@ impl AttrsOwned {
|
|||
metadata: attrs.metadata,
|
||||
cache_key_flags: attrs.cache_key_flags,
|
||||
metrics_opt: attrs.metrics_opt,
|
||||
letter_spacing_opt: attrs.letter_spacing_opt,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -278,6 +322,7 @@ impl AttrsOwned {
|
|||
metadata: self.metadata,
|
||||
cache_key_flags: self.cache_key_flags,
|
||||
metrics_opt: self.metrics_opt,
|
||||
letter_spacing_opt: self.letter_spacing_opt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
14
src/shape.rs
14
src/shape.rs
|
|
@ -155,11 +155,6 @@ fn shape_fallback(
|
|||
glyphs.reserve(glyph_infos.len());
|
||||
let glyph_start = glyphs.len();
|
||||
for (info, pos) in glyph_infos.iter().zip(glyph_positions.iter()) {
|
||||
let x_advance = pos.x_advance as f32 / font_scale;
|
||||
let y_advance = pos.y_advance as f32 / font_scale;
|
||||
let x_offset = pos.x_offset as f32 / font_scale;
|
||||
let y_offset = pos.y_offset as f32 / font_scale;
|
||||
|
||||
let start_glyph = start_run + info.cluster as usize;
|
||||
|
||||
if info.glyph_id == 0 {
|
||||
|
|
@ -167,6 +162,12 @@ fn shape_fallback(
|
|||
}
|
||||
|
||||
let attrs = attrs_list.get_span(start_glyph);
|
||||
let x_advance = pos.x_advance as f32 / font_scale
|
||||
+ attrs.letter_spacing_opt.map_or(0.0, |spacing| spacing.0);
|
||||
let y_advance = pos.y_advance as f32 / font_scale;
|
||||
let x_offset = pos.x_offset as f32 / font_scale;
|
||||
let y_offset = pos.y_offset as f32 / font_scale;
|
||||
|
||||
glyphs.push(ShapeGlyph {
|
||||
start: start_glyph,
|
||||
end: end_run, // Set later
|
||||
|
|
@ -453,7 +454,8 @@ fn shape_skip(
|
|||
.char_indices()
|
||||
.map(|(chr_idx, codepoint)| {
|
||||
let glyph_id = charmap.map(codepoint);
|
||||
let x_advance = glyph_metrics.advance_width(glyph_id);
|
||||
let x_advance = glyph_metrics.advance_width(glyph_id)
|
||||
+ attrs.letter_spacing_opt.map_or(0.0, |spacing| spacing.0);
|
||||
let attrs = attrs_list.get_span(start_run + chr_idx);
|
||||
|
||||
ShapeGlyph {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue