1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/// A precomputed hash of a [`skrifa::instance::Location`].
///
/// Used as a cache key so that we don't have to re-hash the coordinate list
/// for every glyph lookup. Compute once per text run and reuse for every glyph
/// in the run.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub(crate) struct LocationHash(u64);
impl nohash_hasher::IsEnabled for LocationHash {}
impl LocationHash {
#[inline]
pub fn new(location: &skrifa::instance::Location) -> Self {
if location.coords().is_empty() {
// Fast path for the (common) default-coords case.
Self(0)
} else {
Self(crate::util::hash(location))
}
}
}
// ----------------------------------------------------------------------------
/// Metrics for a font at a specific screen-space scale.
#[derive(Clone, Debug, PartialEq, Default)]
pub struct StyledMetrics {
/// The DPI part of the screen-space scale.
pub pixels_per_point: f32,
/// Scale factor, relative to the font's units per em (so, probably much less than 1).
///
/// Translates "unscaled" units to physical (screen) pixels.
pub px_scale_factor: f32,
/// Absolute scale in screen pixels, for skrifa.
pub scale: f32,
/// Vertical offset, in UI points (not screen-space).
pub y_offset_in_points: f32,
/// This is the distance from the top to the baseline.
///
/// Unit: points.
pub ascent: f32,
/// Height of one row of text in points.
///
/// Returns a value rounded to [`emath::GUI_ROUNDING`].
pub row_height: f32,
/// Resolved variation coordinates.
pub location: skrifa::instance::Location,
/// Precomputed hash of [`Self::location`].
///
/// Hashed once per run of text so per-glyph cache lookups don't have to
/// re-hash the full coordinate list.
pub(crate) location_hash: LocationHash,
}
impl StyledMetrics {
/// Metrics to lay out text with when the family has no font at all.
///
/// Modeled on a typical Latin font: the ascent is 80% of the font size,
/// and a row is 120% of it. Text laid out with these still gets one glyph
/// per character and rows of a sensible height, so cursors and selections work.
pub fn without_font(pixels_per_point: f32, font_size: f32) -> Self {
use emath::GuiRounding as _;
let ascent = (0.8 * font_size).round_ui();
Self {
pixels_per_point,
px_scale_factor: 0.0,
scale: font_size * pixels_per_point,
y_offset_in_points: 0.0,
ascent,
row_height: (1.2 * font_size).round_ui().max(ascent),
location: Default::default(),
location_hash: Default::default(),
}
}
}