1
//! Reading of the WOFF2 font format.
2
//!
3
//! <https://www.w3.org/TR/WOFF2/>
4

            
5
mod collection;
6
mod lut;
7

            
8
use std::borrow::Cow;
9
use std::collections::HashMap;
10
use std::io::{Cursor, Read};
11

            
12
use self::lut::{XYTriplet, COORD_LUT, KNOWN_TABLE_TAGS};
13

            
14
/// Sum type that lets a function return one of two iterator shapes
15
/// behind a single `impl Iterator` without pulling in `itertools::Either`.
16
enum Either<L, R> {
17
    Left(L),
18
    Right(R),
19
}
20

            
21
impl<L, R, T> Iterator for Either<L, R>
22
where
23
    L: Iterator<Item = T>,
24
    R: Iterator<Item = T>,
25
{
26
    type Item = T;
27

            
28
    fn next(&mut self) -> Option<T> {
29
        match self {
30
            Either::Left(l) => l.next(),
31
            Either::Right(r) => r.next(),
32
        }
33
    }
34
}
35
use crate::binary::read::{
36
    ReadArray, ReadArrayCow, ReadBinary, ReadBinaryDep, ReadBuf, ReadCtxt, ReadFrom, ReadScope,
37
};
38
use crate::binary::{write, I16Be, U16Be, U8};
39
use crate::error::{ParseError, ReadWriteError};
40
use crate::tables::glyf::{
41
    BoundingBox, CompositeGlyph, CompositeGlyphs, GlyfRecord, GlyfTable, Glyph, Point, SimpleGlyph,
42
    SimpleGlyphFlag, SimpleGlyphFlags,
43
};
44
use crate::tables::loca::{owned, LocaTable};
45
use crate::tables::{
46
    FontTableProvider, HeadTable, HheaTable, HmtxTable, IndexToLocFormat, LongHorMetric, MaxpTable,
47
    SfntVersion, TTCF_MAGIC,
48
};
49
use crate::{read_table, tag};
50

            
51
pub const MAGIC: u32 = tag!(b"wOF2");
52
// This is the default size of the buffer in the brotli crate.
53
// There's no guidance on how to choose this value.
54
const BROTLI_DECODER_BUFFER_SIZE: usize = 4096;
55
const BITS_0_TO_5: u8 = 0x3F;
56
const LOWEST_UCODE: u16 = 253;
57

            
58
/// UIntBase128, Variable-length encoding of 32-bit unsigned integers.
59
#[derive(Copy, Clone)]
60
pub enum U32Base128 {}
61

            
62
/// 255UInt16, Variable-length encoding of a 16-bit unsigned integer for optimized intermediate
63
/// font data storage.
64
#[derive(Copy, Clone)]
65
pub enum PackedU16 {}
66

            
67
#[derive(Clone, Copy)]
68
struct WoffFlag(u8);
69

            
70
#[derive(Clone)]
71
pub struct Woff2Font<'a> {
72
    pub scope: ReadScope<'a>,
73
    pub woff_header: Woff2Header,
74
    // We have to read and parse the table directory to know where the font tables are stored
75
    // so in doing so we hold onto the TableDirectoryEntries produced as a result
76
    pub table_directory: Vec<TableDirectoryEntry>,
77
    pub collection_directory: Option<collection::Directory>,
78
    pub table_data_block: Vec<u8>,
79
}
80

            
81
pub struct Woff2TableProvider {
82
    flavor: u32,
83
    tables: HashMap<u32, Box<[u8]>>,
84
}
85

            
86
#[derive(Clone, Eq, PartialEq, Debug)]
87
pub struct Woff2Header {
88
    pub flavor: u32,
89
    pub length: u32,
90
    pub num_tables: u16,
91
    pub total_sfnt_size: u32,
92
    pub total_compressed_size: u32,
93
    pub _major_version: u16,
94
    pub _minor_version: u16,
95
    pub meta_offset: u32,
96
    pub meta_length: u32,
97
    pub meta_orig_length: u32,
98
    pub priv_offset: u32,
99
    pub priv_length: u32,
100
}
101

            
102
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
103
pub struct TableDirectoryEntry {
104
    pub tag: u32,
105
    pub offset: usize,
106
    pub orig_length: u32,
107
    pub transform_length: Option<u32>,
108
}
109

            
110
struct TransformedGlyphTable<'a> {
111
    /// Number of glyphs
112
    num_glyphs: u16,
113
    /// Offset format for loca table
114
    ///
115
    /// Should be consistent with indexToLocFormat of the original head table
116
    /// (see OpenType specification).
117
    _index_format: u16,
118
    /// Stream of i16 values representing number of contours for each glyph record
119
    n_contour_scope: ReadScope<'a>,
120
    /// Stream of values representing number of outline points for each contour in glyph records
121
    n_points_scope: ReadScope<'a>,
122
    /// Stream of u8 values representing flag values for each outline point.
123
    flag_scope: ReadScope<'a>,
124
    /// Stream of bytes representing point coordinate values using variable length encoding format (defined in subclause 5.2)
125
    glyph_scope: ReadScope<'a>,
126
    /// Stream of bytes representing component flag values and associated composite glyph data
127
    composite_scope: ReadScope<'a>,
128
    /// Bitmap (a numGlyphs-long bit array) indicating explicit bounding boxes
129
    bbox_bitmap_scope: ReadScope<'a>,
130
    /// Stream of i16 values representing glyph bounding box data
131
    bbox_scope: ReadScope<'a>,
132
    /// Stream of u8 values representing a set of instructions for each corresponding glyph
133
    instruction_scope: ReadScope<'a>,
