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
//! The [VVAR (Vertical Metrics Variation)](https://docs.microsoft.com/en-us/typography/opentype/spec/vvar) table
use super::variations::{self, DeltaSetIndexMap, ItemVariationStore};
use types::F48Dot16;
include!("../../generated/generated_vvar.rs");
impl Vvar<'_> {
/// Returns the change a location makes to the advance height of a glyph.
///
/// The value carries every bit the item variation store computed. It is
/// a caller that decides how to round it into a whole design unit, and
/// implementations differ on that.
///
/// Returns `None` where the table says nothing readable about the glyph.
pub fn advance_delta(&self, glyph_id: GlyphId, coords: &[F2Dot14]) -> Option<F48Dot16> {
variations::advance_delta(
self.advance_height_mapping(),
self.item_variation_store(),
glyph_id,
coords,
)
}
/// Returns the change a location makes to the top side bearing of a
/// glyph.
///
/// The value carries every bit the item variation store computed. It is
/// a caller that decides how to round it into a whole design unit, and
/// implementations differ on that.
///
/// Returns `None` where the table says nothing readable about the glyph.
pub fn tsb_delta(&self, glyph_id: GlyphId, coords: &[F2Dot14]) -> Option<F48Dot16> {
variations::item_delta(
self.tsb_mapping(),
self.item_variation_store(),
glyph_id,
coords,
)
}
/// Returns the change a location makes to the bottom side bearing of a
/// glyph.
///
/// The value carries every bit the item variation store computed. It is
/// a caller that decides how to round it into a whole design unit, and
/// implementations differ on that.
///
/// Returns `None` where the table says nothing readable about the glyph.
pub fn bsb_delta(&self, glyph_id: GlyphId, coords: &[F2Dot14]) -> Option<F48Dot16> {
variations::item_delta(
self.bsb_mapping(),
self.item_variation_store(),
glyph_id,
coords,
)
}
/// Returns the change a location makes to the y coordinate of a glyph's
/// vertical origin.
///
/// The x coordinate is not stated by any table: it is half the advance
/// width, and does not vary here.
///
/// The value carries every bit the item variation store computed. It is
/// a caller that decides how to round it into a whole design unit, and
/// implementations differ on that.
///
/// Returns `None` where the table says nothing readable about the glyph.
pub fn v_origin_y_delta(&self, glyph_id: GlyphId, coords: &[F2Dot14]) -> Option<F48Dot16> {
variations::item_delta(
self.v_org_mapping(),
self.item_variation_store(),
glyph_id,
coords,
)
}
}
#[cfg(test)]
mod tests {
use crate::{FontRef, TableProvider};
use types::{F2Dot14, F48Dot16, GlyphId};
/// The only fixture stating `VVAR`. Every one of its mappings resolves to
/// zero at every location, so this covers the shape of the accessors
/// rather than their arithmetic; `HVAR` carries that, over the same code
/// in `variations`.
const VAR: &[u8] = font_test_data::ift::CFF2_FONT;
#[test]
fn a_default_location_moves_nothing() {
let font = FontRef::new(VAR).unwrap();
let vvar = font.vvar().unwrap();
let gid = GlyphId::new(1);
assert_eq!(vvar.advance_delta(gid, &[]), Some(F48Dot16::ZERO));
}
#[test]
fn every_glyph_answers_at_a_location() {
let font = FontRef::new(VAR).unwrap();
let vvar = font.vvar().unwrap();
let num_glyphs = font.maxp().unwrap().num_glyphs() as u32;
for coord in [-1.0, -0.4, 0.25, 1.0] {
let coords = [F2Dot14::from_f32(coord)];
for gid in (0..num_glyphs).map(GlyphId::new) {
assert!(
vvar.advance_delta(gid, &coords).is_some(),
"glyph {gid} at {coord}"
);
}
}
}
#[test]
fn a_mapping_the_font_does_not_state_is_absent() {
// This font maps advance heights and vertical origins, but neither
// side bearing.
let font = FontRef::new(VAR).unwrap();
let vvar = font.vvar().unwrap();
let gid = GlyphId::new(1);
let coords = [F2Dot14::from_f32(-1.0)];
assert!(vvar.advance_delta(gid, &coords).is_some());
assert!(vvar.v_origin_y_delta(gid, &coords).is_some());
assert_eq!(vvar.tsb_delta(gid, &coords), None);
assert_eq!(vvar.bsb_delta(gid, &coords), None);
}
}