1
#![deny(missing_docs)]
2

            
3
//! Bitmap fonts in `EBLC`/`EBDT` and `CBLC`/`CBDT` tables.
4

            
5
use std::fmt;
6

            
7
use super::BitDepth;
8
use crate::binary::read::{
9
    ReadArray, ReadBinary, ReadBinaryDep, ReadCtxt, ReadFixedSizeDep, ReadFrom, ReadScope,
10
};
11
use crate::binary::{U16Be, U32Be, I8, U8};
12
use crate::bitmap::{
13
    Bitmap, BitmapGlyph, BitmapMetrics, EmbeddedBitmap, EmbeddedMetrics, EncapsulatedBitmap,
14
    EncapsulatedFormat, Metrics,
15
};
16
use crate::error::ParseError;
17
use crate::size;
18
use crate::SafeFrom;
19

            
20
/// Flag in `BitmapInfo` `flags` indicating the direction of small glyph metrics is horizontal.
21
///
22
/// <https://docs.microsoft.com/en-us/typography/opentype/spec/eblc#bitmap-flags>
23
const HORIZONTAL_METRICS: i8 = 1;
24

            
25
/// Flag in `BitmapInfo` `flags` indicating the direction of small glyph metrics is vertical.
26
///
27
/// <https://docs.microsoft.com/en-us/typography/opentype/spec/eblc#bitmap-flags>
28
const VERTICAL_METRICS: i8 = 2;
29

            
30
/// `CBLC` — Color Bitmap Location Table
31
pub struct CBLCTable<'a> {
32
    /// Major version of this table.
33
    ///
34
    /// 2 for `EBLC`, 3, for `CBLC`
35
    pub major_version: u16,
36
    /// Minor version of this table.
37
    pub minor_version: u16,
38
    /// Array of "strikes" available for this font.
39
    pub bitmap_sizes: Vec<BitmapSize<'a>>,
40
}
41

            
42
/// A description of a "strike" of bitmap data.
43
pub struct BitmapSize<'a> {
44
    /// Bitmap information.
45
    pub inner: BitmapInfo,
46
    /// Index sub-table records.
47
    index_sub_table_records: ReadArray<'a, IndexSubTableRecord>,
48
    /// Index sub-tables, one for each record.
49
    index_sub_tables: Vec<IndexSubTable<'a>>,
50
}
51

            
52
#[allow(missing_docs)]
53
#[derive(Debug, Clone, Eq, PartialEq)]
54
pub struct SbitLineMetrics {
55
    pub ascender: i8,
56
    pub descender: i8,
57
    pub width_max: u8,
58
    pub caret_slope_numerator: i8,
59
    pub caret_slope_denominator: i8,
60
    pub caret_offset: i8,
61
    pub min_origin_sb: i8,
62
    pub min_advance_sb: i8,
63
    pub max_before_bl: i8,
64
    pub min_after_bl: i8,
65
    pub pad1: i8,
66
    pub pad2: i8,
67
}
68

            
69
/// Subset of BitmapSize that includes common fields.
70
#[derive(Debug, Clone, Eq, PartialEq)]
71
pub struct BitmapInfo {
72
    /// Line metrics for text rendered horizontally.
73
    pub hori: SbitLineMetrics,
74
    /// Line metrics for text rendered vertically.
75
    pub vert: SbitLineMetrics,
76
    /// Lowest glyph index for this size.
77
    pub start_glyph_index: u16,
78
    /// Highest glyph index for this size.
79
    pub end_glyph_index: u16,
80
    /// Horizontal pixels per em.
81
    pub ppem_x: u8,
82
    /// Vertical pixels per em.
83
    pub ppem_y: u8,
84
    /// Bit depth.
85
    ///
86
    /// In addition to already defined bitDepth values 1, 2, 4, and 8 supported by `EBDT` the value
87
    /// of 32 is used to identify color bitmaps with 8 bit per channel RGBA channels in `CBDT`.
88
    pub bit_depth: BitDepth,
89
    /// Vertical or horizontal.
90
    pub flags: i8,
91
}
92

            
93
/// Sub table record of `BitmapSize` describing a range of glyphs and the location of the sub
94
/// table.
95
struct IndexSubTableRecord {
96
    /// First glyph ID of this range.
97
    pub first_glyph_index: u16,
98
    /// Last glyph ID of this range (inclusive).
99
    pub last_glyph_index: u16,
100
    // Add to indexSubTableArrayOffset to get offset from beginning of EBLC.
101
    additional_offset_to_index_sub_table: u32,
102
}
103

            
104
/// An index sub table of a `BitmapSize` describing the image format and location.
105
///
106
/// The `IndexSubTable` provides the offset within `CBDT` where the bitmap data for a range of
107
/// glyphs (described by `IndexSubTableRecord`) can be found, optionally with metrics for the whole
108
/// range of glyphs as well, depending on the format.
109
enum IndexSubTable<'a> {
110
    /// IndexSubTable1: variable-metrics glyphs with 4-byte offsets.
111
    Format1 {
112
        /// Format of EBDT image data.
113
        image_format: ImageFormat,
114
        /// Offset to image data in EBDT table.
115
        image_data_offset: u32,
116
        /// Offsets into `EBDT` for bitmap data.
117
        ///
118
        /// The actual offset for a glyph is `image_data_offset` + the value read from this
119
        /// array.
120
        offsets: ReadArray<'a, U32Be>,
121
    },
122
    /// IndexSubTable2: all glyphs have identical metrics.
123
    Format2 {
124
        /// Format of EBDT image data.
125
        image_format: ImageFormat,
126
        /// Offset to image data in EBDT table.
127
        image_data_offset: u32,
128
        /// The size of the data for each bitmap.
129
        image_size: u32,
130
        /// Metrics for all glyphs in this range.
131
        big_metrics: BigGlyphMetrics,
132
    },
133
    /// IndexSubTable3: variable-metrics glyphs with 2-byte offsets.
134
    Format3 {
135
        /// Format of EBDT image data.
136
        image_format: ImageFormat,
137
        /// Offset to image data in EBDT table.
138
        image_data_offset: u32,
139
        /// Offsets into `EBDT` for bitmap data.
140
        ///
141
        /// The actual offset for a glyph is `image_data_offset` + the value read from this
142
        /// array.
143
        offsets: ReadArray<'a, U16Be>,
144
    },
145
    /// IndexSubTable4: variable-metrics glyphs with sparse glyph codes.
146
    Format4 {
147
        /// Format of EBDT image data.
148
        image_format: ImageFormat,
149
        /// Offset to image data in EBDT table.
150
        image_data_offset: u32,
151
        /// Array of ranges.
152
        glyph_array: ReadArray<'a, GlyphOffsetPair>,
153
    },
154
    /// IndexSubTable5: constant-metrics glyphs with sparse glyph codes.
155
    Format5 {
156
        /// Format of EBDT image data.
157
        image_format: ImageFormat,
158
        /// Offset to image data in EBDT table.
159
        image_data_offset: u32,
160
        /// All glyphs have the same data size.
161
        image_size: u32,
162
        /// All glyphs have the same metrics.
163
        big_metrics: BigGlyphMetrics,
164
        /// One per glyph, sorted by glyph ID.
165
        glyph_id_array: ReadArray<'a, U16Be>,
166
    },
167
}
168

            
169
/// Valid image formats
170
#[allow(missing_docs)]
171
#[derive(Copy, Clone)]
172
pub enum ImageFormat {
173
    Format1,
174
    Format2,
175
    Format5,
176
    Format6,
177
    Format7,
178
    Format8,
179
    Format9,
180
    Format17,
181
    Format18,
182
    Format19,
183
}
184

            
185
#[allow(missing_docs)]
186
#[derive(Debug, Copy, Clone)]
187
pub struct SmallGlyphMetrics {
188
    pub height: u8,
189
    pub width: u8,
190
    pub bearing_x: i8,
191
    pub bearing_y: i8,
192
    pub advance: u8,
193
}
194

            
195
#[allow(missing_docs)]
196
#[derive(Debug, Copy, Clone)]
197
pub struct BigGlyphMetrics {
198
    pub height: u8,
199
    pub width: u8,
200
    pub hori_bearing_x: i8,
201
    pub hori_bearing_y: i8,
202
    pub hori_advance: u8,
203
    pub vert_bearing_x: i8,
204
    pub vert_bearing_y: i8,
205
    pub vert_advance: u8,
206
}
207

            
208
/// The direction of small glyph metrics when present.
209
enum MetricsDirection {
210
    Horizontal,
211
    Vertical,
212
    Unknown,
213
}
214

            
215
/// Record indicating the offset in `EBDT` for a specific glyph id.
216
struct GlyphOffsetPair {
217
    /// Glyph ID of glyph present.
218
    pub glyph_id: u16,
219
    /// Location in EBDT.
220
    pub offset: u16,
221
}
222

            
223
/// `CBDT` — Color Bitmap Data Table
224
pub struct CBDTTable<'a> {
225
    /// Major version of this table.
