chromium/third_party/rust/chromium_crates_io/vendor/read-fonts-0.20.0/src/tables/cvar.rs

//! The [cvar (CVT Variations)](https://learn.microsoft.com/en-us/typography/opentype/spec/cvar)
//! table.

include!("../../generated/generated_cvar.rs");

use super::variations::{
    PackedPointNumbers, TupleDelta, TupleVariationCount, TupleVariationData, TupleVariationHeader,
};

/// Variation data specialized for the CVT variation table.
pub type CvtVariationData<'a> = TupleVariationData<'a, CvtDelta>;

impl<'a> Cvar<'a> {
    /// Returns the variation data containing the tuples and deltas for the
    /// control value table.
    ///
    /// This table doesn't contain an axis count field so this must be provided
    /// by the user and can be read from the `fvar` table.
    pub fn variation_data(&self, axis_count: u16) -> Result<CvtVariationData<'a>, ReadError> {
        let count = self.tuple_variation_count();
        let data = self.data()?;
        let header_data = self.raw_tuple_header_data();
        // if there are shared point numbers, get them now
        let (shared_point_numbers, serialized_data) = if count.shared_point_numbers() {
            let (packed, data) = PackedPointNumbers::split_off_front(data);
            (Some(packed), data)
        } else {
            (None, data)
        };
        Ok(CvtVariationData {
            tuple_count: count,
            axis_count,
            shared_tuples: None,
            shared_point_numbers,
            header_data,
            serialized_data,
            _marker: std::marker::PhantomData,
        })
    }

    /// Computes the accumulated deltas for the given set of normalized
    /// coordinates and stores them in `deltas`.
    ///
    /// The `axis_count` parameter expects the value from the `fvar`
    /// table.
    ///
    /// The `deltas` slice should have a length greater than or equal
    /// to the number of values in the `cvt` table. The values are
    /// computed in 16.16 format.
    pub fn deltas(
        &self,
        axis_count: u16,
        coords: &[F2Dot14],
        deltas: &mut [i32],
    ) -> Result<(), ReadError> {
        let var_data = self.variation_data(axis_count)?;
        for (tuple, scalar) in var_data.active_tuples_at(coords) {
            for delta in tuple.deltas() {
                let ix = delta.position as usize;
                if let Some(value) = deltas.get_mut(ix) {
                    *value += delta.apply_scalar(scalar).to_bits();
                }
            }
        }
        Ok(())
    }

    fn raw_tuple_header_data(&self) -> FontData<'a> {
        let range = self.shape.tuple_variation_headers_byte_range();
        self.data.split_off(range.start).unwrap()
    }
}

/// Delta for an entry in the control value table.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct CvtDelta {
    /// The index in the CVT.
    pub position: u16,
    /// The delta to apply to the value in the CVT.
    pub value: i32,
}

impl CvtDelta {
    /// Applies a tuple scalar to this delta.
    pub fn apply_scalar(self, scalar: Fixed) -> Fixed {
        Fixed::from_i32(self.value) * scalar
    }
}

impl TupleDelta for CvtDelta {
    fn is_point() -> bool {
        false
    }

    fn new(position: u16, x: i32, _y: i32) -> Self {
        Self { position, value: x }
    }
}

#[cfg(test)]
mod tests {
    use font_types::F2Dot14;

    use crate::{FontRef, TableProvider};

