chromium/third_party/rust/chromium_crates_io/vendor/skrifa-0.20.0/src/outline/glyf/outline.rs

//! TrueType outline types.

use std::mem::size_of;

use raw::tables::glyf::{PointCoord, ToPathStyle};
use read_fonts::{
    tables::glyf::{to_path, Glyph, PointFlags, ToPathError},
    types::{F26Dot6, Fixed, GlyphId, Pen, Point},
};

use super::super::Hinting;

/// Represents the information necessary to scale a glyph outline.
///
/// Contains a reference to the glyph data itself as well as metrics that
/// can be used to compute the memory requirements for scaling the glyph.
#[derive(Clone, Default)]
pub struct Outline<'a> {
    pub glyph_id: GlyphId,
    /// The associated top-level glyph for the outline.
    pub glyph: Option<Glyph<'a>>,
    /// Sum of the point counts of all simple glyphs in an outline.
    pub points: usize,
    /// Sum of the contour counts of all simple glyphs in an outline.
    pub contours: usize,
    /// Maximum number of points in a single simple glyph.
    pub max_simple_points: usize,
    /// "Other" points are the unscaled or original scaled points.
    ///
    /// The size of these buffer is the same and this value tracks the size
    /// for one (not both) of the buffers. This is the maximum of
    /// `max_simple_points` and the total number of points for all component
    /// glyphs in a single composite glyph.
    pub max_other_points: usize,
    /// Maximum size of the component delta stack.
    ///
    /// For composite glyphs in variable fonts, delta values are computed
    /// for each component. This tracks the maximum stack depth necessary
    /// to store those values during processing.
    pub max_component_delta_stack: usize,
    /// Number of entries in the hinting value stack.
    pub max_stack: usize,
    /// Number of CVT entries for copy-on-write support.
    pub cvt_count: usize,
    /// Number of storage area entries for copy-on-write support.
    pub storage_count: usize,
    /// Maximum number of points in the twilight zone for hinting.
    pub max_twilight_points: usize,
    /// True if any component of a glyph has bytecode instructions.
    pub has_hinting: bool,
    /// True if the glyph requires variation delta processing.
    pub has_variations: bool,
    /// True if the glyph contains any simple or compound overlap flags.
    pub has_overlaps: bool,
}

impl<'a> Outline<'a> {
    /// Returns the minimum size in bytes required to scale an outline based
    /// on the computed sizes.
    pub fn required_buffer_size(&self, hinting: Hinting) -> usize {
        let mut size = 0;
        let hinting = self.has_hinting && hinting == Hinting::Embedded;
        // Scaled, unscaled and (for hinting) original scaled points
        size += self.points * size_of::<Point<F26Dot6>>();
        // Unscaled and (if hinted) original scaled points
        size += self.max_other_points * size_of::<Point<i32>>() * if hinting { 2 } else { 1 };
        // Contour end points
        size += self.contours * size_of::<u16>();
        // Point flags
        size += self.points * size_of::<PointFlags>();
        if self.has_variations {
            // Interpolation buffer for delta IUP
            size += self.max_simple_points * size_of::<Point<Fixed>>();
            // Delta buffer for points
            size += self.max_simple_points * size_of::<Point<Fixed>>();
            // Delta buffer for composite components
            size += self.max_component_delta_stack * size_of::<Point<Fixed>>();
        }
        if hinting {
            // Hinting value stack
            size += self.max_stack * size_of::<i32>();
            // CVT and storage area copy-on-write buffers
            size += (self.cvt_count + self.storage_count) * size_of::<i32>();
            // Twilight zone storage. Two point buffers plus one point flags buffer
            size += self.max_twilight_points
                * (size_of::<Point<F26Dot6>>() * 2 + size_of::<PointFlags>());
        }
        if size != 0 {
            // If we're given a buffer that is not aligned, we'll need to
            // adjust, so add our maximum alignment requirement in bytes.
            size += std::mem::align_of::<i32>();
        }
        size
    }
}

#[derive(Debug)]
pub struct ScaledOutline<'a, C>
where
    C: PointCoord,
{
    pub points: &'a mut [Point<C>],
    pub flags: &'a mut [PointFlags],
    pub contours: &'a mut [u16],
    pub phantom_points: [Point<C>; 4],
}

impl<'a, C> ScaledOutline<'a, C>
where
    C: PointCoord,
{
    pub(crate) fn new(
        points: &'a mut [Point<C>],
        phantom_points: [Point<C>; 4],
        flags: &'a mut [PointFlags],
        contours: &'a mut [u16],
    ) -> Self {
        let x_shift = phantom_points[0].x;
        if x_shift != C::zeroed() {
            for point in points.iter_mut() {
                point.x = point.x - x_shift;
            }
        }
        Self {
            points,
            flags,
            contours,
            phantom_points,
        }
    }

    pub fn adjusted_lsb(&self) -> C {
        self.phantom_points[0].x
    }

    pub fn adjusted_advance_width(&self) -> C {
        self.phantom_points[1].x - self.phantom_points[0].x
    }

    pub fn to_path(&self, path_style: ToPathStyle, pen: &mut impl Pen) -> Result<(), ToPathError> {
        to_path(self.points, self.flags, self.contours, path_style, pen)
    }
}