diff --git a/src/lib.rs b/src/lib.rs index d7af950..5d12ebd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1337,7 +1337,9 @@ impl<'a> Face<'a> { bdat, cbdt, - cff: raw_tables.cff.and_then(|data| cff::Table::parse(data, head.units_per_em)), + cff: raw_tables + .cff + .and_then(|data| cff::Table::parse_with_upem(data, head.units_per_em)), cmap: raw_tables.cmap.and_then(cmap::Table::parse), colr, ebdt, diff --git a/src/tables/cff/cff1.rs b/src/tables/cff/cff1.rs index e9734c7..4c11d32 100644 --- a/src/tables/cff/cff1.rs +++ b/src/tables/cff/cff1.rs @@ -374,8 +374,13 @@ fn parse_char_string( local_subrs, }; - let transform = (metadata.units_per_em, metadata.matrix()); - let transform = (transform != (1000, Matrix::default())).then_some(transform); + let (upem, transform) = (metadata.units_per_em, metadata.matrix()); + let transform = if let Some(upem) = upem { + ((upem, transform) != (1000, Matrix::default())).then_some((upem, transform)) + } else { + None + }; + let mut inner_builder = Builder { builder, bbox: RectF::new(), @@ -802,7 +807,11 @@ fn parse_sid_metadata<'a>( Some(FontKind::SID(metadata)) } -fn parse_cid_metadata(data: &[u8], top_dict: TopDict, number_of_glyphs: u16) -> Option> { +fn parse_cid_metadata( + data: &[u8], + top_dict: TopDict, + number_of_glyphs: u16, +) -> Option> { let (charset_offset, fd_array_offset, fd_select_offset) = match ( top_dict.charset_offset, top_dict.fd_array_offset, @@ -852,12 +861,23 @@ pub struct Table<'a> { // Copy of Face::units_per_em(). // Required to do glyph outlining, since coordinates must be scaled up by this before applying the `matrix`. - units_per_em: u16, + units_per_em: Option, } impl<'a> Table<'a> { /// Parses a table from raw data. - pub fn parse(data: &'a [u8], units_per_em: u16) -> Option { + pub fn parse(data: &'a [u8]) -> Option { + Self::parse_inner(data, None) + } + + /// The same as [`Table::parse`], with the difference that it allows you to + /// manually pass the units per em of the font, which is needed to properly + /// scale certain fonts with a non-identity matrix. + pub(crate) fn parse_with_upem(data: &'a [u8], units_per_em: u16) -> Option { + Self::parse_inner(data, Some(units_per_em)) + } + + fn parse_inner(data: &'a [u8], units_per_em: Option) -> Option { let mut s = Stream::new(data); // Parse Header. diff --git a/tests/tables/cff1.rs b/tests/tables/cff1.rs index dd59751..261e1d5 100644 --- a/tests/tables/cff1.rs +++ b/tests/tables/cff1.rs @@ -312,7 +312,7 @@ fn unsupported_version() { UInt8(0), // absolute offset ]); - assert!(cff::Table::parse(&data, 1000).is_none()); + assert!(cff::Table::parse(&data).is_none()); } #[test] @@ -360,7 +360,7 @@ fn non_default_header_size() { UInt8(operator::ENDCHAR), ]); - let table = cff::Table::parse(&data, 1000).unwrap(); + let table = cff::Table::parse(&data).unwrap(); let mut builder = Builder(String::new()); let rect = table.outline(GlyphId(0), &mut builder).unwrap(); @@ -377,7 +377,7 @@ macro_rules! test_cs_with_subrs { #[test] fn $name() { let data = gen_cff($glob, $loc, $values); - let table = cff::Table::parse(&data, 1000).unwrap(); + let table = cff::Table::parse(&data).unwrap(); let mut builder = Builder(String::new()); let rect = table.outline(GlyphId(0), &mut builder).unwrap(); @@ -398,7 +398,7 @@ macro_rules! test_cs_err { #[test] fn $name() { let data = gen_cff(&[], &[], $values); - let table = cff::Table::parse(&data, 1000).unwrap(); + let table = cff::Table::parse(&data).unwrap(); let mut builder = Builder(String::new()); let res = table.outline(GlyphId(0), &mut builder); assert_eq!(res.unwrap_err(), $err); @@ -575,7 +575,7 @@ test_cs!(vv_curve_to_with_x, &[ #[test] fn only_endchar() { let data = gen_cff(&[], &[], &[UInt8(operator::ENDCHAR)]); - let table = cff::Table::parse(&data, 1000).unwrap(); + let table = cff::Table::parse(&data).unwrap(); let mut builder = Builder(String::new()); assert!(table.outline(GlyphId(0), &mut builder).is_err()); } @@ -800,7 +800,7 @@ fn endchar_in_subr_with_extra_data_1() { ] ); - let table = cff::Table::parse(&data, 1000).unwrap(); + let table = cff::Table::parse(&data).unwrap(); let mut builder = Builder(String::new()); let res = table.outline(GlyphId(0), &mut builder); assert_eq!(res.unwrap_err(), CFFError::DataAfterEndChar); @@ -827,7 +827,7 @@ fn endchar_in_subr_with_extra_data_2() { ] ); - let table = cff::Table::parse(&data, 1000).unwrap(); + let table = cff::Table::parse(&data).unwrap(); let mut builder = Builder(String::new()); let res = table.outline(GlyphId(0), &mut builder); assert_eq!(res.unwrap_err(), CFFError::DataAfterEndChar); @@ -854,7 +854,7 @@ fn subr_without_return() { ] ); - let table = cff::Table::parse(&data, 1000).unwrap(); + let table = cff::Table::parse(&data).unwrap(); let mut builder = Builder(String::new()); let res = table.outline(GlyphId(0), &mut builder); assert_eq!(res.unwrap_err(), CFFError::DataAfterEndChar); @@ -876,7 +876,7 @@ fn recursive_local_subr() { ] ); - let table = cff::Table::parse(&data, 1000).unwrap(); + let table = cff::Table::parse(&data).unwrap(); let mut builder = Builder(String::new()); let res = table.outline(GlyphId(0), &mut builder); assert_eq!(res.unwrap_err(), CFFError::NestingLimitReached); @@ -898,7 +898,7 @@ fn recursive_global_subr() { ] ); - let table = cff::Table::parse(&data, 1000).unwrap(); + let table = cff::Table::parse(&data).unwrap(); let mut builder = Builder(String::new()); let res = table.outline(GlyphId(0), &mut builder); assert_eq!(res.unwrap_err(), CFFError::NestingLimitReached); @@ -923,7 +923,7 @@ fn recursive_mixed_subr() { ] ); - let table = cff::Table::parse(&data, 1000).unwrap(); + let table = cff::Table::parse(&data).unwrap(); let mut builder = Builder(String::new()); let res = table.outline(GlyphId(0), &mut builder); assert_eq!(res.unwrap_err(), CFFError::NestingLimitReached); @@ -952,7 +952,7 @@ fn zero_char_string_offset() { UInt8(top_dict_operator::CHAR_STRINGS_OFFSET as u8), ]); - assert!(cff::Table::parse(&data, 1000).is_none()); + assert!(cff::Table::parse(&data).is_none()); } #[test] @@ -978,7 +978,7 @@ fn invalid_char_string_offset() { UInt8(top_dict_operator::CHAR_STRINGS_OFFSET as u8), ]); - assert!(cff::Table::parse(&data, 1000).is_none()); + assert!(cff::Table::parse(&data).is_none()); } // TODO: return from main