226
    ///
227
    /// 2 for `EBDT`, 3, for `CBDT`
228
    pub major_version: u16,
229
    /// Minor version of this table.
230
    pub minor_version: u16,
231
    /// The raw data of the whole `CBDT` table.
232
    data: ReadScope<'a>,
233
}
234

            
235
/// Record corresponding to data read from `CBDT`.
236
pub enum GlyphBitmapData<'a> {
237
    /// Format 1: small metrics, byte-aligned data.
238
    Format1 {
239
        /// Metrics information for the glyph.
240
        small_metrics: SmallGlyphMetrics,
241
        /// Byte-aligned bitmap data.
242
        data: &'a [u8],
243
    },
244
    /// Format 2: small metrics, bit-aligned data.
245
    Format2 {
246
        /// Metrics information for the glyph.
247
        small_metrics: SmallGlyphMetrics,
248
        /// Bit-aligned bitmap data.
249
        data: &'a [u8],
250
    },
251
    // Format3 (obsolete, not in OpenType spec)
252
    // Format4 (not supported by OpenType, Apple specific)
253
    /// Format 5: metrics in EBLC, bit-aligned image data only.
254
    Format5 {
255
        /// Metrics information for the glyph.
256
        big_metrics: BigGlyphMetrics,
257
        /// Bit-aligned bitmap data.
258
        data: &'a [u8],
259
    },
260
    /// Format 6: big metrics, byte-aligned data.
261
    Format6 {
262
        /// Metrics information for the glyph.
263
        big_metrics: BigGlyphMetrics,
264
        /// Byte-aligned bitmap data.
265
        data: &'a [u8],
266
    },
267
    /// Format7: big metrics, bit-aligned data.
268
    Format7 {
269
        /// Metrics information for the glyph.
270
        big_metrics: BigGlyphMetrics,
271
        /// Bit-aligned bitmap data.
272
        data: &'a [u8],
273
    },
274
    /// Format 8: small metrics, component data.
275
    Format8 {
276
        /// Metrics information for the glyph.
277
        small_metrics: SmallGlyphMetrics,
278
        /// Array of EbdtComponent records.
279
        components: ReadArray<'a, EbdtComponent>,
280
    },
281
    /// Format 9: big metrics, component data.
282
    Format9 {
283
        /// Metrics information for the glyph.
284
        big_metrics: BigGlyphMetrics,
285
        /// Array of EbdtComponent records.
286
        components: ReadArray<'a, EbdtComponent>,
287
    },
288
    // 10-16 are not defined
289
    /// Format 17: small metrics, PNG image data.
290
    Format17 {
291
        /// Metrics information for the glyph.
292
        small_metrics: SmallGlyphMetrics,
293
        /// Raw PNG data
294
        data: &'a [u8],
295
    },
296
    /// Format 18: big metrics, PNG image data.
297
    Format18 {
298
        /// Metrics information for the glyph.
299
        big_metrics: BigGlyphMetrics,
300
        /// Raw PNG data
301
        data: &'a [u8],
302
    },
303
    /// Format 19: metrics in CBLC table, PNG image data.
304
    Format19 {
305
        /// Metrics information for the glyph.
306
        big_metrics: BigGlyphMetrics,
307
        /// Raw PNG data
308
        data: &'a [u8],
309
    },
310
}
311

            
312
/// The EbdtComponent record is used in glyph bitmap data formats 8 and 9.
313
pub struct EbdtComponent {
314
    /// Component glyph ID
315
    pub glyph_id: u16,
316
    /// Position of component left
317
    pub x_offset: i8,
318
    /// Position of component top
319
    pub y_offset: i8,
320
}
321

            
322
/// Result of `find_strike`.
323
pub struct MatchingStrike<'a, 'b> {
324
    /// The glyph index for which the strike was matched.
325
    glyph_id: u16,
326
    pub(crate) bitmap_size: &'a BitmapSize<'b>,
327
    index_subtable_index: usize,
328
}
329

            
330
impl MatchingStrike<'_, '_> {
331
    /// Retrieve the bitmap data from the supplied strike.
332
    ///
333
    /// * `matching_strike` the strike to lookup the bitmap in. Acquired via
334
    ///   [find_strike](./struct.CBLCTable.html#method.find_strike).
335
    /// * `cbdt` is a reference to the colour bitmap data table.
336
    ///
337
    /// The returned `GlyphBitmapData` contains metrics and data for the bitmap, if found.
338
    ///
339
    /// **Note:** that some fonts may contain bitmaps with `0x0` dimensions, so be prepared to handle
340
    /// those.
341
    pub fn bitmap<'cbdt>(
342
        &self,
343
        cbdt: &CBDTTable<'cbdt>,
344
    ) -> Result<Option<GlyphBitmapData<'cbdt>>, ParseError> {
345
        let glyph_id = self.glyph_id;
346

            
347
        // NOTE(unwrap): Safe as MatchingStrike is only constructed with valid index_subtable_index.
348
        let index_sub_table_header: &IndexSubTableRecord = &self
349
            .bitmap_size
350
            .index_sub_table_records
351
            .get_item(self.index_subtable_index)
352
            .unwrap();