134
}
135

            
136
#[enumflags2::bitflags]
137
#[repr(u8)]
138
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
139
#[allow(non_camel_case_types)]
140
pub enum HmtxTableFlag {
141
    LSB_ABSENT = 0b01,
142
    LEFT_SIDE_BEARING_ABSENT = 0b10,
143
}
144

            
145
pub type HmtxTableFlags = enumflags2::BitFlags<HmtxTableFlag>;
146

            
147
pub enum Woff2GlyfTable {}
148
pub enum Woff2LocaTable {}
149
pub enum Woff2HmtxTable {}
150

            
151
pub struct BitSlice<'a> {
152
    data: &'a [u8],
153
}
154

            
155
impl<'a> Woff2Font<'a> {
156
    /// The "sfnt version" of the input font
157
    pub fn flavor(&self) -> u32 {
158
        self.woff_header.flavor
159
    }
160

            
161
    /// Decompress and return the extended metadata XML if present
162
    pub fn extended_metadata(&self) -> Result<Option<String>, ParseError> {
163
        let offset = usize::try_from(self.woff_header.meta_offset)?;
164
        let length = usize::try_from(self.woff_header.meta_length)?;
165
        if offset == 0 || length == 0 {
166
            return Ok(None);
167
        }
168

            
169
        let compressed_metadata = self.scope.offset_length(offset, length)?;
170

            
171
        let mut input = brotli_decompressor::Decompressor::new(
172
            Cursor::new(compressed_metadata.data()),
173
            BROTLI_DECODER_BUFFER_SIZE,
174
        );
175
        let mut metadata = String::new();
176
        input
177
            .read_to_string(&mut metadata)
178
            .map_err(|_err| ParseError::CompressionError)?;
179

            
180
        Ok(Some(metadata))
181
    }
182

            
183
    pub fn table_data_block_scope(&'a self) -> ReadScope<'a> {
184
        ReadScope::new(&self.table_data_block)
185
    }
186

            
187
    fn read_table_directory(
188
        ctxt: &mut ReadCtxt<'_>,
189
        num_tables: usize,
190
    ) -> Result<Vec<TableDirectoryEntry>, ParseError> {
191
        let mut offset = 0;
192
        let mut table_directory = Vec::with_capacity(num_tables);
193
        for _i in 0..num_tables {
194
            let entry = ctxt.read_dep::<TableDirectoryEntry>(offset)?;
195
            offset += entry.length();
196
            table_directory.push(entry);
197
        }
198

            
199
        Ok(table_directory)
200
    }
201

            
202
    pub fn find_table_entry(&self, tag: u32, index: usize) -> Option<&TableDirectoryEntry> {
203
        if let Some(collection_directory) = &self.collection_directory {
204
            collection_directory
205
                .get(index)
206
                .and_then(|font| font.table_entries(self).find(|entry| entry.tag == tag))
207
        } else {
208
            self.table_directory.iter().find(|entry| entry.tag == tag)
209
        }
210
    }
211

            
212
    pub fn read_table(&self, tag: u32, index: usize) -> Result<Option<ReadBuf<'_>>, ParseError> {
213
        self.find_table_entry(tag, index)
214
            .map(|entry| entry.read_table(&self.table_data_block_scope()))
215
            .transpose()
216
    }
217

            
218
    pub fn table_provider(&self, index: usize) -> Result<Woff2TableProvider, ReadWriteError> {
219
        Woff2TableProvider::new(self, index)
220
    }
221
}
222

            
223
impl ReadBinary for Woff2Font<'_> {
224
    type HostType<'a> = Woff2Font<'a>;
225

            
226
    fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
227
        let scope = ctxt.scope();
228
        let woff_header = ctxt.read::<Woff2Header>()?;
229

            
230
        let table_directory =
231
            Self::read_table_directory(ctxt, usize::from(woff_header.num_tables))?;
232

            
233
        let collection_directory = if woff_header.flavor == TTCF_MAGIC {
234
            Some(ctxt.read::<collection::Directory>()?)
235
        } else {
236
            None
237
        };
238

            
239
        // Read compressed font table data
240
        let compressed_data =
241
            ctxt.read_slice(usize::try_from(woff_header.total_compressed_size)?)?;
242
        let mut input = brotli_decompressor::Decompressor::new(
243
            Cursor::new(compressed_data),
244
            BROTLI_DECODER_BUFFER_SIZE,
245
        );
246
        let mut table_data_block = Vec::new();
247
        input
248
            .read_to_end(&mut table_data_block)
249
            .map_err(|_err| ParseError::CompressionError)?;
250

            
251
        Ok(Woff2Font {
252
            scope,
253
            woff_header,
254
            table_directory,
255
            collection_directory,
256
            table_data_block,
257
        })
258
    }
259
}
260

            
261
impl FontTableProvider for Woff2TableProvider {
262
    fn table_data(&self, tag: u32) -> Result<Option<Cow<'_, [u8]>>, ParseError> {
263
        Ok(self.tables.get(&tag).map(|table| Cow::from(table.as_ref())))
264
    }
265

            
266
    fn has_table(&self, tag: u32) -> bool {
267
        self.tables.contains_key(&tag)
268
    }
269

            
270
    fn table_tags(&self) -> Option<Vec<u32>> {
271
        Some(self.tables.keys().copied().collect())
272
    }
