cff 0.5.0

A zero-allocation CFF parser.
// Copyright 2018 Kyle Mayes
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! CFF glyph encodings.

use tarrasque::{Extract, ExtractError, ExtractResult, Stream, View, extract};

use crate::error::{UNSUPPORTED};

/// The expert glyph encodings.
const EXPERT: &[(u8, u16)] = &[
    (32, 1), (33, 229), (34, 230), (36, 231), (37, 232), (38, 233), (39, 234),
    (40, 235), (41, 236), (42, 237), (43, 238), (44, 13), (45, 14), (46, 15),
    (47, 99), (48, 239), (49, 240), (50, 241), (51, 242), (52, 243), (53, 244),
    (54, 245), (55, 246), (56, 247), (57, 248), (58, 27), (59, 28), (60, 249),
    (61, 250), (62, 251), (63, 252), (65, 253), (66, 254), (67, 255), (68, 256),
    (69, 257), (73, 258), (76, 259), (77, 260), (78, 261), (79, 262), (82, 263),
    (83, 264), (84, 265), (86, 266), (87, 109), (88, 110), (89, 267), (90, 268),
    (91, 269), (93, 270), (94, 271), (95, 272), (96, 273), (97, 274), (98, 275),
    (99, 276), (100, 277), (101, 278), (102, 279), (103, 280), (104, 281),
    (105, 282), (106, 283), (107, 284), (108, 285), (109, 286), (110, 287),
    (111, 288), (112, 289), (113, 290), (114, 291), (115, 292), (116, 293),
    (117, 294), (118, 295), (119, 296), (120, 297), (121, 298), (122, 299),
    (123, 300), (124, 301), (125, 302), (126, 303), (161, 304), (162, 305),
    (163, 306), (166, 307), (167, 308), (168, 309), (169, 310), (170, 311),
    (172, 312), (175, 313), (178, 314), (179, 315), (182, 316), (183, 317),
    (184, 318), (188, 158), (189, 155), (190, 163), (191, 319), (192, 320),
    (193, 321), (194, 322), (195, 323), (196, 324), (197, 325), (200, 326),
    (201, 150), (202, 164), (203, 169), (204, 327), (205, 328), (206, 329),
    (207, 330), (208, 331), (209, 332), (210, 333), (211, 334), (212, 335),
    (213, 336), (214, 337), (215, 338), (216, 339), (217, 340), (218, 341),
    (219, 342), (220, 343), (221, 344), (222, 345), (223, 346), (224, 347),
    (225, 348), (226, 349), (227, 350), (228, 351), (229, 352), (230, 353),
    (231, 354), (232, 355), (233, 356), (234, 357), (235, 358), (236, 359),
    (237, 360), (238, 361), (239, 362), (240, 363), (241, 364), (242, 365),
    (243, 366), (244, 367), (245, 368), (246, 369), (247, 370), (248, 371),
    (249, 372), (250, 373), (251, 374), (252, 375), (253, 376), (254, 377),
    (255, 378),
];

/// The standard glyph encodings.
const STANDARD: &[u8] = &[
    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, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105,
    106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
    121, 122, 123, 124, 125, 126, 161, 162, 163, 164, 165, 166, 167, 168, 169,
    170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 182, 183, 184, 185, 186,
    187, 188, 189, 191, 193, 194, 195, 196, 197, 198, 199, 200, 202, 203, 205,
    206, 207, 208, 225, 227, 232, 233, 234, 235, 241, 245, 248, 249, 250, 251,
];

extract! {
    /// A `Format 0` list of glyph encodings.
    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
    pub struct Format0<'s> {
        /// The number of codes in this list of glyph encodings.
        pub num_codes: u8 = [],
        /// The codes in this list of glyph encodings.
        pub codes: &'s [u8] = [num_codes as usize],
    }
}

impl<'s> Format0<'s> {
    /// Returns the string ID for the supplied codepoint.
    #[inline]
    pub fn find_id(&self, codepoint: u32) -> usize {
        let code = self.codes.get(codepoint as usize).cloned();
        code.map(|i| usize::from(i) + 1).unwrap_or(0)
    }
}

extract! {
    /// A contiguous range of codes for a `Format 1` list of glyph encodings.
    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
    pub struct Range[2] {
        /// The first code in this code range.
        pub first: u8 = [],
        /// The number of codes in this code range.
        pub num_codes: u8 = [],
    }
}

extract! {
    /// A `Format 1` list of glyph encodings.
    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
    pub struct Format1<'s> {
        /// The number of code ranges in this list of glyph encodings.
        pub num_ranges: u8 = [],
        /// The code ranges in this list of glyph encodings.
        pub ranges: View<'s, Range, ()> = [(num_ranges as usize, ())],
    }
}

impl<'s> Format1<'s> {
    /// Returns the string ID for the supplied codepoint.
    #[inline]
    pub fn find_id(&self, mut codepoint: u32) -> usize {
        for range in self.ranges.iter() {
            let num_codes = u32::from(range.num_codes);
            if codepoint < num_codes {
                return range.first as usize + codepoint as usize + 1;
            }

            codepoint -= num_codes + 1;
        }

        0
    }
}

/// A list of glyph encodings.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Encodings<'s> {
    /// The `Expert` list of glyph encodings.
    Expert,
    /// A `Format 0` list of glyph encodings.
    Format0(Format0<'s>),
    /// A `Format 1` list of glyph encodings.
    Format1(Format1<'s>),
    /// The `Standard` list of glyph encodings.
    Standard,
}

impl<'s> Encodings<'s> {
    /// Returns the string ID for the supplied codepoint.
    #[inline]
    pub fn find_id(&self, codepoint: u32) -> usize {
        match self {
            Encodings::Expert => if codepoint <= 255 {
                let codepoint = codepoint as u8;
                EXPERT.binary_search_by_key(&codepoint, |e| e.0)
                    .ok()
                    .map(|i| EXPERT[i].1 as usize)
                    .unwrap_or(0)
            } else {
                0
            },
            Encodings::Format0(encodings) => encodings.find_id(codepoint),
            Encodings::Format1(encodings) => encodings.find_id(codepoint),
            Encodings::Standard => if codepoint <= 251 {
                let codepoint = codepoint as u8;
                STANDARD.binary_search(&codepoint)
                    .ok()
                    .map(|i| i + 1)
                    .unwrap_or(0)
            } else {
                0
            },
        }
    }
}

impl<'s> Extract<'s, i32> for Encodings<'s> {
    #[inline]
    fn extract(
        stream: &mut Stream<'s>, encoding: i32
    ) -> ExtractResult<'s, Self> {
        match encoding {
            0 => Ok(Encodings::Standard),
            1 => Ok(Encodings::Expert),
            _ => match stream.extract::<u8, _>(())? {
                0 => Ok(Encodings::Format0(stream.extract(())?)),
                1 => Ok(Encodings::Format1(stream.extract(())?)),
                _ => Err(ExtractError::Code(UNSUPPORTED)),
            }
        }
    }
}