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
//! The result of a compilation

use write_fonts::{
    tables::{self as wtables, maxp::Maxp},
    BuilderError, FontBuilder,
};

use super::Opts;

use crate::{Diagnostic, GlyphMap};

/// The tables generated by this compilation.
///
/// All tables are optional, and the set of tables that are present depends
/// on the input file.
///
/// Each table is a type defined in the [`write-fonts`][] crate. The caller
/// may either interact with these directly, or else they may use the [`to_binary`]
/// method to generate a binary font.
///
/// [`to_binary`]: Compilation::to_binary
pub struct Compilation {
    /// Any warnings encountered during parsing or compilation
    pub warnings: Vec<Diagnostic>,
    /// The `head` table, if one was generated
    pub head: Option<wtables::head::Head>,
    /// The `hhea` table, if one was generated
    pub hhea: Option<wtables::hhea::Hhea>,
    /// The `vhea` table, if one was generated
    pub vhea: Option<wtables::vhea::Vhea>,
    /// The `OS/2` table, if one was generated
    pub os2: Option<wtables::os2::Os2>,
    /// The `GDEF` table, if one was generated
    pub gdef: Option<wtables::gdef::Gdef>,
    /// The `BASE` table, if one was generated
    pub base: Option<wtables::base::Base>,
    /// The `name` table, if one was generated
    pub name: Option<wtables::name::Name>,
    /// The `STAT` table, if one was generated
    pub stat: Option<wtables::stat::Stat>,
    /// The `GSUB` table, if one was generated
    pub gsub: Option<wtables::gsub::Gsub>,
    /// The `GPOS` table, if one was generated
    pub gpos: Option<wtables::gpos::Gpos>,
}

impl Compilation {
    /// Assemble the output tables into a `FontBuilder`.
    ///
    /// This is a convenience method. To compile a binary font you can use
    /// [`to_binary`] instead, and for more fine-grained control you can inspect
    /// and manipulate the raw tables directly.
    ///
    /// [`to_binary`]: Compilation::to_binary
    pub fn to_font_builder(&self) -> Result<FontBuilder, BuilderError> {
        let mut builder = FontBuilder::default();
        macro_rules! add_if_some {
            ($table:expr) => {
                if let Some(table) = $table.as_ref() {
                    builder.add_table(table)?;
                }
            };
        }
        add_if_some!(self.head);
        add_if_some!(self.hhea);
        add_if_some!(self.vhea);
        add_if_some!(self.os2);
        add_if_some!(self.gdef);
        add_if_some!(self.base);
        add_if_some!(self.name);
        add_if_some!(self.stat);
        add_if_some!(self.gsub);
        add_if_some!(self.gpos);
        Ok(builder)
    }

    /// Compile the output tables into a font.
    ///
    /// This is a convenience method used for things like testing; if you are
    /// building a font compiler you will probably prefer to manipulate the
    /// generated tables directly.
    pub fn to_binary(&self, glyph_map: &GlyphMap, opts: Opts) -> Result<Vec<u8>, BuilderError> {
        // because we often inspect our output with ttx, and ttx fails if maxp is
        // missing, we create a maxp table.
        let mut builder = self.to_font_builder()?;
        let maxp = Maxp::new(glyph_map.len().try_into().unwrap());
        builder.add_table(&maxp)?;
        if opts.make_post_table {
            let post = glyph_map.make_post_table();
            builder.add_table(&post)?;
        }

        Ok(builder.build())
    }
}