273
}
274

            
275
impl SfntVersion for Woff2TableProvider {
276
    fn sfnt_version(&self) -> u32 {
277
        self.flavor
278
    }
279
}
280

            
281
impl ReadBinary for Woff2Header {
282
    type HostType<'a> = Self;
283

            
284
    fn read(ctxt: &mut ReadCtxt<'_>) -> Result<Self, ParseError> {
285
        let signature = ctxt.read_u32be()?;
286
        match signature {
287
            MAGIC => {
288
                let flavor = ctxt.read_u32be()?;
289
                let length = ctxt.read_u32be()?;
290
                let num_tables = ctxt.read_u16be()?;
291
                let reserved = ctxt.read_u16be()?;
292
                // The header includes a reserved field; this MUST be set to zero. If this field is
293
                // non-zero, a conforming user agent MUST reject the file as invalid.
294
                ctxt.check(reserved == 0)?;
295
                let total_sfnt_size = ctxt.read_u32be()?;
296
                let total_compressed_size = ctxt.read_u32be()?;
297
                // The WOFF majorVersion and minorVersion fields specify the version number for a
298
                // given WOFF file, which can be based on the version number of the input font but
299
                // is not required to be. These fields have no effect on font loading or usage
300
                // behavior in user agents.
301
                let _major_version = ctxt.read_u16be()?;
302
                let _minor_version = ctxt.read_u16be()?;
303
                let meta_offset = ctxt.read_u32be()?;
304
                let meta_length = ctxt.read_u32be()?;
305
                let meta_orig_length = ctxt.read_u32be()?;
306
                let priv_offset = ctxt.read_u32be()?;
307
                let priv_length = ctxt.read_u32be()?;
308

            
309
                Ok(Woff2Header {
310
                    flavor,
311
                    length,
312
                    num_tables,
313
                    total_sfnt_size,
314
                    total_compressed_size,
315
                    _major_version,
316
                    _minor_version,
317
                    meta_offset,
318
                    meta_length,
319
                    meta_orig_length,
320
                    priv_offset,
321
                    priv_length,
322
                })
323
            }
324
            _ => Err(ParseError::BadVersion),
325
        }
326
    }
327
}
328

            
329
impl ReadBinaryDep for TableDirectoryEntry {
330
    type Args<'a> = usize;
331
    type HostType<'a> = Self;
332

            
333
    fn read_dep(ctxt: &mut ReadCtxt<'_>, offset: usize) -> Result<Self, ParseError> {
334
        let flags = ctxt.read_u8()?;
335
        let tag = if flags & BITS_0_TO_5 == 63 {
336
            // Tag is the following 4 bytes
337
            ctxt.read_u32be()
338
        } else {
339
            Ok(KNOWN_TABLE_TAGS[usize::from(flags & BITS_0_TO_5)])
340
        }?;
341
        let transformation_version = (flags & 0xC0) >> 6;
342
        let orig_length = ctxt.read::<U32Base128>()?;
343

            
344
        let transform_length = match (transformation_version, tag) {
345
            (3, tag::GLYF) | (3, tag::LOCA) => None,
346
            (_, tag::GLYF) | (_, tag::LOCA) | (1, tag::HMTX) => Some(ctxt.read::<U32Base128>()?),
347
            (0, _) => None,
348
            _ => Some(ctxt.read::<U32Base128>()?),
349
        };
350

            
351
        Ok(TableDirectoryEntry {
352
            tag,
353
            offset,
354
            orig_length,
355
            transform_length,
356
        })
357
    }
358
}
359

            
360
impl ReadBinary for TransformedGlyphTable<'_> {
361
    type HostType<'a> = TransformedGlyphTable<'a>;
362

            
363
    fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
364
        let _version = ctxt.read_u32be()?;
365
        let num_glyphs = ctxt.read_u16be()?;
366
        let index_format = ctxt.read_u16be()?;
367

            
368
        let n_contour_stream_size = usize::try_from(ctxt.read_u32be()?)?;
369
        let n_points_stream_size = usize::try_from(ctxt.read_u32be()?)?;
370
        let flag_stream_size = usize::try_from(ctxt.read_u32be()?)?;
371
        let glyph_stream_size = usize::try_from(ctxt.read_u32be()?)?;
372
        let composite_stream_size = usize::try_from(ctxt.read_u32be()?)?;
373
        let bbox_stream_size = usize::try_from(ctxt.read_u32be()?)?;
374
        let instruction_stream_size = usize::try_from(ctxt.read_u32be()?)?;
375

            
376
        // Build sub contexts for each of the streams, then iterate a glyph at a time pulling from
377
        // those contexts as needed
378
        let n_contour_scope = ReadScope::new(ctxt.read_slice(n_contour_stream_size)?);
379
        let n_points_scope = ReadScope::new(ctxt.read_slice(n_points_stream_size)?);
380
        let flag_scope = ReadScope::new(ctxt.read_slice(flag_stream_size)?);
381
        let glyph_scope = ReadScope::new(ctxt.read_slice(glyph_stream_size)?);
382
        let composite_scope = ReadScope::new(ctxt.read_slice(composite_stream_size)?);
383
        // The total number of bytes in bboxBitmap is equal to 4 * floor((numGlyphs + 31) / 32).
384
        // The bits are packed so that glyph number 0 corresponds to the most significant bit of
385
        // the first byte, glyph number 7 corresponds to the least significant bit of the first
386
        // byte, glyph number 8 corresponds to the most significant bit of the second byte, and so
387
        // on. A bit=1 value indicates an explicitly set bounding box.
388
        let bbox_bitmap_length = (4. * ((num_glyphs + 31) as f64 / 32.).floor()) as usize;
389
        let bbox_bitmap_scope = ReadScope::new(ctxt.read_slice(bbox_bitmap_length)?);
