diff --git a/CHANGELOG.md b/CHANGELOG.md index 2caa9f1..b1be0e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `cff::Table::glyph_index` - `cff::Table::glyph_width` - `cff::Table::number_of_glyphs` +- `cff::Table::matrix` ## [0.15.2] - 2022-06-17 ### Fixed diff --git a/src/tables/cff/cff1.rs b/src/tables/cff/cff1.rs index 0a941b7..e984ec4 100644 --- a/src/tables/cff/cff1.rs +++ b/src/tables/cff/cff1.rs @@ -70,6 +70,7 @@ mod top_dict_operator { pub const ENCODING_OFFSET: u16 = 16; pub const CHAR_STRINGS_OFFSET: u16 = 17; pub const PRIVATE_DICT_SIZE_AND_OFFSET: u16 = 18; + pub const FONT_MATRIX: u16 = 1207; pub const ROS: u16 = 1230; pub const FD_ARRAY: u16 = 1236; pub const FD_SELECT: u16 = 1237; @@ -118,12 +119,31 @@ pub(crate) struct CIDMetadata<'a> { fd_select: FDSelect<'a>, } +/// An affine transformation matrix. +#[allow(missing_docs)] +#[derive(Clone, Copy, Debug)] +pub struct Matrix { + pub sx: f32, + pub ky: f32, + pub kx: f32, + pub sy: f32, + pub tx: f32, + pub ty: f32, +} + +impl Default for Matrix { + fn default() -> Self { + Self { sx: 0.001, ky: 0.0, kx: 0.0, sy: 0.001, tx: 0.0, ty: 0.0 } + } +} + #[derive(Default)] struct TopDict { charset_offset: Option, encoding_offset: Option, char_strings_offset: usize, private_dict_range: Option>, + matrix: Matrix, has_ros: bool, fd_array_offset: Option, fd_select_offset: Option, @@ -137,7 +157,7 @@ fn parse_top_dict(s: &mut Stream) -> Option { // The Top DICT INDEX should have only one dictionary. let data = index.get(0)?; - let mut operands_buffer = [0; MAX_OPERANDS_LEN]; + let mut operands_buffer = [0.0; MAX_OPERANDS_LEN]; let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer); while let Some(operator) = dict_parser.parse_next() { match operator.get() { @@ -153,6 +173,20 @@ fn parse_top_dict(s: &mut Stream) -> Option { top_dict_operator::PRIVATE_DICT_SIZE_AND_OFFSET => { top_dict.private_dict_range = dict_parser.parse_range(); } + top_dict_operator::FONT_MATRIX => { + dict_parser.parse_operands()?; + let operands = dict_parser.operands(); + if operands.len() == 6 { + top_dict.matrix = Matrix { + sx: operands[0], + ky: operands[1], + kx: operands[2], + sy: operands[3], + tx: operands[4], + ty: operands[5], + }; + } + } top_dict_operator::ROS => { top_dict.has_ros = true; } @@ -241,13 +275,13 @@ mod tests { #[derive(Default, Debug)] struct PrivateDict { local_subroutines_offset: Option, - default_width: Option, - nominal_width: Option, + default_width: Option, + nominal_width: Option, } fn parse_private_dict(data: &[u8]) -> PrivateDict { let mut dict = PrivateDict::default(); - let mut operands_buffer = [0; MAX_OPERANDS_LEN]; + let mut operands_buffer = [0.0; MAX_OPERANDS_LEN]; let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer); while let Some(operator) = dict_parser.parse_next() { if operator.get() == private_dict_operator::LOCAL_SUBROUTINES_OFFSET { @@ -263,7 +297,7 @@ fn parse_private_dict(data: &[u8]) -> PrivateDict { } fn parse_font_dict(data: &[u8]) -> Option> { - let mut operands_buffer = [0; MAX_OPERANDS_LEN]; + let mut operands_buffer = [0.0; MAX_OPERANDS_LEN]; let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer); while let Some(operator) = dict_parser.parse_next() { if operator.get() == top_dict_operator::PRIVATE_DICT_SIZE_AND_OFFSET { @@ -788,8 +822,8 @@ fn parse_sid_metadata<'a>( return Some(FontKind::SID(metadata)) }; - metadata.default_width = private_dict.default_width.map(|n| n as f32).unwrap_or(0.0); - metadata.nominal_width = private_dict.nominal_width.map(|n| n as f32).unwrap_or(0.0); + metadata.default_width = private_dict.default_width.unwrap_or(0.0); + metadata.nominal_width = private_dict.nominal_width.unwrap_or(0.0); match (top_dict.private_dict_range, private_dict.local_subroutines_offset) { (Some(private_dict_range), Some(subroutines_offset)) => { @@ -848,6 +882,7 @@ pub struct Table<'a> { global_subrs: Index<'a>, charset: Charset<'a>, number_of_glyphs: NonZeroU16, + matrix: Matrix, char_strings: Index<'a>, kind: FontKind<'a>, } @@ -907,6 +942,8 @@ impl<'a> Table<'a> { None => Charset::ISOAdobe, // default }; + let matrix = top_dict.matrix; + let kind = if top_dict.has_ros { parse_cid_metadata(data, top_dict, number_of_glyphs.get())? } else { @@ -927,6 +964,7 @@ impl<'a> Table<'a> { global_subrs, charset, number_of_glyphs, + matrix, char_strings, kind, }) @@ -940,6 +978,12 @@ impl<'a> Table<'a> { self.number_of_glyphs.get() } + /// Returns a font transformation matrix. + #[inline] + pub fn matrix(&self) -> Matrix { + self.matrix + } + /// Outlines a glyph. pub fn outline( &self, diff --git a/src/tables/cff/cff2.rs b/src/tables/cff/cff2.rs index 51e0b9d..a51879d 100644 --- a/src/tables/cff/cff2.rs +++ b/src/tables/cff/cff2.rs @@ -85,7 +85,7 @@ struct TopDictData { fn parse_top_dict(data: &[u8]) -> Option { let mut dict_data = TopDictData::default(); - let mut operands_buffer = [0; MAX_OPERANDS_LEN]; + let mut operands_buffer = [0.0; MAX_OPERANDS_LEN]; let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer); while let Some(operator) = dict_parser.parse_next() { if operator.get() == top_dict_operator::CHAR_STRINGS_OFFSET { @@ -108,7 +108,7 @@ fn parse_top_dict(data: &[u8]) -> Option { fn parse_font_dict(data: &[u8]) -> Option> { let mut private_dict_range = None; - let mut operands_buffer = [0; MAX_OPERANDS_LEN]; + let mut operands_buffer = [0.0; MAX_OPERANDS_LEN]; let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer); while let Some(operator) = dict_parser.parse_next() { if operator.get() == font_dict_operator::PRIVATE_DICT_SIZE_AND_OFFSET { @@ -116,8 +116,8 @@ fn parse_font_dict(data: &[u8]) -> Option> { let operands = dict_parser.operands(); if operands.len() == 2 { - let len = usize::try_from(operands[0]).ok()?; - let start = usize::try_from(operands[1]).ok()?; + let len = usize::try_from(operands[0] as i32).ok()?; + let start = usize::try_from(operands[1] as i32).ok()?; let end = start.checked_add(len)?; private_dict_range = Some(start..end); } @@ -131,7 +131,7 @@ fn parse_font_dict(data: &[u8]) -> Option> { fn parse_private_dict(data: &[u8]) -> Option { let mut subroutines_offset = None; - let mut operands_buffer = [0; MAX_OPERANDS_LEN]; + let mut operands_buffer = [0.0; MAX_OPERANDS_LEN]; let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer); while let Some(operator) = dict_parser.parse_next() { if operator.get() == private_dict_operator::LOCAL_SUBROUTINES_OFFSET { @@ -139,7 +139,7 @@ fn parse_private_dict(data: &[u8]) -> Option { let operands = dict_parser.operands(); if operands.len() == 1 { - subroutines_offset = usize::try_from(operands[0]).ok(); + subroutines_offset = usize::try_from(operands[0] as i32).ok(); } break; diff --git a/src/tables/cff/dict.rs b/src/tables/cff/dict.rs index a9b0b3a..e05fc67 100644 --- a/src/tables/cff/dict.rs +++ b/src/tables/cff/dict.rs @@ -5,6 +5,7 @@ use crate::Stream; // Limits according to the Adobe Technical Note #5176, chapter 4 DICT Data. const TWO_BYTE_OPERATOR_MARK: u8 = 12; +const FLOAT_STACK_LEN: usize = 64; const END_OF_FLOAT_FLAG: u8 = 0xf; #[derive(Clone, Copy, Debug)] @@ -23,14 +24,14 @@ pub struct DictionaryParser<'a> { // Offset to the last operands start. operands_offset: usize, // Actual operands. - operands: &'a mut [i32], + operands: &'a mut [f32], // An amount of operands in the `operands` array. operands_len: u16, } impl<'a> DictionaryParser<'a> { #[inline] - pub fn new(data: &'a [u8], operands_buffer: &'a mut [i32]) -> Self { + pub fn new(data: &'a [u8], operands_buffer: &'a mut [f32]) -> Self { DictionaryParser { data, offset: 0, @@ -100,12 +101,12 @@ impl<'a> DictionaryParser<'a> { } #[inline] - pub fn operands(&self) -> &[i32] { + pub fn operands(&self) -> &[f32] { &self.operands[..usize::from(self.operands_len)] } #[inline] - pub fn parse_number(&mut self) -> Option { + pub fn parse_number(&mut self) -> Option { self.parse_operands()?; self.operands().get(0).cloned() } @@ -115,7 +116,7 @@ impl<'a> DictionaryParser<'a> { self.parse_operands()?; let operands = self.operands(); if operands.len() == 1 { - usize::try_from(operands[0]).ok() + usize::try_from(operands[0] as i32).ok() } else { None } @@ -126,8 +127,8 @@ impl<'a> DictionaryParser<'a> { self.parse_operands()?; let operands = self.operands(); if operands.len() == 2 { - let len = usize::try_from(operands[0]).ok()?; - let start = usize::try_from(operands[1]).ok()?; + let len = usize::try_from(operands[0] as i32).ok()?; + let start = usize::try_from(operands[1] as i32).ok()?; let end = start.checked_add(len)?; Some(start..end) } else { @@ -149,47 +150,104 @@ pub fn is_dict_one_byte_op(b: u8) -> bool { } // Adobe Technical Note #5177, Table 3 Operand Encoding -pub fn parse_number(b0: u8, s: &mut Stream) -> Option { +pub fn parse_number(b0: u8, s: &mut Stream) -> Option { match b0 { 28 => { let n = i32::from(s.read::()?); - Some(n) + Some(n as f32) } 29 => { let n = s.read::()?; - Some(n) + Some(n as f32) } 30 => { - // We do not parse float, because we don't use it. - // And by skipping it we can remove the core::num::dec2flt dependency. - while !s.at_end() { - let b1 = s.read::()?; - let nibble1 = b1 >> 4; - let nibble2 = b1 & 15; - if nibble1 == END_OF_FLOAT_FLAG || nibble2 == END_OF_FLOAT_FLAG { - break; - } - } - Some(0) + parse_float(s) } 32..=246 => { let n = i32::from(b0) - 139; - Some(n) + Some(n as f32) } 247..=250 => { let b1 = i32::from(s.read::()?); let n = (i32::from(b0) - 247) * 256 + b1 + 108; - Some(n) + Some(n as f32) } 251..=254 => { let b1 = i32::from(s.read::()?); let n = -(i32::from(b0) - 251) * 256 - b1 - 108; - Some(n) + Some(n as f32) } _ => None, } } +fn parse_float(s: &mut Stream) -> Option { + let mut data = [0u8; FLOAT_STACK_LEN]; + let mut idx = 0; + + loop { + let b1: u8 = s.read()?; + let nibble1 = b1 >> 4; + let nibble2 = b1 & 15; + + if nibble1 == END_OF_FLOAT_FLAG { + break; + } + + idx = parse_float_nibble(nibble1, idx, &mut data)?; + + if nibble2 == END_OF_FLOAT_FLAG { + break; + } + + idx = parse_float_nibble(nibble2, idx, &mut data)?; + } + + let s = core::str::from_utf8(&data[..idx]).ok()?; + let n = s.parse().ok()?; + Some(n) +} + +// Adobe Technical Note #5176, Table 5 Nibble Definitions +fn parse_float_nibble(nibble: u8, mut idx: usize, data: &mut [u8]) -> Option { + if idx == FLOAT_STACK_LEN { + return None; + } + + match nibble { + 0..=9 => { + data[idx] = b'0' + nibble; + } + 10 => { + data[idx] = b'.'; + } + 11 => { + data[idx] = b'E'; + } + 12 => { + if idx + 1 == FLOAT_STACK_LEN { + return None; + } + + data[idx] = b'E'; + idx += 1; + data[idx] = b'-'; + } + 13 => { + return None; + } + 14 => { + data[idx] = b'-'; + } + _ => { + return None; + } + } + + idx += 1; + Some(idx) +} + // Just like `parse_number`, but doesn't actually parses the data. pub fn skip_number(b0: u8, s: &mut Stream) -> Option<()> { match b0 { @@ -221,11 +279,11 @@ mod tests { #[test] fn parse_dict_number() { - assert_eq!(parse_number(0xFA, &mut Stream::new(&[0x7C])).unwrap(), 1000); - assert_eq!(parse_number(0xFE, &mut Stream::new(&[0x7C])).unwrap(), -1000); - assert_eq!(parse_number(0x1C, &mut Stream::new(&[0x27, 0x10])).unwrap(), 10000); - assert_eq!(parse_number(0x1C, &mut Stream::new(&[0xD8, 0xF0])).unwrap(), -10000); - assert_eq!(parse_number(0x1D, &mut Stream::new(&[0x00, 0x01, 0x86, 0xA0])).unwrap(), 100000); - assert_eq!(parse_number(0x1D, &mut Stream::new(&[0xFF, 0xFE, 0x79, 0x60])).unwrap(), -100000); + assert_eq!(parse_number(0xFA, &mut Stream::new(&[0x7C])).unwrap(), 1000.0); + assert_eq!(parse_number(0xFE, &mut Stream::new(&[0x7C])).unwrap(), -1000.0); + assert_eq!(parse_number(0x1C, &mut Stream::new(&[0x27, 0x10])).unwrap(), 10000.0); + assert_eq!(parse_number(0x1C, &mut Stream::new(&[0xD8, 0xF0])).unwrap(), -10000.0); + assert_eq!(parse_number(0x1D, &mut Stream::new(&[0x00, 0x01, 0x86, 0xA0])).unwrap(), 100000.0); + assert_eq!(parse_number(0x1D, &mut Stream::new(&[0xFF, 0xFE, 0x79, 0x60])).unwrap(), -100000.0); } }