Coverage Report

Created: 2026-05-24 07:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fontations/skrifa/src/outline/autohint/mod.rs
Line
Count
Source
1
//! Runtime autohinting support.
2
3
mod hint;
4
mod instance;
5
mod metrics;
6
mod outline;
7
mod recorder;
8
mod shape;
9
mod style;
10
mod topo;
11
12
pub use instance::GlyphStyles;
13
pub(crate) use instance::Instance;
14
pub use metrics::{
15
    BlueZones, Scale, ScaleFlags, ScaledAxisMetrics, ScaledBlue, ScaledStyleMetrics, ScaledWidth,
16
    UnscaledAxisMetrics, UnscaledBlue, UnscaledStyleMetrics, WidthMetrics,
17
};
18
pub use outline::Direction;
19
pub use recorder::{EdgeAction, EdgeHint, HintAction, PointAction, PointHint};
20
pub use style::{GlyphStyle, ScriptClass, ScriptGroup, StyleClass};
21
pub use style::{SCRIPT_CLASSES, STYLE_CLASSES};
22
pub use topo::{Axis, BlueProvenance, Dimension, Edge, Segment, TopoFlags};
23
24
use crate::outline::{DrawError, Target};
25
use crate::{FontRef, MetadataProvider};
26
use alloc::vec::Vec;
27
use raw::types::{F2Dot14, GlyphId};
28
29
/// Controls quirks for the different autohinters.
30
#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
31
enum QuirksMode {
32
    /// Just in time hinter; matches FreeType.
33
    #[default]
34
    Jit,
35
    /// Ahead of time hinter; matches ttfautohint.
36
    Aot,
37
}
38
39
/// Plan for hinting an outline.
40
#[derive(Clone, Debug, Default)]
41
pub struct HintPlan {
42
    hints: Vec<HintAction>,
43
    axes: [Option<Axis>; 2],
44
}
45
46
impl HintPlan {
47
    /// Creates a new hint plan.
48
0
    pub fn new(
49
0
        font: &FontRef,
50
0
        coords: &[F2Dot14],
51
0
        ppem: f32,
52
0
        target: Target,
53
0
        glyph_id: GlyphId,
54
0
        glyph_style: GlyphStyle,
55
0
    ) -> Result<Self, DrawError> {
56
0
        let style_class = glyph_style
57
0
            .style_class()
58
0
            .ok_or(DrawError::GlyphNotFound(glyph_id))?;
59
0
        let outline_glyph = font
60
0
            .outline_glyphs()
61
0
            .get(glyph_id)
62
0
            .ok_or(DrawError::GlyphNotFound(glyph_id))?;
63
64
0
        let shaper_mode = if cfg!(feature = "autohint_shaping") {
65
0
            shape::ShaperMode::BestEffort
66
        } else {
67
0
            shape::ShaperMode::Nominal
68
        };
69
0
        let shaper = shape::Shaper::new(font, shaper_mode);
70
0
        let metrics =
71
0
            metrics::compute_unscaled_style_metrics(&shaper, coords, style_class, QuirksMode::Aot);
72
73
0
        let mut outline = outline::Outline::default();
74
0
        outline.fill(&outline_glyph, coords, QuirksMode::Aot)?;
75
76
0
        let scale = metrics::Scale::new(
77
0
            ppem,
78
0
            outline_glyph.units_per_em() as i32,
79
0
            font.attributes().style,
80
0
            target,
81
0
            metrics.style_class().script.group,
82
        );
83
84
0
        let mut recorder = recorder::HintsRecorder::default();
85
0
        let hinted_plan = hint::hint_outline_with_recorder(
86
0
            &mut outline,
87
0
            &metrics,
88
0
            &scale,
89
0
            Some(glyph_style),
90
0
            &mut recorder,
91
        );
92
93
0
        Ok(Self {
94
0
            hints: recorder.actions,
95
0
            axes: hinted_plan.axes,
96
0
        })
97
0
    }
98
99
    /// Returns the collection of hinting actions.
100
0
    pub fn actions(&self) -> &[HintAction] {
101
0
        &self.hints
102
0
    }
103
104
    /// Returns the topological analysis of the horizontal axis.
105
0
    pub fn horizontal_axis(&self) -> Option<&Axis> {
106
0
        self.axes[Dimension::Horizontal].as_ref()
107
0
    }
108
109
    /// Returns the topological analysis of the vertical axis.
110
0
    pub fn vertical_axis(&self) -> Option<&Axis> {
111
0
        self.axes[Dimension::Vertical].as_ref()
112
0
    }
113
}
114
115
/// All constants are defined based on a UPEM of 2048.
116
///
117
/// See <https://gitlab.freedesktop.org/freetype/freetype/-/blob/57617782464411201ce7bbc93b086c1b4d7d84a5/src/autofit/aflatin.h#L34>
118
0
fn derived_constant(units_per_em: i32, value: i32) -> i32 {
119
0
    value * units_per_em / 2048
120
0
}