Skip to content

Commit

Permalink
[meta] Add some tests, fix what was broke
Browse files Browse the repository at this point in the history
  • Loading branch information
cmyr committed Nov 19, 2024
1 parent ebf9038 commit b0d01f0
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 21 deletions.
22 changes: 22 additions & 0 deletions font-test-data/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,25 @@ pub mod colrv1_json {
pub mod ttc {
pub static TTC: &[u8] = include_bytes!("../test_data/ttc/TTC.ttc");
}

pub mod meta {
// the table from the binary for 'Sankofa'
#[rustfmt::skip]
pub static SIMPLE_META_TABLE: &[u8] = &[
0x00, 0x00, 0x00, 0x01, // version 1
0x00, 0x00, 0x00, 0x00, // flags 0
0x00, 0x00, 0x00, 0x28, // reserved (?)
0x00, 0x00, 0x00, 0x02, // data_maps_count 2
0x64, 0x6c, 0x6e, 0x67, // tag: dlng
0x00, 0x00, 0x00, 0x28, // data offset
0x00, 0x00, 0x00, 0x0d, // data length
0x73, 0x6c, 0x6e, 0x67, // tag: slng
0x00, 0x00, 0x00, 0x35, // data offset
0x00, 0x00, 0x00, 0x04, // length
0x65, 0x6e, 0x2d, 0x6c,
0x61, 0x74, 0x6e, 0x2c,
0x20, 0x6c, 0x61, 0x74,
0x6e, 0x6c, 0x61, 0x74,
0x6e, 0x00, 0x00, 0x00,
];
}
3 changes: 2 additions & 1 deletion read-fonts/src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ impl<'a, T: FontRead<'a> + VarSize> VarLenArray<'a, T> {
}

let item_len = T::read_len_at(data, 0)?;
let next = T::read(data);
let item_data = data.slice(..item_len)?;
let next = T::read(item_data);
data = data.split_off(item_len)?;
Some(next)
})
Expand Down
57 changes: 48 additions & 9 deletions read-fonts/src/tables/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub const SLNG: Tag = Tag::new(b"slng");
/// Data stored in the 'meta' table.
pub enum Metadata<'a> {
/// Used for the 'dlng' and 'slng' metadata
ScriptLangTags(VarLenArray<'a, LangScriptTag<'a>>),
ScriptLangTags(VarLenArray<'a, ScriptLangTag<'a>>),
/// Other metadata, which may exist in certain apple fonts
Other(&'a [u8]),
}
Expand All @@ -29,28 +29,29 @@ impl<'a> FontReadWithArgs<'a> for Metadata<'a> {
}
}

pub struct LangScriptTag<'a>(&'a str);
#[derive(Clone, Debug)]
pub struct ScriptLangTag<'a>(&'a str);

impl<'a> LangScriptTag<'a> {
impl<'a> ScriptLangTag<'a> {
pub fn as_str(&self) -> &'a str {
self.0
}
}

impl AsRef<str> for LangScriptTag<'_> {
impl AsRef<str> for ScriptLangTag<'_> {
fn as_ref(&self) -> &str {
self.0
}
}

#[cfg(feature = "std")]
impl From<LangScriptTag<'_>> for String {
fn from(value: LangScriptTag<'_>) -> Self {
impl From<ScriptLangTag<'_>> for String {
fn from(value: ScriptLangTag<'_>) -> Self {
value.0.into()
}
}

impl VarSize for LangScriptTag<'_> {
impl VarSize for ScriptLangTag<'_> {
type Size = u32;

fn read_len_at(data: FontData, pos: usize) -> Option<usize> {
Expand All @@ -68,10 +69,48 @@ impl VarSize for LangScriptTag<'_> {
}
}

impl<'a> FontRead<'a> for LangScriptTag<'a> {
impl<'a> FontRead<'a> for ScriptLangTag<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
std::str::from_utf8(data.as_bytes())
.map_err(|_| ReadError::MalformedData("LangScriptTag must be utf8"))
.map(|s| LangScriptTag(s.trim_matches(',')))
.map(|s| ScriptLangTag(s.trim_matches([' ', ','])))
}
}

