skrifa/outline/autohint/hint/
mod.rs1mod edges;
4mod outline;
5
6use super::{
7 metrics::{scale_style_metrics, Scale, UnscaledStyleMetrics},
8 outline::Outline,
9 recorder::HintsRecorder,
10 style::{GlyphStyle, ScriptGroup},
11 topo::{self, Axis, Dimension},
12 QuirksMode, ScaleFlags,
13};
14
15#[derive(Copy, Clone, PartialEq, Default, Debug)]
18pub(crate) struct EdgeMetrics {
19 pub left_opos: i32,
20 pub left_pos: i32,
21 pub right_opos: i32,
22 pub right_pos: i32,
23}
24
25#[derive(Copy, Clone, PartialEq, Default, Debug)]
26pub(crate) struct HintedMetrics {
27 pub x_scale: i32,
28 pub edge_metrics: Option<EdgeMetrics>,
33}
34
35pub(crate) fn hint_outline(
39 outline: &mut Outline,
40 metrics: &UnscaledStyleMetrics,
41 scale: &Scale,
42 glyph_style: Option<GlyphStyle>,
43) -> HintedMetrics {
44 hint_outline_impl(outline, metrics, scale, glyph_style, None).hinted_metrics
45}
46
47pub(crate) struct HintedPlan {
48 pub hinted_metrics: HintedMetrics,
49 pub axes: [Option<Axis>; 2],
50}
51
52pub(crate) fn hint_outline_with_recorder(
53 outline: &mut Outline,
54 metrics: &UnscaledStyleMetrics,
55 scale: &Scale,
56 glyph_style: Option<GlyphStyle>,
57 recorder: &mut HintsRecorder,
58) -> HintedPlan {
59 hint_outline_impl(outline, metrics, scale, glyph_style, Some(recorder))
60}
61
62fn hint_outline_impl(
63 outline: &mut Outline,
64 metrics: &UnscaledStyleMetrics,
65 scale: &Scale,
66 glyph_style: Option<GlyphStyle>,
67 mut recorder: Option<&mut HintsRecorder>,
68) -> HintedPlan {
69 let quirks = if recorder.is_some() {
70 QuirksMode::Aot
71 } else {
72 QuirksMode::Jit
73 };
74 let scaled_metrics = scale_style_metrics(metrics, *scale, quirks);
75 let scale = &scaled_metrics.scale;
76 let mut axis = Axis::default();
77 let hint_top_to_bottom = metrics.style_class().script.hint_top_to_bottom;
78 outline.scale(&scaled_metrics.scale);
79 let mut hinted_metrics = HintedMetrics {
80 x_scale: scale.x_scale,
81 ..Default::default()
82 };
83 let group = metrics.style_class().script.group;
84 let mut axes = [const { None }; 2];
85 if group == ScriptGroup::Default && scaled_metrics.axes[1].blues.is_empty() {
89 return HintedPlan {
90 hinted_metrics,
91 axes,
92 };
93 }
94 for dim in [Dimension::Horizontal, Dimension::Vertical] {
95 if (dim == Dimension::Horizontal && scale.flags.contains(ScaleFlags::NO_HORIZONTAL))
96 || (dim == Dimension::Vertical && scale.flags.contains(ScaleFlags::NO_VERTICAL))
97 {
98 continue;
99 }
100 axis.reset(dim, outline.orientation);
101 topo::compute_segments(outline, &mut axis, group);
102 topo::link_segments(
103 outline,
104 &mut axis,
105 scaled_metrics.axes[dim].scale,
106 group,
107 metrics.axes[dim].max_width(),
108 );
109 topo::compute_edges(
110 &mut axis,
111 &scaled_metrics.axes[dim],
112 hint_top_to_bottom,
113 scaled_metrics.scale.y_scale,
114 group,
115 );
116 if dim == Dimension::Vertical {
117 if group != ScriptGroup::Default
118 || glyph_style
119 .map(|style| !style.is_non_base())
120 .unwrap_or(true)
121 {
122 topo::compute_blue_edges(
123 &mut axis,
124 scale,
125 &metrics.axes[dim].blues,
126 &scaled_metrics.axes[dim].blues,
127 group,
128 );
129 }
130 } else {
131 hinted_metrics.x_scale = scaled_metrics.axes[0].scale;
132 }
133 edges::hint_edges(
134 &mut axis,
135 &scaled_metrics.axes[dim],
136 group,
137 scale,
138 hint_top_to_bottom,
139 recorder.as_deref_mut(),
140 );
141 outline::align_edge_points(outline, &axis, group, scale);
142 outline::align_strong_points(outline, &mut axis, recorder.as_deref_mut());
143 outline::align_weak_points(outline, dim);
144 if dim == Dimension::Horizontal && axis.edges.len() > 1 {
145 let left = axis.edges.first().unwrap();
146 let right = axis.edges.last().unwrap();
147 hinted_metrics.edge_metrics = Some(EdgeMetrics {
148 left_pos: left.pos,
149 left_opos: left.opos,
150 right_pos: right.pos,
151 right_opos: right.opos,
152 });
153 }
154 if recorder.is_some() {
155 axes[dim as usize] = Some(axis.clone());
156 }
157 }
158 HintedPlan {
159 hinted_metrics,
160 axes,
161 }
162}