mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-24 10:56:51 -06:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0931c8b286 | ||
|
|
3a2d3608d3 |
@@ -60,6 +60,7 @@ pub(crate) fn shape(primary: Option<&Face>, s: &str, height: f64, width_factor:
|
||||
catch_unwind(AssertUnwindSafe(|| shape_chars(primary, &chars, height, width_factor, oblique))).ok()
|
||||
}
|
||||
|
||||
/// Lay out decoded directional runs, keeping advances and decoration spans for empty glyphs.
|
||||
fn shape_chars(primary: Option<&Face>, chars: &[(char, bool, bool)], height: f64, width_factor: f64, oblique: f64) -> Shaped {
|
||||
let h = if height.is_finite() && height > 0.0 { height } else { 1.0 };
|
||||
let wf = if width_factor.is_finite() && width_factor.abs() > 1e-6 { width_factor } else { 1.0 };
|
||||
@@ -107,7 +108,7 @@ fn shape_chars(primary: Option<&Face>, chars: &[(char, bool, bool)], height: f64
|
||||
for p in contours.iter_mut().flatten() {
|
||||
*p += Vec2::new(dy * shear, dy);
|
||||
}
|
||||
out.glyphs.push(contours);
|
||||
out.push_glyph(contours, None);
|
||||
}
|
||||
let adv = g.advance * k;
|
||||
let (u, o) = flags(g.cluster);
|
||||
@@ -217,6 +218,59 @@ fn shape_run(face: &Face, cs: &[char], r: Range<usize>, rtl: bool) -> Vec<Glyph>
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// A single empty glyph with a positive advance, without relying on installed fonts.
|
||||
fn empty_glyph_face() -> Face {
|
||||
let mut head = vec![0_u8; 54];
|
||||
head[..4].copy_from_slice(&0x0001_0000_u32.to_be_bytes());
|
||||
head[18..20].copy_from_slice(&1000_u16.to_be_bytes());
|
||||
let mut hhea = vec![0_u8; 36];
|
||||
hhea[..4].copy_from_slice(&0x0001_0000_u32.to_be_bytes());
|
||||
hhea[4..6].copy_from_slice(&800_i16.to_be_bytes());
|
||||
hhea[6..8].copy_from_slice(&(-200_i16).to_be_bytes());
|
||||
hhea[34..36].copy_from_slice(&1_u16.to_be_bytes());
|
||||
let tables = [
|
||||
(*b"head", head),
|
||||
(*b"hhea", hhea),
|
||||
(*b"hmtx", vec![1, 244, 0, 0]), // Advance 500, left side bearing 0.
|
||||
(*b"maxp", vec![0, 0, 80, 0, 0, 1]), // Version 0.5, one glyph.
|
||||
];
|
||||
let mut bytes = vec![0_u8; 12 + tables.len() * 16];
|
||||
bytes[..4].copy_from_slice(&0x0001_0000_u32.to_be_bytes());
|
||||
bytes[4..6].copy_from_slice(&4_u16.to_be_bytes());
|
||||
bytes[6..8].copy_from_slice(&64_u16.to_be_bytes());
|
||||
bytes[8..10].copy_from_slice(&2_u16.to_be_bytes());
|
||||
for (i, (tag, data)) in tables.into_iter().enumerate() {
|
||||
while !bytes.len().is_multiple_of(4) {
|
||||
bytes.push(0);
|
||||
}
|
||||
let record = 12 + i * 16;
|
||||
let offset = u32::try_from(bytes.len()).unwrap();
|
||||
let len = u32::try_from(data.len()).unwrap();
|
||||
bytes[record..record + 4].copy_from_slice(&tag);
|
||||
bytes[record + 8..record + 12].copy_from_slice(&offset.to_be_bytes());
|
||||
bytes[record + 12..record + 16].copy_from_slice(&len.to_be_bytes());
|
||||
bytes.extend(data);
|
||||
}
|
||||
Face::new(std::sync::Arc::new(bytes), 0).expect("synthetic font parses")
|
||||
}
|
||||
|
||||
/// Empty complex glyphs retain spacing and underlines without adding geometry or text slots.
|
||||
#[test]
|
||||
fn empty_complex_glyph_keeps_advance_without_geometry() {
|
||||
let face = empty_glyph_face();
|
||||
let shaped = shape(Some(&face), " ", 1.0, 1.0, 0.0).expect("shapes empty glyph");
|
||||
assert!(shaped.width > 0.0, "the font's advance is retained");
|
||||
assert!(shaped.is_empty());
|
||||
assert!(shaped.glyphs.is_empty());
|
||||
assert!(shaped.text.is_empty());
|
||||
|
||||
let underlined = shape(Some(&face), "%%u ", 1.0, 1.0, 0.0).expect("shapes decorated empty glyph");
|
||||
assert_eq!(underlined.width, shaped.width);
|
||||
assert!(underlined.glyphs.is_empty());
|
||||
assert!(underlined.text.is_empty());
|
||||
assert!(!underlined.strokes.is_empty(), "decoration spans survive an empty outline");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stroke_font_rtl_lines_keep_latin_and_digits_in_the_stroke_font() {
|
||||
// With or without installed fonts: the Persian words are fallback glyphs or
|
||||
|
||||
Reference in New Issue
Block a user