Skip to main content

read_fonts/tables/
gdef.rs

1//! the [GDEF] table
2//!
3//! [GDEF]: https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
4
5pub use super::layout::{ClassDef, CoverageTable, DeviceOrVariationIndex};
6
7use super::layout::header::HeaderOffset;
8use super::variations::ItemVariationStore;
9
10#[cfg(test)]
11#[path = "../tests/test_gdef.rs"]
12mod tests;
13
14use crate::types::Compatible;
15
16include!("../../generated/generated_gdef.rs");
17
18impl<'a> Gdef<'a> {
19    fn select_offset(
20        &self,
21        original: Nullable<Offset16>,
22        extended: Option<Nullable<Offset32>>,
23    ) -> Result<HeaderOffset, ReadError> {
24        HeaderOffset::select(original, extended, self.version().compatible((1, 4)))
25    }
26
27    fn resolve_selected<T: FontRead<'a, Args = ()>>(
28        &self,
29        original: Nullable<Offset16>,
30        extended: Option<Nullable<Offset32>>,
31    ) -> Option<Result<T, ReadError>> {
32        match self.select_offset(original, extended) {
33            Ok(offset) => offset.resolve(self.offset_data()),
34            Err(error) => Some(Err(error)),
35        }
36    }
37
38    /// Resolves the table, preferring its 32-bit offset when nonzero.
39    pub fn glyph_class_def(&self) -> Option<Result<ClassDef<'a>, ReadError>> {
40        self.resolve_selected(
41            self.glyph_class_def_offset(),
42            self.glyph_class_def2_offset(),
43        )
44    }
45
46    /// Resolves only the original 16-bit offset.
47    pub fn original_glyph_class_def(&self) -> Option<Result<ClassDef<'a>, ReadError>> {
48        self.glyph_class_def_offset().resolve(self.offset_data())
49    }
50
51    /// Resolves the table, preferring its 32-bit offset when nonzero.
52    pub fn attach_list(&self) -> Option<Result<AttachList<'a>, ReadError>> {
53        self.resolve_selected(self.attach_list_offset(), self.attach_list2_offset())
54    }
55
56    /// Resolves only the original 16-bit offset.
57    pub fn original_attach_list(&self) -> Option<Result<AttachList<'a>, ReadError>> {
58        self.attach_list_offset().resolve(self.offset_data())
59    }
60
61    /// Resolves the table, preferring its 32-bit offset when nonzero.
62    pub fn mark_attach_class_def(&self) -> Option<Result<ClassDef<'a>, ReadError>> {
63        self.resolve_selected(
64            self.mark_attach_class_def_offset(),
65            self.mark_attach_class_def2_offset(),
66        )
67    }
68
69    /// Resolves only the original 16-bit offset.
70    pub fn original_mark_attach_class_def(&self) -> Option<Result<ClassDef<'a>, ReadError>> {
71        self.mark_attach_class_def_offset()
72            .resolve(self.offset_data())
73    }
74
75    /// Resolves the table, preferring its 32-bit offset when nonzero.
76    pub fn mark_glyph_sets_def(&self) -> Option<Result<MarkGlyphSets<'a>, ReadError>> {
77        self.resolve_selected(
78            self.mark_glyph_sets_def_offset().unwrap_or_default(),
79            self.mark_glyph_sets_def2_offset(),
80        )
81    }
82
83    /// Resolves only the original 16-bit offset.
84    pub fn original_mark_glyph_sets_def(&self) -> Option<Result<MarkGlyphSets<'a>, ReadError>> {
85        self.mark_glyph_sets_def_offset()
86            .unwrap_or_default()
87            .resolve(self.offset_data())
88    }
89}
90
91/// LigCaretList or LigCaretList2, selected by the GDEF header.
92#[derive(Clone)]
93pub enum SelectedLigCaretList<'a> {
94    /// A LigCaretList, with 16-bit offsets.
95    Original(LigCaretList<'a>),
96    /// A LigCaretList2, with 24-bit offsets.
97    Extended(LigCaretList2<'a>),
98}
99
100impl<'a> SelectedLigCaretList<'a> {
101    /// Returns the coverage of the ligature glyphs.
102    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
103        match self {
104            Self::Original(t) => t.coverage(),
105            Self::Extended(t) => t.coverage(),
106        }
107    }
108
109    /// Returns the number of ligature glyphs.
110    pub fn lig_glyph_count(&self) -> u32 {
111        match self {
112            Self::Original(t) => u32::from(t.lig_glyph_count()),
113            Self::Extended(t) => t.lig_glyph_count().to_u32(),
114        }
115    }
116
117    /// Returns the caret tables of the ligature glyphs, in coverage order.
118    pub fn lig_glyphs(&self) -> super::layout::LayoutOffsetArray<'a, LigGlyph<'a>> {
119        match self {
120            Self::Original(t) => super::layout::LayoutOffsetArray::Offset16(t.lig_glyphs()),
121            Self::Extended(t) => super::layout::LayoutOffsetArray::Offset24(t.lig_glyphs()),
122        }
123    }
124}
125
126impl<'a> Gdef<'a> {
127    /// Resolves the ligature caret list, preferring LigCaretList2 when its
128    /// offset is nonzero.
129    pub fn lig_caret_list(&self) -> Option<Result<SelectedLigCaretList<'a>, ReadError>> {
130        let offset =
131            match self.select_offset(self.lig_caret_list_offset(), self.lig_caret_list2_offset()) {
132                Ok(offset) => offset,
133                Err(error) => return Some(Err(error)),
134            };
135        if offset.is_null() {
136            return None;
137        }
138        let data = self.offset_data();
139        Some(match offset {
140            HeaderOffset::Original(offset) => {
141                offset.resolve(data).map(SelectedLigCaretList::Original)
142            }
143            HeaderOffset::Extended(offset) => {
144                offset.resolve(data).map(SelectedLigCaretList::Extended)
145            }
146        })
147    }
148
149    /// Resolves the original 16-bit offset without applying precedence.
150    pub fn original_lig_caret_list(&self) -> Option<Result<LigCaretList<'a>, ReadError>> {
151        self.lig_caret_list_offset().resolve(self.offset_data())
152    }
153}