1include!("../../generated/generated_bitmap.rs");
4
5impl BitmapSize {
6 pub fn location(
14 &self,
15 offset_data: FontData,
16 glyph_id: GlyphId,
17 ) -> Result<BitmapLocation, ReadError> {
18 if !(self.start_glyph_index()..=self.end_glyph_index()).contains(&glyph_id) {
19 return Err(ReadError::OutOfBounds);
20 }
21 let subtable_list = self.index_subtable_list(offset_data)?;
22 let mut location = BitmapLocation {
23 bit_depth: self.bit_depth,
24 ..BitmapLocation::default()
25 };
26 for record in subtable_list.index_subtable_records() {
27 let subtable = record.index_subtable(subtable_list.offset_data())?;
28 if !(record.first_glyph_index()..=record.last_glyph_index()).contains(&glyph_id) {
29 continue;
30 }
31 let glyph_ix =
33 glyph_id.to_u32() as usize - record.first_glyph_index().to_u32() as usize;
34 match &subtable {
35 IndexSubtable::Format1(st) => {
36 location.format = st.image_format();
37 let start = st.image_data_offset() as usize
38 + st.sbit_offsets()
39 .get(glyph_ix)
40 .ok_or(ReadError::OutOfBounds)?
41 .get() as usize;
42 let end = st.image_data_offset() as usize
43 + st.sbit_offsets()
44 .get(glyph_ix + 1)
45 .ok_or(ReadError::OutOfBounds)?
46 .get() as usize;
47 location.data_offset = start;
48 if end < start {
49 return Err(ReadError::OutOfBounds);
50 }
51 location.data_size = end - start;
52 }
53 IndexSubtable::Format2(st) => {
54 location.format = st.image_format();
55 let data_size = st.image_size() as usize;
56 location.data_size = data_size;
57 location.data_offset = st.image_data_offset() as usize + glyph_ix * data_size;
58 location.metrics = Some(st.big_metrics()[0]);
59 }
60 IndexSubtable::Format3(st) => {
61 location.format = st.image_format();
62 let start = st.image_data_offset() as usize
63 + st.sbit_offsets()
64 .get(glyph_ix)
65 .ok_or(ReadError::OutOfBounds)?
66 .get() as usize;
67 let end = st.image_data_offset() as usize
68 + st.sbit_offsets()
69 .get(glyph_ix + 1)
70 .ok_or(ReadError::OutOfBounds)?
71 .get() as usize;
72 location.data_offset = start;
73 if end < start {
74 return Err(ReadError::OutOfBounds);
75 }
76 location.data_size = end - start;
77 }
78 IndexSubtable::Format4(st) => {
79 location.format = st.image_format();
80 let array = st.glyph_array();
81 let array_ix = match array
82 .binary_search_by(|x| x.glyph_id().to_u32().cmp(&glyph_id.to_u32()))
83 {
84 Ok(ix) => ix,
85 _ => return Err(ReadError::InvalidCollectionIndex(glyph_id.to_u32())),
86 };
87 let start = array[array_ix].sbit_offset() as usize;
88 let end = array
89 .get(array_ix + 1)
90 .ok_or(ReadError::OutOfBounds)?
91 .sbit_offset() as usize;
92 location.data_offset = start;
93 if end < start {
94 return Err(ReadError::OutOfBounds);
95 }
96 location.data_size = end - start;
97 }
98 IndexSubtable::Format5(st) => {
99 location.format = st.image_format();
100 let array = st.glyph_array();
101 let array_ix = match array
102 .binary_search_by(|gid| gid.get().to_u32().cmp(&glyph_id.to_u32()))
103 {
104 Ok(ix) => ix,
105 _ => return Err(ReadError::InvalidCollectionIndex(glyph_id.to_u32())),
106 };
107 let data_size = st.image_size() as usize;
108 location.data_size = data_size;
109 location.data_offset = st.image_data_offset() as usize + array_ix * data_size;
110 location.metrics = Some(st.big_metrics()[0]);
111 }
112 }
113 return Ok(location);
114 }
115 Err(ReadError::OutOfBounds)
116 }
117
118 pub fn index_subtable_list<'a>(
123 &self,
124 offset_data: FontData<'a>,
125 ) -> Result<IndexSubtableList<'a>, ReadError> {
126 let start = self.index_subtable_list_offset() as usize;
127 let end = start
128 .checked_add(self.index_subtable_list_size() as usize)
129 .ok_or(ReadError::OutOfBounds)?;
130 let data = offset_data
131 .slice(start..end)
132 .ok_or(ReadError::OutOfBounds)?;
133 IndexSubtableList::read(data, self.number_of_index_subtables())
134 }
135}
136
137#[derive(Clone, Default)]
138pub struct BitmapLocation {
139 pub format: u16,
141 pub data_offset: usize,
143 pub data_size: usize,
145 pub bit_depth: u8,
148 pub metrics: Option<BigGlyphMetrics>,
150}
151
152impl BitmapLocation {
153 pub fn is_empty(&self) -> bool {
156 self.data_size == 0
157 }
158}
159
160#[derive(Copy, Clone, PartialEq, Eq, Debug)]
161pub enum BitmapDataFormat {
162 BitAligned,
164 ByteAligned,
166 Png,
167}
168
169#[derive(Clone)]
170pub enum BitmapMetrics {
171 Small(SmallGlyphMetrics),
172 Big(BigGlyphMetrics),
173}
174
175#[derive(Clone)]
176pub struct BitmapData<'a> {
177 pub metrics: BitmapMetrics,
178 pub content: BitmapContent<'a>,
179}
180
181#[derive(Clone)]
182pub enum BitmapContent<'a> {
183 Data(BitmapDataFormat, &'a [u8]),
184 Composite(&'a [BdtComponent]),
185}
186
187pub(crate) fn bitmap_data<'a>(
188 offset_data: FontData<'a>,
189 location: &BitmapLocation,
190 is_color: bool,
191) -> Result<BitmapData<'a>, ReadError> {
192 let mut image_data = offset_data
193 .slice(location.data_offset..location.data_offset + location.data_size)
194 .ok_or(ReadError::OutOfBounds)?
195 .cursor();
196 match location.format {
197 1 => {
200 let metrics = read_small_metrics(&mut image_data)?;
201 let pitch = (metrics.width as usize * location.bit_depth as usize + 7) / 8;
203 let height = metrics.height as usize;
204 let data = image_data.read_array::<u8>(pitch * height)?;
205 Ok(BitmapData {
206 metrics: BitmapMetrics::Small(metrics),
207 content: BitmapContent::Data(BitmapDataFormat::ByteAligned, data),
208 })
209 }
210 2 => {
213 let metrics = read_small_metrics(&mut image_data)?;
214 let width = metrics.width as usize * location.bit_depth as usize;
215 let height = metrics.height as usize;
216 let data = image_data.read_array::<u8>((width * height + 7) / 8)?;
218 Ok(BitmapData {
219 metrics: BitmapMetrics::Small(metrics),
220 content: BitmapContent::Data(BitmapDataFormat::BitAligned, data),
221 })
222 }
223 5 => {
231 let metrics = location.metrics.ok_or(ReadError::MalformedData(
232 "expected metrics from location table",
233 ))?;
234 let width = metrics.width as usize * location.bit_depth as usize;
235 let height = metrics.height as usize;
236 let data = image_data.read_array::<u8>((width * height + 7) / 8)?;
238 Ok(BitmapData {
239 metrics: BitmapMetrics::Big(metrics),
240 content: BitmapContent::Data(BitmapDataFormat::BitAligned, data),
241 })
242 }
243 6 => {
246 let metrics = read_big_metrics(&mut image_data)?;
247 let pitch = (metrics.width as usize * location.bit_depth as usize + 7) / 8;
249 let height = metrics.height as usize;
250 let data = image_data.read_array::<u8>(pitch * height)?;
251 Ok(BitmapData {
252 metrics: BitmapMetrics::Big(metrics),
253 content: BitmapContent::Data(BitmapDataFormat::ByteAligned, data),
254 })
255 }
256 7 => {
259 let metrics = read_big_metrics(&mut image_data)?;
260 let width = metrics.width as usize * location.bit_depth as usize;
261 let height = metrics.height as usize;
262 let data = image_data.read_array::<u8>((width * height + 7) / 8)?;
264 Ok(BitmapData {
265 metrics: BitmapMetrics::Big(metrics),
266 content: BitmapContent::Data(BitmapDataFormat::BitAligned, data),
267 })
268 }
269 8 => {
272 let metrics = read_small_metrics(&mut image_data)?;
273 let _pad = image_data.read::<u8>()?;
274 let count = image_data.read::<u16>()? as usize;
275 let components = image_data.read_array::<BdtComponent>(count)?;
276 Ok(BitmapData {
277 metrics: BitmapMetrics::Small(metrics),
278 content: BitmapContent::Composite(components),
279 })
280 }
281 9 => {
284 let metrics = read_big_metrics(&mut image_data)?;
285 let count = image_data.read::<u16>()? as usize;
286 let components = image_data.read_array::<BdtComponent>(count)?;
287 Ok(BitmapData {
288 metrics: BitmapMetrics::Big(metrics),
289 content: BitmapContent::Composite(components),
290 })
291 }
292 17 if is_color => {
295 let metrics = read_small_metrics(&mut image_data)?;
296 let data_len = image_data.read::<u32>()? as usize;
297 let data = image_data.read_array::<u8>(data_len)?;
298 Ok(BitmapData {
299 metrics: BitmapMetrics::Small(metrics),
300 content: BitmapContent::Data(BitmapDataFormat::Png, data),
301 })
302 }
303 18 if is_color => {
306 let metrics = read_big_metrics(&mut image_data)?;
307 let data_len = image_data.read::<u32>()? as usize;
308 let data = image_data.read_array::<u8>(data_len)?;
309 Ok(BitmapData {
310 metrics: BitmapMetrics::Big(metrics),
311 content: BitmapContent::Data(BitmapDataFormat::Png, data),
312 })
313 }
314 19 if is_color => {
317 let metrics = location.metrics.ok_or(ReadError::MalformedData(
318 "expected metrics from location table",
319 ))?;
320 let data_len = image_data.read::<u32>()? as usize;
321 let data = image_data.read_array::<u8>(data_len)?;
322 Ok(BitmapData {
323 metrics: BitmapMetrics::Big(metrics),
324 content: BitmapContent::Data(BitmapDataFormat::Png, data),
325 })
326 }
327 _ => Err(ReadError::MalformedData("unexpected bitmap data format")),
328 }
329}
330
331fn read_small_metrics(cursor: &mut Cursor) -> Result<SmallGlyphMetrics, ReadError> {
332 Ok(cursor.read_array::<SmallGlyphMetrics>(1)?[0])
333}
334
335fn read_big_metrics(cursor: &mut Cursor) -> Result<BigGlyphMetrics, ReadError> {
336 Ok(cursor.read_array::<BigGlyphMetrics>(1)?[0])
337}
338
339#[cfg(feature = "experimental_traverse")]
340impl SbitLineMetrics {
341 pub(crate) fn traversal_type<'a>(&self, data: FontData<'a>) -> FieldType<'a> {
342 FieldType::Record(self.traverse(data))
343 }
344}
345
346#[derive(Clone)]
348pub enum IndexSubtable<'a> {
349 Format1(IndexSubtable1<'a>),
350 Format2(IndexSubtable2<'a>),
351 Format3(IndexSubtable3<'a>),
352 Format4(IndexSubtable4<'a>),
353 Format5(IndexSubtable5<'a>),
354}
355
356impl<'a> IndexSubtable<'a> {
357 pub fn offset_data(&self) -> FontData<'a> {
359 match self {
360 Self::Format1(item) => item.offset_data(),
361 Self::Format2(item) => item.offset_data(),
362 Self::Format3(item) => item.offset_data(),
363 Self::Format4(item) => item.offset_data(),
364 Self::Format5(item) => item.offset_data(),
365 }
366 }
367
368 pub fn index_format(&self) -> u16 {
370 match self {
371 Self::Format1(item) => item.index_format(),
372 Self::Format2(item) => item.index_format(),
373 Self::Format3(item) => item.index_format(),
374 Self::Format4(item) => item.index_format(),
375 Self::Format5(item) => item.index_format(),
376 }
377 }
378
379 pub fn image_format(&self) -> u16 {
381 match self {
382 Self::Format1(item) => item.image_format(),
383 Self::Format2(item) => item.image_format(),
384 Self::Format3(item) => item.image_format(),
385 Self::Format4(item) => item.image_format(),
386 Self::Format5(item) => item.image_format(),
387 }
388 }
389
390 pub fn image_data_offset(&self) -> u32 {
392 match self {
393 Self::Format1(item) => item.image_data_offset(),
394 Self::Format2(item) => item.image_data_offset(),
395 Self::Format3(item) => item.image_data_offset(),
396 Self::Format4(item) => item.image_data_offset(),
397 Self::Format5(item) => item.image_data_offset(),
398 }
399 }
400}
401
402impl ReadArgs for IndexSubtable<'_> {
403 type Args = (GlyphId16, GlyphId16);
404}
405impl<'a> FontReadWithArgs<'a> for IndexSubtable<'a> {
406 fn read_with_args(data: FontData<'a>, args: &Self::Args) -> Result<Self, ReadError> {
407 let format: u16 = data.read_at(0usize)?;
408 match format {
409 IndexSubtable1Marker::FORMAT => {
410 Ok(Self::Format1(FontReadWithArgs::read_with_args(data, args)?))
411 }
412 IndexSubtable2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
413 IndexSubtable3Marker::FORMAT => {
414 Ok(Self::Format3(FontReadWithArgs::read_with_args(data, args)?))
415 }
416 IndexSubtable4Marker::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
417 IndexSubtable5Marker::FORMAT => Ok(Self::Format5(FontRead::read(data)?)),
418 other => Err(ReadError::InvalidFormat(other.into())),
419 }
420 }
421}
422
423impl MinByteRange for IndexSubtable<'_> {
424 fn min_byte_range(&self) -> Range<usize> {
425 match self {
426 Self::Format1(item) => item.min_byte_range(),
427 Self::Format2(item) => item.min_byte_range(),
428 Self::Format3(item) => item.min_byte_range(),
429 Self::Format4(item) => item.min_byte_range(),
430 Self::Format5(item) => item.min_byte_range(),
431 }
432 }
433}
434
435#[cfg(feature = "experimental_traverse")]
436impl<'a> IndexSubtable<'a> {
437 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
438 match self {
439 Self::Format1(table) => table,
440 Self::Format2(table) => table,
441 Self::Format3(table) => table,
442 Self::Format4(table) => table,
443 Self::Format5(table) => table,
444 }
445 }
446}
447
448#[cfg(feature = "experimental_traverse")]
449impl std::fmt::Debug for IndexSubtable<'_> {
450 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
451 self.dyn_inner().fmt(f)
452 }
453}
454
455#[cfg(feature = "experimental_traverse")]
456impl<'a> SomeTable<'a> for IndexSubtable<'a> {
457 fn type_name(&self) -> &str {
458 self.dyn_inner().type_name()
459 }
460 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
461 self.dyn_inner().get_field(idx)
462 }
463}