Files
vectorcraft/crates/text/src/tests_embed.rs
T
bflatasticandClaude Opus 5.5 fa3dcab411 M4.97: SVG Options choose the encoding, SVG Tiny 1.2 and embedded font subsets
SVG export writes UTF-8, UTF-16 (big-endian with a byte order mark) or
ISO 8859-1 (other characters as character references) and SVG/SVGZ
open in any of them. The Tiny 1.2 profile (simplified) writes
presentation attributes only and leaves out filters, masks, blend
modes and symbols with warnings. embedFonts embeds the fonts type uses
as @font-face subsets of the characters used, honouring the fonts'
fsType (whole when subsetting is forbidden, left out when embedding
is). New options: encoding, profile, embedFonts (SVG Options dialog,
document.formats); document.serialize also returns dataBase64 for
non-UTF-8 files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 13:25:15 +07:00

94 lines
4.3 KiB
Rust

//! Embedded fonts: licence flags and subsets a viewer can use.
use skrifa::MetadataProvider;
use skrifa::instance::{LocationRef, Size};
use skrifa::raw::types::Tag;
use skrifa::raw::{FontData, FontRead, TableProvider};
use super::embed::Embedding;
use super::*;
#[test]
fn fs_type_flags_decide_the_embedding() {
assert_eq!(Embedding::from_fs_type(0), Embedding::Subset, "installable");
assert_eq!(Embedding::from_fs_type(0x0004), Embedding::Subset, "preview & print");
assert_eq!(Embedding::from_fs_type(0x0008), Embedding::Subset, "editable");
assert_eq!(Embedding::from_fs_type(0x0002), Embedding::Forbidden, "restricted");
assert_eq!(Embedding::from_fs_type(0x0006), Embedding::Subset, "the most permissive bit wins");
assert_eq!(Embedding::from_fs_type(0x0200), Embedding::Forbidden, "bitmaps only");
assert_eq!(Embedding::from_fs_type(0x0108), Embedding::Whole, "no subsetting");
}
#[test]
fn a_subset_holds_only_the_glyphs_used_and_maps_their_characters() {
let face = FontDb::global().face("Source Sans 3", "Regular").unwrap();
assert_eq!(face.embedding(), Embedding::Subset);
let e = face.embed(&['H', 'e', 'l', 'l', 'o', ' ']).unwrap();
assert!(e.subset && !e.cff);
assert!(e.data.len() * 20 < face.data().len(), "{} of {} bytes", e.data.len(), face.data().len());
let f = skrifa::FontRef::new(&e.data).unwrap();
// .notdef and the five characters' glyphs.
assert_eq!(f.maxp().unwrap().num_glyphs(), 6);
let map = f.charmap();
let metrics = f.glyph_metrics(Size::unscaled(), LocationRef::default());
for c in ['H', 'e', 'l', 'o', ' '] {
let g = map.map(c).unwrap_or_else(|| panic!("{c} mapped"));
assert_eq!(metrics.advance_width(g).unwrap() as f64, face.advance(face.glyph_for(c)), "{c}: same advance");
}
assert!(map.map('x').is_none(), "unused characters are left out");
let h = f.outline_glyphs().get(map.map('H').unwrap()).unwrap();
let mut pen = Commands::default();
h.draw(skrifa::outline::DrawSettings::unhinted(Size::unscaled(), LocationRef::default()), &mut pen).unwrap();
assert!(pen.0 > 4, "H keeps its outline");
// The tables a web viewer needs, the licence flags kept and the file checksum right.
for t in [b"cmap", b"OS/2", b"head", b"hhea", b"hmtx", b"maxp", b"name", b"post", b"glyf", b"loca"] {
assert!(f.table_data(Tag::new(t)).is_some(), "{}", String::from_utf8_lossy(t));
}
let os2 = f.os2().unwrap();
assert_eq!(os2.fs_type(), face.skrifa().unwrap().os2().unwrap().fs_type());
assert_eq!((os2.us_first_char_index(), os2.us_last_char_index()), (' ' as u16, 'o' as u16));
let (words, rest) = e.data.as_chunks::<4>();
assert!(rest.is_empty());
assert_eq!(words.iter().fold(0u32, |s, w| s.wrapping_add(u32::from_be_bytes(*w))), 0xb1b0_afba);
}
#[test]
fn cmaps_map_runs_and_characters_beyond_the_basic_plane() {
let face = FontDb::global().face("Inter", "Regular").unwrap();
let e = face.embed(&['A', 'B', 'z']).unwrap();
let f = skrifa::FontRef::new(&e.data).unwrap();
let cmap = f.cmap().unwrap();
let (a, b, z) = (cmap.map_codepoint('A').unwrap(), cmap.map_codepoint('B').unwrap(), cmap.map_codepoint('z').unwrap());
assert!(a != b && b != z && a.to_u32() != 0);
assert_eq!(cmap.map_codepoint('C'), None);
// No bundled face maps characters beyond the BMP: the table is checked on its own.
let raw = embed::cmap(&[(0x41, 1), (0x42, 2), (0x1f600, 3)]).unwrap();
let cmap = skrifa::raw::tables::cmap::Cmap::read(FontData::new(&raw)).unwrap();
assert_eq!(cmap.encoding_records().len(), 2, "format 4 and format 12");
for (c, g) in [('A', 1), ('B', 2), ('\u{1f600}', 3)] {
assert_eq!(cmap.map_codepoint(c).map(|g| g.to_u32()), Some(g), "{c}");
}
assert_eq!(cmap.map_codepoint('C'), None);
assert!(embed::cmap(&[]).is_none());
}
/// Counts outline commands.
#[derive(Default)]
struct Commands(usize);
impl skrifa::outline::OutlinePen for Commands {
fn move_to(&mut self, _: f32, _: f32) {
self.0 += 1;
}
fn line_to(&mut self, _: f32, _: f32) {
self.0 += 1;
}
fn quad_to(&mut self, _: f32, _: f32, _: f32, _: f32) {
self.0 += 1;
}
fn curve_to(&mut self, _: f32, _: f32, _: f32, _: f32, _: f32, _: f32) {
self.0 += 1;
}
fn close(&mut self) {}
}