390
        let bbox_scope = ReadScope::new(ctxt.read_slice(bbox_stream_size - bbox_bitmap_length)?);
391
        let instruction_scope = ReadScope::new(ctxt.read_slice(instruction_stream_size)?);
392

            
393
        Ok(TransformedGlyphTable {
394
            num_glyphs,
395
            _index_format: index_format,
396
            n_contour_scope,
397
            n_points_scope,
398
            flag_scope,
399
            glyph_scope,
400
            composite_scope,
401
            bbox_bitmap_scope,
402
            bbox_scope,
403
            instruction_scope,
404
        })
405
    }
406
}
407

            
408
impl ReadBinaryDep for Woff2GlyfTable {
409
    type Args<'a> = (&'a TableDirectoryEntry, &'a LocaTable<'a>);
410
    type HostType<'a> = GlyfTable<'a>;
411

            
412
    fn read_dep<'a>(
413
        ctxt: &mut ReadCtxt<'a>,
414
        (entry, loca): Self::Args<'a>,
415
    ) -> Result<Self::HostType<'a>, ParseError> {
416
        if entry.transform_length.is_some() {
417
            let table = ctxt.read::<TransformedGlyphTable<'_>>()?;
418

            
419
            // Read a glyph at a time and handle reconstructing each one
420
            let num_glyphs = usize::from(table.num_glyphs);
421
            let mut n_contour_ctxt = table.n_contour_scope.ctxt();
422
            let mut n_points_ctxt = table.n_points_scope.ctxt();
423
            let mut flags_ctxt = table.flag_scope.ctxt();
424
            let mut glyphs_ctxt = table.glyph_scope.ctxt();
425
            let mut instructions_ctxt = table.instruction_scope.ctxt();
426
            let mut composite_ctxt = table.composite_scope.ctxt();
427
            let bbox_bitmap = BitSlice::new(table.bbox_bitmap_scope.data());
428
            let mut bbox_bitmap_ctxt = table.bbox_scope.ctxt();
429

            
430
            let mut records = Vec::with_capacity(num_glyphs);
431
            for i in 0..num_glyphs {
432
                let number_of_contours = n_contour_ctxt.read_i16be()?;
433

            
434
                let glyf_record = match number_of_contours {
435
                    // Empty glyph
436
                    0 => GlyfRecord::empty(),
437
                    // Composite glyph
438
                    -1 => {
439
                        let glyphs = composite_ctxt.read::<CompositeGlyphs>()?;
440

            
441
                        // Step 3a.
442
                        let instruction_length = if glyphs.have_instructions {
443
                            usize::from(glyphs_ctxt.read::<PackedU16>()?)
444
                        } else {
445
                            0
446
                        };
447
                        let instructions = instructions_ctxt.read_slice(instruction_length)?;
448

            
449
                        // A composite glyph MUST have an explicitly supplied bounding box.
450
                        // A decoder MUST check for presence of the bounding box info as part of
451
                        // the composite glyph record and MUST NOT load a font file with the
452
                        // composite bounding box data missing.
453
                        match bbox_bitmap.get(i) {
454
                            Some(true) => (),
455
                            _ => return Err(ParseError::BadIndex),
456
                        }
457

            
458
                        // Read the bounding box
459
                        let bounding_box = bbox_bitmap_ctxt.read::<BoundingBox>()?;
460

            
461
                        GlyfRecord::Parsed(Glyph::Composite(CompositeGlyph {
462
                            bounding_box,
463
                            glyphs: glyphs.glyphs,
464
                            instructions: Box::from(instructions),
465
                            phantom_points: None,
466
                        }))
467
                    }
468
                    // Simple glyph
469
                    num if num > 0 => {
470
                        let mut data = Self::decode_simple_glyph(
471
                            &mut n_points_ctxt,
472
                            &mut flags_ctxt,
473
                            &mut glyphs_ctxt,
474
                            &mut instructions_ctxt,
475
                            number_of_contours,
476
                        )?;
477

            
478
                        let bounding_box = match bbox_bitmap.get(i) {
479
                            Some(true) => bbox_bitmap_ctxt.read::<BoundingBox>(),
480
                            Some(false) => Ok(data.bounding_box()),
481
                            _ => return Err(ParseError::BadIndex),
482
                        }?;
483
                        data.bounding_box = bounding_box;
484

            
485
                        GlyfRecord::Parsed(Glyph::Simple(data))
486
                    }
487
                    _ => return Err(ParseError::BadValue),
488
                };
489

            
490
                records.push(glyf_record);
491
            }
492

            
493
            GlyfTable::new(records)
494
        } else {
495
            // glyf table has not been transformed
496
            ctxt.read_dep::<GlyfTable<'_>>(loca)
497
        }
498
    }
499
}
500

            
501
impl ReadBinaryDep for Woff2LocaTable {
502
    type Args<'a> = (&'a TableDirectoryEntry, u16, IndexToLocFormat);
503
    type HostType<'a> = LocaTable<'a>;
504

            
505
    fn read_dep<'a>(
506
        ctxt: &mut ReadCtxt<'a>,
507
        (loca_entry, num_glyphs, index_to_loc_format): Self::Args<'a>,
508
    ) -> Result<Self::HostType<'a>, ParseError> {
509
        if loca_entry.transform_length.is_some() {
510
            Ok(LocaTable::empty())
511
        } else {
512
            ctxt.read_dep::<LocaTable<'_>>((num_glyphs, index_to_loc_format))
513
        }
514
    }
515
}
516

            
517
impl ReadBinaryDep for Woff2HmtxTable {
518
    type Args<'a> = (&'a TableDirectoryEntry, &'a GlyfTable<'a>, usize, usize);