353
        match &self.bitmap_size.index_sub_tables[self.index_subtable_index] {
354
            IndexSubTable::Format1 {
355
                image_format,
356
                image_data_offset,
357
                offsets,
358
            } => {
359
                // Should not underflow because find_strike picked a strike that contains this glyph
360
                let glyph_index = usize::from(glyph_id - index_sub_table_header.first_glyph_index);
361
                let start =
362
                    usize::safe_from(offsets.get_item(glyph_index).ok_or(ParseError::BadIndex)?);
363
                let end = usize::safe_from(
364
                    offsets
365
                        .get_item(glyph_index + 1)
366
                        .ok_or(ParseError::BadIndex)?,
367
                );
368
                let length = end - start;
369

            
370
                if length == 0 {
371
                    // A small number of missing glyphs can be efficiently represented in formats 1 or
372
                    // 3 by having the offset for the missing glyph be followed by the same offset for
373
                    // the next glyph, thus indicating a data size of zero.
374
                    return Ok(None);
375
                }
376

            
377
                let offset = usize::safe_from(*image_data_offset) + start;
378
                let mut ctxt = cbdt.data.offset_length(offset, length)?.ctxt();
379
                let bitmap = ctxt.read_dep::<ImageFormat>((*image_format, None))?;
380
                Ok(Some(bitmap))
381
            }
382
            IndexSubTable::Format2 {
383
                image_format,
384
                image_data_offset,
385
                image_size,
386
                big_metrics,
387
            } => {
388
                let glyph_index = u32::from(glyph_id - index_sub_table_header.first_glyph_index);
389
                let offset = usize::try_from(image_data_offset + (glyph_index * image_size))?;
390
                let mut ctxt = cbdt
391
                    .data
392
                    .offset_length(offset, usize::try_from(*image_size)?)?
393
                    .ctxt();
394
                let bitmap = ctxt.read_dep::<ImageFormat>((*image_format, Some(*big_metrics)))?;
395
                Ok(Some(bitmap))
396
            }
397
            IndexSubTable::Format3 {
398
                image_format,
399
                image_data_offset,
400
                offsets,
401
            } => {
402
                // Should not underflow because find_strike picked a strike that contains this glyph
403
                let glyph_index = usize::from(glyph_id - index_sub_table_header.first_glyph_index);
404
                let start = usize::from(offsets.get_item(glyph_index).ok_or(ParseError::BadIndex)?);
405
                let end = usize::from(
406
                    offsets
407
                        .get_item(glyph_index + 1)
408
                        .ok_or(ParseError::BadIndex)?,
409
                );
410
                let length = end - start;
411

            
412
                if length == 0 {
413
                    // A small number of missing glyphs can be efficiently represented in formats 1 or
414
                    // 3 by having the offset for the missing glyph be followed by the same offset for
415
                    // the next glyph, thus indicating a data size of zero.
416
                    return Ok(None);
417
                }
418

            
419
                let offset = usize::try_from(*image_data_offset)? + start;
420
                let mut ctxt = cbdt.data.offset_length(offset, length)?.ctxt();
421
                let bitmap = ctxt.read_dep::<ImageFormat>((*image_format, None))?;
422
                Ok(Some(bitmap))
423
            }
424
            IndexSubTable::Format4 {
425
                image_format,
426
                image_data_offset,
427
                glyph_array,
428
            } => {
429
                // Try to find the desired glyph in the offset pairs
430
                for (glyph_index, glyph_offset_pair) in glyph_array.iter().enumerate() {
431
                    if glyph_offset_pair.glyph_id == glyph_id {
432
                        let offset = usize::try_from(*image_data_offset)?
433
                            + usize::from(glyph_offset_pair.offset);
434

            
435
                        // Get the next pair to determine how big the image data for this glyph is
436
                        let end = glyph_array
437
                            .get_item(glyph_index + 1)
438
                            .ok_or(ParseError::BadIndex)?;
439
                        let length = usize::from(end.offset - glyph_offset_pair.offset);
440
                        let mut ctxt = cbdt.data.offset_length(offset, length)?.ctxt();
441
                        let bitmap = ctxt.read_dep::<ImageFormat>((*image_format, None))?;
442
                        return Ok(Some(bitmap));
443
                    } else if glyph_offset_pair.glyph_id > glyph_id {
444
                        // Pairs are supposed to be ordered by glyph id so if we're past the one we're
445
                        // looking for it won't be found.
446
                        return Ok(None);
447
                    }
448
                }
449

            
450
                Ok(None)
451
            }
452
            IndexSubTable::Format5 {
453
                image_format,
454
                image_data_offset,
455
                image_size,
456
                big_metrics,
457
                glyph_id_array,
458
            } => {
459
                // Try to find the desired glyph in the list of glyphs covered by this index
460
                for (glyph_index, this_glyph_id) in glyph_id_array.iter().enumerate() {
461
                    if this_glyph_id == glyph_id {
462
                        // Found
463
                        // cast is safe because glyph_id_array num_glyphs is a u32
464
                        let offset =
465
                            usize::try_from(image_data_offset + (glyph_index as u32 * image_size))?;
466
                        let mut ctxt = cbdt
467
                            .data
468
                            .offset_length(offset, usize::try_from(*image_size)?)?
469
                            .ctxt();
470
                        let bitmap =
471
                            ctxt.read_dep::<ImageFormat>((*image_format, Some(*big_metrics)))?;
472
                        return Ok(Some(bitmap));
473
                    } else if this_glyph_id > glyph_id {
474
                        // Array is meant to be ordered by glyph id so if we're past the one we're
475
                        // looking for it won't be found.
476
                        return Ok(None);
477
                    }
478
                }
479

            
480
                Ok(None)
481
            }
482
        }
483
    }
484
}
485

            
486
impl ReadBinaryDep for ImageFormat {
487
    type Args<'a> = (ImageFormat, Option<BigGlyphMetrics>);
488
    type HostType<'a> = GlyphBitmapData<'a>;
489

            
490
    fn read_dep<'a>(
491
        ctxt: &mut ReadCtxt<'a>,
492
        (format, metrics): Self::Args<'_>,
493
    ) -> Result<Self::HostType<'a>, ParseError> {
494
        match format {
495
            ImageFormat::Format1 => {
496
                let small_metrics = ctxt.read::<SmallGlyphMetrics>()?;
497
                let data = ctxt.scope().data();
498

            
499
                Ok(GlyphBitmapData::Format1 {
500
                    small_metrics,
501
                    data,
502
                })
503
            }
504
            ImageFormat::Format2 => {
505
                let small_metrics = ctxt.read::<SmallGlyphMetrics>()?;
506
                let data = ctxt.scope().data();
507

            
508
                Ok(GlyphBitmapData::Format2 {
509
                    small_metrics,
510
                    data,
511
                })
512
            }
513
            ImageFormat::Format5 => Ok(GlyphBitmapData::Format5 {
514
                big_metrics: metrics.ok_or(ParseError::MissingValue)?,
515
                data: ctxt.scope().data(),
516
            }),
517
            ImageFormat::Format6 => {
518
                let big_metrics = ctxt.read::<BigGlyphMetrics>()?;
519
                let data = ctxt.scope().data();
520

            
521
                Ok(GlyphBitmapData::Format6 { big_metrics, data })
522
            }
523
            ImageFormat::Format7 => {
524
                let big_metrics = ctxt.read::<BigGlyphMetrics>()?;
525
                let data = ctxt.scope().data();
526

            
527
                Ok(GlyphBitmapData::Format7 { big_metrics, data })
528
            }
529
            ImageFormat::Format8 => {
530
                let small_metrics = ctxt.read::<SmallGlyphMetrics>()?;
531
                let _pad = ctxt.read_u8()?;
532
                let num_components = usize::from(ctxt.read_u16be()?);
533
                let components = ctxt.read_array::<EbdtComponent>(num_components)?;
534

            
535
                Ok(GlyphBitmapData::Format8 {
536
                    small_metrics,
537
                    components,
538
                })
539
            }
540
            ImageFormat::Format9 => {
541
                let big_metrics = ctxt.read::<BigGlyphMetrics>()?;
542
                let num_components = usize::from(ctxt.read_u16be()?);
543
                let components = ctxt.read_array::<EbdtComponent>(num_components)?;
544

            
545
                Ok(GlyphBitmapData::Format9 {
546
                    big_metrics,
547
                    components,
548
                })
549
            }
550
            ImageFormat::Format17 => {
551
                let small_metrics = ctxt.read::<SmallGlyphMetrics>()?;
552
                let data_len = usize::try_from(ctxt.read_u32be()?)?;
553
                let data = ctxt.read_slice(data_len)?;
554

            
555
                Ok(GlyphBitmapData::Format17 {
556
                    small_metrics,
557
                    data,
558
                })
559
            }
560
            ImageFormat::Format18 => {
561
                let big_metrics = ctxt.read::<BigGlyphMetrics>()?;
562
                let data_len = usize::try_from(ctxt.read_u32be()?)?;
563
                let data = ctxt.read_slice(data_len)?;
564

            
565
                Ok(GlyphBitmapData::Format18 { big_metrics, data })
566
            }
567
            ImageFormat::Format19 => {
568
                let data_len = usize::try_from(ctxt.read_u32be()?)?;
569
                let data = ctxt.read_slice(data_len)?;
570

            
571
                Ok(GlyphBitmapData::Format19 {
572
                    big_metrics: metrics.ok_or(ParseError::MissingValue)?,
573
                    data,
574
                })
575
            }
576
        }
577
    }
