Skip to main content

read_fonts/ps/
hinting.rs

1//! Hinting parameters.
2
3use types::Fixed;
4
5/// Maximum number of values in a set of blue alignment zones.
6// <https://gitlab.freedesktop.org/freetype/freetype/-/blob/80a507a6b8e3d2906ad2c8ba69329bd2fb2a85ef/src/psaux/psblues.h#L141>
7pub const MAX_BLUE_VALUES: usize = 7;
8
9/// Operand for the `BlueValues`, `OtherBlues`, `FamilyBlues` and
10/// `FamilyOtherBlues` operators.
11///
12/// These are used to generate zones when applying hints.
13#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
14pub struct Blues {
15    values: [(Fixed, Fixed); MAX_BLUE_VALUES],
16    len: u32,
17}
18
19impl Blues {
20    /// Creates a new set of blues from the given values.
21    pub fn new(values: impl Iterator<Item = Fixed>) -> Self {
22        let mut blues = Self::default();
23        let mut stash = Fixed::ZERO;
24        for (i, value) in values.take(MAX_BLUE_VALUES * 2).enumerate() {
25            if (i & 1) == 0 {
26                stash = value;
27            } else {
28                blues.values[i / 2] = (stash, value);
29                blues.len += 1;
30            }
31        }
32        blues
33    }
34
35    /// Returns the blue value regions.
36    pub fn values(&self) -> &[(Fixed, Fixed)] {
37        &self.values[..self.len as usize]
38    }
39}
40
41/// Maximum number of stem snap parameters.
42// Summary: older PostScript interpreters accept two values, but newer ones
43// accept 12. We'll assume that as maximum.
44// <https://adobe-type-tools.github.io/font-tech-notes/pdfs/5049.StemSnap.pdf>
45pub const MAX_STEM_SNAPS: usize = 12;
46
47/// Operand for the `StemSnapH` and `StemSnapV` operators.
48///
49/// These are used for stem darkening when applying hints.
50#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
51pub struct StemSnaps {
52    values: [Fixed; MAX_STEM_SNAPS],
53    len: u32,
54}
55
56impl StemSnaps {
57    /// Creates a new set of stem snaps for the given values.
58    pub fn new(values: impl Iterator<Item = Fixed>) -> Self {
59        let mut snaps = Self::default();
60        for (value, target_value) in values.take(MAX_STEM_SNAPS).zip(&mut snaps.values) {
61            *target_value = value;
62            snaps.len += 1;
63        }
64        snaps
65    }
66
67    /// Returns the stem snap values.
68    pub fn values(&self) -> &[Fixed] {
69        &self.values[..self.len as usize]
70    }
71}
72
73/// Parameters used to generate the stem and counter zones for the hinting
74/// algorithm.
75#[derive(Clone, PartialEq, Eq, Debug)]
76pub struct HintingParams {
77    pub blues: Blues,
78    pub family_blues: Blues,
79    pub other_blues: Blues,
80    pub family_other_blues: Blues,
81    pub blue_scale: Fixed,
82    pub blue_shift: Fixed,
83    pub blue_fuzz: Fixed,
84    pub language_group: i32,
85}
86
87impl Default for HintingParams {
88    fn default() -> Self {
89        Self {
90            blues: Blues::default(),
91            other_blues: Blues::default(),
92            family_blues: Blues::default(),
93            family_other_blues: Blues::default(),
94            // See <https://learn.microsoft.com/en-us/typography/opentype/spec/cff2#table-16-private-dict-operators>
95            blue_scale: Fixed::from_f64(0.039625),
96            blue_shift: Fixed::from_i32(7),
97            blue_fuzz: Fixed::ONE,
98            language_group: 0,
99        }
100    }
101}