#[cfg(test)]
mod tests {
use super::*;
use font_test_data::meta as test_data;

impl PartialEq<&str> for ScriptLangTag<'_> {
fn eq(&self, other: &&str) -> bool {
self.as_ref() == *other
}
}

fn expect_script_lang_tags(table: Metadata, expected: &[&str]) -> bool {
let Metadata::ScriptLangTags(langs) = table else {
panic!("wrong metadata");
};
let result = langs.iter().map(|x| x.unwrap()).collect::<Vec<_>>();
result == expected
}

#[test]
fn parse_simple() {
let table = Meta::read(test_data::SIMPLE_META_TABLE.into()).unwrap();
let rec1 = table.data_maps()[0];
let rec2 = table.data_maps()[1];

assert_eq!(rec1.tag(), Tag::new(b"dlng"));
assert_eq!(rec2.tag(), Tag::new(b"slng"));
assert!(expect_script_lang_tags(
rec1.data(table.offset_data()).unwrap(),
&["en-latn", "latn"]
));
assert!(expect_script_lang_tags(
rec2.data(table.offset_data()).unwrap(),
&["latn"]
));
}
}
2 changes: 1 addition & 1 deletion resources/codegen_inputs/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ record DataMapRecord {
#[validate(validate_data_type)]
data_offset: Offset32<Metadata>,
/// Length of the data, in bytes. The data is not required to be padded to any byte boundary.
#[compile(skip)]
#[compile(self.compute_data_len())]
data_length: u32,
}

1 change: 1 addition & 0 deletions write-fonts/generated/generated_meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ impl FontWrite for DataMapRecord {
fn write_into(&self, writer: &mut TableWriter) {
self.tag.write_into(writer);
self.data.write_into(writer);
(self.compute_data_len() as u32).write_into(writer);
}
fn table_type(&self) -> TableType {
TableType::Named("DataMapRecord")
Expand Down
54 changes: 44 additions & 10 deletions write-fonts/src/tables/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,31 +59,36 @@ impl DataMapRecord {
ctx.report("'slng' or 'dlng' tags use ScriptLangTag data");
}
}

fn compute_data_len(&self) -> usize {
match self.data.as_ref() {
Metadata::ScriptLangTags(items) => {
let sum_len: usize = items.iter().map(|tag| tag.as_str().len()).sum();
let toss_some_commas_in_there = items.len().saturating_sub(1);
sum_len + toss_some_commas_in_there
}
Metadata::Other(vec) => vec.len(),
}
}
}

impl FontWrite for Metadata {
fn write_into(&self, writer: &mut TableWriter) {
let len = match self {
match self {
Metadata::ScriptLangTags(langs) => {
let mut len = 0;
let mut first = true;
for lang in langs {
if len > 0 {
if !first {
b','.write_into(writer);
len += 1;
}
first = false;
lang.0.as_bytes().write_into(writer);
len += lang.0.as_bytes().len();
}
len
}
Metadata::Other(vec) => {
vec.write_into(writer);
vec.len()
}
};

let len: u32 = len.try_into().unwrap();
len.write_into(writer);
}
}

Expand Down Expand Up @@ -135,3 +140,32 @@ impl FromObjRef<read_fonts::tables::meta::DataMapRecord> for DataMapRecord {
}
}
}

#[cfg(test)]
mod tests {

use super::*;
use font_test_data::meta as test_data;

#[test]
fn convert_from_read() {
let table = Meta::read(test_data::SIMPLE_META_TABLE.into()).unwrap();
let rec1 = &table.data_maps[0];
assert_eq!(
rec1.data.as_ref(),
&Metadata::ScriptLangTags(vec![
ScriptLangTag::new("en-latn".into()).unwrap(),
ScriptLangTag::new("latn".into()).unwrap()
])
);

let round_trip = crate::dump_table(&table).unwrap();
let read_back = Meta::read(round_trip.as_slice().into()).unwrap();
let readr = read_fonts::tables::meta::Meta::read(round_trip.as_slice().into()).unwrap();
dbg!(readr);

//eprintln!("{read_back:#?}");

assert_eq!(table, read_back);
}
}

0 comments on commit b0d01f0

Please sign in to comment.