1#![cfg_attr(docsrs, feature(doc_cfg))]
4#![allow(non_snake_case)]
5#![allow(non_upper_case_globals)]
6#![allow(unused_imports)]
7#![allow(dead_code)]
8#![allow(clippy::needless_range_loop)]
9#![allow(clippy::collapsible_if)]
10
11mod decompress_woff1;
12mod decompress_woff2;
13mod error;
14mod table_tags;
15mod variable_length;
16mod woff;
17
18use bytes::BufMut;
19pub use decompress_woff1::decompress_woff1_with_custom_z;
20pub use decompress_woff2::decompress_woff2_with_custom_brotli;
21pub use error::WuffErr;
22
23#[cfg(feature = "z")]
24#[cfg_attr(docsrs, doc(cfg(feature = "z")))]
25pub use decompress_woff1::decompress_woff1;
26
27#[cfg(feature = "brotli")]
28#[cfg_attr(docsrs, doc(cfg(feature = "brotli")))]
29pub use decompress_woff2::decompress_woff2;
30
31const HEAD: Tag = Tag::new(b"head");
32const HHEA: Tag = Tag::new(b"hhea");
33const HMTX: Tag = Tag::new(b"hmtx");
34const GLYF: Tag = Tag::new(b"glyf");
35const LOCA: Tag = Tag::new(b"loca");
36
37#[derive(Copy, Clone)]
38pub(crate) struct Point {
39 pub x: i32,
40 pub y: i32,
41 pub on_curve: bool,
42}
43
44macro_rules! Round4 {
49 ($value:expr) => {
50 match $value.checked_add(3) {
51 Some(value_plus_3) => value_plus_3 & !3,
52 None => $value,
53 }
54 };
55}
56use Round4;
57use font_types::Tag;
58
59pub(crate) fn compute_checksum(buf: &[u8]) -> u32 {
61 let mut checksum: u32 = 0;
62 let mut iter = buf.chunks_exact(4);
63 for chunk in &mut iter {
64 let bytes: [u8; 4] = chunk.try_into().unwrap();
65 checksum = checksum.wrapping_add(u32::from_be_bytes(bytes));
66 }
67
68 checksum = checksum.wrapping_add(match iter.remainder() {
70 &[a, b, c] => u32::from_be_bytes([a, b, c, 0]),
71 &[a, b] => u32::from_be_bytes([a, b, 0, 0]),
72 &[a] => u32::from_be_bytes([a, 0, 0, 0]),
73 [] => 0,
74 _ => unreachable!("chunk size was 4 so remainder will be a slice of length 3 or smaller"),
75 });
76
77 checksum
78}
79
80fn write_table_directory_header(output: &mut impl BufMut, flavor: Tag, num_tables: u16) {
84 let mut max_pow2: u16 = 0;
85 while 1u32 << (max_pow2 + 1) <= (num_tables as u32) {
86 max_pow2 += 1;
87 }
88 let entry_selector = max_pow2;
89 let search_range: u16 = (1u16 << max_pow2) << 4;
90 let range_shift = (((num_tables as u32) << 4) - search_range as u32) as u16;
91
92 output.put_u32(u32::from_be_bytes(flavor.to_be_bytes())); output.put_u16(num_tables); output.put_u16(search_range); output.put_u16(entry_selector); output.put_u16(range_shift); }