519
    type HostType<'a> = HmtxTable<'a>;
520

            
521
    /// Read hmtx table from WOFF2 file
522
    ///
523
    /// num_h_metrics is defined by the `hhea` table
524
    fn read_dep<'a>(
525
        ctxt: &mut ReadCtxt<'a>,
526
        (hmtx_entry, glyf, num_glyphs, num_h_metrics): Self::Args<'a>,
527
    ) -> Result<Self::HostType<'a>, ParseError> {
528
        if hmtx_entry.transform_length.is_some() {
529
            let flags = ctxt.read::<HmtxTableFlags>()?;
530
            let advance_width_stream = ctxt.read_array::<U16Be>(num_h_metrics)?;
531

            
532
            let lsb = if flags.lsb_is_present() {
533
                // read the lsb stream
534
                ReadArrayCow::Borrowed(ctxt.read_array::<I16Be>(num_h_metrics)?)
535
            } else {
536
                // Reconstitute lsb from glyf
537
                //
538
                // The transformation version "1" exploits the built-in redundancy of the TrueType
539
                // glyphs where the outlines of the glyphs designed according to the TrueType
540
                // recommendations would likely have their left side bearing values equal to xMin
541
                // value of the glyph bounding box.
542
                //
543
                // If the hmtx table transform is both applicable and desired, the encoder MUST
544
                // check that leftSideBearing values match the xMin values of the glyph bounding
545
                // box for every glyph in a font (or check that leftSideBearing == 0 for an empty
546
                // glyph)
547
                ReadArrayCow::Owned(
548
                    glyf.records()
549
                        .iter()
550
                        .map(|glyf_record| match glyf_record {
551
                            GlyfRecord::Present { .. } => unreachable!(),
552
                            GlyfRecord::Parsed(glyph) => {
553
                                glyph.bounding_box().map(|bbox| bbox.x_min).unwrap_or(0)
554
                            }
555
                        })
556
                        .collect(),
557
                )
558
            };
559

            
560
            let length = num_glyphs
561
                .checked_sub(num_h_metrics)
562
                .ok_or(ParseError::BadIndex)?;
563
            let left_side_bearings = if flags.left_side_bearing_is_present() {
564
                ReadArrayCow::Borrowed(ctxt.read_array::<I16Be>(length)?)
565
            } else {
566
                // Reconstitute from glyf
567
                ReadArrayCow::Owned(
568
                    glyf.records()
569
                        .iter()
570
                        .map(|glyf_record| match glyf_record {
571
                            GlyfRecord::Present { .. } => unreachable!(),
572
                            GlyfRecord::Parsed(glyph) => {
573
                                glyph.bounding_box().map(|bbox| bbox.x_min).unwrap_or(0)
574
                            }
575
                        })
576
                        .collect(),
577
                )
578
            };
579

            
580
            let h_metrics = lsb
581
                .iter()
582
                .zip(advance_width_stream.iter())
583
                .map(|(lsb, advance_width)| LongHorMetric { advance_width, lsb })
584
                .collect();
585

            
586
            Ok(HmtxTable {
587
                h_metrics: ReadArrayCow::Owned(h_metrics),
588
                left_side_bearings,
589
            })
590
        } else {
591
            ctxt.read_dep::<HmtxTable<'a>>((num_glyphs, num_h_metrics))
592
        }
593
    }