578
}
579

            
580
impl<'a> CBLCTable<'a> {
581
    /// Find a strike matching the supplied criteria.
582
    ///
583
    /// * `glyph_id` is the glyph to lookup.
584
    /// * `target_ppem` is the desired size. If an exact match can't be found the nearest one will
585
    ///    be returned, favouring being oversize vs. undersized.
586
    /// * `max_bit_depth` is the maximum accepted bit depth of the bitmap to return. If you accept
587
    ///   all bit depths then use `BitDepth::ThirtyTwo`.
588
    pub fn find_strike(
589
        &self,
590
        glyph_id: u16,
591
        target_ppem: u8,
592
        max_bit_depth: BitDepth,
593
    ) -> Option<MatchingStrike<'_, 'a>> {
594
        // Find a strike that contains the glyph we want, then find one with an appropriate size
595
        let candidates = self.bitmap_sizes.iter().filter_map(|bitmap_size| {
596
            bitmap_size
597
                .index_sub_table_index(glyph_id)
598
                .and_then(|index| {
599
                    if bitmap_size.inner.bit_depth <= max_bit_depth {
600
                        Some((bitmap_size, index))
601
                    } else {
602
                        // Strike has higher bit depth than max_bit_depth
603
                        None
604
                    }
605
                })
606
        });
607

            
608
        // Pick a candidate that maximises size and bit depth according to `size_ppem` and `max_bit_depth`.
609
        let size_ppem = i16::from(target_ppem);
610
        let mut best: Option<(i16, &BitmapSize<'a>, usize)> = None;
611

            
612
        for (bitmap_size, index) in candidates {
613
            let difference = i16::from(bitmap_size.inner.ppem_x) - size_ppem;
614
            match best {
615
                Some((current_best_difference, current_best_bitmap_size, _))
616
                    if same_size_higher_bit_depth(
617
                        difference,
618
                        current_best_difference,
619
                        bitmap_size.inner.bit_depth,
620
                        current_best_bitmap_size.inner.bit_depth,
621
                    ) =>
622
                {
623
                    best = Some((difference, bitmap_size, index))
624
                }
625
                Some((current_best_difference, _, _))
626
                    if super::bigger_or_closer_to_zero(
627
                        i32::from(difference),
628
                        i32::from(current_best_difference),
629
                    ) =>
630
                {
631
                    best = Some((difference, bitmap_size, index))
632
                }
633
                None => best = Some((difference, bitmap_size, index)),
634
                _ => (),
635
            }
636
        }
637

            
638
        best.map(|(_, bitmap_size, index)| MatchingStrike {
639
            glyph_id,
640
            bitmap_size,
641
            index_subtable_index: index,
642
        })
643
    }
644
}
645

            
646
fn same_size_higher_bit_depth(
647
    difference: i16,
648
    current_best_difference: i16,
649
    candiate_bit_depth: BitDepth,
650
    current_best_bit_depth: BitDepth,
651
) -> bool {
652
    difference == current_best_difference && candiate_bit_depth > current_best_bit_depth
653
}
654

            
655
impl ReadBinary for CBLCTable<'_> {
656
    type HostType<'a> = CBLCTable<'a>;
657

            
658
    fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
659
        let table = ctxt.scope();
660

            
661
        let major_version = ctxt.read_u16be()?;
662
        // version 2 is EBLT, version 3 is CBLC, 3 is backward compatible but defines additional
663
        // formats and bit depth.
664
        ctxt.check_version((2..=3).contains(&major_version))?;
665
        let minor_version = ctxt.read_u16be()?;
666
        let num_sizes = ctxt.read_u32be()?;
667
        let bitmap_sizes = ctxt
668
            .read_array_dep::<BitmapSize<'_>>(usize::try_from(num_sizes)?, table)?
669
            .iter_res()
670
            .collect::<Result<Vec<_>, _>>()?;
671

            
672
        Ok(CBLCTable {
673
            major_version,
674
            minor_version,
675
            bitmap_sizes,
676
        })
677
    }
678
}
679

            
680
impl ReadBinary for CBDTTable<'_> {
681
    type HostType<'a> = CBDTTable<'a>;
682

            
683
    fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
684
        // The locators in the CBLC table are relative to the start of the CBDT table.
685
        // So we hold on to a scope at the start of the table for later use.
686
        let data = ctxt.scope();
687
        let major_version = ctxt.read_u16be()?;
688
        // version 2 is EBLT, version 3 is CBLC, 3 is backward compatible but defines additional
689
        // formats and bit depth.
690
        ctxt.check_version((2..=3).contains(&major_version))?;
691
        let minor_version = ctxt.read_u16be()?;
692
        Ok(CBDTTable {
693
            major_version,
694
            minor_version,
695
            data,
696
        })
697
    }
698
}
699

            
700
impl BitmapSize<'_> {
701
    /// Returns the index of the index sub table for the supplied glyph, if found.
702
    fn index_sub_table_index(&self, glyph_id: u16) -> Option<usize> {
703
        // The startGlyphIndex and endGlyphIndex describe the minimum and maximum glyph IDs in the
704
        // strike, but a strike does not necessarily contain bitmaps for all glyph IDs in this
705
        // range. The IndexSubTables determine which glyphs are actually present in the CBDT table.
706
        // https://docs.microsoft.com/en-us/typography/opentype/spec/eblc#sbitlinemetrics
707
        if (self.inner.start_glyph_index..=self.inner.end_glyph_index).contains(&glyph_id) {
708
            self.index_sub_table_records
709
                .iter()
710
                .position(|record| record.contains_glyph(glyph_id))
711
        } else {
712
            None
713
        }
714
    }
715
}
716

            
717
impl MatchingStrike<'_, '_> {
718
    /// Returns the bit depth of this `MatchingStrike`.
719
    pub fn bit_depth(&self) -> BitDepth {
720
        self.bitmap_size.inner.bit_depth
721
    }
722
}
723

            
724
impl ReadBinaryDep for BitmapSize<'_> {
725
    type Args<'a> = ReadScope<'a>;
726
    type HostType<'a> = BitmapSize<'a>;
727

            
728
    fn read_dep<'a>(
729
        ctxt: &mut ReadCtxt<'a>,
730
        cblc_scope: Self::Args<'a>,
731
    ) -> Result<Self::HostType<'a>, ParseError> {
732
        let index_sub_table_array_offset = usize::try_from(ctxt.read_u32be()?)?;
733
        let _index_tables_size = ctxt.read_u32be()?;
734
        let number_of_index_sub_tables = ctxt.read_u32be()?;
735
        let _color_ref = ctxt.read_u32be()?; // Not used; set to 0.
736
        let hori = ctxt.read::<SbitLineMetrics>()?;
737
        let vert = ctxt.read::<SbitLineMetrics>()?;
738
        let start_glyph_index = ctxt.read_u16be()?;
739
        let end_glyph_index = ctxt.read_u16be()?;
740
        let ppem_x = ctxt.read_u8()?;
741
        let ppem_y = ctxt.read_u8()?;
742
        let bit_depth = BitDepth::try_from(ctxt.read_u8()?)?;
743
        let flags = ctxt.read_i8()?;
744

            
745
        // Read the index sub tables
746
        let index_sub_table_records: ReadArray<'_, IndexSubTableRecord> = cblc_scope
747
            .offset(index_sub_table_array_offset)
748
            .ctxt()
749
            .read_array::<IndexSubTableRecord>(usize::try_from(number_of_index_sub_tables)?)?;
750
        let mut index_sub_tables = Vec::with_capacity(usize::try_from(number_of_index_sub_tables)?);
751
        for index_sub_table_record in index_sub_table_records.iter() {
752
            let offset = index_sub_table_array_offset
753
                .checked_add(usize::try_from(
754
                    index_sub_table_record.additional_offset_to_index_sub_table,
755
                )?)
756
                .ok_or(ParseError::BadOffset)?;
757
            // Read the index sub table
758
            let index_sub_table = cblc_scope
759
                .offset(offset)
760
                .ctxt()
761
                .read_dep::<IndexSubTable<'_>>((
762
                    index_sub_table_record.first_glyph_index,
763
                    index_sub_table_record.last_glyph_index,
764
                ))?;
765
            index_sub_tables.push(index_sub_table);
766
        }
767

            
768
        Ok(BitmapSize {
769
            inner: BitmapInfo {
770
                hori,
771
                vert,
772
                start_glyph_index,
773
                end_glyph_index,
774
                ppem_x,
775
                ppem_y,
776
                bit_depth,
777
                flags,
778
            },
779
            index_sub_table_records,
780
            index_sub_tables,
781
        })
782
    }
783
}
784

            
785
impl ReadFixedSizeDep for BitmapSize<'_> {
786
    fn size(_: Self::Args<'_>) -> usize {
787
        // Offset32         indexSubTableArrayOffset
788
        // uint32           indexTablesSize
789
        // uint32           numberofIndexSubTables
790
        // uint32           colorRef
791
        (4 * size::U32)
792
        // SbitLineMetrics  hori
793
        // SbitLineMetrics  vert
794
        + (2 * SbitLineMetrics::size(()))
795
        // uint16           startGlyphIndex
796
        // uint16           endGlyphIndex
797
        + (2 * size::U16)
798
        // uint8            ppemX
799
        // uint8            ppemY
800
        // uint8            bitDepth
801
        // int8             flags
802
        + 4
803
    }
