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
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
//! OS/2 and Windows metrics table.
use crate::parse_prelude::*;
/// Tag for the `OS/2` table.
pub const OS2: Tag = Tag::new(b"OS/2");
/// OS/2 and Windows metrics table.
///
/// <https://docs.microsoft.com/en-us/typography/opentype/spec/os2>
pub struct Os2<'a>(Buffer<'a>);
impl<'a> Os2<'a> {
/// Creates a new OS/2 and Windows metrics table from a byte slice
/// containing the table data.
pub fn new(data: &'a [u8]) -> Self {
Self(Buffer::new(data))
}
/// Returns the version number for the OS/2 table: 0x0000 to 0x0005.
pub fn version(&self) -> u16 {
self.0.read(0).unwrap_or(0)
}
/// Returns the average advance width of all non-zero width glyphs in the
/// font.
pub fn average_char_width(&self) -> UfWord {
self.0.read(2).unwrap_or(0)
}
/// Returns the visual weight class on a scale from 1 to 1000.
/// Common values:
/// - 100: Thin
/// - 200: Extra-light (Ultra-light)
/// - 300: Light
/// - 400: Normal (Regular)
/// - 500: Medium
/// - 600: Semi-bold
/// - 700: Bold
/// - 800: Extra-bold (Ultra-bold)
/// - 900: Black (Heavy)
pub fn weight_class(&self) -> u16 {
self.0.read(4).unwrap_or(0)
}
/// Returns the visual width class-- a relative change from the normal aspect
/// ratio.
/// - 1: Ultra-condensed
/// - 2: Extra-condensed
/// - 3: Condensed
/// - 4: Semi-condensed
/// - 5: Medium (Normal)
/// - 6: Semi-expanded
/// - 7: Expanded
/// - 8: Extra-expanded
/// - 9: Ultra-expanded
pub fn width_class(&self) -> u16 {
self.0.read(6).unwrap_or(0)
}
/// Returns the font type bit flags.
/// Bits:
/// - 0-3: Usage permissions
/// - 4-7: Reserved (set to 0)
/// - 8: No subsetting
/// - 9: Bitmap embedding only
/// - 10-15: Reserved (set to 0)
pub fn type_flags(&self) -> u16 {
self.0.read(8).unwrap_or(0)
}
/// Returns the recommended horizontal size units for subscripts.
pub fn subscript_x_size(&self) -> FWord {
self.0.read(10).unwrap_or(0)
}
/// Returns the recommended vertical size units for subscripts.
pub fn subscript_y_size(&self) -> FWord {
self.0.read(12).unwrap_or(0)
}
/// Returns the recommended horizontal offset units for subscripts.
pub fn subscript_x_offset(&self) -> FWord {
self.0.read(14).unwrap_or(0)
}
/// Returns the recommended vertical offset for subscripts.
pub fn subscript_y_offset(&self) -> FWord {
self.0.read(16).unwrap_or(0)
}
/// Returns the recommended horizontal size units for subscripts.
pub fn superscript_x_size(&self) -> FWord {
self.0.read(18).unwrap_or(0)
}
/// Returns the recommended vertical size in for subscripts.
pub fn superscript_y_size(&self) -> FWord {
self.0.read(20).unwrap_or(0)
}
/// Returns the recommended horizontal offset for subscripts.
pub fn superscript_x_offset(&self) -> FWord {
self.0.read(22).unwrap_or(0)
}
/// Returns the recommended vertical offset for subscripts.
pub fn superscript_y_offset(&self) -> FWord {
self.0.read(24).unwrap_or(0)
}
/// Returns the suggested thickness for the strikeout stroke.
pub fn strikeout_size(&self) -> FWord {
self.0.read(26).unwrap_or(0)
}
/// Returns the position of the top of the strikeout stroke relative
/// to the baseline.
pub fn strikeout_position(&self) -> FWord {
self.0.read(28).unwrap_or(0)
}
/// Returns the font family class and subclass. For values:
/// <https://docs.microsoft.com/en-us/typography/opentype/spec/ibmfc>
pub fn family_class(&self) -> i16 {
self.0.read(30).unwrap_or(0)
}
/// Returns a 10-byte PANOSE classification number.
/// <https://monotype.github.io/panose/>
pub fn panose(&self) -> &[u8] {
self.0.read_bytes(32, 10).unwrap_or(&[0; 10])
}
/// Returns a 128-bit value describing the Unicode blocks that are
/// supported by the font.
pub fn unicode_range(&self) -> [u32; 4] {
[
self.0.read_u32(42).unwrap_or(0),
self.0.read_u32(46).unwrap_or(0),
self.0.read_u32(50).unwrap_or(0),
self.0.read_u32(54).unwrap_or(0),
]
}
/// Returns a four character font vendor identifier.
pub fn vendor_id(&self) -> &str {
core::str::from_utf8(
self.0
.read_bytes(58, 4)
.unwrap_or(&[b'n', b'o', b'n', b'e']),
)
.unwrap_or("none")
}
/// Returns the font selection bit flags.
/// Bits:
/// - 0: Italic
/// - 1: Underscore
/// - 2: Negative
/// - 3: Outlined
/// - 4: Strikeout
/// - 5: Bold
/// - 6: Regular
/// - 7: Use typographic metrics
/// - 8: WWS (Weight/Width/Slope names)
/// - 9: Oblique
/// - 10-15: Reserved (set to 0)
pub fn selection_flags(&self) -> u16 {
self.0.read(62).unwrap_or(0)
}
/// Returns the minimum Unicode index supported by the font.
pub fn first_char_index(&self) -> u16 {
self.0.read_u16(64).unwrap_or(0)
}
/// Returns the maximum Unicode index supported by the font.
pub fn last_char_index(&self) -> u16 {
self.0.read_u16(66).unwrap_or(0)
}
/// Returns the typographic ascender.
pub fn typographic_ascender(&self) -> FWord {
self.0.read(68).unwrap_or(0)
}
/// Returns the typographic descender.
pub fn typographic_descender(&self) -> FWord {
self.0.read(70).unwrap_or(0)
}
/// Returns the typographic line gap.
pub fn typographic_line_gap(&self) -> FWord {
self.0.read(72).unwrap_or(0)
}
/// Returns a Windows specific value that defines the upper extent of
/// the clipping region.
pub fn win_ascent(&self) -> UfWord {
self.0.read(74).unwrap_or(0)
}
/// Returns a Windows specific value that defines the lower extent of
/// the clipping region.
pub fn win_descent(&self) -> UfWord {
self.0.read(76).unwrap_or(0)
}
/// Returns Windows specific code page ranges supported by the font.
/// (table version >= 1)
pub fn code_page_range(&self) -> Option<[u32; 2]> {
if self.version() < 1 {
return None;
}
Some([
self.0.read_u32(78).unwrap_or(0),
self.0.read_u32(82).unwrap_or(0),
])
}
/// Returns the approximate distance above the baseline for non-descending
/// lowercase letters (table version >= 2)
pub fn x_height(&self) -> Option<FWord> {
if self.version() < 2 {
None
} else {
self.0.read(86)
}
}
/// Returns the approximate distance above the baseline for uppercase letters.
/// (table version >= 2)
pub fn cap_height(&self) -> Option<FWord> {
if self.version() < 2 {
None
} else {
self.0.read(88)
}
}
/// Returns a Unicode codepoint for the default character to use if
/// a requested character is not supported by the font.
/// (table version >= 2)
pub fn default_char(&self) -> Option<u16> {
if self.version() < 2 {
None
} else {
self.0.read(90)
}
}
/// Returns a Unicode codepoint for the default character used to separate
/// words and justify text. (table version >= 2)
pub fn break_char(&self) -> Option<u16> {
if self.version() < 2 {
None
} else {
self.0.read(92)
}
}
/// Returns the maximum length of a target glyph context for any feature in
/// the font. (table version >= 2)
pub fn max_context(&self) -> Option<u16> {
if self.version() < 2 {
None
} else {
self.0.read(94)
}
}
/// Returns the lower value of the size range for which this font has been
/// designed. The units are TWIPS (1/20 points). (table version >= 5)
pub fn lower_optical_point_size(&self) -> Option<u16> {
if self.version() < 5 {
None
} else {
self.0.read(96)
}
}
/// Returns the upper value of the size range for which this font has been
/// designed. The units are TWIPS (1/20 points). (table version >= 5)
pub fn upper_optical_point_size(&self) -> Option<u16> {
if self.version() < 5 {
None
} else {
self.0.read(98)
}
}
}