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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright (c) 2023 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
// Use of this source is governed by Lesser General Public License that can be found
// in the LICENSE file.
use bitflags::bitflags;
use crate::core::scalar::Scalar;
/// `FontMetrics` represents the metrics of a Font.
///
/// The metric values are consistent with the y-down coordinate system.
pub struct FontMetrics {
/// FontMetricsFlags indicating which metrics are valid
pub flags: FontMetricsFlags,
/// Greatest extent above origin of any glyph bounding box, typically negative;
/// deprecated with variable fonts.
pub top: Scalar,
/// Distance to reserve above baseline, typically negative.
pub ascent: Scalar,
/// Distance to reserve below baseline, typically positive.
pub descent: Scalar,
/// Greatest extent below origin of any glyph bounding box, typically positive;
/// deprecated with variable fonts.
pub bottom: Scalar,
/// Distance to add between lines, typically positive or zero.
pub leading: Scalar,
/// Average character width, zero if unknown.
pub avg_char_width: Scalar,
/// Maximum character width, zero if unknown.
pub max_char_width: Scalar,
/// Greatest extent to left of origin of any glyph bounding box, typically negative;
/// deprecated with variable fonts.
pub x_min: Scalar,
/// Greatest extent to right of origin of any glyph bounding box, typically positive;
/// deprecated with variable fonts.
pub x_max: Scalar,
/// Height of lower-case 'x', zero if unknown, typically negative.
pub x_height: Scalar,
/// Height of an upper-case letter, zero if unknown, typically negative.
pub cap_height: Scalar,
/// Underline thickness.
pub underline_thickness: Scalar,
/// Distance from baseline to top of stroke, typically positive.
pub underline_position: Scalar,
/// Strikeout thickness.
pub strikeout_thickness: Scalar,
/// Distance from baseline to bottom of stroke, typically negative.
pub strikeout_position: Scalar,
}
bitflags! {
/// FontMetricsFlags indicate when certain metrics are valid;
/// the underline or strikeout metrics may be valid and zero.
///
/// Fonts with embedded bitmaps may not have valid underline or strikeout metrics.
pub struct FontMetricsFlags : u16 {
/// Set if fUnderlineThickness is valid.
const UnderlineThicknessIsValid = 1 << 0;
/// Set if fUnderlinePosition is valid.
const UnderlinePositionIsValid = 1 << 1;
/// Set if fStrikeoutThickness is valid.
const StrikeoutThicknessIsValid = 1 << 2;
/// Set if fStrikeoutPosition is valid.
const StrikeoutPositionIsValid = 1 << 3;
/// Set if fTop, fBottom, fXMin, fXMax invalid.
const BoundsInvalid = 1 << 4;
}
}
impl FontMetrics {
/// Returns `Some(thickness)` if `FontMetrics` has a valid underline thickness.
///
/// If the underline thickness is not valid, return None.
#[must_use]
pub const fn has_underline_thickness(&self) -> Option<Scalar> {
if self
.flags
.contains(FontMetricsFlags::UnderlineThicknessIsValid)
{
Some(self.underline_thickness)
} else {
None
}
}
/// Returns `Some(position)` value if `FontMetrics` has a valid underline position.
///
/// If the underline position is not valid, return None.
#[must_use]
pub const fn has_underline_position(&self) -> Option<Scalar> {
if self
.flags
.contains(FontMetricsFlags::UnderlinePositionIsValid)
{
Some(self.underline_position)
} else {
None
}
}
/// Returns `Some(thickness)` if `FontMetrics` has a valid strikeout thickness.
///
/// If the underline thickness is not valid, return None.
#[must_use]
pub const fn has_strikeout_thickness(&self) -> Option<Scalar> {
if self
.flags
.contains(FontMetricsFlags::StrikeoutThicknessIsValid)
{
Some(self.strikeout_thickness)
} else {
None
}
}
/// Returns `Some(position)` if `FontMetrics` has a valid strikeout position.
///
/// If the underline position is not valid, return None.
#[must_use]
pub const fn has_strikeout_position(&self) -> Option<Scalar> {
if self
.flags
.contains(FontMetricsFlags::StrikeoutPositionIsValid)
{
Some(self.strikeout_position)
} else {
None
}
}
/// Returns true if `FontMetrics` has a valid top, bottom, `x_min`, and `x_max`.
///
/// If the bounds are not valid, return false.
///
/// Returns true if font specifies maximum glyph bounds.
#[must_use]
pub const fn has_bounds(&self) -> bool {
!self.flags.contains(FontMetricsFlags::BoundsInvalid)
}
}