1#![deny(missing_docs)]
2
3use std::convert::TryFrom;
6use std::fmt;
7
8use bitreader::{BitReader, BitReaderError};
9
10use super::BitDepth;
11use crate::binary::read::{
12 CheckIndex, ReadArray, ReadBinary, ReadBinaryDep, ReadCtxt, ReadFixedSizeDep, ReadFrom,
13 ReadScope,
14};
15use crate::binary::{U16Be, U32Be, I8, U8};
16use crate::bitmap::{
17 Bitmap, BitmapGlyph, BitmapMetrics, EmbeddedBitmap, EmbeddedMetrics, EncapsulatedBitmap,
18 EncapsulatedFormat, Metrics,
19};
20use crate::error::ParseError;
21use crate::size;
22
23const HORIZONTAL_METRICS: i8 = 1;
27
28const VERTICAL_METRICS: i8 = 2;
32
33pub struct CBLCTable<'a> {
35 pub major_version: u16,
39 pub minor_version: u16,
41 pub bitmap_sizes: Vec<BitmapSize<'a>>,
43}
44
45pub struct BitmapSize<'a> {
47 pub inner: BitmapInfo,
49 index_sub_table_records: ReadArray<'a, IndexSubTableRecord>,
51 index_sub_tables: Vec<IndexSubTable<'a>>,
53}
54
55#[allow(missing_docs)]
56#[derive(Debug, Clone, Eq, PartialEq)]
57pub struct SbitLineMetrics {
58 pub ascender: i8,
59 pub descender: i8,
60 pub width_max: u8,
61 pub caret_slope_numerator: i8,
62 pub caret_slope_denominator: i8,
63 pub caret_offset: i8,
64 pub min_origin_sb: i8,
65 pub min_advance_sb: i8,
66 pub max_before_bl: i8,
67 pub min_after_bl: i8,
68 pub pad1: i8,
69 pub pad2: i8,
70}
71
72#[derive(Debug, Clone, Eq, PartialEq)]
74pub struct BitmapInfo {
75 pub hori: SbitLineMetrics,
77 pub vert: SbitLineMetrics,
79 pub start_glyph_index: u16,
81 pub end_glyph_index: u16,
83 pub ppem_x: u8,
85 pub ppem_y: u8,
87 pub bit_depth: BitDepth,
92 pub flags: i8,
94}
95
96struct IndexSubTableRecord {
99 pub first_glyph_index: u16,
101 pub last_glyph_index: u16,
103 additional_offset_to_index_sub_table: u32,
105}
106
107enum IndexSubTable<'a> {
113 Format1 {
115 image_format: ImageFormat,
117 image_data_offset: u32,
119 offsets: ReadArray<'a, U32Be>,
124 },
125 Format2 {
127 image_format: ImageFormat,
129 image_data_offset: u32,
131 image_size: u32,
133 big_metrics: BigGlyphMetrics,
135 },
136 Format3 {
138 image_format: ImageFormat,
140 image_data_offset: u32,
142 offsets: ReadArray<'a, U16Be>,
147 },
148 Format4 {
150 image_format: ImageFormat,
152 image_data_offset: u32,
154 glyph_array: ReadArray<'a, GlyphOffsetPair>,
156 },
157 Format5 {
159 image_format: ImageFormat,
161 image_data_offset: u32,
163 image_size: u32,
165 big_metrics: BigGlyphMetrics,
167 glyph_id_array: ReadArray<'a, U16Be>,
169 },
170}
171
172#[allow(missing_docs)]
174#[derive(Copy, Clone)]
175pub enum ImageFormat {
176 Format1,
177 Format2,
178 Format5,
179 Format6,
180 Format7,
181 Format8,
182 Format9,
183 Format17,
184 Format18,
185 Format19,
186}
187
188#[allow(missing_docs)]
189#[derive(Debug, Copy, Clone)]
190pub struct SmallGlyphMetrics {
191 pub height: u8,
192 pub width: u8,
193 pub bearing_x: i8,
194 pub bearing_y: i8,
195 pub advance: u8,
196}
197
198#[allow(missing_docs)]
199#[derive(Debug, Copy, Clone)]
200pub struct BigGlyphMetrics {
201 pub height: u8,
202 pub width: u8,
203 pub hori_bearing_x: i8,
204 pub hori_bearing_y: i8,
205 pub hori_advance: u8,
206 pub vert_bearing_x: i8,
207 pub vert_bearing_y: i8,
208 pub vert_advance: u8,
209}
210
211enum MetricsDirection {
213 Horizontal,
214 Vertical,
215 Unknown,
216}
217
218struct GlyphOffsetPair {
220 pub glyph_id: u16,
222 pub offset: u16,
224}
225
226pub struct CBDTTable<'a> {
228 pub major_version: u16,
232 pub minor_version: u16,
234 data: ReadScope<'a>,
236}
237
238pub enum GlyphBitmapData<'a> {
240 Format1 {
242 small_metrics: SmallGlyphMetrics,
244 data: &'a [u8],
246 },
247 Format2 {
249 small_metrics: SmallGlyphMetrics,
251 data: &'a [u8],
253 },
254 Format5 {
258 big_metrics: BigGlyphMetrics,
260 data: &'a [u8],
262 },
263 Format6 {
265 big_metrics: BigGlyphMetrics,
267 data: &'a [u8],
269 },
270 Format7 {
272 big_metrics: BigGlyphMetrics,
274 data: &'a [u8],
276 },
277 Format8 {
279 small_metrics: SmallGlyphMetrics,
281 components: ReadArray<'a, EbdtComponent>,
283 },
284 Format9 {
286 big_metrics: BigGlyphMetrics,
288 components: ReadArray<'a, EbdtComponent>,
290 },
291 Format17 {
294 small_metrics: SmallGlyphMetrics,
296 data: &'a [u8],
298 },
299 Format18 {
301 big_metrics: BigGlyphMetrics,
303 data: &'a [u8],
305 },
306 Format19 {
308 big_metrics: BigGlyphMetrics,
310 data: &'a [u8],
312 },
313}
314
315pub struct EbdtComponent {
317 pub glyph_id: u16,
319 pub x_offset: i8,
321 pub y_offset: i8,
323}
324
325pub struct MatchingStrike<'a, 'b> {
327 pub(crate) bitmap_size: &'a BitmapSize<'b>,
328 index_subtable_index: usize,
329}
330
331pub fn lookup<'b>(
343 glyph_id: u16,
344 matching_strike: &MatchingStrike<'_, '_>,
345 cbdt: &CBDTTable<'b>,
346) -> Result<Option<GlyphBitmapData<'b>>, ParseError> {
347 let index_sub_table_header: &IndexSubTableRecord = &matching_strike
348 .bitmap_size
349 .index_sub_table_records
350 .get_item(matching_strike.index_subtable_index);
351 match &matching_strike.bitmap_size.index_sub_tables[matching_strike.index_subtable_index] {
352 IndexSubTable::Format1 {
353 image_format,
354 image_data_offset,
355 offsets,
356 } => {
357 let glyph_index = usize::from(glyph_id - index_sub_table_header.first_glyph_index);
359 offsets.check_index(glyph_index + 1)?;
360 let start = usize::try_from(offsets.get_item(glyph_index))?;
361 let end = usize::try_from(offsets.get_item(glyph_index + 1))?;
362 let length = end - start;
363
364 if length == 0 {
365 return Ok(None);
369 }
370
371 let offset = usize::try_from(*image_data_offset)? + start;
372 let mut ctxt = cbdt.data.offset_length(offset, length)?.ctxt();
373 let bitmap = ctxt.read_dep::<ImageFormat>((*image_format, None))?;
374 Ok(Some(bitmap))
375 }
376 IndexSubTable::Format2 {
377 image_format,
378 image_data_offset,
379 image_size,
380 big_metrics,
381 } => {
382 let glyph_index = u32::from(glyph_id - index_sub_table_header.first_glyph_index);
383 let offset = usize::try_from(image_data_offset + (glyph_index * image_size))?;
384 let mut ctxt = cbdt
385 .data
386 .offset_length(offset, usize::try_from(*image_size)?)?
387 .ctxt();
388 let bitmap = ctxt.read_dep::<ImageFormat>((*image_format, Some(*big_metrics)))?;
389 Ok(Some(bitmap))
390 }
391 IndexSubTable::Format3 {
392 image_format,
393 image_data_offset,
394 offsets,
395 } => {
396 let glyph_index = usize::from(glyph_id - index_sub_table_header.first_glyph_index);
398 offsets.check_index(glyph_index + 1)?;
399 let start = usize::from(offsets.get_item(glyph_index));
400 let end = usize::from(offsets.get_item(glyph_index + 1));
401 let length = end - start;
402
403 if length == 0 {
404 return Ok(None);
408 }
409
410 let offset = usize::try_from(*image_data_offset)? + start;
411 let mut ctxt = cbdt.data.offset_length(offset, length)?.ctxt();
412 let bitmap = ctxt.read_dep::<ImageFormat>((*image_format, None))?;
413 Ok(Some(bitmap))
414 }
415 IndexSubTable::Format4 {
416 image_format,
417 image_data_offset,
418 glyph_array,
419 } => {
420 for (glyph_index, glyph_offset_pair) in glyph_array.iter().enumerate() {
422 if glyph_offset_pair.glyph_id == glyph_id {
423 let offset = usize::try_from(*image_data_offset)?
424 + usize::from(glyph_offset_pair.offset);
425
426 glyph_array.check_index(glyph_index + 1)?;
428 let end = glyph_array.get_item(glyph_index + 1);
429 let length = usize::from(end.offset - glyph_offset_pair.offset);
430 let mut ctxt = cbdt.data.offset_length(offset, length)?.ctxt();
431 let bitmap = ctxt.read_dep::<ImageFormat>((*image_format, None))?;
432 return Ok(Some(bitmap));
433 } else if glyph_offset_pair.glyph_id > glyph_id {
434 return Ok(None);
437 }
438 }
439
440 Ok(None)
441 }
442 IndexSubTable::Format5 {
443 image_format,
444 image_data_offset,
445 image_size,
446 big_metrics,
447 glyph_id_array,
448 } => {
449 for (glyph_index, this_glyph_id) in glyph_id_array.iter().enumerate() {
451 if this_glyph_id == glyph_id {
452 let offset =
455 usize::try_from(image_data_offset + (glyph_index as u32 * image_size))?;
456 let mut ctxt = cbdt
457 .data
458 .offset_length(offset, usize::try_from(*image_size)?)?
459 .ctxt();
460 let bitmap =
461 ctxt.read_dep::<ImageFormat>((*image_format, Some(*big_metrics)))?;
462 return Ok(Some(bitmap));
463 } else if this_glyph_id > glyph_id {
464 return Ok(None);
467 }
468 }
469
470 Ok(None)
471 }
472 }
473}
474
475impl ReadBinaryDep for ImageFormat {
476 type Args<'a> = (ImageFormat, Option<BigGlyphMetrics>);
477 type HostType<'a> = GlyphBitmapData<'a>;
478
479 fn read_dep<'a>(
480 ctxt: &mut ReadCtxt<'a>,
481 (format, metrics): Self::Args<'_>,
482 ) -> Result<Self::HostType<'a>, ParseError> {
483 match format {
484 ImageFormat::Format1 => {
485 let small_metrics = ctxt.read::<SmallGlyphMetrics>()?;
486 let data = ctxt.scope().data();
487
488 Ok(GlyphBitmapData::Format1 {
489 small_metrics,
490 data,
491 })
492 }
493 ImageFormat::Format2 => {
494 let small_metrics = ctxt.read::<SmallGlyphMetrics>()?;
495 let data = ctxt.scope().data();
496
497 Ok(GlyphBitmapData::Format2 {
498 small_metrics,
499 data,
500 })
501 }
502 ImageFormat::Format5 => Ok(GlyphBitmapData::Format5 {
503 big_metrics: metrics.ok_or(ParseError::MissingValue)?,
504 data: ctxt.scope().data(),
505 }),
506 ImageFormat::Format6 => {
507 let big_metrics = ctxt.read::<BigGlyphMetrics>()?;
508 let data = ctxt.scope().data();
509
510 Ok(GlyphBitmapData::Format6 { big_metrics, data })
511 }
512 ImageFormat::Format7 => {
513 let big_metrics = ctxt.read::<BigGlyphMetrics>()?;
514 let data = ctxt.scope().data();
515
516 Ok(GlyphBitmapData::Format7 { big_metrics, data })
517 }
518 ImageFormat::Format8 => {
519 let small_metrics = ctxt.read::<SmallGlyphMetrics>()?;
520 let _pad = ctxt.read_u8()?;
521 let num_components = usize::from(ctxt.read_u16be()?);
522 let components = ctxt.read_array::<EbdtComponent>(num_components)?;
523
524 Ok(GlyphBitmapData::Format8 {
525 small_metrics,
526 components,
527 })
528 }
529 ImageFormat::Format9 => {
530 let big_metrics = ctxt.read::<BigGlyphMetrics>()?;
531 let num_components = usize::from(ctxt.read_u16be()?);
532 let components = ctxt.read_array::<EbdtComponent>(num_components)?;
533
534 Ok(GlyphBitmapData::Format9 {
535 big_metrics,
536 components,
537 })
538 }
539 ImageFormat::Format17 => {
540 let small_metrics = ctxt.read::<SmallGlyphMetrics>()?;
541 let data_len = usize::try_from(ctxt.read_u32be()?)?;
542 let data = ctxt.read_slice(data_len)?;
543
544 Ok(GlyphBitmapData::Format17 {
545 small_metrics,
546 data,
547 })
548 }
549 ImageFormat::Format18 => {
550 let big_metrics = ctxt.read::<BigGlyphMetrics>()?;
551 let data_len = usize::try_from(ctxt.read_u32be()?)?;
552 let data = ctxt.read_slice(data_len)?;
553
554 Ok(GlyphBitmapData::Format18 { big_metrics, data })
555 }
556 ImageFormat::Format19 => {
557 let data_len = usize::try_from(ctxt.read_u32be()?)?;
558 let data = ctxt.read_slice(data_len)?;
559
560 Ok(GlyphBitmapData::Format19 {
561 big_metrics: metrics.ok_or(ParseError::MissingValue)?,
562 data,
563 })
564 }
565 }
566 }
567}
568
569impl<'a> CBLCTable<'a> {
570 pub fn find_strike(
578 &self,
579 glyph_id: u16,
580 target_ppem: u8,
581 max_bit_depth: BitDepth,
582 ) -> Option<MatchingStrike<'_, 'a>> {
583 let candidates = self.bitmap_sizes.iter().filter_map(|bitmap_size| {
585 bitmap_size
586 .index_sub_table_index(glyph_id)
587 .and_then(|index| {
588 if bitmap_size.inner.bit_depth <= max_bit_depth {
589 Some((bitmap_size, index))
590 } else {
591 None
593 }
594 })
595 });
596
597 let size_ppem = i16::from(target_ppem);
599 let mut best: Option<(i16, &BitmapSize<'a>, usize)> = None;
600
601 for (bitmap_size, index) in candidates {
602 let difference = i16::from(bitmap_size.inner.ppem_x) - size_ppem;
603 match best {
604 Some((current_best_difference, current_best_bitmap_size, _))
605 if same_size_higher_bit_depth(
606 difference,
607 current_best_difference,
608 bitmap_size.inner.bit_depth,
609 current_best_bitmap_size.inner.bit_depth,
610 ) =>
611 {
612 best = Some((difference, bitmap_size, index))
613 }
614 Some((current_best_difference, _, _))
615 if super::bigger_or_closer_to_zero(difference, current_best_difference) =>
616 {
617 best = Some((difference, bitmap_size, index))
618 }
619 None => best = Some((difference, bitmap_size, index)),
620 _ => (),
621 }
622 }
623
624 best.map(|(_, bitmap_size, index)| MatchingStrike {
625 bitmap_size,
626 index_subtable_index: index,
627 })
628 }
629}
630
631fn same_size_higher_bit_depth(
632 difference: i16,
633 current_best_difference: i16,
634 candiate_bit_depth: BitDepth,
635 current_best_bit_depth: BitDepth,
636) -> bool {
637 difference == current_best_difference && candiate_bit_depth > current_best_bit_depth
638}
639
640impl<'b> ReadBinary for CBLCTable<'b> {
641 type HostType<'a> = CBLCTable<'a>;
642
643 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
644 let table = ctxt.scope();
645
646 let major_version = ctxt.read_u16be()?;
647 ctxt.check_version(major_version >= 2 && major_version <= 3)?;
650 let minor_version = ctxt.read_u16be()?;
651 let num_sizes = ctxt.read_u32be()?;
652 let bitmap_sizes = ctxt
653 .read_array_dep::<BitmapSize<'_>>(usize::try_from(num_sizes)?, table)?
654 .iter_res()
655 .collect::<Result<Vec<_>, _>>()?;
656
657 Ok(CBLCTable {
658 major_version,
659 minor_version,
660 bitmap_sizes,
661 })
662 }
663}
664
665impl<'b> ReadBinary for CBDTTable<'b> {
666 type HostType<'a> = CBDTTable<'a>;
667
668 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
669 let data = ctxt.scope();
672 let major_version = ctxt.read_u16be()?;
673 ctxt.check_version(major_version >= 2 && major_version <= 3)?;
676 let minor_version = ctxt.read_u16be()?;
677 Ok(CBDTTable {
678 major_version,
679 minor_version,
680 data,
681 })
682 }
683}
684
685impl<'a> BitmapSize<'a> {
686 fn index_sub_table_index(&self, glyph_id: u16) -> Option<usize> {
688 if (self.inner.start_glyph_index..=self.inner.end_glyph_index).contains(&glyph_id) {
693 self.index_sub_table_records
694 .iter()
695 .position(|record| record.contains_glyph(glyph_id))
696 } else {
697 None
698 }
699 }
700}
701
702impl<'a, 'b> MatchingStrike<'a, 'b> {
703 pub fn bit_depth(&self) -> BitDepth {
705 self.bitmap_size.inner.bit_depth
706 }
707}
708
709impl<'b> ReadBinaryDep for BitmapSize<'b> {
710 type Args<'a> = ReadScope<'a>;
711 type HostType<'a> = BitmapSize<'a>;
712
713 fn read_dep<'a>(
714 ctxt: &mut ReadCtxt<'a>,
715 cblc_scope: Self::Args<'a>,
716 ) -> Result<Self::HostType<'a>, ParseError> {
717 let index_sub_table_array_offset = usize::try_from(ctxt.read_u32be()?)?;
718 let _index_tables_size = ctxt.read_u32be()?;
719 let number_of_index_sub_tables = ctxt.read_u32be()?;
720 let _color_ref = ctxt.read_u32be()?; let hori = ctxt.read::<SbitLineMetrics>()?;
722 let vert = ctxt.read::<SbitLineMetrics>()?;
723 let start_glyph_index = ctxt.read_u16be()?;
724 let end_glyph_index = ctxt.read_u16be()?;
725 let ppem_x = ctxt.read_u8()?;
726 let ppem_y = ctxt.read_u8()?;
727 let bit_depth = BitDepth::try_from(ctxt.read_u8()?)?;
728 let flags = ctxt.read_i8()?;
729
730 let index_sub_table_records: ReadArray<'_, IndexSubTableRecord> = cblc_scope
732 .offset(index_sub_table_array_offset)
733 .ctxt()
734 .read_array::<IndexSubTableRecord>(usize::try_from(number_of_index_sub_tables)?)?;
735 let mut index_sub_tables = Vec::with_capacity(usize::try_from(number_of_index_sub_tables)?);
736 for index_sub_table_record in index_sub_table_records.iter() {
737 let offset = index_sub_table_array_offset
738 .checked_add(usize::try_from(
739 index_sub_table_record.additional_offset_to_index_sub_table,
740 )?)
741 .ok_or(ParseError::BadOffset)?;
742 let index_sub_table = cblc_scope
744 .offset(offset)
745 .ctxt()
746 .read_dep::<IndexSubTable<'_>>((
747 index_sub_table_record.first_glyph_index,
748 index_sub_table_record.last_glyph_index,
749 ))?;
750 index_sub_tables.push(index_sub_table);
751 }
752
753 Ok(BitmapSize {
754 inner: BitmapInfo {
755 hori,
756 vert,
757 start_glyph_index,
758 end_glyph_index,
759 ppem_x,
760 ppem_y,
761 bit_depth,
762 flags,
763 },
764 index_sub_table_records,
765 index_sub_tables,
766 })
767 }
768}
769
770impl<'a> ReadFixedSizeDep for BitmapSize<'a> {
771 fn size(_: Self::Args<'_>) -> usize {
772 (4 * size::U32)
777 + (2 * SbitLineMetrics::size(()))
780 + (2 * size::U16)
783 + 4
788 }
789}
790
791impl ReadBinary for SbitLineMetrics {
792 type HostType<'b> = Self;
793
794 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self, ParseError> {
795 let ascender = ctxt.read_i8()?;
796 let descender = ctxt.read_i8()?;
797 let width_max = ctxt.read_u8()?;
798 let caret_slope_numerator = ctxt.read_i8()?;
799 let caret_slope_denominator = ctxt.read_i8()?;
800 let caret_offset = ctxt.read_i8()?;
801 let min_origin_sb = ctxt.read_i8()?;
802 let min_advance_sb = ctxt.read_i8()?;
803 let max_before_bl = ctxt.read_i8()?;
804 let min_after_bl = ctxt.read_i8()?;
805 let pad1 = ctxt.read_i8()?;
806 let pad2 = ctxt.read_i8()?;
807
808 Ok(SbitLineMetrics {
809 ascender,
810 descender,
811 width_max,
812 caret_slope_numerator,
813 caret_slope_denominator,
814 caret_offset,
815 min_origin_sb,
816 min_advance_sb,
817 max_before_bl,
818 min_after_bl,
819 pad1,
820 pad2,
821 })
822 }
823}
824
825impl ReadFixedSizeDep for SbitLineMetrics {
826 fn size(_scope: Self::Args<'_>) -> usize {
827 12
829 }
830}
831
832impl TryFrom<u8> for BitDepth {
833 type Error = ParseError;
834
835 fn try_from(value: u8) -> Result<Self, Self::Error> {
836 match value {
837 1 => Ok(BitDepth::One),
838 2 => Ok(BitDepth::Two),
839 4 => Ok(BitDepth::Four),
840 8 => Ok(BitDepth::Eight),
841 32 => Ok(BitDepth::ThirtyTwo),
842 _ => Err(ParseError::BadValue),
843 }
844 }
845}
846
847impl IndexSubTableRecord {
848 fn contains_glyph(&self, glyph_id: u16) -> bool {
849 (self.first_glyph_index..=self.last_glyph_index).contains(&glyph_id)
850 }
851}
852
853impl ReadFrom for IndexSubTableRecord {
854 type ReadType = (U16Be, U16Be, U32Be);
855
856 fn read_from(
857 (first_glyph_index, last_glyph_index, additional_offset_to_index_sub_table): (
858 u16,
859 u16,
860 u32,
861 ),
862 ) -> Self {
863 IndexSubTableRecord {
864 first_glyph_index,
865 last_glyph_index,
866 additional_offset_to_index_sub_table,
867 }
868 }
869}
870
871impl<'b> ReadBinaryDep for IndexSubTable<'b> {
872 type Args<'a> = (u16, u16);
873 type HostType<'a> = IndexSubTable<'a>;
874
875 fn read_dep<'a>(
876 ctxt: &mut ReadCtxt<'a>,
877 (first_glyph_index, last_glyph_index): (u16, u16),
878 ) -> Result<Self::HostType<'a>, ParseError> {
879 let index_format = ctxt.read_u16be()?;
880 let image_format = ImageFormat::try_from(ctxt.read_u16be()?)?;
881 let image_data_offset = ctxt.read_u32be()?;
882
883 match index_format {
884 1 => {
885 let offsets = ctxt.read_array::<U32Be>(usize::from(
888 last_glyph_index - first_glyph_index + 1 + 1,
889 ))?;
890 Ok(IndexSubTable::Format1 {
891 image_format,
892 image_data_offset,
893 offsets,
894 })
895 }
896 2 => {
897 let image_size = ctxt.read_u32be()?;
898 let big_metrics = ctxt.read::<BigGlyphMetrics>()?;
899 Ok(IndexSubTable::Format2 {
900 image_format,
901 image_data_offset,
902 image_size,
903 big_metrics,
904 })
905 }
906 3 => {
907 let offsets = ctxt.read_array::<U16Be>(usize::from(
910 last_glyph_index - first_glyph_index + 1 + 1,
911 ))?;
912 Ok(IndexSubTable::Format3 {
913 image_format,
914 image_data_offset,
915 offsets,
916 })
917 }
918 4 => {
919 let num_glyphs = ctxt.read_u32be()?;
920 let glyph_array =
921 ctxt.read_array::<GlyphOffsetPair>(usize::try_from(num_glyphs + 1)?)?;
922 Ok(IndexSubTable::Format4 {
923 image_format,
924 image_data_offset,
925 glyph_array,
926 })
927 }
928 5 => {
929 let image_size = ctxt.read_u32be()?;
930 let big_metrics = ctxt.read::<BigGlyphMetrics>()?;
931 let num_glyphs = ctxt.read_u32be()?;
932 let glyph_id_array = ctxt.read_array::<U16Be>(usize::try_from(num_glyphs)?)?;
933 Ok(IndexSubTable::Format5 {
934 image_format,
935 image_data_offset,
936 image_size,
937 big_metrics,
938 glyph_id_array,
939 })
940 }
941 _ => Err(ParseError::BadValue),
942 }
943 }
944}
945
946impl ReadFrom for SmallGlyphMetrics {
947 type ReadType = ((U8, U8), (I8, I8, U8));
948
949 fn read_from(
950 ((height, width), (bearing_x, bearing_y, advance)): ((u8, u8), (i8, i8, u8)),
951 ) -> Self {
952 SmallGlyphMetrics {
953 height,
954 width,
955 bearing_x,
956 bearing_y,
957 advance,
958 }
959 }
960}
961
962impl ReadBinary for BigGlyphMetrics {
963 type HostType<'b> = Self;
964
965 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self, ParseError> {
966 let height = ctxt.read_u8()?;
967 let width = ctxt.read_u8()?;
968 let hori_bearing_x = ctxt.read_i8()?;
969 let hori_bearing_y = ctxt.read_i8()?;
970 let hori_advance = ctxt.read_u8()?;
971 let vert_bearing_x = ctxt.read_i8()?;
972 let vert_bearing_y = ctxt.read_i8()?;
973 let vert_advance = ctxt.read_u8()?;
974
975 Ok(BigGlyphMetrics {
976 height,
977 width,
978 hori_bearing_x,
979 hori_bearing_y,
980 hori_advance,
981 vert_bearing_x,
982 vert_bearing_y,
983 vert_advance,
984 })
985 }
986}
987
988impl ReadFixedSizeDep for BigGlyphMetrics {
989 fn size(_scope: Self::Args<'_>) -> usize {
990 8
992 }
993}
994
995impl ReadFrom for GlyphOffsetPair {
996 type ReadType = (U16Be, U16Be);
997
998 fn read_from((glyph_id, offset): (u16, u16)) -> Self {
999 GlyphOffsetPair { glyph_id, offset }
1000 }
1001}
1002
1003impl ReadFrom for EbdtComponent {
1004 type ReadType = (U16Be, I8, I8);
1005
1006 fn read_from((glyph_id, x_offset, y_offset): (u16, i8, i8)) -> Self {
1007 EbdtComponent {
1008 glyph_id,
1009 x_offset,
1010 y_offset,
1011 }
1012 }
1013}
1014
1015impl TryFrom<u16> for ImageFormat {
1016 type Error = ParseError;
1017
1018 fn try_from(value: u16) -> Result<Self, Self::Error> {
1019 match value {
1020 1 => Ok(ImageFormat::Format1),
1021 2 => Ok(ImageFormat::Format2),
1022 5 => Ok(ImageFormat::Format5),
1023 6 => Ok(ImageFormat::Format6),
1024 7 => Ok(ImageFormat::Format7),
1025 8 => Ok(ImageFormat::Format8),
1026 9 => Ok(ImageFormat::Format9),
1027 17 => Ok(ImageFormat::Format17),
1028 18 => Ok(ImageFormat::Format18),
1029 19 => Ok(ImageFormat::Format19),
1030 _ => Err(ParseError::BadValue),
1031 }
1032 }
1033}
1034
1035impl<'a> TryFrom<(&BitmapInfo, GlyphBitmapData<'a>)> for BitmapGlyph {
1036 type Error = ParseError;
1037
1038 fn try_from((info, glyph): (&BitmapInfo, GlyphBitmapData<'a>)) -> Result<Self, Self::Error> {
1039 let res = match glyph {
1040 GlyphBitmapData::Format1 {
1042 small_metrics,
1043 data,
1044 } => {
1045 let data = bgra_to_rgba(info.bit_depth, data.to_vec())?;
1046 let metrics = EmbeddedMetrics::try_from((info, &small_metrics))?;
1047 BitmapGlyph {
1048 bitmap: Bitmap::Embedded(EmbeddedBitmap {
1049 format: info.bit_depth,
1050 width: small_metrics.width,
1051 height: small_metrics.height,
1052 data: Box::from(data),
1053 }),
1054 metrics: Metrics::Embedded(metrics),
1055 ppem_x: Some(u16::from(info.ppem_x)),
1056 ppem_y: Some(u16::from(info.ppem_y)),
1057 }
1058 }
1059 GlyphBitmapData::Format2 {
1061 small_metrics,
1062 data,
1063 } => {
1064 let metrics = EmbeddedMetrics::try_from((info, &small_metrics))?;
1065 let unpacked = unpack_bit_aligned_data(
1066 info.bit_depth,
1067 small_metrics.width,
1068 small_metrics.height,
1069 data,
1070 )
1071 .map_err(parse_error_from_bitreader_error)
1072 .and_then(|data| bgra_to_rgba(info.bit_depth, data))?;
1073 BitmapGlyph {
1074 bitmap: Bitmap::Embedded(EmbeddedBitmap {
1075 format: info.bit_depth,
1076 width: small_metrics.width,
1077 height: small_metrics.height,
1078 data: unpacked.into(),
1079 }),
1080 metrics: Metrics::Embedded(metrics),
1081 ppem_x: Some(u16::from(info.ppem_x)),
1082 ppem_y: Some(u16::from(info.ppem_y)),
1083 }
1084 }
1085 GlyphBitmapData::Format5 { big_metrics, data } => {
1087 let metrics = EmbeddedMetrics::try_from((info, &big_metrics))?;
1088 let unpacked = unpack_bit_aligned_data(
1089 info.bit_depth,
1090 big_metrics.width,
1091 big_metrics.height,
1092 data,
1093 )
1094 .map_err(parse_error_from_bitreader_error)
1095 .and_then(|data| bgra_to_rgba(info.bit_depth, data))?;
1096 BitmapGlyph {
1097 bitmap: Bitmap::Embedded(EmbeddedBitmap {
1098 format: info.bit_depth,
1099 width: big_metrics.width,
1100 height: big_metrics.height,
1101 data: unpacked.into(),
1102 }),
1103 metrics: Metrics::Embedded(metrics),
1104 ppem_x: Some(u16::from(info.ppem_x)),
1105 ppem_y: Some(u16::from(info.ppem_y)),
1106 }
1107 }
1108 GlyphBitmapData::Format6 { big_metrics, data } => {
1110 let data = bgra_to_rgba(info.bit_depth, data.to_vec())?;
1111 let metrics = EmbeddedMetrics::try_from((info, &big_metrics))?;
1112 BitmapGlyph {
1113 bitmap: Bitmap::Embedded(EmbeddedBitmap {
1114 format: info.bit_depth,
1115 width: big_metrics.width,
1116 height: big_metrics.height,
1117 data: Box::from(data),
1118 }),
1119 metrics: Metrics::Embedded(metrics),
1120 ppem_x: Some(u16::from(info.ppem_x)),
1121 ppem_y: Some(u16::from(info.ppem_y)),
1122 }
1123 }
1124 GlyphBitmapData::Format7 { big_metrics, data } => {
1126 let metrics = EmbeddedMetrics::try_from((info, &big_metrics))?;
1127 let unpacked = unpack_bit_aligned_data(
1128 info.bit_depth,
1129 big_metrics.width,
1130 big_metrics.height,
1131 data,
1132 )
1133 .map_err(parse_error_from_bitreader_error)
1134 .and_then(|data| bgra_to_rgba(info.bit_depth, data))?;
1135 BitmapGlyph {
1136 bitmap: Bitmap::Embedded(EmbeddedBitmap {
1137 format: info.bit_depth,
1138 width: big_metrics.width,
1139 height: big_metrics.height,
1140 data: unpacked.into(),
1141 }),
1142 metrics: Metrics::Embedded(metrics),
1143 ppem_x: Some(u16::from(info.ppem_x)),
1144 ppem_y: Some(u16::from(info.ppem_y)),
1145 }
1146 }
1147 GlyphBitmapData::Format8 { .. } => return Err(ParseError::NotImplemented),
1149 GlyphBitmapData::Format9 { .. } => return Err(ParseError::NotImplemented),
1151 GlyphBitmapData::Format17 {
1153 small_metrics,
1154 data,
1155 } => {
1156 let metrics = EmbeddedMetrics::try_from((info, &small_metrics))?;
1157 let bitmap = EncapsulatedBitmap {
1158 format: EncapsulatedFormat::Png,
1159 data: Box::from(data),
1160 };
1161 BitmapGlyph {
1162 bitmap: Bitmap::Encapsulated(bitmap),
1163 metrics: Metrics::Embedded(metrics),
1164 ppem_x: Some(u16::from(info.ppem_x)),
1165 ppem_y: Some(u16::from(info.ppem_y)),
1166 }
1167 }
1168 GlyphBitmapData::Format18 { big_metrics, data }
1171 | GlyphBitmapData::Format19 { big_metrics, data } => {
1172 let metrics = EmbeddedMetrics::try_from((info, &big_metrics))?;
1173 let bitmap = EncapsulatedBitmap {
1174 format: EncapsulatedFormat::Png,
1175 data: Box::from(data),
1176 };
1177 BitmapGlyph {
1178 bitmap: Bitmap::Encapsulated(bitmap),
1179 metrics: Metrics::Embedded(metrics),
1180 ppem_x: Some(u16::from(info.ppem_x)),
1181 ppem_y: Some(u16::from(info.ppem_y)),
1182 }
1183 }
1184 };
1185
1186 Ok(res)
1187 }
1188}
1189
1190impl<'a> GlyphBitmapData<'a> {
1191 pub fn width(&self) -> u8 {
1193 match self {
1194 GlyphBitmapData::Format1 {
1195 small_metrics: SmallGlyphMetrics { width, .. },
1196 ..
1197 } => *width,
1198 GlyphBitmapData::Format2 {
1199 small_metrics: SmallGlyphMetrics { width, .. },
1200 ..
1201 } => *width,
1202 GlyphBitmapData::Format5 {
1203 big_metrics: BigGlyphMetrics { width, .. },
1204 ..
1205 } => *width,
1206 GlyphBitmapData::Format6 {
1207 big_metrics: BigGlyphMetrics { width, .. },
1208 ..
1209 } => *width,
1210 GlyphBitmapData::Format7 {
1211 big_metrics: BigGlyphMetrics { width, .. },
1212 ..
1213 } => *width,
1214 GlyphBitmapData::Format8 {
1215 small_metrics: SmallGlyphMetrics { width, .. },
1216 ..
1217 } => *width,
1218 GlyphBitmapData::Format9 {
1219 big_metrics: BigGlyphMetrics { width, .. },
1220 ..
1221 } => *width,
1222 GlyphBitmapData::Format17 {
1223 small_metrics: SmallGlyphMetrics { width, .. },
1224 ..
1225 } => *width,
1226 GlyphBitmapData::Format18 {
1227 big_metrics: BigGlyphMetrics { width, .. },
1228 ..
1229 } => *width,
1230 GlyphBitmapData::Format19 {
1231 big_metrics: BigGlyphMetrics { width, .. },
1232 ..
1233 } => *width,
1234 }
1235 }
1236
1237 pub fn height(&self) -> u8 {
1239 match self {
1240 GlyphBitmapData::Format1 {
1241 small_metrics: SmallGlyphMetrics { height, .. },
1242 ..
1243 } => *height,
1244 GlyphBitmapData::Format2 {
1245 small_metrics: SmallGlyphMetrics { height, .. },
1246 ..
1247 } => *height,
1248 GlyphBitmapData::Format5 {
1249 big_metrics: BigGlyphMetrics { height, .. },
1250 ..
1251 } => *height,
1252 GlyphBitmapData::Format6 {
1253 big_metrics: BigGlyphMetrics { height, .. },
1254 ..
1255 } => *height,
1256 GlyphBitmapData::Format7 {
1257 big_metrics: BigGlyphMetrics { height, .. },
1258 ..
1259 } => *height,
1260 GlyphBitmapData::Format8 {
1261 small_metrics: SmallGlyphMetrics { height, .. },
1262 ..
1263 } => *height,
1264 GlyphBitmapData::Format9 {
1265 big_metrics: BigGlyphMetrics { height, .. },
1266 ..
1267 } => *height,
1268 GlyphBitmapData::Format17 {
1269 small_metrics: SmallGlyphMetrics { height, .. },
1270 ..
1271 } => *height,
1272 GlyphBitmapData::Format18 {
1273 big_metrics: BigGlyphMetrics { height, .. },
1274 ..
1275 } => *height,
1276 GlyphBitmapData::Format19 {
1277 big_metrics: BigGlyphMetrics { height, .. },
1278 ..
1279 } => *height,
1280 }
1281 }
1282}
1283
1284impl<'a> fmt::Debug for GlyphBitmapData<'a> {
1285 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1286 match self {
1287 GlyphBitmapData::Format1 {
1288 small_metrics,
1289 data,
1290 } => f
1291 .debug_struct("GlyphBitmapData::Format1")
1292 .field("small_metrics", &small_metrics)
1293 .field("data", &format_args!("[{} bytes]", data.len()))
1294 .finish(),
1295 GlyphBitmapData::Format2 {
1296 small_metrics,
1297 data,
1298 } => f
1299 .debug_struct("GlyphBitmapData::Format2")
1300 .field("small_metrics", &small_metrics)
1301 .field("data", &format_args!("[{} bytes]", data.len()))
1302 .finish(),
1303 GlyphBitmapData::Format5 { big_metrics, data } => f
1304 .debug_struct("GlyphBitmapData::Format5")
1305 .field("big_metrics", &big_metrics)
1306 .field("data", &format_args!("[{} bytes]", data.len()))
1307 .finish(),
1308 GlyphBitmapData::Format6 { big_metrics, data } => f
1309 .debug_struct("GlyphBitmapData::Format6")
1310 .field("big_metrics", &big_metrics)
1311 .field("data", &format_args!("[{} bytes]", data.len()))
1312 .finish(),
1313 GlyphBitmapData::Format7 { big_metrics, data } => f
1314 .debug_struct("GlyphBitmapData::Format7")
1315 .field("big_metrics", &big_metrics)
1316 .field("data", &format_args!("[{} bytes]", data.len()))
1317 .finish(),
1318 GlyphBitmapData::Format8 { small_metrics, .. } => f
1319 .debug_struct("GlyphBitmapData::Format8")
1320 .field("small_metrics", &small_metrics)
1321 .finish(),
1322 GlyphBitmapData::Format9 { big_metrics, .. } => f
1323 .debug_struct("GlyphBitmapData::Format9")
1324 .field("big_metrics", &big_metrics)
1325 .finish(),
1326 GlyphBitmapData::Format17 {
1327 small_metrics,
1328 data,
1329 } => f
1330 .debug_struct("GlyphBitmapData::Format17")
1331 .field("small_metrics", &small_metrics)
1332 .field("data", &format_args!("[{} bytes]", data.len()))
1333 .finish(),
1334 GlyphBitmapData::Format18 { big_metrics, data } => f
1335 .debug_struct("GlyphBitmapData::Format18")
1336 .field("big_metrics", &big_metrics)
1337 .field("data", &format_args!("[{} bytes]", data.len()))
1338 .finish(),
1339 GlyphBitmapData::Format19 { big_metrics, data } => f
1340 .debug_struct("GlyphBitmapData::Format19")
1341 .field("big_metrics", &big_metrics)
1342 .field("data", &format_args!("[{} bytes]", data.len()))
1343 .finish(),
1344 }
1345 }
1346}
1347
1348impl TryFrom<(&BitmapInfo, &SmallGlyphMetrics)> for EmbeddedMetrics {
1349 type Error = ParseError;
1350
1351 fn try_from(
1352 (info, small_metrics): (&BitmapInfo, &SmallGlyphMetrics),
1353 ) -> Result<Self, Self::Error> {
1354 match info.small_glyph_metrics_direction() {
1355 MetricsDirection::Horizontal | MetricsDirection::Unknown => EmbeddedMetrics::new(
1356 info.ppem_x,
1357 info.ppem_y,
1358 Some(BitmapMetrics {
1359 origin_offset_x: i16::from(small_metrics.bearing_x),
1360 origin_offset_y: i16::from(small_metrics.bearing_y)
1362 - i16::from(small_metrics.height),
1363 advance: small_metrics.advance,
1364 ascender: info.hori.ascender,
1365 descender: info.hori.descender,
1366 }),
1367 None,
1368 ),
1369 MetricsDirection::Vertical => EmbeddedMetrics::new(
1370 info.ppem_x,
1371 info.ppem_y,
1372 None,
1373 Some(BitmapMetrics {
1374 origin_offset_x: i16::from(small_metrics.bearing_x),
1375 origin_offset_y: i16::from(small_metrics.bearing_y)
1377 - i16::from(small_metrics.height),
1378 advance: small_metrics.advance,
1379 ascender: info.vert.ascender,
1380 descender: info.vert.descender,
1381 }),
1382 ),
1383 }
1384 }
1385}
1386
1387impl TryFrom<(&BitmapInfo, &BigGlyphMetrics)> for EmbeddedMetrics {
1388 type Error = ParseError;
1389
1390 fn try_from((info, big_metrics): (&BitmapInfo, &BigGlyphMetrics)) -> Result<Self, Self::Error> {
1391 EmbeddedMetrics::new(
1392 info.ppem_x,
1393 info.ppem_y,
1394 Some(BitmapMetrics {
1395 origin_offset_x: i16::from(big_metrics.hori_bearing_x),
1396 origin_offset_y: i16::from(big_metrics.hori_bearing_y)
1397 - i16::from(big_metrics.height),
1398 advance: big_metrics.hori_advance,
1399 ascender: info.hori.ascender,
1400 descender: info.hori.descender,
1401 }),
1402 Some(BitmapMetrics {
1403 origin_offset_x: i16::from(big_metrics.vert_bearing_x),
1404 origin_offset_y: i16::from(big_metrics.vert_bearing_y)
1405 - i16::from(big_metrics.height),
1406 advance: big_metrics.vert_advance,
1407 ascender: info.vert.ascender,
1408 descender: info.vert.descender,
1409 }),
1410 )
1411 }
1412}
1413
1414impl BitmapInfo {
1415 fn small_glyph_metrics_direction(&self) -> MetricsDirection {
1416 if self.flags & HORIZONTAL_METRICS == HORIZONTAL_METRICS {
1417 MetricsDirection::Horizontal
1418 } else if self.flags & VERTICAL_METRICS == VERTICAL_METRICS {
1419 MetricsDirection::Vertical
1420 } else {
1421 MetricsDirection::Unknown
1422 }
1423 }
1424}
1425
1426fn unpack_bit_aligned_data(
1427 bit_depth: BitDepth,
1428 width: u8,
1429 height: u8,
1430 data: &[u8],
1431) -> Result<Vec<u8>, BitReaderError> {
1432 let bits_per_row = bit_depth as usize * usize::from(width);
1433 let whole_bytes_per_row = bits_per_row >> 3;
1434 let remaining_bits = (bits_per_row & 7) as u8;
1435 let bytes_per_row = whole_bytes_per_row + if remaining_bits != 0 { 1 } else { 0 };
1436
1437 let mut offset = 0;
1438 let mut image_data = vec![0u8; usize::from(height) * bytes_per_row];
1439 let mut reader = BitReader::new(data);
1440 for _ in 0..height {
1441 for byte in image_data[offset..(offset + whole_bytes_per_row)].iter_mut() {
1443 *byte = reader.read_u8(8)?;
1444 }
1445 offset += whole_bytes_per_row;
1446 if remaining_bits != 0 {
1447 let byte = reader.read_u8(remaining_bits)?;
1448 image_data[offset] = byte << (8 - remaining_bits);
1449 offset += 1;
1450 }
1451 }
1452
1453 Ok(image_data)
1454}
1455
1456fn parse_error_from_bitreader_error(err: BitReaderError) -> ParseError {
1457 match err {
1458 BitReaderError::NotEnoughData { .. } => ParseError::BadEof,
1459 BitReaderError::TooManyBitsForType { .. } => {
1460 unreachable!("{}", err)
1463 }
1464 }
1465}
1466
1467fn bgra_to_rgba(bit_depth: BitDepth, mut data: Vec<u8>) -> Result<Vec<u8>, ParseError> {
1468 match bit_depth {
1469 BitDepth::One | BitDepth::Two | BitDepth::Four | BitDepth::Eight => Ok(data),
1470 BitDepth::ThirtyTwo => {
1471 if data.len() % 4 != 0 {
1472 return Err(ParseError::BadEof);
1473 }
1474 data.chunks_exact_mut(4).for_each(|chunk| chunk.swap(0, 2));
1475 Ok(data)
1476 }
1477 }
1478}
1479
1480#[cfg(test)]
1481mod tests {
1482 use itertools::Itertools;
1483 use std::borrow::Borrow;
1484 use std::path::Path;
1485
1486 use super::*;
1487 use crate::font_data::FontData;
1488 use crate::tables::FontTableProvider;
1489 use crate::tag;
1490 use crate::tests::read_fixture;
1491
1492 #[test]
1493 fn test_parse_cblc() {
1494 let cblc_data = read_fixture(Path::new("tests/fonts/opentype/CBLC.bin"));
1495 let cblc = ReadScope::new(&cblc_data).read::<CBLCTable<'_>>().unwrap();
1496
1497 let strikes = &cblc.bitmap_sizes;
1498 assert_eq!(strikes.len(), 1);
1499 assert_eq!(strikes[0].index_sub_tables.len(), 3);
1500 let ranges = strikes[0]
1501 .index_sub_table_records
1502 .iter()
1503 .map(|rec| rec.first_glyph_index..=rec.last_glyph_index)
1504 .collect_vec();
1505 assert_eq!(ranges, &[4..=17, 19..=1316, 1354..=3112]);
1506 }
1507
1508 #[test]
1509 fn test_parse_eblc() {
1510 let buffer = read_fixture(Path::new("tests/fonts/opentype/TerminusTTF-4.47.0.ttf"));
1511 let scope = ReadScope::new(&buffer);
1512 let font_file = scope
1513 .read::<FontData<'_>>()
1514 .expect("unable to parse font file");
1515 let table_provider = font_file
1516 .table_provider(0)
1517 .expect("unable to create font provider");
1518 let table = table_provider
1519 .table_data(tag::EBLC)
1520 .expect("no EBLC table")
1521 .expect("no EBLC table");
1522 let scope = ReadScope::new(table.borrow());
1523 let eblc = scope.read::<CBLCTable<'_>>().unwrap();
1524
1525 let strikes = &eblc.bitmap_sizes;
1526 assert_eq!(strikes.len(), 9);
1527 }
1528
1529 #[test]
1530 fn test_lookup_eblc() {
1531 let buffer = read_fixture(Path::new("tests/fonts/opentype/TerminusTTF-4.47.0.ttf"));
1532 let scope = ReadScope::new(&buffer);
1533 let font_file = scope
1534 .read::<FontData<'_>>()
1535 .expect("unable to parse font file");
1536 let table_provider = font_file
1537 .table_provider(0)
1538 .expect("unable to create font provider");
1539 let table = table_provider
1540 .table_data(tag::EBLC)
1541 .expect("no EBLC table")
1542 .expect("no EBLC table");
1543 let scope = ReadScope::new(table.borrow());
1544 let eblc = scope.read::<CBLCTable<'_>>().unwrap();
1545 let table = table_provider
1546 .table_data(tag::EBDT)
1547 .expect("no EBDT table")
1548 .expect("no EBDT table");
1549 let scope = ReadScope::new(table.borrow());
1550 let ebdt = scope.read::<CBDTTable<'_>>().unwrap();
1551
1552 let strike = eblc
1555 .find_strike(10, 30, BitDepth::ThirtyTwo)
1556 .expect("no matching strike");
1557 let res = lookup(10, &strike, &ebdt).expect("error looking up glyph");
1558 match res {
1559 Some(GlyphBitmapData::Format5 { data, .. }) => assert_eq!(data.len(), 64),
1560 _ => panic!("expected GlyphBitmapData::Format5 got something else"),
1561 }
1562 }
1563
1564 #[test]
1565 fn test_lookup_cblc() {
1566 let cblc_data = read_fixture(Path::new("tests/fonts/opentype/CBLC.bin"));
1568 let cblc = ReadScope::new(&cblc_data).read::<CBLCTable<'_>>().unwrap();
1569 let cbdt_data = read_fixture(Path::new("tests/fonts/opentype/CBDT.bin"));
1570 let cbdt = ReadScope::new(&cbdt_data).read::<CBDTTable<'_>>().unwrap();
1571
1572 let strike = cblc
1574 .find_strike(1077, 30, BitDepth::ThirtyTwo)
1575 .expect("no matching strike");
1576 let res = lookup(1077, &strike, &cbdt).expect("error looking up glyph");
1577 match res {
1578 Some(GlyphBitmapData::Format17 {
1579 data,
1580 small_metrics: SmallGlyphMetrics { width, height, .. },
1581 }) => {
1582 assert_eq!((width, height), (136, 128));
1583 assert_eq!(&data[1..4], b"PNG");
1584 }
1585 _ => panic!("expected PNG data got something else"),
1586 }
1587
1588 assert!(cblc.find_strike(1077, 30, BitDepth::Four).is_none());
1590 }
1591
1592 #[test]
1593 fn test_unpack_bit_aligned_data() {
1594 let data = &[0xD3, 0xAA, 0x70];
1595 let expected = &[0xD3, 0x80, 0xA9, 0xC0];
1596 let actual = unpack_bit_aligned_data(BitDepth::Two, 5, 2, data).unwrap();
1597 assert_eq!(&actual, expected);
1598 }
1599
1600 #[test]
1601 fn test_bgra_to_rgba_no_change() {
1602 let original = vec![1, 2, 3, 4, 5, 6, 7, 8];
1603 let actual = bgra_to_rgba(BitDepth::One, original.clone()).unwrap();
1604 assert_eq!(actual, original);
1605 }
1606
1607 #[test]
1608 fn test_bgra_to_rgba_reorder() {
1609 let data = vec![1, 2, 3, 4, 5, 6, 7, 8];
1610 let expected = &[3, 2, 1, 4, 7, 6, 5, 8];
1611 let actual = bgra_to_rgba(BitDepth::ThirtyTwo, data).unwrap();
1612 assert_eq!(&actual, expected);
1613 }
1614
1615 #[test]
1616 fn test_bgra_to_rgba_too_short() {
1617 let data = vec![1, 2, 3, 4, 5, 6, 7];
1618 let res = bgra_to_rgba(BitDepth::ThirtyTwo, data);
1619 assert_eq!(res, Err(ParseError::BadEof));
1620 }
1621}