| 1 | //! A [Math Table](https://docs.microsoft.com/en-us/typography/opentype/spec/math) implementation. |
| 2 | |
| 3 | use crate::gpos::Device; |
| 4 | use crate::opentype_layout::Coverage; |
| 5 | use crate::parser::{ |
| 6 | FromData, FromSlice, LazyArray16, LazyOffsetArray16, Offset, Offset16, Stream, |
| 7 | }; |
| 8 | use crate::GlyphId; |
| 9 | |
| 10 | /// A [Math Value](https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathvaluerecord) |
| 11 | /// with optional device corrections. |
| 12 | #[derive (Clone, Copy, Debug)] |
| 13 | pub struct MathValue<'a> { |
| 14 | /// The X or Y value in font design units. |
| 15 | pub value: i16, |
| 16 | /// Device corrections for this value. |
| 17 | pub device: Option<Device<'a>>, |
| 18 | } |
| 19 | |
| 20 | impl<'a> MathValue<'a> { |
| 21 | fn parse(data: &'a [u8], parent: &'a [u8]) -> Option<Self> { |
| 22 | Some(MathValueRecord::parse(data)?.get(data:parent)) |
| 23 | } |
| 24 | } |
| 25 | |
| 26 | /// A math value record with unresolved offset. |
| 27 | #[derive (Clone, Copy)] |
| 28 | struct MathValueRecord { |
| 29 | value: i16, |
| 30 | device_offset: Option<Offset16>, |
| 31 | } |
| 32 | |
| 33 | impl FromData for MathValueRecord { |
| 34 | const SIZE: usize = 4; |
| 35 | |
| 36 | fn parse(data: &[u8]) -> Option<Self> { |
| 37 | let mut s: Stream<'_> = Stream::new(data); |
| 38 | let value: i16 = s.read::<i16>()?; |
| 39 | let device_offset: Option = s.read::<Option<Offset16>>()?; |
| 40 | Some(MathValueRecord { |
| 41 | value, |
| 42 | device_offset, |
| 43 | }) |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | impl MathValueRecord { |
| 48 | fn get(self, data: &[u8]) -> MathValue { |
| 49 | let device: Option> = self |
| 50 | .device_offset |
| 51 | .and_then(|offset: Offset16| data.get(index:offset.to_usize()..)) |
| 52 | .and_then(Device::parse); |
| 53 | MathValue { |
| 54 | value: self.value, |
| 55 | device, |
| 56 | } |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | /// A mapping from glyphs to |
| 61 | /// [Math Values](https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathvaluerecord). |
| 62 | #[derive (Clone, Copy)] |
| 63 | pub struct MathValues<'a> { |
| 64 | data: &'a [u8], |
| 65 | coverage: Coverage<'a>, |
| 66 | records: LazyArray16<'a, MathValueRecord>, |
| 67 | } |
| 68 | |
| 69 | impl<'a> FromSlice<'a> for MathValues<'a> { |
| 70 | fn parse(data: &'a [u8]) -> Option<Self> { |
| 71 | let mut s: Stream<'_> = Stream::new(data); |
| 72 | let coverage: Coverage<'_> = s.parse_at_offset16::<Coverage>(data)?; |
| 73 | let count: u16 = s.read::<u16>()?; |
| 74 | let records: LazyArray16<'_, MathValueRecord> = s.read_array16::<MathValueRecord>(count)?; |
| 75 | Some(MathValues { |
| 76 | data, |
| 77 | coverage, |
| 78 | records, |
| 79 | }) |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | impl<'a> MathValues<'a> { |
| 84 | /// Returns the value for the glyph or `None` if it is not covered. |
| 85 | #[inline ] |
| 86 | pub fn get(&self, glyph: GlyphId) -> Option<MathValue<'a>> { |
| 87 | let index: u16 = self.coverage.get(glyph)?; |
| 88 | Some(self.records.get(index)?.get(self.data)) |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | impl core::fmt::Debug for MathValues<'_> { |
| 93 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
| 94 | write!(f, "MathValues {{ ... }}" ) |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | /// A [Math Constants Table](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathconstants-table). |
| 99 | #[derive (Clone, Copy)] |
| 100 | pub struct Constants<'a> { |
| 101 | data: &'a [u8], |
| 102 | } |
| 103 | |
| 104 | impl<'a> FromSlice<'a> for Constants<'a> { |
| 105 | fn parse(data: &'a [u8]) -> Option<Self> { |
| 106 | Some(Constants { data }) |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | impl core::fmt::Debug for Constants<'_> { |
| 111 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
| 112 | write!(f, "Constants {{ ... }}" ) |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | const SCRIPT_PERCENT_SCALE_DOWN_OFFSET: usize = 0; |
| 117 | const SCRIPT_SCRIPT_PERCENT_SCALE_DOWN_OFFSET: usize = 2; |
| 118 | const DELIMITED_SUB_FORMULA_MIN_HEIGHT_OFFSET: usize = 4; |
| 119 | const DISPLAY_OPERATOR_MIN_HEIGHT_OFFSET: usize = 6; |
| 120 | const MATH_LEADING_OFFSET: usize = 8; |
| 121 | const AXIS_HEIGHT_OFFSET: usize = 12; |
| 122 | const ACCENT_BASE_HEIGHT_OFFSET: usize = 16; |
| 123 | const FLATTENED_ACCENT_BASE_HEIGHT_OFFSET: usize = 20; |
| 124 | const SUBSCRIPT_SHIFT_DOWN_OFFSET: usize = 24; |
| 125 | const SUBSCRIPT_TOP_MAX_OFFSET: usize = 28; |
| 126 | const SUBSCRIPT_BASELINE_DROP_MIN_OFFSET: usize = 32; |
| 127 | const SUPERSCRIPT_SHIFT_UP_OFFSET: usize = 36; |
| 128 | const SUPERSCRIPT_SHIFT_UP_CRAMPED_OFFSET: usize = 40; |
| 129 | const SUPERSCRIPT_BOTTOM_MIN_OFFSET: usize = 44; |
| 130 | const SUPERSCRIPT_BASELINE_DROP_MAX_OFFSET: usize = 48; |
| 131 | const SUB_SUPERSCRIPT_GAP_MIN_OFFSET: usize = 52; |
| 132 | const SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT_OFFSET: usize = 56; |
| 133 | const SPACE_AFTER_SCRIPT_OFFSET: usize = 60; |
| 134 | const UPPER_LIMIT_GAP_MIN_OFFSET: usize = 64; |
| 135 | const UPPER_LIMIT_BASELINE_RISE_MIN_OFFSET: usize = 68; |
| 136 | const LOWER_LIMIT_GAP_MIN_OFFSET: usize = 72; |
| 137 | const LOWER_LIMIT_BASELINE_DROP_MIN_OFFSET: usize = 76; |
| 138 | const STACK_TOP_SHIFT_UP_OFFSET: usize = 80; |
| 139 | const STACK_TOP_DISPLAY_STYLE_SHIFT_UP_OFFSET: usize = 84; |
| 140 | const STACK_BOTTOM_SHIFT_DOWN_OFFSET: usize = 88; |
| 141 | const STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN_OFFSET: usize = 92; |
| 142 | const STACK_GAP_MIN_OFFSET: usize = 96; |
| 143 | const STACK_DISPLAY_STYLE_GAP_MIN_OFFSET: usize = 100; |
| 144 | const STRETCH_STACK_TOP_SHIFT_UP_OFFSET: usize = 104; |
| 145 | const STRETCH_STACK_BOTTOM_SHIFT_DOWN_OFFSET: usize = 108; |
| 146 | const STRETCH_STACK_GAP_ABOVE_MIN_OFFSET: usize = 112; |
| 147 | const STRETCH_STACK_GAP_BELOW_MIN_OFFSET: usize = 116; |
| 148 | const FRACTION_NUMERATOR_SHIFT_UP_OFFSET: usize = 120; |
| 149 | const FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP_OFFSET: usize = 124; |
| 150 | const FRACTION_DENOMINATOR_SHIFT_DOWN_OFFSET: usize = 128; |
| 151 | const FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN_OFFSET: usize = 132; |
| 152 | const FRACTION_NUMERATOR_GAP_MIN_OFFSET: usize = 136; |
| 153 | const FRACTION_NUM_DISPLAY_STYLE_GAP_MIN_OFFSET: usize = 140; |
| 154 | const FRACTION_RULE_THICKNESS_OFFSET: usize = 144; |
| 155 | const FRACTION_DENOMINATOR_GAP_MIN_OFFSET: usize = 148; |
| 156 | const FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN_OFFSET: usize = 152; |
| 157 | const SKEWED_FRACTION_HORIZONTAL_GAP_OFFSET: usize = 156; |
| 158 | const SKEWED_FRACTION_VERTICAL_GAP_OFFSET: usize = 160; |
| 159 | const OVERBAR_VERTICAL_GAP_OFFSET: usize = 164; |
| 160 | const OVERBAR_RULE_THICKNESS_OFFSET: usize = 168; |
| 161 | const OVERBAR_EXTRA_ASCENDER_OFFSET: usize = 172; |
| 162 | const UNDERBAR_VERTICAL_GAP_OFFSET: usize = 176; |
| 163 | const UNDERBAR_RULE_THICKNESS_OFFSET: usize = 180; |
| 164 | const UNDERBAR_EXTRA_DESCENDER_OFFSET: usize = 184; |
| 165 | const RADICAL_VERTICAL_GAP_OFFSET: usize = 188; |
| 166 | const RADICAL_DISPLAY_STYLE_VERTICAL_GAP_OFFSET: usize = 192; |
| 167 | const RADICAL_RULE_THICKNESS_OFFSET: usize = 196; |
| 168 | const RADICAL_EXTRA_ASCENDER_OFFSET: usize = 200; |
| 169 | const RADICAL_KERN_BEFORE_DEGREE_OFFSET: usize = 204; |
| 170 | const RADICAL_KERN_AFTER_DEGREE_OFFSET: usize = 208; |
| 171 | const RADICAL_DEGREE_BOTTOM_RAISE_PERCENT_OFFSET: usize = 212; |
| 172 | |
| 173 | impl<'a> Constants<'a> { |
| 174 | /// Percentage of scaling down for level 1 superscripts and subscripts. |
| 175 | #[inline ] |
| 176 | pub fn script_percent_scale_down(&self) -> i16 { |
| 177 | self.read_i16(SCRIPT_PERCENT_SCALE_DOWN_OFFSET) |
| 178 | } |
| 179 | |
| 180 | /// Percentage of scaling down for level 2 (scriptScript) superscripts and subscripts. |
| 181 | #[inline ] |
| 182 | pub fn script_script_percent_scale_down(&self) -> i16 { |
| 183 | self.read_i16(SCRIPT_SCRIPT_PERCENT_SCALE_DOWN_OFFSET) |
| 184 | } |
| 185 | |
| 186 | /// Minimum height required for a delimited expression (contained within parentheses, etc.) to |
| 187 | /// be treated as a sub-formula. |
| 188 | #[inline ] |
| 189 | pub fn delimited_sub_formula_min_height(&self) -> u16 { |
| 190 | self.read_u16(DELIMITED_SUB_FORMULA_MIN_HEIGHT_OFFSET) |
| 191 | } |
| 192 | |
| 193 | /// Minimum height of n-ary operators (such as integral and summation) for formulas in display |
| 194 | /// mode (that is, appearing as standalone page elements, not embedded inline within text). |
| 195 | #[inline ] |
| 196 | pub fn display_operator_min_height(&self) -> u16 { |
| 197 | self.read_u16(DISPLAY_OPERATOR_MIN_HEIGHT_OFFSET) |
| 198 | } |
| 199 | |
| 200 | /// White space to be left between math formulas to ensure proper line spacing. |
| 201 | #[inline ] |
| 202 | pub fn math_leading(&self) -> MathValue<'a> { |
| 203 | self.read_record(MATH_LEADING_OFFSET) |
| 204 | } |
| 205 | |
| 206 | /// Axis height of the font. |
| 207 | #[inline ] |
| 208 | pub fn axis_height(&self) -> MathValue<'a> { |
| 209 | self.read_record(AXIS_HEIGHT_OFFSET) |
| 210 | } |
| 211 | |
| 212 | /// Maximum (ink) height of accent base that does not require raising the accents. |
| 213 | #[inline ] |
| 214 | pub fn accent_base_height(&self) -> MathValue<'a> { |
| 215 | self.read_record(ACCENT_BASE_HEIGHT_OFFSET) |
| 216 | } |
| 217 | |
| 218 | /// Maximum (ink) height of accent base that does not require flattening the accents. |
| 219 | #[inline ] |
| 220 | pub fn flattened_accent_base_height(&self) -> MathValue<'a> { |
| 221 | self.read_record(FLATTENED_ACCENT_BASE_HEIGHT_OFFSET) |
| 222 | } |
| 223 | |
| 224 | /// The standard shift down applied to subscript elements. |
| 225 | #[inline ] |
| 226 | pub fn subscript_shift_down(&self) -> MathValue<'a> { |
| 227 | self.read_record(SUBSCRIPT_SHIFT_DOWN_OFFSET) |
| 228 | } |
| 229 | |
| 230 | /// Maximum allowed height of the (ink) top of subscripts that does not require moving |
| 231 | /// subscripts further down. |
| 232 | #[inline ] |
| 233 | pub fn subscript_top_max(&self) -> MathValue<'a> { |
| 234 | self.read_record(SUBSCRIPT_TOP_MAX_OFFSET) |
| 235 | } |
| 236 | |
| 237 | /// Minimum allowed drop of the baseline of subscripts relative to the (ink) bottom of the |
| 238 | /// base. |
| 239 | #[inline ] |
| 240 | pub fn subscript_baseline_drop_min(&self) -> MathValue<'a> { |
| 241 | self.read_record(SUBSCRIPT_BASELINE_DROP_MIN_OFFSET) |
| 242 | } |
| 243 | |
| 244 | /// Standard shift up applied to superscript elements. |
| 245 | #[inline ] |
| 246 | pub fn superscript_shift_up(&self) -> MathValue<'a> { |
| 247 | self.read_record(SUPERSCRIPT_SHIFT_UP_OFFSET) |
| 248 | } |
| 249 | |
| 250 | /// Standard shift of superscripts relative to the base, in cramped style. |
| 251 | #[inline ] |
| 252 | pub fn superscript_shift_up_cramped(&self) -> MathValue<'a> { |
| 253 | self.read_record(SUPERSCRIPT_SHIFT_UP_CRAMPED_OFFSET) |
| 254 | } |
| 255 | |
| 256 | /// Minimum allowed height of the (ink) bottom of superscripts that does not require moving |
| 257 | /// subscripts further up. |
| 258 | #[inline ] |
| 259 | pub fn superscript_bottom_min(&self) -> MathValue<'a> { |
| 260 | self.read_record(SUPERSCRIPT_BOTTOM_MIN_OFFSET) |
| 261 | } |
| 262 | |
| 263 | /// Maximum allowed drop of the baseline of superscripts relative to the (ink) top of the |
| 264 | /// base. |
| 265 | #[inline ] |
| 266 | pub fn superscript_baseline_drop_max(&self) -> MathValue<'a> { |
| 267 | self.read_record(SUPERSCRIPT_BASELINE_DROP_MAX_OFFSET) |
| 268 | } |
| 269 | |
| 270 | /// Minimum gap between the superscript and subscript ink. |
| 271 | #[inline ] |
| 272 | pub fn sub_superscript_gap_min(&self) -> MathValue<'a> { |
| 273 | self.read_record(SUB_SUPERSCRIPT_GAP_MIN_OFFSET) |
| 274 | } |
| 275 | |
| 276 | /// The maximum level to which the (ink) bottom of superscript can be pushed to increase the |
| 277 | /// gap between superscript and subscript, before subscript starts being moved down. |
| 278 | #[inline ] |
| 279 | pub fn superscript_bottom_max_with_subscript(&self) -> MathValue<'a> { |
| 280 | self.read_record(SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT_OFFSET) |
| 281 | } |
| 282 | |
| 283 | /// Extra white space to be added after each subscript and superscript. |
| 284 | #[inline ] |
| 285 | pub fn space_after_script(&self) -> MathValue<'a> { |
| 286 | self.read_record(SPACE_AFTER_SCRIPT_OFFSET) |
| 287 | } |
| 288 | |
| 289 | /// Minimum gap between the (ink) bottom of the upper limit, and the (ink) top of the base |
| 290 | /// operator. |
| 291 | #[inline ] |
| 292 | pub fn upper_limit_gap_min(&self) -> MathValue<'a> { |
| 293 | self.read_record(UPPER_LIMIT_GAP_MIN_OFFSET) |
| 294 | } |
| 295 | |
| 296 | /// Minimum distance between baseline of upper limit and (ink) top of the base operator. |
| 297 | #[inline ] |
| 298 | pub fn upper_limit_baseline_rise_min(&self) -> MathValue<'a> { |
| 299 | self.read_record(UPPER_LIMIT_BASELINE_RISE_MIN_OFFSET) |
| 300 | } |
| 301 | |
| 302 | /// Minimum gap between (ink) top of the lower limit, and (ink) bottom of the base operator. |
| 303 | #[inline ] |
| 304 | pub fn lower_limit_gap_min(&self) -> MathValue<'a> { |
| 305 | self.read_record(LOWER_LIMIT_GAP_MIN_OFFSET) |
| 306 | } |
| 307 | |
| 308 | /// Minimum distance between baseline of the lower limit and (ink) bottom of the base operator. |
| 309 | #[inline ] |
| 310 | pub fn lower_limit_baseline_drop_min(&self) -> MathValue<'a> { |
| 311 | self.read_record(LOWER_LIMIT_BASELINE_DROP_MIN_OFFSET) |
| 312 | } |
| 313 | |
| 314 | /// Standard shift up applied to the top element of a stack. |
| 315 | #[inline ] |
| 316 | pub fn stack_top_shift_up(&self) -> MathValue<'a> { |
| 317 | self.read_record(STACK_TOP_SHIFT_UP_OFFSET) |
| 318 | } |
| 319 | |
| 320 | /// Standard shift up applied to the top element of a stack in display style. |
| 321 | #[inline ] |
| 322 | pub fn stack_top_display_style_shift_up(&self) -> MathValue<'a> { |
| 323 | self.read_record(STACK_TOP_DISPLAY_STYLE_SHIFT_UP_OFFSET) |
| 324 | } |
| 325 | |
| 326 | /// Standard shift down applied to the bottom element of a stack. |
| 327 | #[inline ] |
| 328 | pub fn stack_bottom_shift_down(&self) -> MathValue<'a> { |
| 329 | self.read_record(STACK_BOTTOM_SHIFT_DOWN_OFFSET) |
| 330 | } |
| 331 | |
| 332 | /// Standard shift down applied to the bottom element of a stack in display style. |
| 333 | #[inline ] |
| 334 | pub fn stack_bottom_display_style_shift_down(&self) -> MathValue<'a> { |
| 335 | self.read_record(STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN_OFFSET) |
| 336 | } |
| 337 | |
| 338 | /// Minimum gap between (ink) bottom of the top element of a stack, and the (ink) top of the |
| 339 | /// bottom element. |
| 340 | #[inline ] |
| 341 | pub fn stack_gap_min(&self) -> MathValue<'a> { |
| 342 | self.read_record(STACK_GAP_MIN_OFFSET) |
| 343 | } |
| 344 | |
| 345 | /// Minimum gap between (ink) bottom of the top element of a stack, and the (ink) top of the |
| 346 | /// bottom element in display style. |
| 347 | #[inline ] |
| 348 | pub fn stack_display_style_gap_min(&self) -> MathValue<'a> { |
| 349 | self.read_record(STACK_DISPLAY_STYLE_GAP_MIN_OFFSET) |
| 350 | } |
| 351 | |
| 352 | /// Standard shift up applied to the top element of the stretch stack. |
| 353 | #[inline ] |
| 354 | pub fn stretch_stack_top_shift_up(&self) -> MathValue<'a> { |
| 355 | self.read_record(STRETCH_STACK_TOP_SHIFT_UP_OFFSET) |
| 356 | } |
| 357 | |
| 358 | /// Standard shift down applied to the bottom element of the stretch stack. |
| 359 | #[inline ] |
| 360 | pub fn stretch_stack_bottom_shift_down(&self) -> MathValue<'a> { |
| 361 | self.read_record(STRETCH_STACK_BOTTOM_SHIFT_DOWN_OFFSET) |
| 362 | } |
| 363 | |
| 364 | /// Minimum gap between the ink of the stretched element, and the (ink) bottom of the element above. |
| 365 | #[inline ] |
| 366 | pub fn stretch_stack_gap_above_min(&self) -> MathValue<'a> { |
| 367 | self.read_record(STRETCH_STACK_GAP_ABOVE_MIN_OFFSET) |
| 368 | } |
| 369 | |
| 370 | /// Minimum gap between the ink of the stretched element, and the (ink) top of the element below. |
| 371 | #[inline ] |
| 372 | pub fn stretch_stack_gap_below_min(&self) -> MathValue<'a> { |
| 373 | self.read_record(STRETCH_STACK_GAP_BELOW_MIN_OFFSET) |
| 374 | } |
| 375 | |
| 376 | /// Standard shift up applied to the numerator. |
| 377 | #[inline ] |
| 378 | pub fn fraction_numerator_shift_up(&self) -> MathValue<'a> { |
| 379 | self.read_record(FRACTION_NUMERATOR_SHIFT_UP_OFFSET) |
| 380 | } |
| 381 | |
| 382 | /// Standard shift up applied to the numerator in display style. |
| 383 | #[inline ] |
| 384 | pub fn fraction_numerator_display_style_shift_up(&self) -> MathValue<'a> { |
| 385 | self.read_record(FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP_OFFSET) |
| 386 | } |
| 387 | |
| 388 | /// Standard shift down applied to the denominator. |
| 389 | #[inline ] |
| 390 | pub fn fraction_denominator_shift_down(&self) -> MathValue<'a> { |
| 391 | self.read_record(FRACTION_DENOMINATOR_SHIFT_DOWN_OFFSET) |
| 392 | } |
| 393 | |
| 394 | /// Standard shift down applied to the denominator in display style. |
| 395 | #[inline ] |
| 396 | pub fn fraction_denominator_display_style_shift_down(&self) -> MathValue<'a> { |
| 397 | self.read_record(FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN_OFFSET) |
| 398 | } |
| 399 | |
| 400 | /// Minimum tolerated gap between the (ink) bottom of the numerator and the ink of the |
| 401 | /// fraction bar. |
| 402 | #[inline ] |
| 403 | pub fn fraction_numerator_gap_min(&self) -> MathValue<'a> { |
| 404 | self.read_record(FRACTION_NUMERATOR_GAP_MIN_OFFSET) |
| 405 | } |
| 406 | |
| 407 | /// Minimum tolerated gap between the (ink) bottom of the numerator and the ink of the |
| 408 | /// fraction bar in display style. |
| 409 | #[inline ] |
| 410 | pub fn fraction_num_display_style_gap_min(&self) -> MathValue<'a> { |
| 411 | self.read_record(FRACTION_NUM_DISPLAY_STYLE_GAP_MIN_OFFSET) |
| 412 | } |
| 413 | |
| 414 | /// Thickness of the fraction bar. |
| 415 | #[inline ] |
| 416 | pub fn fraction_rule_thickness(&self) -> MathValue<'a> { |
| 417 | self.read_record(FRACTION_RULE_THICKNESS_OFFSET) |
| 418 | } |
| 419 | |
| 420 | /// Minimum tolerated gap between the (ink) top of the denominator and the ink of the fraction bar. |
| 421 | #[inline ] |
| 422 | pub fn fraction_denominator_gap_min(&self) -> MathValue<'a> { |
| 423 | self.read_record(FRACTION_DENOMINATOR_GAP_MIN_OFFSET) |
| 424 | } |
| 425 | |
| 426 | /// Minimum tolerated gap between the (ink) top of the denominator and the ink of the fraction |
| 427 | /// bar in display style. |
| 428 | #[inline ] |
| 429 | pub fn fraction_denom_display_style_gap_min(&self) -> MathValue<'a> { |
| 430 | self.read_record(FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN_OFFSET) |
| 431 | } |
| 432 | |
| 433 | /// Horizontal distance between the top and bottom elements of a skewed fraction. |
| 434 | #[inline ] |
| 435 | pub fn skewed_fraction_horizontal_gap(&self) -> MathValue<'a> { |
| 436 | self.read_record(SKEWED_FRACTION_HORIZONTAL_GAP_OFFSET) |
| 437 | } |
| 438 | |
| 439 | /// Vertical distance between the ink of the top and bottom elements of a skewed fraction. |
| 440 | #[inline ] |
| 441 | pub fn skewed_fraction_vertical_gap(&self) -> MathValue<'a> { |
| 442 | self.read_record(SKEWED_FRACTION_VERTICAL_GAP_OFFSET) |
| 443 | } |
| 444 | |
| 445 | /// Distance between the overbar and the (ink) top of he base. |
| 446 | #[inline ] |
| 447 | pub fn overbar_vertical_gap(&self) -> MathValue<'a> { |
| 448 | self.read_record(OVERBAR_VERTICAL_GAP_OFFSET) |
| 449 | } |
| 450 | |
| 451 | /// Thickness of overbar. |
| 452 | #[inline ] |
| 453 | pub fn overbar_rule_thickness(&self) -> MathValue<'a> { |
| 454 | self.read_record(OVERBAR_RULE_THICKNESS_OFFSET) |
| 455 | } |
| 456 | |
| 457 | /// Extra white space reserved above the overbar. |
| 458 | #[inline ] |
| 459 | pub fn overbar_extra_ascender(&self) -> MathValue<'a> { |
| 460 | self.read_record(OVERBAR_EXTRA_ASCENDER_OFFSET) |
| 461 | } |
| 462 | |
| 463 | /// Distance between underbar and (ink) bottom of the base. |
| 464 | #[inline ] |
| 465 | pub fn underbar_vertical_gap(&self) -> MathValue<'a> { |
| 466 | self.read_record(UNDERBAR_VERTICAL_GAP_OFFSET) |
| 467 | } |
| 468 | |
| 469 | /// Thickness of underbar. |
| 470 | #[inline ] |
| 471 | pub fn underbar_rule_thickness(&self) -> MathValue<'a> { |
| 472 | self.read_record(UNDERBAR_RULE_THICKNESS_OFFSET) |
| 473 | } |
| 474 | |
| 475 | /// Extra white space reserved below the underbar. |
| 476 | #[inline ] |
| 477 | pub fn underbar_extra_descender(&self) -> MathValue<'a> { |
| 478 | self.read_record(UNDERBAR_EXTRA_DESCENDER_OFFSET) |
| 479 | } |
| 480 | |
| 481 | /// Space between the (ink) top of the expression and the bar over it. |
| 482 | #[inline ] |
| 483 | pub fn radical_vertical_gap(&self) -> MathValue<'a> { |
| 484 | self.read_record(RADICAL_VERTICAL_GAP_OFFSET) |
| 485 | } |
| 486 | |
| 487 | /// Space between the (ink) top of the expression and the bar over it. |
| 488 | #[inline ] |
| 489 | pub fn radical_display_style_vertical_gap(&self) -> MathValue<'a> { |
| 490 | self.read_record(RADICAL_DISPLAY_STYLE_VERTICAL_GAP_OFFSET) |
| 491 | } |
| 492 | |
| 493 | /// Thickness of the radical rule. |
| 494 | #[inline ] |
| 495 | pub fn radical_rule_thickness(&self) -> MathValue<'a> { |
| 496 | self.read_record(RADICAL_RULE_THICKNESS_OFFSET) |
| 497 | } |
| 498 | |
| 499 | /// Extra white space reserved above the radical. |
| 500 | #[inline ] |
| 501 | pub fn radical_extra_ascender(&self) -> MathValue<'a> { |
| 502 | self.read_record(RADICAL_EXTRA_ASCENDER_OFFSET) |
| 503 | } |
| 504 | |
| 505 | /// Extra horizontal kern before the degree of a radical, if such is present. |
| 506 | #[inline ] |
| 507 | pub fn radical_kern_before_degree(&self) -> MathValue<'a> { |
| 508 | self.read_record(RADICAL_KERN_BEFORE_DEGREE_OFFSET) |
| 509 | } |
| 510 | |
| 511 | /// Negative kern after the degree of a radical, if such is present. |
| 512 | #[inline ] |
| 513 | pub fn radical_kern_after_degree(&self) -> MathValue<'a> { |
| 514 | self.read_record(RADICAL_KERN_AFTER_DEGREE_OFFSET) |
| 515 | } |
| 516 | |
| 517 | /// Height of the bottom of the radical degree, if such is present, in proportion to the |
| 518 | /// ascender of the radical sign. |
| 519 | #[inline ] |
| 520 | pub fn radical_degree_bottom_raise_percent(&self) -> i16 { |
| 521 | self.read_i16(RADICAL_DEGREE_BOTTOM_RAISE_PERCENT_OFFSET) |
| 522 | } |
| 523 | |
| 524 | /// Read an `i16` at an offset into the table. |
| 525 | #[inline ] |
| 526 | fn read_i16(&self, offset: usize) -> i16 { |
| 527 | Stream::read_at(self.data, offset).unwrap_or(0) |
| 528 | } |
| 529 | |
| 530 | /// Read an `u16` at an offset into the table. |
| 531 | #[inline ] |
| 532 | fn read_u16(&self, offset: usize) -> u16 { |
| 533 | Stream::read_at(self.data, offset).unwrap_or(0) |
| 534 | } |
| 535 | |
| 536 | /// Read a `MathValueRecord` at an offset into the table. |
| 537 | #[inline ] |
| 538 | fn read_record(&self, offset: usize) -> MathValue<'a> { |
| 539 | self.data |
| 540 | .get(offset..) |
| 541 | .and_then(|data| MathValue::parse(data, self.data)) |
| 542 | .unwrap_or(MathValue { |
| 543 | value: 0, |
| 544 | device: None, |
| 545 | }) |
| 546 | } |
| 547 | } |
| 548 | |
| 549 | /// A [Math Kern Table](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathkern-table). |
| 550 | #[derive (Clone)] |
| 551 | pub struct Kern<'a> { |
| 552 | data: &'a [u8], |
| 553 | heights: LazyArray16<'a, MathValueRecord>, |
| 554 | kerns: LazyArray16<'a, MathValueRecord>, |
| 555 | } |
| 556 | |
| 557 | impl<'a> Kern<'a> { |
| 558 | /// Number of heights at which the kern value changes. |
| 559 | pub fn count(&self) -> u16 { |
| 560 | self.heights.len() |
| 561 | } |
| 562 | |
| 563 | /// The correction height at the given index. |
| 564 | /// |
| 565 | /// The index must be smaller than `count()`. |
| 566 | pub fn height(&self, index: u16) -> Option<MathValue<'a>> { |
| 567 | Some(self.heights.get(index)?.get(self.data)) |
| 568 | } |
| 569 | |
| 570 | /// The kern value at the given index. |
| 571 | /// |
| 572 | /// The index must be smaller than or equal to `count()`. |
| 573 | pub fn kern(&self, index: u16) -> Option<MathValue<'a>> { |
| 574 | Some(self.kerns.get(index)?.get(self.data)) |
| 575 | } |
| 576 | } |
| 577 | |
| 578 | impl<'a> FromSlice<'a> for Kern<'a> { |
| 579 | fn parse(data: &'a [u8]) -> Option<Self> { |
| 580 | let mut s: Stream<'_> = Stream::new(data); |
| 581 | let count: u16 = s.read::<u16>()?; |
| 582 | let heights: LazyArray16<'_, MathValueRecord> = s.read_array16::<MathValueRecord>(count)?; |
| 583 | let kerns: LazyArray16<'_, MathValueRecord> = s.read_array16::<MathValueRecord>(count:count + 1)?; |
| 584 | Some(Kern { |
| 585 | data, |
| 586 | heights, |
| 587 | kerns, |
| 588 | }) |
| 589 | } |
| 590 | } |
| 591 | |
| 592 | impl core::fmt::Debug for Kern<'_> { |
| 593 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
| 594 | write!(f, "Kern {{ ... }}" ) |
| 595 | } |
| 596 | } |
| 597 | |
| 598 | #[derive (Clone, Copy)] |
| 599 | struct KernInfoRecord { |
| 600 | top_right: Option<Offset16>, |
| 601 | top_left: Option<Offset16>, |
| 602 | bottom_right: Option<Offset16>, |
| 603 | bottom_left: Option<Offset16>, |
| 604 | } |
| 605 | |
| 606 | impl FromData for KernInfoRecord { |
| 607 | const SIZE: usize = 8; |
| 608 | |
| 609 | fn parse(data: &[u8]) -> Option<Self> { |
| 610 | let mut s: Stream<'_> = Stream::new(data); |
| 611 | Some(KernInfoRecord { |
| 612 | top_right: s.read::<Option<Offset16>>()?, |
| 613 | top_left: s.read::<Option<Offset16>>()?, |
| 614 | bottom_right: s.read::<Option<Offset16>>()?, |
| 615 | bottom_left: s.read::<Option<Offset16>>()?, |
| 616 | }) |
| 617 | } |
| 618 | } |
| 619 | |
| 620 | impl KernInfoRecord { |
| 621 | fn get<'a>(&self, data: &'a [u8]) -> KernInfo<'a> { |
| 622 | let parse_field: impl Fn(Option) -> … = |offset: Option<Offset16>| { |
| 623 | offsetOption<&[u8]> |
| 624 | .and_then(|offset: Offset16| data.get(index:offset.to_usize()..)) |
| 625 | .and_then(Kern::parse) |
| 626 | }; |
| 627 | KernInfo { |
| 628 | top_right: parse_field(self.top_right), |
| 629 | top_left: parse_field(self.top_left), |
| 630 | bottom_right: parse_field(self.bottom_right), |
| 631 | bottom_left: parse_field(self.bottom_left), |
| 632 | } |
| 633 | } |
| 634 | } |
| 635 | |
| 636 | /// An [entry in a Math Kern Info Table]( |
| 637 | /// https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathkerninforecord). |
| 638 | #[derive (Clone, Debug)] |
| 639 | pub struct KernInfo<'a> { |
| 640 | /// The kerning data for the top-right corner. |
| 641 | pub top_right: Option<Kern<'a>>, |
| 642 | /// The kerning data for the top-left corner. |
| 643 | pub top_left: Option<Kern<'a>>, |
| 644 | /// The kerning data for the bottom-right corner. |
| 645 | pub bottom_right: Option<Kern<'a>>, |
| 646 | /// The kerning data for the bottom-left corner. |
| 647 | pub bottom_left: Option<Kern<'a>>, |
| 648 | } |
| 649 | |
| 650 | /// A [Math Kern Info Table](https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathkerninfo-table). |
| 651 | #[derive (Clone, Copy)] |
| 652 | pub struct KernInfos<'a> { |
| 653 | data: &'a [u8], |
| 654 | coverage: Coverage<'a>, |
| 655 | records: LazyArray16<'a, KernInfoRecord>, |
| 656 | } |
| 657 | |
| 658 | impl<'a> FromSlice<'a> for KernInfos<'a> { |
| 659 | fn parse(data: &'a [u8]) -> Option<Self> { |
| 660 | let mut s: Stream<'_> = Stream::new(data); |
| 661 | let coverage: Coverage<'_> = s.parse_at_offset16::<Coverage>(data)?; |
| 662 | let count: u16 = s.read::<u16>()?; |
| 663 | let records: LazyArray16<'_, KernInfoRecord> = s.read_array16::<KernInfoRecord>(count)?; |
| 664 | Some(KernInfos { |
| 665 | data, |
| 666 | coverage, |
| 667 | records, |
| 668 | }) |
| 669 | } |
| 670 | } |
| 671 | |
| 672 | impl<'a> KernInfos<'a> { |
| 673 | /// Returns the kerning info for the glyph or `None` if it is not covered. |
| 674 | #[inline ] |
| 675 | pub fn get(&self, glyph: GlyphId) -> Option<KernInfo<'a>> { |
| 676 | let index: u16 = self.coverage.get(glyph)?; |
| 677 | Some(self.records.get(index)?.get(self.data)) |
| 678 | } |
| 679 | } |
| 680 | |
| 681 | impl core::fmt::Debug for KernInfos<'_> { |
| 682 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
| 683 | write!(f, "KernInfos {{ ... }}" ) |
| 684 | } |
| 685 | } |
| 686 | |
| 687 | /// A [Math Glyph Info Table](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathglyphinfo-table). |
| 688 | #[derive (Clone, Copy, Debug)] |
| 689 | pub struct GlyphInfo<'a> { |
| 690 | /// Per-glyph italics correction values. |
| 691 | pub italic_corrections: Option<MathValues<'a>>, |
| 692 | /// Per-glyph horizontal positions for attaching mathematical accents. |
| 693 | pub top_accent_attachments: Option<MathValues<'a>>, |
| 694 | /// Glyphs which are _extended shapes_. |
| 695 | pub extended_shapes: Option<Coverage<'a>>, |
| 696 | /// Per-glyph information for mathematical kerning. |
| 697 | pub kern_infos: Option<KernInfos<'a>>, |
| 698 | } |
| 699 | |
| 700 | impl<'a> FromSlice<'a> for GlyphInfo<'a> { |
| 701 | fn parse(data: &'a [u8]) -> Option<Self> { |
| 702 | let mut s: Stream<'_> = Stream::new(data); |
| 703 | Some(GlyphInfo { |
| 704 | italic_corrections: s.parse_at_offset16::<MathValues>(data), |
| 705 | top_accent_attachments: s.parse_at_offset16::<MathValues>(data), |
| 706 | extended_shapes: s.parse_at_offset16::<Coverage>(data), |
| 707 | kern_infos: s.parse_at_offset16::<KernInfos>(data), |
| 708 | }) |
| 709 | } |
| 710 | } |
| 711 | |
| 712 | /// Glyph part flags. |
| 713 | #[derive (Clone, Copy, Debug)] |
| 714 | pub struct PartFlags(pub u16); |
| 715 | |
| 716 | #[allow (missing_docs)] |
| 717 | impl PartFlags { |
| 718 | #[inline ] |
| 719 | pub fn extender(self) -> bool { |
| 720 | self.0 & 0x0001 != 0 |
| 721 | } |
| 722 | } |
| 723 | |
| 724 | impl FromData for PartFlags { |
| 725 | const SIZE: usize = 2; |
| 726 | |
| 727 | fn parse(data: &[u8]) -> Option<Self> { |
| 728 | u16::parse(data).map(PartFlags) |
| 729 | } |
| 730 | } |
| 731 | |
| 732 | /// Details for a glyph part in an assembly. |
| 733 | #[derive (Clone, Copy, Debug)] |
| 734 | pub struct GlyphPart { |
| 735 | /// Glyph ID for the part. |
| 736 | pub glyph_id: GlyphId, |
| 737 | /// Lengths of the connectors on the start of the glyph, in font design units. |
| 738 | pub start_connector_length: u16, |
| 739 | /// Lengths of the connectors on the end of the glyph, in font design units. |
| 740 | pub end_connector_length: u16, |
| 741 | /// The full advance of the part, in font design units. |
| 742 | pub full_advance: u16, |
| 743 | /// Part flags. |
| 744 | pub part_flags: PartFlags, |
| 745 | } |
| 746 | |
| 747 | impl FromData for GlyphPart { |
| 748 | const SIZE: usize = 10; |
| 749 | |
| 750 | fn parse(data: &[u8]) -> Option<Self> { |
| 751 | let mut s: Stream<'_> = Stream::new(data); |
| 752 | Some(GlyphPart { |
| 753 | glyph_id: s.read::<GlyphId>()?, |
| 754 | start_connector_length: s.read::<u16>()?, |
| 755 | end_connector_length: s.read::<u16>()?, |
| 756 | full_advance: s.read::<u16>()?, |
| 757 | part_flags: s.read::<PartFlags>()?, |
| 758 | }) |
| 759 | } |
| 760 | } |
| 761 | |
| 762 | /// A [Glyph Assembly Table](https://learn.microsoft.com/en-us/typography/opentype/spec/math#glyphassembly-table). |
| 763 | #[derive (Clone, Copy, Debug)] |
| 764 | pub struct GlyphAssembly<'a> { |
| 765 | /// The italics correction of the assembled glyph. |
| 766 | pub italics_correction: MathValue<'a>, |
| 767 | /// Parts the assembly is composed of. |
| 768 | pub parts: LazyArray16<'a, GlyphPart>, |
| 769 | } |
| 770 | |
| 771 | impl<'a> FromSlice<'a> for GlyphAssembly<'a> { |
| 772 | fn parse(data: &'a [u8]) -> Option<Self> { |
| 773 | let mut s: Stream<'_> = Stream::new(data); |
| 774 | let italics_correction: MathValue<'_> = s.read::<MathValueRecord>()?.get(data); |
| 775 | let count: u16 = s.read::<u16>()?; |
| 776 | let parts: LazyArray16<'_, GlyphPart> = s.read_array16::<GlyphPart>(count)?; |
| 777 | Some(GlyphAssembly { |
| 778 | italics_correction, |
| 779 | parts, |
| 780 | }) |
| 781 | } |
| 782 | } |
| 783 | |
| 784 | /// Description of math glyph variants. |
| 785 | #[derive (Clone, Copy, Debug)] |
| 786 | pub struct GlyphVariant { |
| 787 | /// The ID of the variant glyph. |
| 788 | pub variant_glyph: GlyphId, |
| 789 | /// Advance width/height, in design units, of the variant glyph. |
| 790 | pub advance_measurement: u16, |
| 791 | } |
| 792 | |
| 793 | impl FromData for GlyphVariant { |
| 794 | const SIZE: usize = 4; |
| 795 | |
| 796 | fn parse(data: &[u8]) -> Option<Self> { |
| 797 | let mut s: Stream<'_> = Stream::new(data); |
| 798 | Some(GlyphVariant { |
| 799 | variant_glyph: s.read::<GlyphId>()?, |
| 800 | advance_measurement: s.read::<u16>()?, |
| 801 | }) |
| 802 | } |
| 803 | } |
| 804 | |
| 805 | /// A [Math Glyph Construction Table]( |
| 806 | /// https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathglyphconstruction-table). |
| 807 | #[derive (Clone, Copy, Debug)] |
| 808 | pub struct GlyphConstruction<'a> { |
| 809 | /// A general recipe on how to construct a variant with large advance width/height. |
| 810 | pub assembly: Option<GlyphAssembly<'a>>, |
| 811 | /// Prepared variants of the glyph with varying advances. |
| 812 | pub variants: LazyArray16<'a, GlyphVariant>, |
| 813 | } |
| 814 | |
| 815 | impl<'a> FromSlice<'a> for GlyphConstruction<'a> { |
| 816 | fn parse(data: &'a [u8]) -> Option<Self> { |
| 817 | let mut s: Stream<'_> = Stream::new(data); |
| 818 | let assembly: Option> = s.parse_at_offset16::<GlyphAssembly>(data); |
| 819 | let variant_count: u16 = s.read::<u16>()?; |
| 820 | let variants: LazyArray16<'_, GlyphVariant> = s.read_array16::<GlyphVariant>(variant_count)?; |
| 821 | Some(GlyphConstruction { assembly, variants }) |
| 822 | } |
| 823 | } |
| 824 | |
| 825 | /// A mapping from glyphs to |
| 826 | /// [Math Glyph Construction Tables]( |
| 827 | /// https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathglyphconstruction-table). |
| 828 | #[derive (Clone, Copy)] |
| 829 | pub struct GlyphConstructions<'a> { |
| 830 | coverage: Coverage<'a>, |
| 831 | constructions: LazyOffsetArray16<'a, GlyphConstruction<'a>>, |
| 832 | } |
| 833 | |
| 834 | impl<'a> GlyphConstructions<'a> { |
| 835 | fn new( |
| 836 | data: &'a [u8], |
| 837 | coverage: Option<Coverage<'a>>, |
| 838 | offsets: LazyArray16<'a, Option<Offset16>>, |
| 839 | ) -> Self { |
| 840 | GlyphConstructions { |
| 841 | coverage: coverage.unwrap_or(default:Coverage::Format1 { |
| 842 | glyphs: LazyArray16::new(&[]), |
| 843 | }), |
| 844 | constructions: LazyOffsetArray16::new(data, offsets), |
| 845 | } |
| 846 | } |
| 847 | |
| 848 | /// Returns the construction for the glyph or `None` if it is not covered. |
| 849 | #[inline ] |
| 850 | pub fn get(&self, glyph: GlyphId) -> Option<GlyphConstruction<'a>> { |
| 851 | let index: u16 = self.coverage.get(glyph)?; |
| 852 | self.constructions.get(index) |
| 853 | } |
| 854 | } |
| 855 | |
| 856 | impl core::fmt::Debug for GlyphConstructions<'_> { |
| 857 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
| 858 | write!(f, "GlyphConstructions {{ ... }}" ) |
| 859 | } |
| 860 | } |
| 861 | |
| 862 | /// A [Math Variants Table]( |
| 863 | /// https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathvariants-table). |
| 864 | #[derive (Clone, Copy, Debug)] |
| 865 | pub struct Variants<'a> { |
| 866 | /// Minimum overlap of connecting glyphs during glyph construction, in design units. |
| 867 | pub min_connector_overlap: u16, |
| 868 | /// Constructions for shapes growing in the vertical direction. |
| 869 | pub vertical_constructions: GlyphConstructions<'a>, |
| 870 | /// Constructions for shapes growing in the horizontal direction. |
| 871 | pub horizontal_constructions: GlyphConstructions<'a>, |
| 872 | } |
| 873 | |
| 874 | impl<'a> FromSlice<'a> for Variants<'a> { |
| 875 | fn parse(data: &'a [u8]) -> Option<Self> { |
| 876 | let mut s = Stream::new(data); |
| 877 | let min_connector_overlap = s.read::<u16>()?; |
| 878 | let vertical_coverage = s.parse_at_offset16::<Coverage>(data); |
| 879 | let horizontal_coverage = s.parse_at_offset16::<Coverage>(data); |
| 880 | let vertical_count = s.read::<u16>()?; |
| 881 | let horizontal_count = s.read::<u16>()?; |
| 882 | let vertical_offsets = s.read_array16::<Option<Offset16>>(vertical_count)?; |
| 883 | let horizontal_offsets = s.read_array16::<Option<Offset16>>(horizontal_count)?; |
| 884 | Some(Variants { |
| 885 | min_connector_overlap, |
| 886 | vertical_constructions: GlyphConstructions::new( |
| 887 | data, |
| 888 | vertical_coverage, |
| 889 | vertical_offsets, |
| 890 | ), |
| 891 | horizontal_constructions: GlyphConstructions::new( |
| 892 | data, |
| 893 | horizontal_coverage, |
| 894 | horizontal_offsets, |
| 895 | ), |
| 896 | }) |
| 897 | } |
| 898 | } |
| 899 | |
| 900 | /// A [Math Table](https://docs.microsoft.com/en-us/typography/opentype/spec/math). |
| 901 | #[derive (Clone, Copy, Debug)] |
| 902 | pub struct Table<'a> { |
| 903 | /// Math positioning constants. |
| 904 | pub constants: Option<Constants<'a>>, |
| 905 | /// Per-glyph positioning information. |
| 906 | pub glyph_info: Option<GlyphInfo<'a>>, |
| 907 | /// Variants and assembly recipes for growable glyphs. |
| 908 | pub variants: Option<Variants<'a>>, |
| 909 | } |
| 910 | |
| 911 | impl<'a> Table<'a> { |
| 912 | /// Parses a table from raw data. |
| 913 | pub fn parse(data: &'a [u8]) -> Option<Self> { |
| 914 | let mut s: Stream<'_> = Stream::new(data); |
| 915 | let major_version: u8 = s.read::<u16>()? as u8; |
| 916 | s.skip::<u16>(); // minor version |
| 917 | if major_version != 1 { |
| 918 | return None; |
| 919 | } |
| 920 | |
| 921 | Some(Table { |
| 922 | constants: s.parse_at_offset16::<Constants>(data), |
| 923 | glyph_info: s.parse_at_offset16::<GlyphInfo>(data), |
| 924 | variants: s.parse_at_offset16::<Variants>(data), |
| 925 | }) |
| 926 | } |
| 927 | } |
| 928 | |
| 929 | trait StreamExt<'a> { |
| 930 | fn parse_at_offset16<T: FromSlice<'a>>(&mut self, data: &'a [u8]) -> Option<T>; |
| 931 | } |
| 932 | |
| 933 | impl<'a> StreamExt<'a> for Stream<'a> { |
| 934 | fn parse_at_offset16<T: FromSlice<'a>>(&mut self, data: &'a [u8]) -> Option<T> { |
| 935 | let offset: usize = self.read::<Option<Offset16>>()??.to_usize(); |
| 936 | data.get(index:offset..).and_then(T::parse) |
| 937 | } |
| 938 | } |
| 939 | |