594
}
595

            
596
impl ReadFrom for WoffFlag {
597
    type ReadType = U8;
598

            
599
    fn read_from(flag: u8) -> Self {
600
        WoffFlag::new(flag)
601
    }
602
}
603

            
604
// Parse "255UInt16" Data Type
605
// https://w3c.github.io/woff/woff2/#255UInt16-0
606
impl ReadBinary for PackedU16 {
607
    type HostType<'a> = u16;
608

            
609
    fn read(ctxt: &mut ReadCtxt<'_>) -> Result<u16, ParseError> {
610
        match ctxt.read_u8()? {
611
            253 => ctxt.read_u16be(),
612
            254 => ctxt
613
                .read_u8()
614
                .map(|value| u16::from(value) + LOWEST_UCODE * 2),
615
            255 => ctxt.read_u8().map(|value| u16::from(value) + LOWEST_UCODE),
616
            code => Ok(u16::from(code)),
617
        }
618
        .map_err(ParseError::from)
619
    }
620
}
621

            
622
// Parse "UIntBase128" Data Type
623
// https://w3c.github.io/woff/woff2/#UIntBase128-0
624
impl ReadBinary for U32Base128 {
625
    type HostType<'a> = u32;
626

            
627
    fn read(ctxt: &mut ReadCtxt<'_>) -> Result<u32, ParseError> {
628
        let mut accum = 0u32;
629

            
630
        for i in 0..5 {
631
            let byte = ctxt.read_u8()?;
632

            
633
            // No leading 0's
634
            if i == 0 && byte == 0x80 {
635
                return Err(ParseError::BadValue);
636
            }
637

            
638
            // If any of the top 7 bits are set then << 7 would overflow
639
            if accum & 0xFE000000 != 0 {
640
                return Err(ParseError::BadValue);
641
            }
642

            
643
            // value = old value times 128 + (byte bitwise-and 127)
644
            accum = (accum << 7) | u32::from(byte & 0x7F);
645

            
646
            // Spin until most significant bit of data byte is false
647
            if byte & 0x80 == 0 {
648
                return Ok(accum);
649
            }
650
        }
651

            
652
        // UIntBase128 sequence exceeds 5 bytes
653
        Err(ParseError::BadValue)
654
    }
655
}
656

            
657
impl ReadFrom for HmtxTableFlags {
658
    type ReadType = U8;
659

            
660
    fn read_from(flag: u8) -> Self {
661
        HmtxTableFlags::from_bits_truncate(flag)
662
    }
663
}
664

            
665
impl WoffFlag {
666
    fn new(flag: u8) -> Self {
667
        WoffFlag(flag)
668
    }
669

            
670
    fn bytes_to_read(&self) -> usize {
671
        usize::from(self.xy_triplet().byte_count)
672
    }
673

            
674
    fn is_on_curve_point(&self) -> bool {
675
        // WOFF2 says this about the MSB of flags:
676
        // The most significant bit of a flag indicates whether the point is on- or off-curve point.
677
        // The OpenType equivalent of this bit (Simple Glyph Flags) is defined as:
678
        // Bit 0: If set, the point is on the curve; otherwise, it is off the curve.
679
        // However it appears that in WOFF2 the bit is cleared to indicate that it is on-curve.
680
        // I.e. opposite to OpenType. MicroType, which WOFF2 is based on adds:
681
        // if the most significant bit is 0, then the point is on-curve.
682
        self.0 & 0x80 == 0
683
    }
684

            
685
    fn xy_triplet(&self) -> &XYTriplet {
686
        &COORD_LUT[usize::from(self.0 & 0x7F)]
687
    }
688
}
689

            
690
impl From<WoffFlag> for SimpleGlyphFlags {
691
    fn from(woff_flag: WoffFlag) -> Self {
692
        if woff_flag.is_on_curve_point() {
693
            SimpleGlyphFlag::ON_CURVE_POINT.into()
694
        } else {
695
            SimpleGlyphFlags::empty()
696
        }
697
    }
698
}
699

            
700
impl Woff2GlyfTable {
701
    fn compute_end_pts_of_contours(
702
        n_points_ctxt: &mut ReadCtxt<'_>,
703
        number_of_contours: i16,
704
    ) -> Result<(Vec<u16>, u16), ParseError> {
705
        // Read numberOfContours 255UInt16 values from the nPoints stream. Each of
706
        // these is the number of points of that contour. Convert this into the
707
        // endPtsOfContours[] array by computing the cumulative sum, then
708
        // subtracting one.
709

            
710
        // Also, the sum of all the values in the array is the total number of
711
        // points in the glyph, nPoints.
712
        let mut n_points = 0;
713
        let end_pts_of_contours = (0..number_of_contours)
714
            .map(|_i| {
715
                n_points_ctxt.read::<PackedU16>().map(|n_contours| {
716
                    n_points += n_contours;
717
                    n_points - 1
718
                })
719
            })
720
            .collect::<Result<Vec<_>, _>>()?;
721

            
722
        Ok((end_pts_of_contours, n_points))
723
    }
724

            
725
    fn decode_coordinates(flag: WoffFlag, coordinates: ReadArray<'_, U8>) -> Point {
726
        let xy_triplet = flag.xy_triplet();
727

            
728
        let data = coordinates.iter().fold(0u32, |mut data, byte| {
729
            data <<= 8;
730
            data |= u32::from(byte);
731
            data
732
        });
733

            
734
        // Extract x-bits and y-bits from the data value
735
        Point(xy_triplet.dx(data), xy_triplet.dy(data))
736
    }
737

            
738
    fn decode_simple_glyph(
739
        n_points_ctxt: &mut ReadCtxt<'_>,
740
        flags_ctxt: &mut ReadCtxt<'_>,
741
        glyphs_ctxt: &mut ReadCtxt<'_>,
742
        instructions_ctxt: &mut ReadCtxt<'_>,
743
        number_of_contours: i16,
744
    ) -> Result<SimpleGlyph, ParseError> {
745
        // Step 1. from spec section 5.1, Decoding of Simple Glyphs
746
        let (end_pts_of_contours, n_points) =
747
            Self::compute_end_pts_of_contours(n_points_ctxt, number_of_contours)?;
748

            
749
        // Step 2.
750
        let flags = flags_ctxt.read_array::<WoffFlag>(usize::from(n_points))?;
751

            
752
        // Step 3.
753
        let mut prev_point = Point::zero();
754
        let mut points = Vec::with_capacity(flags.len());
755
        for flag in flags.iter() {
756
            let coordinates = glyphs_ctxt.read_array::<U8>(flag.bytes_to_read())?;
757
            let point = Self::decode_coordinates(flag, coordinates);
758

            
759
            // The x and y coordinates are stored as deltas against the previous point, with the
760
            // first one being implicitly against (0, 0). Here we resolve these deltas into
761
            // absolute (x, y) values.
762
            prev_point = Point(prev_point.0 + point.0, prev_point.1 + point.1);
763
            points.push((From::from(flag), prev_point));
764
        }
765

            
766
        // Step 4.
767
        let instruction_length = usize::from(glyphs_ctxt.read::<PackedU16>()?);
768

            
769
        // Step 5.
770
        let instructions = instructions_ctxt.read_slice(instruction_length)?;
771

            
772
        Ok(SimpleGlyph {
773
            bounding_box: BoundingBox::empty(), // filled in later
774
            end_pts_of_contours,
775
            instructions: Box::from(instructions),
776
            coordinates: points,
777
            phantom_points: None,
778
        })
779
    }
780
}
781

            
782
impl TableDirectoryEntry {
783
    fn length(&self) -> usize {
784
        self.transform_length.unwrap_or(self.orig_length) as usize
785
    }
786

            
787
    /// Read the contents of a table entry
788
    pub fn read_table<'a>(&self, scope: &ReadScope<'a>) -> Result<ReadBuf<'a>, ParseError> {
