1mod collection;
6mod lut;
7
8use std::borrow::Cow;
9use std::collections::HashMap;
10use std::convert::TryFrom;
11use std::io::{Cursor, Read};
12
13use bitflags::bitflags;
14use itertools::Either;
15
16use self::lut::{XYTriplet, COORD_LUT, KNOWN_TABLE_TAGS};
17use crate::binary::read::{
18 ReadArray, ReadArrayCow, ReadBinary, ReadBinaryDep, ReadBuf, ReadCtxt, ReadFrom, ReadScope,
19};
20use crate::binary::{write, I16Be, U16Be, U8};
21use crate::error::{ParseError, ReadWriteError};
22use crate::tables::glyf::{
23 BoundingBox, CompositeGlyph, CompositeGlyphs, GlyfRecord, GlyfTable, Glyph, Point, SimpleGlyph,
24 SimpleGlyphFlag,
25};
26use crate::tables::loca::{owned, LocaTable};
27use crate::tables::{
28 FontTableProvider, HeadTable, HheaTable, HmtxTable, IndexToLocFormat, LongHorMetric, MaxpTable,
29 SfntVersion, TTCF_MAGIC,
30};
31use crate::{read_table, tag};
32
33pub const MAGIC: u32 = tag!(b"wOF2");
34const BROTLI_DECODER_BUFFER_SIZE: usize = 4096;
37const BITS_0_TO_5: u8 = 0x3F;
38const LOWEST_UCODE: u16 = 253;
39
40#[derive(Copy, Clone)]
42pub enum U32Base128 {}
43
44#[derive(Copy, Clone)]
47pub enum PackedU16 {}
48
49#[derive(Clone, Copy)]
50struct WoffFlag(u8);
51
52#[derive(Clone)]
53pub struct Woff2Font<'a> {
54 pub scope: ReadScope<'a>,
55 pub woff_header: Woff2Header,
56 pub table_directory: Vec<TableDirectoryEntry>,
59 pub collection_directory: Option<collection::Directory>,
60 pub table_data_block: Vec<u8>,
61}
62
63pub struct Woff2TableProvider {
64 flavor: u32,
65 tables: HashMap<u32, Box<[u8]>>,
66}
67
68#[derive(Clone, Eq, PartialEq, Debug)]
69pub struct Woff2Header {
70 pub flavor: u32,
71 pub length: u32,
72 pub num_tables: u16,
73 pub total_sfnt_size: u32,
74 pub total_compressed_size: u32,
75 pub _major_version: u16,
76 pub _minor_version: u16,
77 pub meta_offset: u32,
78 pub meta_length: u32,
79 pub meta_orig_length: u32,
80 pub priv_offset: u32,
81 pub priv_length: u32,
82}
83
84#[derive(Copy, Clone, Eq, PartialEq, Debug)]
85pub struct TableDirectoryEntry {
86 pub tag: u32,
87 pub offset: usize,
88 pub orig_length: u32,
89 pub transform_length: Option<u32>,
90}
91
92struct TransformedGlyphTable<'a> {
93 num_glyphs: u16,
95 _index_format: u16,
97 n_contour_scope: ReadScope<'a>,
99 n_points_scope: ReadScope<'a>,
101 flag_scope: ReadScope<'a>,
103 glyph_scope: ReadScope<'a>,
105 composite_scope: ReadScope<'a>,
107 bbox_bitmap_scope: ReadScope<'a>,
109 bbox_scope: ReadScope<'a>,
111 instruction_scope: ReadScope<'a>,
113}
114
115bitflags! {
116 pub struct HmtxTableFlag: u8 {
117 const LSB_ABSENT = 0b01;
118 const LEFT_SIDE_BEARING_ABSENT = 0b10;
119 }
120}
121
122pub enum Woff2GlyfTable {}
123pub enum Woff2LocaTable {}
124pub enum Woff2HmtxTable {}
125
126pub struct BitSlice<'a> {
127 data: &'a [u8],
128}
129
130impl<'a> Woff2Font<'a> {
131 pub fn flavor(&self) -> u32 {
133 self.woff_header.flavor
134 }
135
136 pub fn extended_metadata(&self) -> Result<Option<String>, ParseError> {
138 let offset = usize::try_from(self.woff_header.meta_offset)?;
139 let length = usize::try_from(self.woff_header.meta_length)?;
140 if offset == 0 || length == 0 {
141 return Ok(None);
142 }
143
144 let compressed_metadata = self.scope.offset_length(offset, length)?;
145
146 let mut input = brotli_decompressor::Decompressor::new(
147 Cursor::new(compressed_metadata.data()),
148 BROTLI_DECODER_BUFFER_SIZE,
149 );
150 let mut metadata = String::new();
151 input
152 .read_to_string(&mut metadata)
153 .map_err(|_err| ParseError::CompressionError)?;
154
155 Ok(Some(metadata))
156 }
157
158 pub fn table_data_block_scope(&'a self) -> ReadScope<'a> {
159 ReadScope::new(&self.table_data_block)
160 }
161
162 fn read_table_directory(
163 ctxt: &mut ReadCtxt<'_>,
164 num_tables: usize,
165 ) -> Result<Vec<TableDirectoryEntry>, ParseError> {
166 let mut offset = 0;
167 let mut table_directory = Vec::with_capacity(num_tables);
168 for _i in 0..num_tables {
169 let entry = ctxt.read_dep::<TableDirectoryEntry>(offset)?;
170 offset += entry.length();
171 table_directory.push(entry);
172 }
173
174 Ok(table_directory)
175 }
176
177 pub fn find_table_entry(&self, tag: u32, index: usize) -> Option<&TableDirectoryEntry> {
178 if let Some(collection_directory) = &self.collection_directory {
179 collection_directory
180 .get(index)
181 .and_then(|font| font.table_entries(self).find(|entry| entry.tag == tag))
182 } else {
183 self.table_directory.iter().find(|entry| entry.tag == tag)
184 }
185 }
186
187 pub fn read_table(&self, tag: u32, index: usize) -> Result<Option<ReadBuf<'_>>, ParseError> {
188 self.find_table_entry(tag, index)
189 .map(|entry| entry.read_table(&self.table_data_block_scope()))
190 .transpose()
191 }
192
193 pub fn table_provider(&self, index: usize) -> Result<Woff2TableProvider, ReadWriteError> {
194 Woff2TableProvider::new(self, index)
195 }
196}
197
198impl<'b> ReadBinary for Woff2Font<'b> {
199 type HostType<'a> = Woff2Font<'a>;
200
201 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
202 let scope = ctxt.scope();
203 let woff_header = ctxt.read::<Woff2Header>()?;
204
205 let table_directory =
206 Self::read_table_directory(ctxt, usize::from(woff_header.num_tables))?;
207
208 let collection_directory = if woff_header.flavor == TTCF_MAGIC {
209 Some(ctxt.read::<collection::Directory>()?)
210 } else {
211 None
212 };
213
214 let compressed_data =
216 ctxt.read_slice(usize::try_from(woff_header.total_compressed_size)?)?;
217 let mut input = brotli_decompressor::Decompressor::new(
218 Cursor::new(compressed_data),
219 BROTLI_DECODER_BUFFER_SIZE,
220 );
221 let mut table_data_block = Vec::new();
222 input
223 .read_to_end(&mut table_data_block)
224 .map_err(|_err| ParseError::CompressionError)?;
225
226 Ok(Woff2Font {
227 scope,
228 woff_header,
229 table_directory,
230 collection_directory,
231 table_data_block,
232 })
233 }
234}
235
236impl FontTableProvider for Woff2TableProvider {
237 fn table_data(&self, tag: u32) -> Result<Option<Cow<'_, [u8]>>, ParseError> {
238 Ok(self.tables.get(&tag).map(|table| Cow::from(table.as_ref())))
239 }
240
241 fn has_table(&self, tag: u32) -> bool {
242 self.tables.contains_key(&tag)
243 }
244
245 fn table_tags(&self) -> Option<Vec<u32>> {
246 Some(self.tables.keys().copied().collect())
247 }
248}
249
250impl SfntVersion for Woff2TableProvider {
251 fn sfnt_version(&self) -> u32 {
252 self.flavor
253 }
254}
255
256impl ReadBinary for Woff2Header {
257 type HostType<'a> = Self;
258
259 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self, ParseError> {
260 let signature = ctxt.read_u32be()?;
261 match signature {
262 MAGIC => {
263 let flavor = ctxt.read_u32be()?;
264 let length = ctxt.read_u32be()?;
265 let num_tables = ctxt.read_u16be()?;
266 let reserved = ctxt.read_u16be()?;
267 ctxt.check(reserved == 0)?;
270 let total_sfnt_size = ctxt.read_u32be()?;
271 let total_compressed_size = ctxt.read_u32be()?;
272 let _major_version = ctxt.read_u16be()?;
277 let _minor_version = ctxt.read_u16be()?;
278 let meta_offset = ctxt.read_u32be()?;
279 let meta_length = ctxt.read_u32be()?;
280 let meta_orig_length = ctxt.read_u32be()?;
281 let priv_offset = ctxt.read_u32be()?;
282 let priv_length = ctxt.read_u32be()?;
283
284 Ok(Woff2Header {
285 flavor,
286 length,
287 num_tables,
288 total_sfnt_size,
289 total_compressed_size,
290 _major_version,
291 _minor_version,
292 meta_offset,
293 meta_length,
294 meta_orig_length,
295 priv_offset,
296 priv_length,
297 })
298 }
299 _ => Err(ParseError::BadVersion),
300 }
301 }
302}
303
304impl ReadBinaryDep for TableDirectoryEntry {
305 type Args<'a> = usize;
306 type HostType<'a> = Self;
307
308 fn read_dep<'a>(ctxt: &mut ReadCtxt<'a>, offset: usize) -> Result<Self, ParseError> {
309 let flags = ctxt.read_u8()?;
310 let tag = if flags & BITS_0_TO_5 == 63 {
311 ctxt.read_u32be()
313 } else {
314 Ok(KNOWN_TABLE_TAGS[usize::from(flags & BITS_0_TO_5)])
315 }?;
316 let transformation_version = (flags & 0xC0) >> 6;
317 let orig_length = ctxt.read::<U32Base128>()?;
318
319 let transform_length = match (transformation_version, tag) {
320 (3, tag::GLYF) | (3, tag::LOCA) => None,
321 (_, tag::GLYF) | (_, tag::LOCA) | (1, tag::HMTX) => Some(ctxt.read::<U32Base128>()?),
322 (0, _) => None,
323 _ => Some(ctxt.read::<U32Base128>()?),
324 };
325
326 Ok(TableDirectoryEntry {
327 tag,
328 offset,
329 orig_length,
330 transform_length,
331 })
332 }
333}
334
335impl<'b> ReadBinary for TransformedGlyphTable<'b> {
336 type HostType<'a> = TransformedGlyphTable<'a>;
337
338 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
339 let _version = ctxt.read_u32be()?;
340 let num_glyphs = ctxt.read_u16be()?;
341 let index_format = ctxt.read_u16be()?;
342
343 let n_contour_stream_size = usize::try_from(ctxt.read_u32be()?)?;
344 let n_points_stream_size = usize::try_from(ctxt.read_u32be()?)?;
345 let flag_stream_size = usize::try_from(ctxt.read_u32be()?)?;
346 let glyph_stream_size = usize::try_from(ctxt.read_u32be()?)?;
347 let composite_stream_size = usize::try_from(ctxt.read_u32be()?)?;
348 let bbox_stream_size = usize::try_from(ctxt.read_u32be()?)?;
349 let instruction_stream_size = usize::try_from(ctxt.read_u32be()?)?;
350
351 let n_contour_scope = ReadScope::new(ctxt.read_slice(n_contour_stream_size)?);
354 let n_points_scope = ReadScope::new(ctxt.read_slice(n_points_stream_size)?);
355 let flag_scope = ReadScope::new(ctxt.read_slice(flag_stream_size)?);
356 let glyph_scope = ReadScope::new(ctxt.read_slice(glyph_stream_size)?);
357 let composite_scope = ReadScope::new(ctxt.read_slice(composite_stream_size)?);
358 let bbox_bitmap_length = (4. * ((num_glyphs + 31) as f64 / 32.).floor()) as usize;
364 let bbox_bitmap_scope = ReadScope::new(ctxt.read_slice(bbox_bitmap_length)?);
365 let bbox_scope = ReadScope::new(ctxt.read_slice(bbox_stream_size - bbox_bitmap_length)?);
366 let instruction_scope = ReadScope::new(ctxt.read_slice(instruction_stream_size)?);
367
368 Ok(TransformedGlyphTable {
369 num_glyphs,
370 _index_format: index_format,
371 n_contour_scope,
372 n_points_scope,
373 flag_scope,
374 glyph_scope,
375 composite_scope,
376 bbox_bitmap_scope,
377 bbox_scope,
378 instruction_scope,
379 })
380 }
381}
382
383impl ReadBinaryDep for Woff2GlyfTable {
384 type Args<'a> = (&'a TableDirectoryEntry, &'a LocaTable<'a>);
385 type HostType<'a> = GlyfTable<'a>;
386
387 fn read_dep<'a>(
388 ctxt: &mut ReadCtxt<'a>,
389 (entry, loca): Self::Args<'a>,
390 ) -> Result<Self::HostType<'a>, ParseError> {
391 if entry.transform_length.is_some() {
392 let table = ctxt.read::<TransformedGlyphTable<'_>>()?;
393
394 let num_glyphs = usize::from(table.num_glyphs);
396 let mut n_contour_ctxt = table.n_contour_scope.ctxt();
397 let mut n_points_ctxt = table.n_points_scope.ctxt();
398 let mut flags_ctxt = table.flag_scope.ctxt();
399 let mut glyphs_ctxt = table.glyph_scope.ctxt();
400 let mut instructions_ctxt = table.instruction_scope.ctxt();
401 let mut composite_ctxt = table.composite_scope.ctxt();
402 let bbox_bitmap = BitSlice::new(table.bbox_bitmap_scope.data());
403 let mut bbox_bitmap_ctxt = table.bbox_scope.ctxt();
404
405 let mut records = Vec::with_capacity(num_glyphs);
406 for i in 0..num_glyphs {
407 let number_of_contours = n_contour_ctxt.read_i16be()?;
408
409 let glyf_record = match number_of_contours {
410 0 => GlyfRecord::empty(),
412 -1 => {
414 let glyphs = composite_ctxt.read::<CompositeGlyphs>()?;
415
416 let instruction_length = if glyphs.have_instructions {
418 usize::from(glyphs_ctxt.read::<PackedU16>()?)
419 } else {
420 0
421 };
422 let instructions = instructions_ctxt.read_slice(instruction_length)?;
423
424 match bbox_bitmap.get(i) {
429 Some(true) => (),
430 _ => return Err(ParseError::BadIndex),
431 }
432
433 let bounding_box = bbox_bitmap_ctxt.read::<BoundingBox>()?;
435
436 GlyfRecord::Parsed(Glyph::Composite(CompositeGlyph {
437 bounding_box,
438 glyphs: glyphs.glyphs,
439 instructions,
440 phantom_points: None,
441 }))
442 }
443 num if num > 0 => {
445 let mut data = Self::decode_simple_glyph(
446 &mut n_points_ctxt,
447 &mut flags_ctxt,
448 &mut glyphs_ctxt,
449 &mut instructions_ctxt,
450 number_of_contours,
451 )?;
452
453 let bounding_box = match bbox_bitmap.get(i) {
454 Some(true) => bbox_bitmap_ctxt.read::<BoundingBox>(),
455 Some(false) => Ok(data.bounding_box()),
456 _ => return Err(ParseError::BadIndex),
457 }?;
458 data.bounding_box = bounding_box;
459
460 GlyfRecord::Parsed(Glyph::Simple(data))
461 }
462 _ => return Err(ParseError::BadValue),
463 };
464
465 records.push(glyf_record);
466 }
467
468 GlyfTable::new(records)
469 } else {
470 ctxt.read_dep::<GlyfTable<'_>>(loca)
472 }
473 }
474}
475
476impl ReadBinaryDep for Woff2LocaTable {
477 type Args<'a> = (&'a TableDirectoryEntry, usize, IndexToLocFormat);
478 type HostType<'a> = LocaTable<'a>;
479
480 fn read_dep<'a>(
481 ctxt: &mut ReadCtxt<'a>,
482 (loca_entry, num_glyphs, index_to_loc_format): Self::Args<'a>,
483 ) -> Result<Self::HostType<'a>, ParseError> {
484 if loca_entry.transform_length.is_some() {
485 Ok(LocaTable::empty())
486 } else {
487 ctxt.read_dep::<LocaTable<'_>>((num_glyphs, index_to_loc_format))
488 }
489 }
490}
491
492impl ReadBinaryDep for Woff2HmtxTable {
493 type Args<'a> = (&'a TableDirectoryEntry, &'a GlyfTable<'a>, usize, usize);
494 type HostType<'a> = HmtxTable<'a>;
495
496 fn read_dep<'a>(
500 ctxt: &mut ReadCtxt<'a>,
501 (hmtx_entry, glyf, num_glyphs, num_h_metrics): Self::Args<'a>,
502 ) -> Result<Self::HostType<'a>, ParseError> {
503 if hmtx_entry.transform_length.is_some() {
504 let flags = ctxt.read::<HmtxTableFlag>()?;
505 let advance_width_stream = ctxt.read_array::<U16Be>(num_h_metrics)?;
506
507 let lsb = if flags.lsb_is_present() {
508 ReadArrayCow::Borrowed(ctxt.read_array::<I16Be>(num_h_metrics)?)
510 } else {
511 ReadArrayCow::Owned(
523 glyf.records()
524 .iter()
525 .map(|glyf_record| match glyf_record {
526 GlyfRecord::Present { .. } => unreachable!(),
527 GlyfRecord::Parsed(glyph) => {
528 glyph.bounding_box().map(|bbox| bbox.x_min).unwrap_or(0)
529 }
530 })
531 .collect(),
532 )
533 };
534
535 let length = num_glyphs
536 .checked_sub(num_h_metrics)
537 .ok_or(ParseError::BadIndex)?;
538 let left_side_bearings = if flags.left_side_bearing_is_present() {
539 ReadArrayCow::Borrowed(ctxt.read_array::<I16Be>(length)?)
540 } else {
541 ReadArrayCow::Owned(
543 glyf.records()
544 .iter()
545 .map(|glyf_record| match glyf_record {
546 GlyfRecord::Present { .. } => unreachable!(),
547 GlyfRecord::Parsed(glyph) => {
548 glyph.bounding_box().map(|bbox| bbox.x_min).unwrap_or(0)
549 }
550 })
551 .collect(),
552 )
553 };
554
555 let h_metrics = lsb
556 .iter()
557 .zip(advance_width_stream.iter())
558 .map(|(lsb, advance_width)| LongHorMetric { advance_width, lsb })
559 .collect();
560
561 Ok(HmtxTable {
562 h_metrics: ReadArrayCow::Owned(h_metrics),
563 left_side_bearings,
564 })
565 } else {
566 ctxt.read_dep::<HmtxTable<'a>>((num_glyphs, num_h_metrics))
567 }
568 }
569}
570
571impl ReadFrom for WoffFlag {
572 type ReadType = U8;
573
574 fn read_from(flag: u8) -> Self {
575 WoffFlag::new(flag)
576 }
577}
578
579impl ReadBinary for PackedU16 {
582 type HostType<'a> = u16;
583
584 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<u16, ParseError> {
585 match ctxt.read_u8()? {
586 253 => ctxt.read_u16be(),
587 254 => ctxt
588 .read_u8()
589 .map(|value| u16::from(value) + LOWEST_UCODE * 2),
590 255 => ctxt.read_u8().map(|value| u16::from(value) + LOWEST_UCODE),
591 code => Ok(u16::from(code)),
592 }
593 .map_err(ParseError::from)
594 }
595}
596
597impl ReadBinary for U32Base128 {
600 type HostType<'a> = u32;
601
602 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<u32, ParseError> {
603 let mut accum = 0u32;
604
605 for i in 0..5 {
606 let byte = ctxt.read_u8()?;
607
608 if i == 0 && byte == 0x80 {
610 return Err(ParseError::BadValue);
611 }
612
613 if accum & 0xFE000000 != 0 {
615 return Err(ParseError::BadValue);
616 }
617
618 accum = (accum << 7) | u32::from(byte & 0x7F);
620
621 if byte & 0x80 == 0 {
623 return Ok(accum);
624 }
625 }
626
627 Err(ParseError::BadValue)
629 }
630}
631
632impl ReadFrom for HmtxTableFlag {
633 type ReadType = U8;
634
635 fn read_from(flag: u8) -> Self {
636 HmtxTableFlag::from_bits_truncate(flag)
637 }
638}
639
640impl WoffFlag {
641 fn new(flag: u8) -> Self {
642 WoffFlag(flag)
643 }
644
645 fn bytes_to_read(&self) -> usize {
646 usize::from(self.xy_triplet().byte_count)
647 }
648
649 fn is_on_curve_point(&self) -> bool {
650 self.0 & 0x80 == 0
658 }
659
660 fn xy_triplet(&self) -> &XYTriplet {
661 &COORD_LUT[usize::from(self.0 & 0x7F)]
662 }
663}
664
665impl From<WoffFlag> for SimpleGlyphFlag {
666 fn from(woff_flag: WoffFlag) -> Self {
667 if woff_flag.is_on_curve_point() {
668 SimpleGlyphFlag::ON_CURVE_POINT
669 } else {
670 SimpleGlyphFlag::empty()
671 }
672 }
673}
674
675impl Woff2GlyfTable {
676 fn compute_end_pts_of_contours(
677 n_points_ctxt: &mut ReadCtxt<'_>,
678 number_of_contours: i16,
679 ) -> Result<(Vec<u16>, u16), ParseError> {
680 let mut n_points = 0;
688 let end_pts_of_contours = (0..number_of_contours)
689 .map(|_i| {
690 n_points_ctxt.read::<PackedU16>().map(|n_contours| {
691 n_points += n_contours;
692 n_points - 1
693 })
694 })
695 .collect::<Result<Vec<_>, _>>()?;
696
697 Ok((end_pts_of_contours, n_points))
698 }
699
700 fn decode_coordinates(flag: WoffFlag, coordinates: ReadArray<'_, U8>) -> Point {
701 let xy_triplet = flag.xy_triplet();
702
703 let data = coordinates.iter().fold(0u32, |mut data, byte| {
704 data <<= 8;
705 data |= u32::from(byte);
706 data
707 });
708
709 Point(xy_triplet.dx(data), xy_triplet.dy(data))
711 }
712
713 fn decode_simple_glyph<'a>(
714 n_points_ctxt: &mut ReadCtxt<'_>,
715 flags_ctxt: &mut ReadCtxt<'_>,
716 glyphs_ctxt: &mut ReadCtxt<'_>,
717 instructions_ctxt: &mut ReadCtxt<'a>,
718 number_of_contours: i16,
719 ) -> Result<SimpleGlyph<'a>, ParseError> {
720 let (end_pts_of_contours, n_points) =
722 Self::compute_end_pts_of_contours(n_points_ctxt, number_of_contours)?;
723
724 let flags = flags_ctxt.read_array::<WoffFlag>(usize::from(n_points))?;
726
727 let mut prev_point = Point::zero();
729 let mut points = Vec::with_capacity(flags.len());
730 for flag in flags.iter() {
731 let coordinates = glyphs_ctxt.read_array::<U8>(flag.bytes_to_read())?;
732 let point = Self::decode_coordinates(flag, coordinates);
733
734 prev_point = Point(prev_point.0 + point.0, prev_point.1 + point.1);
738 points.push((From::from(flag), prev_point));
739 }
740
741 let instruction_length = usize::from(glyphs_ctxt.read::<PackedU16>()?);
743
744 let instructions = instructions_ctxt.read_slice(instruction_length)?;
746
747 Ok(SimpleGlyph {
748 bounding_box: BoundingBox::empty(), end_pts_of_contours,
750 instructions,
751 coordinates: points,
752 phantom_points: None,
753 })
754 }
755}
756
757impl TableDirectoryEntry {
758 fn length(&self) -> usize {
759 self.transform_length.unwrap_or(self.orig_length) as usize
760 }
761
762 pub fn read_table<'a>(&self, scope: &ReadScope<'a>) -> Result<ReadBuf<'a>, ParseError> {
764 let table_data = scope.offset_length(self.offset, self.length())?;
765
766 Ok(ReadBuf::from(table_data.data()))
767 }
768}
769
770impl HmtxTableFlag {
771 pub fn lsb_is_present(self) -> bool {
772 self & Self::LSB_ABSENT == Self::empty()
773 }
774
775 pub fn left_side_bearing_is_present(self) -> bool {
776 self & Self::LEFT_SIDE_BEARING_ABSENT == Self::empty()
777 }
778}
779
780impl<'a> BitSlice<'a> {
781 pub fn new(data: &'a [u8]) -> Self {
782 BitSlice { data }
783 }
784
785 pub fn get(&self, index: usize) -> Option<bool> {
786 if index >= self.len() {
787 return None;
788 }
789
790 let byte_index = index / 8;
792 let shl = 8 - (index % 8) - 1;
797 let mask = 1 << shl;
798
799 Some(self.data[byte_index] & mask == mask)
800 }
801
802 pub fn len(&self) -> usize {
803 self.data.len() * 8
804 }
805}
806
807impl Woff2TableProvider {
812 fn new<'a>(woff: &Woff2Font<'a>, index: usize) -> Result<Self, ReadWriteError> {
813 let mut tables = HashMap::with_capacity(woff.table_directory.len());
814
815 let hmtx_entry = woff.find_table_entry(tag::HMTX, index);
818 let glyf_entry = woff.find_table_entry(tag::GLYF, index);
819 let hmtx_is_transformed = hmtx_entry
820 .map(|entry| entry.transform_length.is_some())
821 .unwrap_or(false);
822 let glyf_is_transformed = glyf_entry
823 .map(|entry| entry.transform_length.is_some())
824 .unwrap_or(false);
825
826 if hmtx_is_transformed || glyf_is_transformed {
827 let glyf_entry = glyf_entry.ok_or(ParseError::MissingValue)?;
828 let glyf_table = glyf_entry.read_table(&woff.table_data_block_scope())?;
829 let mut head = read_table!(woff, tag::HEAD, HeadTable, index)?;
830 let maxp = read_table!(woff, tag::MAXP, MaxpTable, index)?;
831 let hhea = read_table!(woff, tag::HHEA, HheaTable, index)?;
832 let loca_entry = woff
833 .find_table_entry(tag::LOCA, index)
834 .ok_or(ParseError::MissingValue)?;
835 let loca = loca_entry.read_table(&woff.table_data_block_scope())?;
836 let loca = loca.scope().read_dep::<Woff2LocaTable>((
837 loca_entry,
838 usize::from(maxp.num_glyphs),
839 head.index_to_loc_format,
840 ))?;
841 let glyf = glyf_table
842 .scope()
843 .read_dep::<Woff2GlyfTable>((glyf_entry, &loca))?;
844
845 if hmtx_is_transformed {
846 let hmtx_entry = hmtx_entry.ok_or(ParseError::MissingValue)?;
847 let hmtx_table = hmtx_entry.read_table(&woff.table_data_block_scope())?;
848 let hmtx = hmtx_table.scope().read_dep::<Woff2HmtxTable>((
849 hmtx_entry,
850 &glyf,
851 usize::from(maxp.num_glyphs),
852 usize::from(hhea.num_h_metrics),
853 ))?;
854 let ((), data) = write::buffer::<_, HmtxTable<'_>>(&hmtx, ())?;
855 tables.insert(tag::HMTX, Box::from(data.into_inner()));
856 }
857
858 let (loca, data) = write::buffer::<_, GlyfTable<'_>>(glyf, head.index_to_loc_format)?;
860 tables.insert(tag::GLYF, Box::from(data.into_inner()));
861 match loca.offsets.last() {
862 Some(&last) if (last / 2) > u32::from(std::u16::MAX) => {
863 head.index_to_loc_format = IndexToLocFormat::Long
864 }
865 _ => {}
866 }
867 let (_placeholder, data) = write::buffer::<_, HeadTable>(&head, ())?;
868 tables.insert(tag::HEAD, Box::from(data.into_inner()));
869 let ((), data) = write::buffer::<_, owned::LocaTable>(loca, head.index_to_loc_format)?;
870 tables.insert(tag::LOCA, Box::from(data.into_inner()));
871 }
872
873 for table_entry in Self::table_directory(woff, index) {
875 let tag = table_entry.tag;
876 if tables.contains_key(&tag) {
877 continue;
879 }
880 let data: Box<[u8]> = Box::from(
881 table_entry
882 .read_table(&woff.table_data_block_scope())?
883 .scope()
884 .data(),
885 );
886 tables.insert(tag, data);
887 }
888
889 Ok(Woff2TableProvider {
890 flavor: woff.woff_header.flavor,
891 tables,
892 })
893 }
894
895 pub fn into_tables(self) -> HashMap<u32, Box<[u8]>> {
896 self.tables
897 }
898
899 fn table_directory<'a>(
900 woff: &'a Woff2Font<'a>,
901 index: usize,
902 ) -> impl Iterator<Item = &TableDirectoryEntry> {
903 if let Some(collection_directory) = &woff.collection_directory {
904 Either::Left(
905 collection_directory
906 .get(index)
907 .map(|font| font.table_entries(woff))
908 .unwrap(), )
910 } else {
911 Either::Right(woff.table_directory.iter())
912 }
913 }
914}
915
916#[cfg(test)]
917mod tests {
918 use super::*;
919
920 #[test]
921 fn test_compute_end_pts_of_contours() {
922 let data = [2u8, 4];
923 let mut ctxt = ReadScope::new(&data).ctxt();
924 let (end_pts_of_contours, n_points) =
925 Woff2GlyfTable::compute_end_pts_of_contours(&mut ctxt, data.len() as i16)
926 .expect("unable to decode simple glyph");
927 assert_eq!(end_pts_of_contours, vec![1, 5]);
928 assert_eq!(n_points, 6);
929 }
930
931 #[test]
932 fn test_xy_triplet_dx_dy() {
933 let triplet = XYTriplet {
934 byte_count: 2,
935 x_bits: 8,
936 y_bits: 8,
937 delta_x: 1,
938 delta_y: 257,
939 x_is_negative: true,
940 y_is_negative: false,
941 };
942 let data = 0x7AD2;
943
944 assert_eq!(triplet.dx(data), -(0x7A + 1));
945 assert_eq!(triplet.dy(data), 0xD2 + 257);
946 }
947
948 #[test]
949 fn test_bit_slice_len() {
950 let inner = vec![0b1000000, 0b00000001];
951 let bits = BitSlice::new(&inner);
952
953 assert_eq!(bits.len(), 16);
954 }
955
956 #[test]
957 fn test_bit_slice_get_out_of_bounds() {
958 let inner = vec![0b1000000, 0b00000001];
959 let bits = BitSlice::new(&inner);
960
961 assert_eq!(bits.get(16), None);
962 }
963
964 #[test]
965 fn test_bit_slice_start() {
966 let inner = vec![0b1000_0000, 0b0000_0000];
967 let bits = BitSlice::new(&inner);
968
969 assert_eq!(bits.get(0), Some(true));
970 }
971
972 #[test]
973 fn test_bit_slice_middle() {
974 let inner = vec![0b1111_1110, 0b1111_1111];
975 let bits = BitSlice::new(&inner);
976
977 assert_eq!(bits.get(7), Some(false));
978 }
979
980 #[test]
981 fn test_bit_slice_end() {
982 let inner = vec![0b0000_0000, 0b0000_0001];
983 let bits = BitSlice::new(&inner);
984
985 assert_eq!(bits.get(15), Some(true));
986 }
987
988 #[test]
989 fn test_read_packed_u16() {
990 assert_eq!(
991 ReadScope::new(&[255, 253]).read::<PackedU16>().unwrap(),
992 506
993 );
994 assert_eq!(ReadScope::new(&[254, 0]).read::<PackedU16>().unwrap(), 506);
995 assert_eq!(
996 ReadScope::new(&[253, 1, 250]).read::<PackedU16>().unwrap(),
997 506
998 );
999 assert_eq!(ReadScope::new(&[5u8]).read::<PackedU16>().unwrap(), 5);
1000 assert!(ReadScope::new(&[254u8]).read::<PackedU16>().is_err());
1001 }
1002
1003 #[test]
1004 fn test_read_u32base128() {
1005 assert_eq!(ReadScope::new(&[0x3F]).read::<U32Base128>().unwrap(), 63);
1006 assert_eq!(
1007 ReadScope::new(&[0x85, 0x07]).read::<U32Base128>().unwrap(),
1008 647
1009 );
1010 assert_eq!(
1011 ReadScope::new(&[0xFF, 0xFA, 0x00])
1012 .read::<U32Base128>()
1013 .unwrap(),
1014 2_096_384
1015 );
1016 assert_eq!(
1017 ReadScope::new(&[0x8F, 0xFF, 0xFF, 0xFF, 0x7F])
1018 .read::<U32Base128>()
1019 .unwrap(),
1020 0xFFFFFFFF
1021 );
1022 }
1023
1024 #[test]
1025 fn test_read_u32base128_err() {
1026 assert!(ReadScope::new(&[0x80, 0x01]).read::<U32Base128>().is_err());
1028
1029 assert!(ReadScope::new(&[0xFF, 0xFF, 0xFF, 0xFF, 0x7F])
1031 .read::<U32Base128>()
1032 .is_err());
1033
1034 assert!(ReadScope::new(&[0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F])
1036 .read::<U32Base128>()
1037 .is_err());
1038 }
1039}