Skip to main content

woff/version2/
mod.rs

1//! [Web Open Font Format][1] of version 2.0.
2//!
3//! [1]: https://www.w3.org/TR/WOFF2/
4
5mod ffi;
6
7/// Compress.
8pub fn compress<T>(data: &[u8], metadata: T, quality: usize, transform: bool) -> Option<Vec<u8>>
9where
10    T: Into<Vec<u8>>,
11{
12    let metadata = match std::ffi::CString::new(metadata) {
13        Ok(metadata) => metadata,
14        _ => return None,
15    };
16    let metadata_size = metadata.count_bytes();
17    let size = unsafe {
18        ffi::ComputeTTFToWOFF2Size(
19            data.as_ptr() as *const _,
20            data.len(),
21            metadata.as_ptr() as *const _,
22            metadata_size,
23        )
24    };
25    let mut buffer = vec![0; size];
26    let mut size = buffer.len();
27    let status = unsafe {
28        ffi::ConvertTTFToWOFF2(
29            data.as_ptr() as *const _,
30            data.len(),
31            buffer.as_mut_ptr() as *mut _,
32            &mut size as *mut _,
33            metadata.as_ptr() as *const _,
34            metadata_size,
35            quality as core::ffi::c_int,
36            transform as core::ffi::c_int,
37        )
38    };
39    debug_assert_ne!(status, 0);
40    if status == 0 {
41        return None;
42    }
43    buffer.truncate(size);
44    buffer.into()
45}
46
47/// Decompress.
48pub fn decompress(data: &[u8]) -> Option<Vec<u8>> {
49    let size = unsafe { ffi::ComputeWOFF2ToTTFSize(data.as_ptr() as *const _, data.len()) };
50    let mut buffer = vec![0; size];
51    let status = unsafe {
52        ffi::ConvertWOFF2ToTTF(
53            buffer.as_mut_ptr() as *mut _,
54            size,
55            data.as_ptr() as *const _,
56            data.len(),
57        )
58    };
59    debug_assert_ne!(status, 0);
60    if status == 0 {
61        return None;
62    }
63    buffer.into()
64}
65
66#[cfg(test)]
67mod tests {
68    use std::fs::{read, write};
69
70    const DEFAULT_METADATA: &str = "";
71    const DEFAULT_QUALITY: usize = 8;
72    const DEFAULT_TRANSFORM: bool = true;
73
74    macro_rules! ok(($result:expr) => ($result.unwrap()));
75
76    #[test]
77    fn otf() {
78        ok!(write(
79            "tests/fixtures/Roboto-Regular.otf.woff2",
80            ok!(super::compress(
81                &ok!(read("tests/fixtures/Roboto-Regular.otf")),
82                DEFAULT_METADATA,
83                DEFAULT_QUALITY,
84                DEFAULT_TRANSFORM,
85            )),
86        ));
87        ok!(write(
88            "tests/fixtures/Roboto-Regular.otf",
89            ok!(super::decompress(&ok!(read(
90                "tests/fixtures/Roboto-Regular.otf.woff2"
91            )))),
92        ));
93    }
94
95    #[test]
96    fn ttf() {
97        ok!(write(
98            "tests/fixtures/Roboto-Regular.ttf.woff2",
99            ok!(super::compress(
100                &ok!(read("tests/fixtures/Roboto-Regular.ttf")),
101                DEFAULT_METADATA,
102                DEFAULT_QUALITY,
103                DEFAULT_TRANSFORM,
104            )),
105        ));
106        ok!(write(
107            "tests/fixtures/Roboto-Regular.ttf",
108            ok!(super::decompress(&ok!(read(
109                "tests/fixtures/Roboto-Regular.ttf.woff2"
110            )))),
111        ));
112    }
113}