ttf_parser/tables/
loca.rs1use core::convert::TryFrom;
5use core::num::NonZeroU16;
6use core::ops::Range;
7
8use crate::parser::{LazyArray16, NumFrom, Stream};
9use crate::{GlyphId, IndexToLocationFormat};
10
11#[derive(Clone, Copy, Debug)]
13pub enum Table<'a> {
14 Short(LazyArray16<'a, u16>),
16 Long(LazyArray16<'a, u32>),
18}
19
20impl<'a> Table<'a> {
21 pub fn parse(
26 number_of_glyphs: NonZeroU16,
27 format: IndexToLocationFormat,
28 data: &'a [u8],
29 ) -> Option<Self> {
30 let mut total = if number_of_glyphs.get() == u16::MAX {
34 number_of_glyphs.get()
35 } else {
36 number_of_glyphs.get() + 1
37 };
38
39 let actual_total = match format {
47 IndexToLocationFormat::Short => data.len() / 2,
48 IndexToLocationFormat::Long => data.len() / 4,
49 };
50 let actual_total = u16::try_from(actual_total).ok()?;
51 total = total.min(actual_total);
52
53 let mut s = Stream::new(data);
54 match format {
55 IndexToLocationFormat::Short => Some(Table::Short(s.read_array16::<u16>(total)?)),
56 IndexToLocationFormat::Long => Some(Table::Long(s.read_array16::<u32>(total)?)),
57 }
58 }
59
60 #[inline]
62 pub fn len(&self) -> u16 {
63 match self {
64 Table::Short(ref array) => array.len(),
65 Table::Long(ref array) => array.len(),
66 }
67 }
68
69 pub fn is_empty(&self) -> bool {
71 self.len() == 0
72 }
73
74 #[inline]
76 pub fn glyph_range(&self, glyph_id: GlyphId) -> Option<Range<usize>> {
77 let glyph_id = glyph_id.0;
78 if glyph_id == u16::MAX {
79 return None;
80 }
81
82 if glyph_id + 1 >= self.len() {
84 return None;
85 }
86
87 let range = match self {
88 Table::Short(ref array) => {
89 usize::from(array.get(glyph_id)?) * 2..usize::from(array.get(glyph_id + 1)?) * 2
91 }
92 Table::Long(ref array) => {
93 usize::num_from(array.get(glyph_id)?)..usize::num_from(array.get(glyph_id + 1)?)
94 }
95 };
96
97 if range.start >= range.end {
98 None
101 } else {
102 Some(range)
103 }
104 }
105}