    #[test]
    fn scaled_deltas() {
        let font = FontRef::new(font_test_data::CVAR).unwrap();
        // Elements are ([coords], [deltas]) where deltas are fixed point
        // values.
        // These were generated by fancy printf debugging in FreeType.
        let cases = &[
            (
                [0.5, 0.5],
                [
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 720896, 3276800, 1179648, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 622592, 0, 1179648, 0, 0, 0, 0, 0, 622592,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                ],
            ),
            (
                [-0.5, 0.5],
                [
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1441792, -2162688, -1277952, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -917504, 0, -1277952, 0, 0, 0, 0, 0,
                    -720896, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0,
                ],
            ),
            (
                [0.5, -0.5],
                [
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1900544, 2621440, 2129920, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 360448, 0, 1015808, 0, 0, 0, 0, 0,
                    524288, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0,
                ],
            ),
            (
                [-0.5, -0.5],
                [
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1212416, -2293760, -1130496, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1097728, 0, -1277952, 0, 0, 0, 0, 0,
                    -737280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0,
                ],
            ),
            (
                [-1.0, -1.0],
                [
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2490368, -4325376, -2490368, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1835008, 0, -2555904, 0, 0, 0, 0, 0,
                    -1441792, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0,
                ],
            ),
            (
                [1.0, 1.0],
                [
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1441792, 6553600, 2359296, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1245184, 0, 2359296, 0, 0, 0, 0, 0,
                    1245184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0,
                ],
            ),
            (
                [-1.0, 1.0],
                [
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2883584, -4325376, -2555904, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1835008, 0, -2555904, 0, 0, 0, 0, 0,
                    -1441792, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0,
                ],
            ),
            (
                [1.0, -1.0],
                [
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5636096, 4456448, 5636096, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 917504, 0, 1703936, 0, 0, 0, 0, 0,
                    917504, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0,
                ],
            ),
        ];
        let cvar = font.cvar().unwrap();
        let axis_count = font.fvar().unwrap().axis_count();
        let cvar_data = cvar.variation_data(axis_count).unwrap();
        for (coords, expected_deltas) in cases {
            let coords = coords.map(F2Dot14::from_f32);
            let mut deltas = vec![0; expected_deltas.len()];
            for (tuple, weight) in cvar_data.active_tuples_at(&coords) {
                for delta in tuple.deltas() {
                    let scaled_delta = delta.apply_scalar(weight);
                    deltas[delta.position as usize] += scaled_delta.to_bits();
                }
            }
            assert_eq!(&deltas, expected_deltas);
        }
    }

    #[test]
    fn raw_tuple_deltas() {
        let font = FontRef::new(font_test_data::CVAR).unwrap();
        let cvar = font.cvar().unwrap();
        let axis_count = font.fvar().unwrap().axis_count();
        let cvar_data = cvar.variation_data(axis_count).unwrap();
        // An array of slices of (point number, delta) pairs, one for each
        // tuple.
        // These were taken directly from the ttx
        let expected = [
            &[(65, 8), (66, -8), (67, 8), (85, -11), (87, 0), (93, -1)],
            &[(65, -2), (66, 8), (67, -7), (85, 11), (87, 0), (93, 1)],
            &[(65, 56), (66, -24), (67, 42), (85, 6), (87, -10), (93, -4)],
            &[
                (65, -44),
                (66, -66),
                (67, -39),
                (85, -28),
                (87, -39),
                (93, -22),
            ],
            &[(65, 22), (66, 100), (67, 36), (85, 19), (87, 36), (93, 19)],
            &[(65, 8), (66, 0), (67, 8), (85, -43), (87, -49), (93, -32)],
            &[(65, -8), (66, 0), (67, -8), (85, 11), (87, 9), (93, 1)],
            &[(65, -80), (66, 0), (67, -90), (85, -6), (87, -47), (93, 4)],
            &[(65, -16), (66, 0), (67, -21), (85, 28), (87, 39), (93, 22)],
            &[
                (65, -46),
                (66, 0),
                (67, -22),
                (85, -19),
                (87, 35),
                (93, -19),
            ],
            &[(65, 2), (66, 0), (67, 7), (85, -11), (87, -9), (93, -1)],
        ];
        let mut count = 0;
        for (tuple, expected) in cvar_data.tuples().zip(&expected) {
            count += 1;
            let deltas = tuple
                .deltas()
                .map(|delta| (delta.position, delta.value))
                .collect::<Vec<_>>();
            assert_eq!(&deltas, expected);
        }
        assert_eq!(count, expected.len());
    }
}