789
        let table_data = scope.offset_length(self.offset, self.length())?;
790

            
791
        Ok(ReadBuf::from(table_data.data()))
792
    }
793
}
794

            
795
pub trait HmtxTableFlagExt {
796
    fn lsb_is_present(self) -> bool;
797
    fn left_side_bearing_is_present(self) -> bool;
798
}
799

            
800
impl HmtxTableFlagExt for HmtxTableFlags {
801
    fn lsb_is_present(self) -> bool {
802
        !self.contains(HmtxTableFlag::LSB_ABSENT)
803
    }
804

            
805
    fn left_side_bearing_is_present(self) -> bool {
806
        !self.contains(HmtxTableFlag::LEFT_SIDE_BEARING_ABSENT)
807
    }
808
}
809

            
810
impl<'a> BitSlice<'a> {
811
    pub fn new(data: &'a [u8]) -> Self {
812
        BitSlice { data }
813
    }
814

            
815
    pub fn get(&self, index: usize) -> Option<bool> {
816
        if index >= self.len() {
817
            return None;
818
        }
819

            
820
        // Find byte that holds the bit we're after
821
        let byte_index = index / 8;
822
        // The bits are packed so that glyph number 0 corresponds to the most significant bit of
823
        // the first byte, glyph number 7 corresponds to the least significant bit of the first
824
        // byte, glyph number 8 corresponds to the most significant bit of the second byte,
825
        // and so on.
826
        let shl = 8 - (index % 8) - 1;
827
        let mask = 1 << shl;
828

            
829
        Some(self.data[byte_index] & mask == mask)
830
    }
831

            
832
    pub fn len(&self) -> usize {
833
        self.data.len() * 8
834
    }
835
}
836

            
837
// The FontTableProvider implementation for WOFF2 provides some challenges because there's
838
// dependencies between the tables. The implementation as it stands takes the somewhat brute force
839
// approach of eager loading all the tables up front, which makes accessing them individually later
840
// much easier.
841
impl Woff2TableProvider {
842
    fn new(woff: &Woff2Font<'_>, index: usize) -> Result<Self, ReadWriteError> {
843
        let mut tables = HashMap::with_capacity(woff.table_directory.len());
844

            
845
        // if hmtx is transformed then that means we have to parse glyf
846
        // otherwise we only have to parse glyf if it's transformed
847
        let hmtx_entry = woff.find_table_entry(tag::HMTX, index);
848
        let glyf_entry = woff.find_table_entry(tag::GLYF, index);
849
        let hmtx_is_transformed = hmtx_entry
850
            .map(|entry| entry.transform_length.is_some())
851
            .unwrap_or(false);
852
        let glyf_is_transformed = glyf_entry
853
            .map(|entry| entry.transform_length.is_some())
854
            .unwrap_or(false);
855

            
856
        if hmtx_is_transformed || glyf_is_transformed {
857
            let glyf_entry = glyf_entry.ok_or(ParseError::MissingValue)?;
858
            let glyf_table = glyf_entry.read_table(&woff.table_data_block_scope())?;
859
            let mut head = read_table!(woff, tag::HEAD, HeadTable, index)?;
860
            let maxp = read_table!(woff, tag::MAXP, MaxpTable, index)?;
861
            let hhea = read_table!(woff, tag::HHEA, HheaTable, index)?;
862
            let loca_entry = woff
863
                .find_table_entry(tag::LOCA, index)
864
                .ok_or(ParseError::MissingValue)?;
865
            let loca = loca_entry.read_table(&woff.table_data_block_scope())?;
866
            let loca = loca.scope().read_dep::<Woff2LocaTable>((
867
                loca_entry,
868
                maxp.num_glyphs,
869
                head.index_to_loc_format,
870
            ))?;
871
            let glyf = glyf_table
872
                .scope()
873
                .read_dep::<Woff2GlyfTable>((glyf_entry, &loca))?;
874

            
875
            if hmtx_is_transformed {
876
                let hmtx_entry = hmtx_entry.ok_or(ParseError::MissingValue)?;
877
                let hmtx_table = hmtx_entry.read_table(&woff.table_data_block_scope())?;
878
                let hmtx = hmtx_table.scope().read_dep::<Woff2HmtxTable>((
879
                    hmtx_entry,
880
                    &glyf,
881
                    usize::from(maxp.num_glyphs),
882
                    usize::from(hhea.num_h_metrics),
883
                ))?;
884
                let ((), data) = write::buffer::<_, HmtxTable<'_>>(&hmtx, ())?;
885
                tables.insert(tag::HMTX, Box::from(data.into_inner()));
886
            }
887

            
888
            // Add head, glyf and loca
889
            let (loca, data) = write::buffer::<_, GlyfTable<'_>>(glyf, head.index_to_loc_format)?;
890
            tables.insert(tag::GLYF, Box::from(data.into_inner()));
891
            match loca.offsets.last() {
892
                Some(&last) if (last / 2) > u32::from(u16::MAX) => {
893
                    head.index_to_loc_format = IndexToLocFormat::Long
894
                }
895
                _ => {}
896
            }
897
            let (_placeholder, data) = write::buffer::<_, HeadTable>(&head, ())?;
898
            tables.insert(tag::HEAD, Box::from(data.into_inner()));
899
            let ((), data) = write::buffer::<_, owned::LocaTable>(loca, head.index_to_loc_format)?;
900
            tables.insert(tag::LOCA, Box::from(data.into_inner()));
901
        }
902

            
903
        // Add remaining tables
904
        for table_entry in Self::table_directory(woff, index) {
905
            let tag = table_entry.tag;
906
            if tables.contains_key(&tag) {
907
                // Skip tables that were inserted above
908
                continue;
909
            }
910
            let data: Box<[u8]> = Box::from(
911
                table_entry
912
                    .read_table(&woff.table_data_block_scope())?
913
                    .scope()
914
                    .data(),
915
            );
916
            tables.insert(tag, data);
917
        }
918

            
919
        Ok(Woff2TableProvider {
920
            flavor: woff.woff_header.flavor,
921
            tables,
922
        })
923
    }
924

            
925
    pub fn into_tables(self) -> HashMap<u32, Box<[u8]>> {
926
        self.tables
927
    }
928

            
929
    fn table_directory<'a>(
930
        woff: &'a Woff2Font<'a>,
931
        index: usize,
932
    ) -> impl Iterator<Item = &'a TableDirectoryEntry> {
