use crate::cff::charset::Charset;
use crate::cff::strings::{glyph_name_to_codepoint, Strings};
use crate::parser::{read_u16, read_u8};
use crate::Error;
pub(crate) const STANDARD_ENCODING: [u16; 256] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
0, 111, 112, 113, 114, 0, 115, 116, 117, 118, 119, 120, 121, 122, 0, 123,
0, 124, 125, 126, 127, 128, 129, 130, 131, 0, 132, 133, 0, 134, 135, 136,
137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 138, 0, 139, 0, 0, 0, 0, 140, 141, 142, 143, 0, 0, 0, 0,
0, 144, 0, 0, 0, 145, 0, 0, 146, 147, 148, 149, 0, 0, 0, 0,
];
pub(crate) const EXPERT_ENCODING: [u16; 256] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 229, 230, 0, 231, 232, 233, 234, 235, 236, 237, 238, 13, 14, 15, 99,
239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 252,
0, 253, 254, 255, 256, 257, 0, 0, 0, 258, 0, 0, 259, 260, 261, 262,
0, 0, 263, 264, 265, 0, 266, 109, 110, 267, 268, 269, 0, 270, 271, 272,
273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288,
289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 304, 305, 306, 0, 0, 307, 308, 309, 310, 311, 0, 312, 0, 0, 313,
0, 0, 314, 315, 0, 0, 316, 317, 318, 0, 0, 0, 158, 155, 163, 319,
320, 321, 322, 323, 324, 325, 0, 0, 326, 150, 164, 169, 327, 328, 329, 330,
331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346,
347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362,
363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378,
];
#[derive(Debug, Clone)]
pub(crate) enum Encoding<'a> {
Standard,
Expert,
Format0 {
codes: &'a [u8],
},
#[allow(dead_code)]
Format1 {
runs: &'a [u8],
},
}
impl<'a> Encoding<'a> {
pub(crate) fn parse(bytes: &'a [u8], top_off: i32) -> Result<Self, Error> {
match top_off {
0 => Ok(Self::Standard),
1 => Ok(Self::Expert),
n if n < 0 => Err(Error::Cff("negative encoding offset")),
n => {
let off = n as usize;
if off >= bytes.len() {
return Err(Error::UnexpectedEof);
}
let format_byte = read_u8(bytes, off)?;
let format = format_byte & 0x7f;
let after = off + 1;
match format {
0 => {
let n_codes = read_u8(bytes, after)? as usize;
let payload = bytes
.get(after + 1..after + 1 + n_codes)
.ok_or(Error::UnexpectedEof)?;
Ok(Self::Format0 { codes: payload })
}
1 => {
let n_ranges = read_u8(bytes, after)? as usize;
let runs = bytes
.get(after + 1..after + 1 + n_ranges * 2)
.ok_or(Error::UnexpectedEof)?;
Ok(Self::Format1 { runs })
}
_ => Err(Error::Cff("unknown Encoding format")),
}
}
}
}
pub(crate) fn lookup(
&self,
code: u8,
charset: &Charset<'_>,
strings: &Strings<'_>,
) -> Option<u16> {
match self {
Self::Standard => {
let _ = strings;
let sid = STANDARD_ENCODING[code as usize];
if sid == 0 {
return None;
}
charset.gid_of_sid(sid)
}
Self::Expert => {
let _ = strings;
let sid = EXPERT_ENCODING[code as usize];
if sid == 0 {
return None;
}
charset.gid_of_sid(sid)
}
Self::Format0 { codes } => {
for (i, &c) in codes.iter().enumerate() {
if c == code {
return Some(i as u16 + 1);
}
}
None
}
Self::Format1 { runs } => {
let mut gid: u16 = 1;
let mut off = 0;
while off + 1 < runs.len() {
let first = runs[off];
let n_left = runs[off + 1];
off += 2;
let last = first.saturating_add(n_left);
if code >= first && code <= last {
return Some(gid + (code - first) as u16);
}
gid = gid.saturating_add(n_left as u16 + 1);
}
None
}
}
}
}
#[allow(dead_code)]
fn _unused() {
let _ = (
read_u16 as fn(&[u8], usize) -> _,
glyph_name_to_codepoint as fn(&str) -> _,
);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cff::charset::Charset;
use crate::cff::index::Index;
#[test]
fn format0_lookup() {
let mut table = vec![0u8; 4]; table.push(0); table.push(2); table.push(65);
table.push(66);
let enc = Encoding::parse(&table, 4).unwrap();
let charset = Charset::IsoAdobe;
let custom = Index::parse(&[0u8, 0], 0).unwrap();
let strings = Strings::new(custom);
assert_eq!(enc.lookup(65, &charset, &strings), Some(1));
assert_eq!(enc.lookup(66, &charset, &strings), Some(2));
assert_eq!(enc.lookup(67, &charset, &strings), None);
}
#[test]
fn standard_encoding_landmark_codes() {
assert_eq!(STANDARD_ENCODING[b' ' as usize], 1); assert_eq!(STANDARD_ENCODING[b'!' as usize], 2); assert_eq!(STANDARD_ENCODING[b'A' as usize], 34); assert_eq!(STANDARD_ENCODING[b'Z' as usize], 59); assert_eq!(STANDARD_ENCODING[b'a' as usize], 66); assert_eq!(STANDARD_ENCODING[b'z' as usize], 91); assert_eq!(STANDARD_ENCODING[0], 0); assert_eq!(STANDARD_ENCODING[127], 0); assert_eq!(STANDARD_ENCODING[208], 137); assert_eq!(STANDARD_ENCODING[225], 138); assert_eq!(STANDARD_ENCODING[241], 144); assert_eq!(STANDARD_ENCODING[251], 149); assert_eq!(STANDARD_ENCODING[252], 0);
assert_eq!(STANDARD_ENCODING[255], 0);
}
#[test]
fn standard_encoding_routes_through_charset() {
let charset_payload = vec![0x00, 0x22]; let charset = Charset::Format0 {
bytes: &charset_payload,
num_glyphs: 2, };
let custom = Index::parse(&[0u8, 0], 0).unwrap();
let strings = Strings::new(custom);
let enc = Encoding::Standard;
assert_eq!(enc.lookup(b'A', &charset, &strings), Some(1));
assert_eq!(enc.lookup(b'B', &charset, &strings), None);
assert_eq!(enc.lookup(0, &charset, &strings), None);
}
#[test]
fn expert_encoding_landmark_codes() {
assert_eq!(EXPERT_ENCODING[b' ' as usize], 1); assert_eq!(EXPERT_ENCODING[33], 229); assert_eq!(EXPERT_ENCODING[34], 230); assert_eq!(EXPERT_ENCODING[35], 0); assert_eq!(EXPERT_ENCODING[36], 231); assert_eq!(EXPERT_ENCODING[44], 13); assert_eq!(EXPERT_ENCODING[45], 14); assert_eq!(EXPERT_ENCODING[46], 15); assert_eq!(EXPERT_ENCODING[47], 99); assert_eq!(EXPERT_ENCODING[48], 239); assert_eq!(EXPERT_ENCODING[57], 248); assert_eq!(EXPERT_ENCODING[58], 27); assert_eq!(EXPERT_ENCODING[59], 28); assert_eq!(EXPERT_ENCODING[63], 252); assert_eq!(EXPERT_ENCODING[65], 253); assert_eq!(EXPERT_ENCODING[86], 266); assert_eq!(EXPERT_ENCODING[87], 109); assert_eq!(EXPERT_ENCODING[88], 110); assert_eq!(EXPERT_ENCODING[97], 274); assert_eq!(EXPERT_ENCODING[122], 299); assert_eq!(EXPERT_ENCODING[126], 303); assert_eq!(EXPERT_ENCODING[127], 0); assert_eq!(EXPERT_ENCODING[161], 304); assert_eq!(EXPERT_ENCODING[188], 158); assert_eq!(EXPERT_ENCODING[189], 155); assert_eq!(EXPERT_ENCODING[190], 163); assert_eq!(EXPERT_ENCODING[201], 150); assert_eq!(EXPERT_ENCODING[202], 164); assert_eq!(EXPERT_ENCODING[203], 169); assert_eq!(EXPERT_ENCODING[224], 347); assert_eq!(EXPERT_ENCODING[255], 378); }
#[test]
fn expert_encoding_sids_within_standard_strings() {
for (code, &sid) in EXPERT_ENCODING.iter().enumerate() {
assert!(
sid <= 390,
"Expert Encoding code {} maps to SID {} > 390",
code,
sid,
);
}
}
#[test]
fn expert_encoding_unassigned_count_matches_spec() {
let unassigned = EXPERT_ENCODING.iter().filter(|&&s| s == 0).count();
assert_eq!(unassigned, 256 - 165);
}
#[test]
fn expert_encoding_routes_through_charset() {
let charset_payload = vec![0x00, 0xE5]; let charset = Charset::Format0 {
bytes: &charset_payload,
num_glyphs: 2,
};
let custom = Index::parse(&[0u8, 0], 0).unwrap();
let strings = Strings::new(custom);
let enc = Encoding::Expert;
assert_eq!(enc.lookup(33, &charset, &strings), Some(1));
assert_eq!(enc.lookup(34, &charset, &strings), None);
assert_eq!(enc.lookup(35, &charset, &strings), None);
}
#[test]
fn expert_encoding_routes_through_predefined_expert_charset() {
let charset = Charset::Expert;
let custom = Index::parse(&[0u8, 0], 0).unwrap();
let strings = Strings::new(custom);
let enc = Encoding::Expert;
assert_eq!(enc.lookup(32, &charset, &strings), Some(1));
assert_eq!(enc.lookup(33, &charset, &strings), Some(2));
assert_eq!(enc.lookup(255, &charset, &strings), Some(165));
assert_eq!(enc.lookup(0, &charset, &strings), None);
}
#[test]
fn expert_predefined_parses() {
let enc = Encoding::parse(&[], 1).unwrap();
assert!(matches!(enc, Encoding::Expert));
}
#[test]
fn format1_run_lookup() {
let mut table = vec![0u8; 2];
table.push(1); table.push(1); table.push(65);
table.push(2);
let enc = Encoding::parse(&table, 2).unwrap();
let charset = Charset::IsoAdobe;
let custom = Index::parse(&[0u8, 0], 0).unwrap();
let strings = Strings::new(custom);
assert_eq!(enc.lookup(65, &charset, &strings), Some(1));
assert_eq!(enc.lookup(66, &charset, &strings), Some(2));
assert_eq!(enc.lookup(67, &charset, &strings), Some(3));
assert_eq!(enc.lookup(68, &charset, &strings), None);
}
}