Skip to content

Commit

Permalink
Add cff::Table::matrix.
Browse files Browse the repository at this point in the history
  • Loading branch information
RazrFalcon committed Aug 19, 2022
1 parent ebe6c99 commit 44d8c8b
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 43 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -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
Expand Down
58 changes: 51 additions & 7 deletions src/tables/cff/cff1.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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<usize>,
encoding_offset: Option<usize>,
char_strings_offset: usize,
private_dict_range: Option<Range<usize>>,
matrix: Matrix,
has_ros: bool,
fd_array_offset: Option<usize>,
fd_select_offset: Option<usize>,
Expand All @@ -137,7 +157,7 @@ fn parse_top_dict(s: &mut Stream) -> Option<TopDict> {
// 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() {
Expand All @@ -153,6 +173,20 @@ fn parse_top_dict(s: &mut Stream) -> Option<TopDict> {
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;
}
Expand Down Expand Up @@ -241,13 +275,13 @@ mod tests {
#[derive(Default, Debug)]
struct PrivateDict {
local_subroutines_offset: Option<usize>,
default_width: Option<i32>,
nominal_width: Option<i32>,
default_width: Option<f32>,
nominal_width: Option<f32>,
}

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 {
Expand All @@ -263,7 +297,7 @@ fn parse_private_dict(data: &[u8]) -> PrivateDict {
}

fn parse_font_dict(data: &[u8]) -> Option<Range<usize>> {
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 {
Expand Down Expand Up @@ -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)) => {
Expand Down Expand Up @@ -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>,
}
Expand Down Expand Up @@ -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 {
Expand All @@ -927,6 +964,7 @@ impl<'a> Table<'a> {
global_subrs,
charset,
number_of_glyphs,
matrix,
char_strings,
kind,
})
Expand All @@ -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,
Expand Down
12 changes: 6 additions & 6 deletions src/tables/cff/cff2.rs
Expand Up @@ -85,7 +85,7 @@ struct TopDictData {
fn parse_top_dict(data: &[u8]) -> Option<TopDictData> {
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 {
Expand All @@ -108,16 +108,16 @@ fn parse_top_dict(data: &[u8]) -> Option<TopDictData> {
fn parse_font_dict(data: &[u8]) -> Option<Range<usize>> {
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 {
dict_parser.parse_operands()?;
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);
}
Expand All @@ -131,15 +131,15 @@ fn parse_font_dict(data: &[u8]) -> Option<Range<usize>> {

fn parse_private_dict(data: &[u8]) -> Option<usize> {
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 {
dict_parser.parse_operands()?;
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;
Expand Down
118 changes: 88 additions & 30 deletions src/tables/cff/dict.rs
Expand Up @@ -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)]
Expand All @@ -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,
Expand Down Expand Up @@ -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<i32> {
pub fn parse_number(&mut self) -> Option<f32> {
self.parse_operands()?;
self.operands().get(0).cloned()
}
Expand All @@ -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
}
Expand All @@ -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 {
Expand All @@ -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<i32> {
pub fn parse_number(b0: u8, s: &mut Stream) -> Option<f32> {
match b0 {
28 => {
let n = i32::from(s.read::<i16>()?);
Some(n)
Some(n as f32)
}
29 => {
let n = s.read::<i32>()?;
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::<u8>()?;
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::<u8>()?);
let n = (i32::from(b0) - 247) * 256 + b1 + 108;
Some(n)
Some(n as f32)
}
251..=254 => {
let b1 = i32::from(s.read::<u8>()?);
let n = -(i32::from(b0) - 251) * 256 - b1 - 108;
Some(n)
Some(n as f32)
}
_ => None,
}
}

fn parse_float(s: &mut Stream) -> Option<f32> {
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<usize> {
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 {
Expand Down Expand Up @@ -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);
}
}

0 comments on commit 44d8c8b

Please sign in to comment.