933
        if let Some(collection_directory) = &woff.collection_directory {
934
            // NOTE(unwrap): index is determined valid in woff2_read_tables.
935
            Either::Left(
936
                collection_directory
937
                    .get(index)
938
                    .map(|font| font.table_entries(woff))
939
                    .unwrap(),
940
            )
941
        } else {
942
            Either::Right(woff.table_directory.iter())
943
        }
944
    }
945
}
946

            
947
#[cfg(test)]
948
mod tests {
949
    use super::*;
950

            
951
    #[test]
952
    fn test_compute_end_pts_of_contours() {
953
        let data = [2u8, 4];
954
        let mut ctxt = ReadScope::new(&data).ctxt();
955
        let (end_pts_of_contours, n_points) =
956
            Woff2GlyfTable::compute_end_pts_of_contours(&mut ctxt, data.len() as i16)
957
                .expect("unable to decode simple glyph");
958
        assert_eq!(end_pts_of_contours, vec![1, 5]);
959
        assert_eq!(n_points, 6);
960
    }
961

            
962
    #[test]
963
    fn test_xy_triplet_dx_dy() {
964
        let triplet = XYTriplet {
965
            byte_count: 2,
966
            x_bits: 8,
967
            y_bits: 8,
968
            delta_x: 1,
969
            delta_y: 257,
970
            x_is_negative: true,
971
            y_is_negative: false,
972
        };
973
        let data = 0x7AD2;
974

            
975
        assert_eq!(triplet.dx(data), -(0x7A + 1));
976
        assert_eq!(triplet.dy(data), 0xD2 + 257);
977
    }
978

            
979
    #[test]
980
    fn test_bit_slice_len() {
981
        let inner = vec![0b1000000, 0b00000001];
982
        let bits = BitSlice::new(&inner);
983

            
984
        assert_eq!(bits.len(), 16);
985
    }
986

            
987
    #[test]
988
    fn test_bit_slice_get_out_of_bounds() {
989
        let inner = vec![0b1000000, 0b00000001];
990
        let bits = BitSlice::new(&inner);
991

            
992
        assert_eq!(bits.get(16), None);
993
    }
994

            
995
    #[test]
996
    fn test_bit_slice_start() {
997
        let inner = vec![0b1000_0000, 0b0000_0000];
998
        let bits = BitSlice::new(&inner);
999

            
        assert_eq!(bits.get(0), Some(true));
    }
    #[test]
    fn test_bit_slice_middle() {
        let inner = vec![0b1111_1110, 0b1111_1111];
        let bits = BitSlice::new(&inner);
        assert_eq!(bits.get(7), Some(false));
    }
    #[test]
    fn test_bit_slice_end() {
        let inner = vec![0b0000_0000, 0b0000_0001];
        let bits = BitSlice::new(&inner);
        assert_eq!(bits.get(15), Some(true));
    }
    #[test]
    fn test_read_packed_u16() {
        assert_eq!(
            ReadScope::new(&[255, 253]).read::<PackedU16>().unwrap(),
            506
        );
        assert_eq!(ReadScope::new(&[254, 0]).read::<PackedU16>().unwrap(), 506);
        assert_eq!(
            ReadScope::new(&[253, 1, 250]).read::<PackedU16>().unwrap(),
            506
        );
        assert_eq!(ReadScope::new(&[5u8]).read::<PackedU16>().unwrap(), 5);
        assert!(ReadScope::new(&[254u8]).read::<PackedU16>().is_err());
    }
    #[test]
    fn test_read_u32base128() {
        assert_eq!(ReadScope::new(&[0x3F]).read::<U32Base128>().unwrap(), 63);
        assert_eq!(
            ReadScope::new(&[0x85, 0x07]).read::<U32Base128>().unwrap(),
            647
        );
        assert_eq!(
            ReadScope::new(&[0xFF, 0xFA, 0x00])
                .read::<U32Base128>()
                .unwrap(),
            2_096_384
        );
        assert_eq!(
            ReadScope::new(&[0x8F, 0xFF, 0xFF, 0xFF, 0x7F])
                .read::<U32Base128>()
                .unwrap(),
            0xFFFFFFFF
        );
    }
    #[test]
    fn test_read_u32base128_err() {
        // Leading zeros
        assert!(ReadScope::new(&[0x80, 0x01]).read::<U32Base128>().is_err());
        // Overflow
        assert!(ReadScope::new(&[0xFF, 0xFF, 0xFF, 0xFF, 0x7F])
            .read::<U32Base128>()
            .is_err());
        // More than 5 bytes
        assert!(ReadScope::new(&[0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F])
            .read::<U32Base128>()
            .is_err());
    }
}