1
//! Top-level font file representation.
2

            
3
use std::borrow::Cow;
4

            
5
use crate::binary::read::{ReadBinary, ReadCtxt};
6
use crate::error::{ParseError, ReadWriteError};
7
use crate::tables::{
8
    FontTableProvider, OpenTypeFont, SfntVersion, CFF_MAGIC, TRUE_MAGIC, TTCF_MAGIC, TTF_MAGIC,
9
};
10
use crate::woff::{self, WoffFont};
11
use crate::woff2::{self, Woff2Font};
12

            
13
/// Type that can represent any of the supported font formats.
14
#[derive(Clone)]
15
pub enum FontData<'a> {
16
    OpenType(OpenTypeFont<'a>),
17
    Woff(WoffFont<'a>),
18
    Woff2(Woff2Font<'a>),
19
}
20

            
21
/// Generic implementation of the `FontTableProvider` trait
22
pub struct DynamicFontTableProvider<'a> {
23
    sfnt_version: u32,
24
    provider: Box<dyn FontTableProvider + Send + Sync + 'a>,
25
}
26

            
27
impl ReadBinary for FontData<'_> {
28
    type HostType<'a> = FontData<'a>;
29

            
30
51678
    fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
31
51678
        let mut peek = ctxt.clone();
32
51678
        let magic = peek.read_u32be()?;
33
51678
        match magic {
34
51678
            TTF_MAGIC | TRUE_MAGIC | CFF_MAGIC => Ok(FontData::OpenType(OpenTypeFont::read(ctxt)?)),
35
            TTCF_MAGIC => Ok(FontData::OpenType(OpenTypeFont::read(ctxt)?)),
36
            woff::MAGIC => Ok(FontData::Woff(WoffFont::read(ctxt)?)),
37
            woff2::MAGIC => Ok(FontData::Woff2(Woff2Font::read(ctxt)?)),
38
            _ => Err(ParseError::BadVersion),
39
        }
40
51678
    }
41
}
42

            
43
impl FontTableProvider for DynamicFontTableProvider<'_> {
44
49464
    fn table_data(&self, tag: u32) -> Result<Option<Cow<'_, [u8]>>, ParseError> {
45
49464
        self.provider.table_data(tag)
46
49464
    }
47

            
48
13500
    fn has_table(&self, tag: u32) -> bool {
49
13500
        self.provider.has_table(tag)
50
13500
    }
51

            
52
    fn table_tags(&self) -> Option<Vec<u32>> {
53
        self.provider.table_tags()
54
    }
55
}
56

            
57
impl SfntVersion for DynamicFontTableProvider<'_> {
58
    fn sfnt_version(&self) -> u32 {
59
        self.sfnt_version
60
    }
61
}
62

            
63
impl<'a> FontData<'a> {
64
    /// Obtain an implementation of `FontTableProvider` for this font.
65
29214
    pub fn table_provider(
66
29214
        &self,
67
29214
        index: usize,
68
29214
    ) -> Result<DynamicFontTableProvider<'a>, ReadWriteError> {
69
29214
        match self {
70
29214
            FontData::OpenType(font) => {
71
29214
                let provider = font.table_provider(index)?;
72
29214
                Ok(DynamicFontTableProvider {
73
29214
                    sfnt_version: provider.sfnt_version(),
74
29214
                    provider: Box::new(provider),
75
29214
                })
76
            }
77
            FontData::Woff(font) => {
78
                // This clone is relatively cheap as WoffFile is mostly holding borrowed data
79
                Ok(DynamicFontTableProvider {
80
                    sfnt_version: font.sfnt_version(),
81
                    provider: Box::new(font.clone()),
82
                })
83
            }
84
            FontData::Woff2(font) => {
85
                let provider = font.table_provider(index)?;
86
                Ok(DynamicFontTableProvider {
87
                    sfnt_version: provider.sfnt_version(),
88
                    provider: Box::new(provider),
89
                })
90
            }
91
        }
92
29214
    }
93
}