804
}
805

            
806
impl ReadBinary for SbitLineMetrics {
807
    type HostType<'b> = Self;
808

            
809
    fn read(ctxt: &mut ReadCtxt<'_>) -> Result<Self, ParseError> {
810
        let ascender = ctxt.read_i8()?;
811
        let descender = ctxt.read_i8()?;
812
        let width_max = ctxt.read_u8()?;
813
        let caret_slope_numerator = ctxt.read_i8()?;
814
        let caret_slope_denominator = ctxt.read_i8()?;
815
        let caret_offset = ctxt.read_i8()?;
816
        let min_origin_sb = ctxt.read_i8()?;
817
        let min_advance_sb = ctxt.read_i8()?;
818
        let max_before_bl = ctxt.read_i8()?;
819
        let min_after_bl = ctxt.read_i8()?;
820
        let pad1 = ctxt.read_i8()?;
821
        let pad2 = ctxt.read_i8()?;
822

            
823
        Ok(SbitLineMetrics {
824
            ascender,
825
            descender,
826
            width_max,
827
            caret_slope_numerator,
828
            caret_slope_denominator,
829
            caret_offset,
830
            min_origin_sb,
831
            min_advance_sb,
832
            max_before_bl,
833
            min_after_bl,
834
            pad1,
835
            pad2,
836
        })
837
    }
838
}
839

            
840
impl ReadFixedSizeDep for SbitLineMetrics {
841
    fn size(_scope: Self::Args<'_>) -> usize {
842
        // 12 fields, all 1 byte
843
        12
844
    }
845
}
846

            
847
impl TryFrom<u8> for BitDepth {
848
    type Error = ParseError;
849

            
850
    fn try_from(value: u8) -> Result<Self, Self::Error> {
851
        match value {
852
            1 => Ok(BitDepth::One),
853
            2 => Ok(BitDepth::Two),
854
            4 => Ok(BitDepth::Four),
855
            8 => Ok(BitDepth::Eight),
856
            32 => Ok(BitDepth::ThirtyTwo),
857
            _ => Err(ParseError::BadValue),
858
        }
859
    }
860
}
861

            
862
impl IndexSubTableRecord {
863
    fn contains_glyph(&self, glyph_id: u16) -> bool {
864
        (self.first_glyph_index..=self.last_glyph_index).contains(&glyph_id)
865
    }
866
}
867

            
868
impl ReadFrom for IndexSubTableRecord {
869
    type ReadType = (U16Be, U16Be, U32Be);
870

            
871
    fn read_from(
872
        (first_glyph_index, last_glyph_index, additional_offset_to_index_sub_table): (
873
            u16,
874
            u16,
875
            u32,
876
        ),
877
    ) -> Self {
878
        IndexSubTableRecord {
879
            first_glyph_index,
880
            last_glyph_index,
881
            additional_offset_to_index_sub_table,
882
        }
883
    }
884
}
885

            
886
impl ReadBinaryDep for IndexSubTable<'_> {
887
    type Args<'a> = (u16, u16);
888
    type HostType<'a> = IndexSubTable<'a>;
889

            
890
    fn read_dep<'a>(
891
        ctxt: &mut ReadCtxt<'a>,
892
        (first_glyph_index, last_glyph_index): (u16, u16),
893
    ) -> Result<Self::HostType<'a>, ParseError> {
894
        let index_format = ctxt.read_u16be()?;
895
        let image_format = ImageFormat::try_from(ctxt.read_u16be()?)?;
896
        let image_data_offset = ctxt.read_u32be()?;
897

            
898
        match index_format {
899
            1 => {
900
                // +1 for last_glyph_index being inclusive,
901
                // +1 for there being an extra record at the end
902
                let offsets = ctxt.read_array::<U32Be>(usize::from(
903
                    last_glyph_index - first_glyph_index + 1 + 1,
904
                ))?;
905
                Ok(IndexSubTable::Format1 {
906
                    image_format,
907
                    image_data_offset,
908
                    offsets,
909
                })
910
            }
911
            2 => {
912
                let image_size = ctxt.read_u32be()?;
913
                let big_metrics = ctxt.read::<BigGlyphMetrics>()?;
914
                Ok(IndexSubTable::Format2 {
915
                    image_format,
916
                    image_data_offset,
917
                    image_size,
918
                    big_metrics,
919
                })
920
            }
921
            3 => {
922
                // +1 for last_glyph_index being inclusive,
923
                // +1 for there being an extra record at the end
924
                let offsets = ctxt.read_array::<U16Be>(usize::from(
925
                    last_glyph_index - first_glyph_index + 1 + 1,
926
                ))?;
927
                Ok(IndexSubTable::Format3 {
928
                    image_format,
929
                    image_data_offset,
930
                    offsets,
931
                })
932
            }
933
            4 => {
934
                let num_glyphs = ctxt.read_u32be()?;
935
                let glyph_array =
936
                    ctxt.read_array::<GlyphOffsetPair>(usize::try_from(num_glyphs + 1)?)?;
937
                Ok(IndexSubTable::Format4 {
938
                    image_format,
939
                    image_data_offset,
940
                    glyph_array,
941
                })
942
            }
943
            5 => {
944
                let image_size = ctxt.read_u32be()?;
945
                let big_metrics = ctxt.read::<BigGlyphMetrics>()?;
946
                let num_glyphs = ctxt.read_u32be()?;
947
                let glyph_id_array = ctxt.read_array::<U16Be>(usize::try_from(num_glyphs)?)?;
948
                Ok(IndexSubTable::Format5 {
949
                    image_format,
950
                    image_data_offset,
951
                    image_size,
952
                    big_metrics,
953
                    glyph_id_array,
954
                })
955
            }
956
            _ => Err(ParseError::BadValue),
957
        }
958
    }
