allsorts_subset_browser/bitmap/
cbdt.rs

1#![deny(missing_docs)]
2
3//! Bitmap fonts in `EBLC`/`EBDT` and `CBLC`/`CBDT` tables.
4
5use 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
23/// Flag in `BitmapInfo` `flags` indicating the direction of small glyph metrics is horizontal.
24///
25/// https://docs.microsoft.com/en-us/typography/opentype/spec/eblc#bitmap-flags
26const HORIZONTAL_METRICS: i8 = 1;
27
28/// Flag in `BitmapInfo` `flags` indicating the direction of small glyph metrics is vertical.
29///
30/// https://docs.microsoft.com/en-us/typography/opentype/spec/eblc#bitmap-flags
31const VERTICAL_METRICS: i8 = 2;
32
33/// `CBLC` — Color Bitmap Location Table
34pub struct CBLCTable<'a> {
35    /// Major version of this table.
36    ///
37    /// 2 for `EBLC`, 3, for `CBLC`
38    pub major_version: u16,
39    /// Minor version of this table.
40    pub minor_version: u16,
41    /// Array of "strikes" available for this font.
42    pub bitmap_sizes: Vec<BitmapSize<'a>>,
43}
44
45/// A description of a "strike" of bitmap data.
46pub struct BitmapSize<'a> {
47    /// Bitmap information.
48    pub inner: BitmapInfo,
49    /// Index sub-table records.
50    index_sub_table_records: ReadArray<'a, IndexSubTableRecord>,
51    /// Index sub-tables, one for each record.
52    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/// Subset of BitmapSize that includes common fields.
73#[derive(Debug, Clone, Eq, PartialEq)]
74pub struct BitmapInfo {
75    /// Line metrics for text rendered horizontally.
76    pub hori: SbitLineMetrics,
77    /// Line metrics for text rendered vertically.
78    pub vert: SbitLineMetrics,
79    /// Lowest glyph index for this size.
80    pub start_glyph_index: u16,
81    /// Highest glyph index for this size.
82    pub end_glyph_index: u16,
83    /// Horizontal pixels per em.
84    pub ppem_x: u8,
85    /// Vertical pixels per em.
86    pub ppem_y: u8,
87    /// Bit depth.
88    ///
89    /// In addition to already defined bitDepth values 1, 2, 4, and 8 supported by `EBDT` the value
90    /// of 32 is used to identify color bitmaps with 8 bit per channel RGBA channels in `CBDT`.
91    pub bit_depth: BitDepth,
92    /// Vertical or horizontal.
93    pub flags: i8,
94}
95
96/// Sub table record of `BitmapSize` describing a range of glyphs and the location of the sub
97/// table.
98struct IndexSubTableRecord {
99    /// First glyph ID of this range.
100    pub first_glyph_index: u16,
101    /// Last glyph ID of this range (inclusive).
102    pub last_glyph_index: u16,
103    // Add to indexSubTableArrayOffset to get offset from beginning of EBLC.
104    additional_offset_to_index_sub_table: u32,
105}
106
107/// An index sub table of a `BitmapSize` describing the image format and location.
108///
109/// The `IndexSubTable` provides the offset within `CBDT` where the bitmap data for a range of
110/// glyphs (described by `IndexSubTableRecord`) can be found, optionally with metrics for the whole
111/// range of glyphs as well, depending on the format.
112enum IndexSubTable<'a> {
113    /// IndexSubTable1: variable-metrics glyphs with 4-byte offsets.
114    Format1 {
115        /// Format of EBDT image data.
116        image_format: ImageFormat,
117        /// Offset to image data in EBDT table.
118        image_data_offset: u32,
119        /// Offsets into `EBDT` for bitmap data.
120        ///
121        /// The actual offset for a glyph is `image_data_offset` + the value read from this
122        /// array.
123        offsets: ReadArray<'a, U32Be>,
124    },
125    /// IndexSubTable2: all glyphs have identical metrics.
126    Format2 {
127        /// Format of EBDT image data.
128        image_format: ImageFormat,
129        /// Offset to image data in EBDT table.
130        image_data_offset: u32,
131        /// The size of the data for each bitmap.
132        image_size: u32,
133        /// Metrics for all glyphs in this range.
134        big_metrics: BigGlyphMetrics,
135    },
136    /// IndexSubTable3: variable-metrics glyphs with 2-byte offsets.
137    Format3 {
138        /// Format of EBDT image data.
139        image_format: ImageFormat,
140        /// Offset to image data in EBDT table.
141        image_data_offset: u32,
142        /// Offsets into `EBDT` for bitmap data.
143        ///
144        /// The actual offset for a glyph is `image_data_offset` + the value read from this
145        /// array.
146        offsets: ReadArray<'a, U16Be>,
147    },
148    /// IndexSubTable4: variable-metrics glyphs with sparse glyph codes.
149    Format4 {
150        /// Format of EBDT image data.
151        image_format: ImageFormat,
152        /// Offset to image data in EBDT table.
153        image_data_offset: u32,
154        /// Array of ranges.
155        glyph_array: ReadArray<'a, GlyphOffsetPair>,
156    },
157    /// IndexSubTable5: constant-metrics glyphs with sparse glyph codes.
158    Format5 {
159        /// Format of EBDT image data.
160        image_format: ImageFormat,
161        /// Offset to image data in EBDT table.
162        image_data_offset: u32,
163        /// All glyphs have the same data size.
164        image_size: u32,
165        /// All glyphs have the same metrics.
166        big_metrics: BigGlyphMetrics,
167        /// One per glyph, sorted by glyph ID.
168        glyph_id_array: ReadArray<'a, U16Be>,
169    },
170}
171
172/// Valid image formats
173#[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
211/// The direction of small glyph metrics when present.
212enum MetricsDirection {
213    Horizontal,
214    Vertical,
215    Unknown,
216}
217
218/// Record indicating the offset in `EBDT` for a specific glyph id.
219struct GlyphOffsetPair {
220    /// Glyph ID of glyph present.
221    pub glyph_id: u16,
222    /// Location in EBDT.
223    pub offset: u16,
224}
225
226/// `CBDT` — Color Bitmap Data Table
227pub struct CBDTTable<'a> {
228    /// Major version of this table.
229    ///
230    /// 2 for `EBDT`, 3, for `CBDT`
231    pub major_version: u16,
232    /// Minor version of this table.
233    pub minor_version: u16,
234    /// The raw data of the whole `CBDT` table.
235    data: ReadScope<'a>,
236}
237
238/// Record corresponding to data read from `CBDT`.
239pub enum GlyphBitmapData<'a> {
240    /// Format 1: small metrics, byte-aligned data.
241    Format1 {
242        /// Metrics information for the glyph.
243        small_metrics: SmallGlyphMetrics,
244        /// Byte-aligned bitmap data.
245        data: &'a [u8],
246    },
247    /// Format 2: small metrics, bit-aligned data.
248    Format2 {
249        /// Metrics information for the glyph.
250        small_metrics: SmallGlyphMetrics,
251        /// Bit-aligned bitmap data.
252        data: &'a [u8],
253    },
254    // Format3 (obsolete, not in OpenType spec)
255    // Format4 (not supported by OpenType, Apple specific)
256    /// Format 5: metrics in EBLC, bit-aligned image data only.
257    Format5 {
258        /// Metrics information for the glyph.
259        big_metrics: BigGlyphMetrics,
260        /// Bit-aligned bitmap data.
261        data: &'a [u8],
262    },
263    /// Format 6: big metrics, byte-aligned data.
264    Format6 {
265        /// Metrics information for the glyph.
266        big_metrics: BigGlyphMetrics,
267        /// Byte-aligned bitmap data.
268        data: &'a [u8],
269    },
270    /// Format7: big metrics, bit-aligned data.
271    Format7 {
272        /// Metrics information for the glyph.
273        big_metrics: BigGlyphMetrics,
274        /// Bit-aligned bitmap data.
275        data: &'a [u8],
276    },
277    /// Format 8: small metrics, component data.
278    Format8 {
279        /// Metrics information for the glyph.
280        small_metrics: SmallGlyphMetrics,
281        /// Array of EbdtComponent records.
282        components: ReadArray<'a, EbdtComponent>,
283    },
284    /// Format 9: big metrics, component data.
285    Format9 {
286        /// Metrics information for the glyph.
287        big_metrics: BigGlyphMetrics,
288        /// Array of EbdtComponent records.
289        components: ReadArray<'a, EbdtComponent>,
290    },
291    // 10-16 are not defined
292    /// Format 17: small metrics, PNG image data.
293    Format17 {
294        /// Metrics information for the glyph.
295        small_metrics: SmallGlyphMetrics,
296        /// Raw PNG data
297        data: &'a [u8],
298    },
299    /// Format 18: big metrics, PNG image data.
300    Format18 {
301        /// Metrics information for the glyph.
302        big_metrics: BigGlyphMetrics,
303        /// Raw PNG data
304        data: &'a [u8],
305    },
306    /// Format 19: metrics in CBLC table, PNG image data.
307    Format19 {
308        /// Metrics information for the glyph.
309        big_metrics: BigGlyphMetrics,
310        /// Raw PNG data
311        data: &'a [u8],
312    },
313}
314
315/// The EbdtComponent record is used in glyph bitmap data formats 8 and 9.
316pub struct EbdtComponent {
317    /// Component glyph ID
318    pub glyph_id: u16,
319    /// Position of component left
320    pub x_offset: i8,
321    /// Position of component top
322    pub y_offset: i8,
323}
324
325/// Result of `find_strike`.
326pub struct MatchingStrike<'a, 'b> {
327    pub(crate) bitmap_size: &'a BitmapSize<'b>,
328    index_subtable_index: usize,
329}
330
331/// Lookup a glyph in the supplied strike.
332///
333/// * `glyph_id` is the glyph to lookup.
334/// * `matching_strike` the strike to lookup the bitmap in. Acquired via
335///   [find_strike](./struct.CBLCTable.html#method.find_strike).
336/// * `cbdt` is a reference to the colour bitmap data table.
337///
338/// The returned `GlyphBitmapData` contains metrics and data for the bitmap, if found.
339///
340/// **Note:** that some fonts may contain bitmaps with `0x0` dimensions, so be prepared to handle
341/// those.
342pub 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            // Should not underflow because find_strike picked a strike that contains this glyph
358            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                // A small number of missing glyphs can be efficiently represented in formats 1 or
366                // 3 by having the offset for the missing glyph be followed by the same offset for
367                // the next glyph, thus indicating a data size of zero.
368                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            // Should not underflow because find_strike picked a strike that contains this glyph
397            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                // A small number of missing glyphs can be efficiently represented in formats 1 or
405                // 3 by having the offset for the missing glyph be followed by the same offset for
406                // the next glyph, thus indicating a data size of zero.
407                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            // Try to find the desired glyph in the offset pairs
421            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                    // Get the next pair to determine how big the image data for this glyph is
427                    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                    // Pairs are supposed to be ordered by glyph id so if we're past the one we're
435                    // looking for it won't be found.
436                    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            // Try to find the desired glyph in the list of glyphs covered by this index
450            for (glyph_index, this_glyph_id) in glyph_id_array.iter().enumerate() {
451                if this_glyph_id == glyph_id {
452                    // Found
453                    // cast is safe because glyph_id_array num_glyphs is a u32
454                    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                    // Array is meant to be ordered by glyph id so if we're past the one we're
465                    // looking for it won't be found.
466                    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    /// Find a strike matching the supplied criteria.
571    ///
572    /// * `glyph_id` is the glyph to lookup.
573    /// * `target_ppem` is the desired size. If an exact match can't be found the nearest one will
574    ///    be returned, favouring being oversize vs. undersized.
575    /// * `max_bit_depth` is the maximum accepted bit depth of the bitmap to return. If you accept
576    ///   all bit depths then use `BitDepth::ThirtyTwo`.
577    pub fn find_strike(
578        &self,
579        glyph_id: u16,
580        target_ppem: u8,
581        max_bit_depth: BitDepth,
582    ) -> Option<MatchingStrike<'_, 'a>> {
583        // Find a strike that contains the glyph we want, then find one with an appropriate size
584        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                        // Strike has higher bit depth than max_bit_depth
592                        None
593                    }
594                })
595        });
596
597        // Pick a candidate that maximises size and bit depth according to `size_ppem` and `max_bit_depth`.
598        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        // version 2 is EBLT, version 3 is CBLC, 3 is backward compatible but defines additional
648        // formats and bit depth.
649        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        // The locators in the CBLC table are relative to the start of the CBDT table.
670        // So we hold on to a scope at the start of the table for later use.
671        let data = ctxt.scope();
672        let major_version = ctxt.read_u16be()?;
673        // version 2 is EBLT, version 3 is CBLC, 3 is backward compatible but defines additional
674        // formats and bit depth.
675        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    /// Returns the index of the index sub table for the supplied glyph, if found.
687    fn index_sub_table_index(&self, glyph_id: u16) -> Option<usize> {
688        // The startGlyphIndex and endGlyphIndex describe the minimum and maximum glyph IDs in the
689        // strike, but a strike does not necessarily contain bitmaps for all glyph IDs in this
690        // range. The IndexSubTables determine which glyphs are actually present in the CBDT table.
691        // https://docs.microsoft.com/en-us/typography/opentype/spec/eblc#sbitlinemetrics
692        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    /// Returns the bit depth of this `MatchingStrike`.
704    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()?; // Not used; set to 0.
721        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        // Read the index sub tables
731        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            // Read the index sub table
743            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        // Offset32         indexSubTableArrayOffset
773        // uint32           indexTablesSize
774        // uint32           numberofIndexSubTables
775        // uint32           colorRef
776        (4 * size::U32)
777        // SbitLineMetrics  hori
778        // SbitLineMetrics  vert
779        + (2 * SbitLineMetrics::size(()))
780        // uint16           startGlyphIndex
781        // uint16           endGlyphIndex
782        + (2 * size::U16)
783        // uint8            ppemX
784        // uint8            ppemY
785        // uint8            bitDepth
786        // int8             flags
787        + 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 fields, all 1 byte
828        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                // +1 for last_glyph_index being inclusive,
886                // +1 for there being an extra record at the end
887                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                // +1 for last_glyph_index being inclusive,
908                // +1 for there being an extra record at the end
909                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 fields, all 1 byte
991        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            // Format 1: small metrics, byte-aligned data.
1041            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            // Format 2: small metrics, bit-aligned data.
1060            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            // Format 5: metrics in EBLC, bit-aligned image data only.
1086            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            // Format 6: big metrics, byte-aligned data.
1109            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            // Format7: big metrics, bit-aligned data.
1125            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            // Format 8: small metrics, component data.
1148            GlyphBitmapData::Format8 { .. } => return Err(ParseError::NotImplemented),
1149            // Format 9: big metrics, component data.
1150            GlyphBitmapData::Format9 { .. } => return Err(ParseError::NotImplemented),
1151            // Format 17: small metrics, PNG image data.
1152            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            // Format 18: big metrics, PNG image data.
1169            // Format 19: metrics in CBLC table, PNG image data.
1170            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    /// The width of the bitmap.
1192    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    /// The height of the bitmap.
1238    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                    // Convert from offset to the top of the image to bottom
1361                    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                    // Convert from offset to the top of the image to bottom
1376                    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        // Read whole bytes, then the remainder
1442        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            // This should only happen as a result of programmer error as we only call bitreader
1461            // with values <= 8.
1462            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        // Font has strikes in 12 14 16 18 20 22 24 28 32 ppem
1553        // Glyph 10 is ampersand
1554        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        // Test tables are from Noto Color Emoji
1567        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        // Glyph 1077 is Nerd Face U+1F913
1573        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        // Repeat the lookup with a lower max bit depth, should now fail to find suitable strike
1589        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}