959
}
960

            
961
impl ReadFrom for SmallGlyphMetrics {
962
    type ReadType = ((U8, U8), (I8, I8, U8));
963

            
964
    fn read_from(
965
        ((height, width), (bearing_x, bearing_y, advance)): ((u8, u8), (i8, i8, u8)),
966
    ) -> Self {
967
        SmallGlyphMetrics {
968
            height,
969
            width,
970
            bearing_x,
971
            bearing_y,
972
            advance,
973
        }
974
    }
975
}
976

            
977
impl ReadBinary for BigGlyphMetrics {
978
    type HostType<'b> = Self;
979

            
980
    fn read(ctxt: &mut ReadCtxt<'_>) -> Result<Self, ParseError> {
981
        let height = ctxt.read_u8()?;
982
        let width = ctxt.read_u8()?;
983
        let hori_bearing_x = ctxt.read_i8()?;
984
        let hori_bearing_y = ctxt.read_i8()?;
985
        let hori_advance = ctxt.read_u8()?;
986
        let vert_bearing_x = ctxt.read_i8()?;
987
        let vert_bearing_y = ctxt.read_i8()?;
988
        let vert_advance = ctxt.read_u8()?;
989

            
990
        Ok(BigGlyphMetrics {
991
            height,
992
            width,
993
            hori_bearing_x,
994
            hori_bearing_y,
995
            hori_advance,
996
            vert_bearing_x,
997
            vert_bearing_y,
998
            vert_advance,
999
        })
    }
}
impl ReadFixedSizeDep for BigGlyphMetrics {
    fn size(_scope: Self::Args<'_>) -> usize {
        // 8 fields, all 1 byte
        8
    }
}
impl ReadFrom for GlyphOffsetPair {
    type ReadType = (U16Be, U16Be);
    fn read_from((glyph_id, offset): (u16, u16)) -> Self {
        GlyphOffsetPair { glyph_id, offset }
    }
}
impl ReadFrom for EbdtComponent {
    type ReadType = (U16Be, I8, I8);
    fn read_from((glyph_id, x_offset, y_offset): (u16, i8, i8)) -> Self {
        EbdtComponent {
            glyph_id,
            x_offset,
            y_offset,
        }
    }
}
impl TryFrom<u16> for ImageFormat {
    type Error = ParseError;
    fn try_from(value: u16) -> Result<Self, Self::Error> {
        match value {
            1 => Ok(ImageFormat::Format1),
            2 => Ok(ImageFormat::Format2),
            5 => Ok(ImageFormat::Format5),
            6 => Ok(ImageFormat::Format6),
            7 => Ok(ImageFormat::Format7),
            8 => Ok(ImageFormat::Format8),
            9 => Ok(ImageFormat::Format9),
            17 => Ok(ImageFormat::Format17),
            18 => Ok(ImageFormat::Format18),
            19 => Ok(ImageFormat::Format19),
            _ => Err(ParseError::BadValue),
        }
    }
}
impl<'a> TryFrom<(&BitmapInfo, GlyphBitmapData<'a>, u16)> for BitmapGlyph {
    type Error = ParseError;
    fn try_from(
        (info, glyph, bitmap_id): (&BitmapInfo, GlyphBitmapData<'a>, u16),
    ) -> Result<Self, Self::Error> {
        let res = match glyph {
            // Format 1: small metrics, byte-aligned data.
            GlyphBitmapData::Format1 {
                small_metrics,
                data,
            } => {
                let data = bgra_to_rgba(info.bit_depth, data.to_vec())?;
                let metrics = EmbeddedMetrics::try_from((info, &small_metrics))?;
                BitmapGlyph {
                    bitmap: Bitmap::Embedded(EmbeddedBitmap {
                        format: info.bit_depth,
                        width: small_metrics.width,
                        height: small_metrics.height,
                        data: Box::from(data),
                    }),
                    bitmap_id,
                    metrics: Metrics::Embedded(metrics),
                    ppem_x: Some(u16::from(info.ppem_x)),
                    ppem_y: Some(u16::from(info.ppem_y)),
                    should_flip_hori: false,
                }
            }
            // Format 2: small metrics, bit-aligned data.
            GlyphBitmapData::Format2 {
                small_metrics,
                data,
            } => {
                let metrics = EmbeddedMetrics::try_from((info, &small_metrics))?;
                let unpacked = unpack_bit_aligned_data(
                    info.bit_depth,
                    small_metrics.width,
                    small_metrics.height,
                    data,
                )
                .and_then(|data| bgra_to_rgba(info.bit_depth, data))?;
                BitmapGlyph {
                    bitmap: Bitmap::Embedded(EmbeddedBitmap {
                        format: info.bit_depth,
                        width: small_metrics.width,
                        height: small_metrics.height,
                        data: unpacked.into(),
                    }),
                    bitmap_id,
                    metrics: Metrics::Embedded(metrics),
                    ppem_x: Some(u16::from(info.ppem_x)),
                    ppem_y: Some(u16::from(info.ppem_y)),
                    should_flip_hori: false,
                }
            }
            // Format 5: metrics in EBLC, bit-aligned image data only.
            GlyphBitmapData::Format5 { big_metrics, data } => {
                let metrics = EmbeddedMetrics::try_from((info, &big_metrics))?;
                let unpacked = unpack_bit_aligned_data(
                    info.bit_depth,
                    big_metrics.width,
                    big_metrics.height,
                    data,
                )
                .and_then(|data| bgra_to_rgba(info.bit_depth, data))?;
                BitmapGlyph {
                    bitmap: Bitmap::Embedded(EmbeddedBitmap {
                        format: info.bit_depth,
                        width: big_metrics.width,
                        height: big_metrics.height,
                        data: unpacked.into(),
                    }),
                    bitmap_id,
                    metrics: Metrics::Embedded(metrics),
                    ppem_x: Some(u16::from(info.ppem_x)),
                    ppem_y: Some(u16::from(info.ppem_y)),
                    should_flip_hori: false,
                }
            }
            // Format 6: big metrics, byte-aligned data.
            GlyphBitmapData::Format6 { big_metrics, data } => {
                let data = bgra_to_rgba(info.bit_depth, data.to_vec())?;
                let metrics = EmbeddedMetrics::try_from((info, &big_metrics))?;
                BitmapGlyph {
                    bitmap: Bitmap::Embedded(EmbeddedBitmap {
                        format: info.bit_depth,
                        width: big_metrics.width,
                        height: big_metrics.height,
                        data: Box::from(data),
                    }),
                    bitmap_id,
                    metrics: Metrics::Embedded(metrics),
                    ppem_x: Some(u16::from(info.ppem_x)),
                    ppem_y: Some(u16::from(info.ppem_y)),
                    should_flip_hori: false,
                }
            }
            // Format7: big metrics, bit-aligned data.
            GlyphBitmapData::Format7 { big_metrics, data } => {
                let metrics = EmbeddedMetrics::try_from((info, &big_metrics))?;
                let unpacked = unpack_bit_aligned_data(
                    info.bit_depth,
                    big_metrics.width,
                    big_metrics.height,
                    data,
                )
                .and_then(|data| bgra_to_rgba(info.bit_depth, data))?;
                BitmapGlyph {
                    bitmap: Bitmap::Embedded(EmbeddedBitmap {
                        format: info.bit_depth,
                        width: big_metrics.width,
                        height: big_metrics.height,
                        data: unpacked.into(),
                    }),
                    bitmap_id,
                    metrics: Metrics::Embedded(metrics),
                    ppem_x: Some(u16::from(info.ppem_x)),
                    ppem_y: Some(u16::from(info.ppem_y)),
                    should_flip_hori: false,
                }
            }
            // Format 8: small metrics, component data.
            GlyphBitmapData::Format8 { .. } => return Err(ParseError::NotImplemented),
            // Format 9: big metrics, component data.
            GlyphBitmapData::Format9 { .. } => return Err(ParseError::NotImplemented),
            // Format 17: small metrics, PNG image data.
            GlyphBitmapData::Format17 {
                small_metrics,
                data,
            } => {
                let metrics = EmbeddedMetrics::try_from((info, &small_metrics))?;
                let bitmap = EncapsulatedBitmap {
                    format: EncapsulatedFormat::Png,
                    data: Box::from(data),
                };
                BitmapGlyph {
                    bitmap: Bitmap::Encapsulated(bitmap),
                    bitmap_id,
                    metrics: Metrics::Embedded(metrics),
                    ppem_x: Some(u16::from(info.ppem_x)),
                    ppem_y: Some(u16::from(info.ppem_y)),
                    should_flip_hori: false,
                }
            }
            // Format 18: big metrics, PNG image data.
            // Format 19: metrics in CBLC table, PNG image data.
            GlyphBitmapData::Format18 { big_metrics, data }
            | GlyphBitmapData::Format19 { big_metrics, data } => {
                let metrics = EmbeddedMetrics::try_from((info, &big_metrics))?;
                let bitmap = EncapsulatedBitmap {
                    format: EncapsulatedFormat::Png,
                    data: Box::from(data),
                };
                BitmapGlyph {
                    bitmap: Bitmap::Encapsulated(bitmap),
                    bitmap_id,
                    metrics: Metrics::Embedded(metrics),
                    ppem_x: Some(u16::from(info.ppem_x)),
                    ppem_y: Some(u16::from(info.ppem_y)),
                    should_flip_hori: false,
                }
            }
        };
        Ok(res)
    }
}
impl GlyphBitmapData<'_> {
    /// The width of the bitmap.
    pub fn width(&self) -> u8 {
        match self {
            GlyphBitmapData::Format1 {
                small_metrics: SmallGlyphMetrics { width, .. },
                ..
            } => *width,
            GlyphBitmapData::Format2 {
                small_metrics: SmallGlyphMetrics { width, .. },
                ..
            } => *width,
            GlyphBitmapData::Format5 {
                big_metrics: BigGlyphMetrics { width, .. },
                ..
            } => *width,
            GlyphBitmapData::Format6 {
                big_metrics: BigGlyphMetrics { width, .. },
                ..
            } => *width,
            GlyphBitmapData::Format7 {
                big_metrics: BigGlyphMetrics { width, .. },
                ..
            } => *width,
            GlyphBitmapData::Format8 {
                small_metrics: SmallGlyphMetrics { width, .. },
                ..
            } => *width,
            GlyphBitmapData::Format9 {
                big_metrics: BigGlyphMetrics { width, .. },
                ..
            } => *width,
            GlyphBitmapData::Format17 {
                small_metrics: SmallGlyphMetrics { width, .. },
                ..
            } => *width,
            GlyphBitmapData::Format18 {
                big_metrics: BigGlyphMetrics { width, .. },
                ..
            } => *width,
            GlyphBitmapData::Format19 {
                big_metrics: BigGlyphMetrics { width, .. },
                ..
            } => *width,
        }
    }
    /// The height of the bitmap.
    pub fn height(&self) -> u8 {
        match self {
            GlyphBitmapData::Format1 {
                small_metrics: SmallGlyphMetrics { height, .. },
                ..
            } => *height,
            GlyphBitmapData::Format2 {
                small_metrics: SmallGlyphMetrics { height, .. },
                ..
            } => *height,
            GlyphBitmapData::Format5 {
                big_metrics: BigGlyphMetrics { height, .. },
                ..
            } => *height,
            GlyphBitmapData::Format6 {
                big_metrics: BigGlyphMetrics { height, .. },
                ..
            } => *height,
            GlyphBitmapData::Format7 {
                big_metrics: BigGlyphMetrics { height, .. },
                ..
            } => *height,
            GlyphBitmapData::Format8 {
                small_metrics: SmallGlyphMetrics { height, .. },
                ..
            } => *height,
            GlyphBitmapData::Format9 {
                big_metrics: BigGlyphMetrics { height, .. },
                ..
            } => *height,
            GlyphBitmapData::Format17 {
                small_metrics: SmallGlyphMetrics { height, .. },
                ..
            } => *height,
            GlyphBitmapData::Format18 {
                big_metrics: BigGlyphMetrics { height, .. },
                ..
            } => *height,
            GlyphBitmapData::Format19 {
                big_metrics: BigGlyphMetrics { height, .. },
                ..
            } => *height,
        }
    }
}
impl fmt::Debug for GlyphBitmapData<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            GlyphBitmapData::Format1 {
                small_metrics,
                data,
            } => f
                .debug_struct("GlyphBitmapData::Format1")
                .field("small_metrics", &small_metrics)
                .field("data", &format_args!("[{} bytes]", data.len()))
                .finish(),
            GlyphBitmapData::Format2 {
                small_metrics,
                data,
            } => f
                .debug_struct("GlyphBitmapData::Format2")
                .field("small_metrics", &small_metrics)
                .field("data", &format_args!("[{} bytes]", data.len()))
                .finish(),
            GlyphBitmapData::Format5 { big_metrics, data } => f
                .debug_struct("GlyphBitmapData::Format5")
                .field("big_metrics", &big_metrics)
                .field("data", &format_args!("[{} bytes]", data.len()))
                .finish(),
            GlyphBitmapData::Format6 { big_metrics, data } => f
                .debug_struct("GlyphBitmapData::Format6")
                .field("big_metrics", &big_metrics)
                .field("data", &format_args!("[{} bytes]", data.len()))
                .finish(),
            GlyphBitmapData::Format7 { big_metrics, data } => f
                .debug_struct("GlyphBitmapData::Format7")
                .field("big_metrics", &big_metrics)
                .field("data", &format_args!("[{} bytes]", data.len()))
                .finish(),
            GlyphBitmapData::Format8 { small_metrics, .. } => f
                .debug_struct("GlyphBitmapData::Format8")
                .field("small_metrics", &small_metrics)
                .finish(),
            GlyphBitmapData::Format9 { big_metrics, .. } => f
                .debug_struct("GlyphBitmapData::Format9")
                .field("big_metrics", &big_metrics)
                .finish(),
            GlyphBitmapData::Format17 {
                small_metrics,
                data,
            } => f
                .debug_struct("GlyphBitmapData::Format17")
                .field("small_metrics", &small_metrics)
                .field("data", &format_args!("[{} bytes]", data.len()))
                .finish(),
            GlyphBitmapData::Format18 { big_metrics, data } => f
                .debug_struct("GlyphBitmapData::Format18")
                .field("big_metrics", &big_metrics)
                .field("data", &format_args!("[{} bytes]", data.len()))
                .finish(),
            GlyphBitmapData::Format19 { big_metrics, data } => f
                .debug_struct("GlyphBitmapData::Format19")
                .field("big_metrics", &big_metrics)
                .field("data", &format_args!("[{} bytes]", data.len()))
                .finish(),
        }
    }
}
impl TryFrom<(&BitmapInfo, &SmallGlyphMetrics)> for EmbeddedMetrics {
    type Error = ParseError;
    fn try_from(
        (info, small_metrics): (&BitmapInfo, &SmallGlyphMetrics),
    ) -> Result<Self, Self::Error> {
        match info.small_glyph_metrics_direction() {
            MetricsDirection::Horizontal | MetricsDirection::Unknown => EmbeddedMetrics::new(
                info.ppem_x,
                info.ppem_y,
                Some(BitmapMetrics {
                    origin_offset_x: i16::from(small_metrics.bearing_x),
                    // Convert from offset to the top of the image to bottom
                    origin_offset_y: i16::from(small_metrics.bearing_y)
                        - i16::from(small_metrics.height),
                    advance: small_metrics.advance,
                    ascender: info.hori.ascender,
                    descender: info.hori.descender,
                }),
                None,
            ),
            MetricsDirection::Vertical => EmbeddedMetrics::new(
                info.ppem_x,
                info.ppem_y,
                None,
                Some(BitmapMetrics {
                    origin_offset_x: i16::from(small_metrics.bearing_x),
                    // Convert from offset to the top of the image to bottom
                    origin_offset_y: i16::from(small_metrics.bearing_y)
                        - i16::from(small_metrics.height),
                    advance: small_metrics.advance,
                    ascender: info.vert.ascender,
                    descender: info.vert.descender,
                }),
            ),
        }
    }
}
impl TryFrom<(&BitmapInfo, &BigGlyphMetrics)> for EmbeddedMetrics {
    type Error = ParseError;
    fn try_from((info, big_metrics): (&BitmapInfo, &BigGlyphMetrics)) -> Result<Self, Self::Error> {
        EmbeddedMetrics::new(
            info.ppem_x,
            info.ppem_y,
            Some(BitmapMetrics {
                origin_offset_x: i16::from(big_metrics.hori_bearing_x),
                origin_offset_y: i16::from(big_metrics.hori_bearing_y)
                    - i16::from(big_metrics.height),
                advance: big_metrics.hori_advance,
                ascender: info.hori.ascender,
                descender: info.hori.descender,
            }),
            Some(BitmapMetrics {
                origin_offset_x: i16::from(big_metrics.vert_bearing_x),
                origin_offset_y: i16::from(big_metrics.vert_bearing_y)
                    - i16::from(big_metrics.height),
                advance: big_metrics.vert_advance,
                ascender: info.vert.ascender,
                descender: info.vert.descender,
            }),
        )
    }
}
impl BitmapInfo {
    fn small_glyph_metrics_direction(&self) -> MetricsDirection {
        if self.flags & HORIZONTAL_METRICS == HORIZONTAL_METRICS {
            MetricsDirection::Horizontal
        } else if self.flags & VERTICAL_METRICS == VERTICAL_METRICS {
            MetricsDirection::Vertical
        } else {
            MetricsDirection::Unknown
        }
    }
}
fn unpack_bit_aligned_data(
    bit_depth: BitDepth,
    width: u8,
    height: u8,
    data: &[u8],
) -> Result<Vec<u8>, ParseError> {
    let bits_per_row = bit_depth as usize * usize::from(width);
    let whole_bytes_per_row = bits_per_row >> 3;
    let remaining_bits = (bits_per_row & 7) as u8;
    let bytes_per_row = whole_bytes_per_row + if remaining_bits != 0 { 1 } else { 0 };
    let mut offset = 0;
    let mut image_data = vec![0u8; usize::from(height) * bytes_per_row];
    let mut reader = BitReader::new(data);
    for _ in 0..height {
        // Read whole bytes, then the remainder
        for byte in image_data[offset..(offset + whole_bytes_per_row)].iter_mut() {
            *byte = reader.read_u8(8)?;
        }
        offset += whole_bytes_per_row;
        if remaining_bits != 0 {
            let byte = reader.read_u8(remaining_bits)?;
            image_data[offset] = byte << (8 - remaining_bits);
            offset += 1;
        }
    }
    Ok(image_data)
}
/// MSB-first bit reader for CBDT/EBDT bit-aligned glyph data.
///
/// Only the 1..=8 bit case is exercised by callers in this file, which
/// matches the CBDT/EBDT-spec-defined range for `BitDepth` values.
struct BitReader<'a> {
    data: &'a [u8],
    bit_pos: usize,
}
impl<'a> BitReader<'a> {
    fn new(data: &'a [u8]) -> Self {
        BitReader { data, bit_pos: 0 }
    }
    /// Read `bits` bits (1..=8) as a big-endian-packed `u8`.
    ///
    /// Returns `ParseError::BadEof` if there aren't enough bits remaining.
    fn read_u8(&mut self, bits: u8) -> Result<u8, ParseError> {
        debug_assert!(bits <= 8);
        if bits == 0 {
            return Ok(0);
        }
        let total_bits = self.data.len() * 8;
        if self.bit_pos + usize::from(bits) > total_bits {
            return Err(ParseError::BadEof);
        }
        let byte_index = self.bit_pos >> 3;
        let bit_offset = (self.bit_pos & 7) as u32;
        // Pull up to two bytes into a 16-bit window so we can shift out the
        // requested run regardless of byte alignment.
        let hi = u16::from(self.data[byte_index]);
        let lo = if byte_index + 1 < self.data.len() {
            u16::from(self.data[byte_index + 1])
        } else {
            0
        };
        let window = (hi << 8) | lo;
        let shift = 16 - bit_offset - u32::from(bits);
        let mask = (1u16 << bits) - 1;
        let value = ((window >> shift) & mask) as u8;
        self.bit_pos += usize::from(bits);
        Ok(value)
    }
}
fn bgra_to_rgba(bit_depth: BitDepth, mut data: Vec<u8>) -> Result<Vec<u8>, ParseError> {
    match bit_depth {
        BitDepth::One | BitDepth::Two | BitDepth::Four | BitDepth::Eight => Ok(data),
        BitDepth::ThirtyTwo => {
            if data.len() % 4 != 0 {
                return Err(ParseError::BadEof);
            }
            data.chunks_exact_mut(4).for_each(|chunk| chunk.swap(0, 2));
            Ok(data)
        }
    }
}
#[cfg(test)]
mod tests {
    use std::borrow::Borrow;
    use std::path::Path;
    use super::*;
    use crate::font_data::FontData;
    use crate::tables::FontTableProvider;
    use crate::tag;
    use crate::tests::read_fixture;
    #[test]
    fn test_parse_cblc() {
        let cblc_data = read_fixture(Path::new("tests/fonts/opentype/CBLC.bin"));
        let cblc = ReadScope::new(&cblc_data).read::<CBLCTable<'_>>().unwrap();
        let strikes = &cblc.bitmap_sizes;
        assert_eq!(strikes.len(), 1);
        assert_eq!(strikes[0].index_sub_tables.len(), 3);
        let ranges = strikes[0]
            .index_sub_table_records
            .iter()
            .map(|rec| rec.first_glyph_index..=rec.last_glyph_index)
            .collect::<Vec<_>>();
        assert_eq!(ranges, &[4..=17, 19..=1316, 1354..=3112]);
    }
    #[test]
    fn test_parse_eblc() {
        let buffer = read_fixture(Path::new("tests/fonts/opentype/TerminusTTF-4.47.0.ttf"));
        let scope = ReadScope::new(&buffer);
        let font_file = scope
            .read::<FontData<'_>>()
            .expect("unable to parse font file");
        let table_provider = font_file
            .table_provider(0)
            .expect("unable to create font provider");
        let table = table_provider
            .table_data(tag::EBLC)
            .expect("no EBLC table")
            .expect("no EBLC table");
        let scope = ReadScope::new(table.borrow());
        let eblc = scope.read::<CBLCTable<'_>>().unwrap();
        let strikes = &eblc.bitmap_sizes;
        assert_eq!(strikes.len(), 9);
    }
    #[test]
    fn test_lookup_eblc() {
        let buffer = read_fixture(Path::new("tests/fonts/opentype/TerminusTTF-4.47.0.ttf"));
        let scope = ReadScope::new(&buffer);
        let font_file = scope
            .read::<FontData<'_>>()
            .expect("unable to parse font file");
        let table_provider = font_file
            .table_provider(0)
            .expect("unable to create font provider");
        let table = table_provider
            .table_data(tag::EBLC)
            .expect("no EBLC table")
            .expect("no EBLC table");
        let scope = ReadScope::new(table.borrow());
        let eblc = scope.read::<CBLCTable<'_>>().unwrap();
        let table = table_provider
            .table_data(tag::EBDT)
            .expect("no EBDT table")
            .expect("no EBDT table");
        let scope = ReadScope::new(table.borrow());
        let ebdt = scope.read::<CBDTTable<'_>>().unwrap();
        // Font has strikes in 12 14 16 18 20 22 24 28 32 ppem
        // Glyph 10 is ampersand
        let strike = eblc
            .find_strike(10, 30, BitDepth::ThirtyTwo)
            .expect("no matching strike");
        let res = strike.bitmap(&ebdt).expect("error looking up glyph");
        match res {
            Some(GlyphBitmapData::Format5 { data, .. }) => assert_eq!(data.len(), 64),
            _ => panic!("expected GlyphBitmapData::Format5 got something else"),
        }
    }
    #[test]
    fn test_lookup_cblc() {
        // Test tables are from Noto Color Emoji
        let cblc_data = read_fixture(Path::new("tests/fonts/opentype/CBLC.bin"));
        let cblc = ReadScope::new(&cblc_data).read::<CBLCTable<'_>>().unwrap();
        let cbdt_data = read_fixture(Path::new("tests/fonts/opentype/CBDT.bin"));
        let cbdt = ReadScope::new(&cbdt_data).read::<CBDTTable<'_>>().unwrap();
        // Glyph 1077 is Nerd Face U+1F913
        let strike = cblc
            .find_strike(1077, 30, BitDepth::ThirtyTwo)
            .expect("no matching strike");
        let res = strike.bitmap(&cbdt).expect("error looking up glyph");
        match res {
            Some(GlyphBitmapData::Format17 {
                data,
                small_metrics: SmallGlyphMetrics { width, height, .. },
            }) => {
                assert_eq!((width, height), (136, 128));
                assert_eq!(&data[1..4], b"PNG");
            }
            _ => panic!("expected PNG data got something else"),
        }
        // Repeat the lookup with a lower max bit depth, should now fail to find suitable strike
        assert!(cblc.find_strike(1077, 30, BitDepth::Four).is_none());
    }
    #[test]
    fn test_unpack_bit_aligned_data() {
        let data = &[0xD3, 0xAA, 0x70];
        let expected = &[0xD3, 0x80, 0xA9, 0xC0];
        let actual = unpack_bit_aligned_data(BitDepth::Two, 5, 2, data).unwrap();
        assert_eq!(&actual, expected);
    }
    #[test]
    fn test_bgra_to_rgba_no_change() {
        let original = vec![1, 2, 3, 4, 5, 6, 7, 8];
        let actual = bgra_to_rgba(BitDepth::One, original.clone()).unwrap();
        assert_eq!(actual, original);
    }
    #[test]
    fn test_bgra_to_rgba_reorder() {
        let data = vec![1, 2, 3, 4, 5, 6, 7, 8];
        let expected = &[3, 2, 1, 4, 7, 6, 5, 8];
        let actual = bgra_to_rgba(BitDepth::ThirtyTwo, data).unwrap();
        assert_eq!(&actual, expected);
    }
    #[test]
    fn test_bgra_to_rgba_too_short() {
        let data = vec![1, 2, 3, 4, 5, 6, 7];
        let res = bgra_to_rgba(BitDepth::ThirtyTwo, data);
        assert_eq!(res, Err(ParseError::BadEof));
    }
}