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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/// Structures for handling components within a composite glyph
use bitflags::bitflags;
use kurbo::Affine;
use otspec::types::*;
use otspec::{DeserializationError, Deserialize, Deserializer, ReaderContext};
use otspec_macros::{Deserialize, Serialize};
bitflags! {
/// Flags used when serializing/deserializing the component.
///
/// These are computed automatically, so you don't need to worry about them.
#[derive(Serialize, Deserialize)]
pub struct ComponentFlags: u16 {
/// If this is set, the arguments are 16-bit (uint16 or int16); otherwise, they are bytes (uint8 or int8).
const ARG_1_AND_2_ARE_WORDS = 0x0001;
/// If this is set, the arguments are signed xy values; otherwise, they are unsigned point numbers.
const ARGS_ARE_XY_VALUES = 0x0002;
/// For the xy values if the preceding is true.
///
/// (Whatever that means.)
const ROUND_XY_TO_GRID = 0x0004;
/// The transform matrix is a simple linear scale.
const WE_HAVE_A_SCALE = 0x0008;
/// Indicates at least one more component after this one.
const MORE_COMPONENTS = 0x0020;
/// The transform matrix is a scaling transform with independent X and Y scales.
const WE_HAVE_AN_X_AND_Y_SCALE = 0x0040;
/// The transform matrix is a full two-by-two matrix with scaleXY and scaleYX values.
const WE_HAVE_A_TWO_BY_TWO = 0x0080;
/// TrueType instructions follow this component.
const WE_HAVE_INSTRUCTIONS = 0x0100;
/// The metrics of the composite glyph should be the same as the metrics of this component.
const USE_MY_METRICS = 0x0200;
/// The contours of the components overlap.
///
/// Generally unused, but if used, should be set on the first component of a glyph.
const OVERLAP_COMPOUND = 0x0400;
/// The component's offset should be scaled.
const SCALED_COMPONENT_OFFSET = 0x0800;
/// The component's offset should not be scaled.
const UNSCALED_COMPONENT_OFFSET = 0x1000;
}
}
/*
#[derive(Debug, PartialEq)]
enum ComponentScalingMode {
ScaledOffset,
UnscaledOffset,
Default,
}
*/
/// A high-level representation of a component within a glyph
#[derive(Debug, PartialEq, Clone)]
pub struct Component {
/// The glyph ID that this component references.
pub glyph_index: uint16,
/// An affine transformation applied to the component's contours.
pub transformation: Affine,
/// Alternate, and rarely used, method of positioning components using contour point numbers.
pub match_points: Option<(uint16, uint16)>,
/// Flags.
/// Most of these are calculated automatically on serialization. Those which can be
/// meaningfully manually set are `ROUND_XY_TO_GRID`, `USE_MY_METRICS`,
/// `SCALED_COMPONENT_OFFSET`, `UNSCALED_COMPONENT_OFFSET` and `OVERLAP_COMPOUND`.
pub flags: ComponentFlags,
}
impl Component {
/// Recompute the flags prior to serialization. `more` should be true if this
/// is not the final component in a glyph; `instructions` should be true if
/// there are TrueType instructions in the glyph. This is called automatically
/// on serialization; you don't have to do it yourself.
pub fn recompute_flags(&self, more: bool, instructions: bool) -> ComponentFlags {
let mut flags = self.flags
& (ComponentFlags::ROUND_XY_TO_GRID
| ComponentFlags::USE_MY_METRICS
| ComponentFlags::SCALED_COMPONENT_OFFSET
| ComponentFlags::UNSCALED_COMPONENT_OFFSET
| ComponentFlags::OVERLAP_COMPOUND);
if more {
flags |= ComponentFlags::MORE_COMPONENTS;
} else if instructions {
flags |= ComponentFlags::WE_HAVE_INSTRUCTIONS;
}
let [x_scale, scale01, scale10, scale_y, translate_x, translate_y] =
self.transformation.as_coeffs();
if self.match_points.is_some() {
let (x, y) = self.match_points.unwrap();
if !(x <= 255 && y <= 255) {
flags |= ComponentFlags::ARG_1_AND_2_ARE_WORDS;
}
} else {
flags |= ComponentFlags::ARGS_ARE_XY_VALUES;
let (x, y) = (translate_x, translate_y);
if !((-128.0..=127.0).contains(&x) && (-128.0..=127.0).contains(&y)) {
flags |= ComponentFlags::ARG_1_AND_2_ARE_WORDS;
}
}
if scale01 != 0.0 || scale10 != 0.0 {
flags |= ComponentFlags::WE_HAVE_A_TWO_BY_TWO;
} else if (x_scale - scale_y).abs() > f64::EPSILON {
flags |= ComponentFlags::WE_HAVE_AN_X_AND_Y_SCALE;
} else if (x_scale - 1.0).abs() > f64::EPSILON {
flags |= ComponentFlags::WE_HAVE_A_SCALE;
}
flags
}
}
fn read_f64_from_f2dot14(c: &mut ReaderContext) -> Result<f64, DeserializationError> {
let x: F2DOT14 = c.de()?;
let x_f32: f32 = x.into();
Ok(x_f32 as f64)
}
impl Deserialize for Component {
fn from_bytes(c: &mut ReaderContext) -> Result<Self, DeserializationError> {
let flags: ComponentFlags = c.de()?;
let glyph_index: uint16 = c.de()?;
let mut match_points: Option<(uint16, uint16)> = None;
let mut x_offset: i16 = 0;
let mut y_offset: i16 = 0;
if !flags.contains(ComponentFlags::ARGS_ARE_XY_VALUES) {
// unsigned point values
if flags.contains(ComponentFlags::ARG_1_AND_2_ARE_WORDS) {
let p1: u16 = c.de()?;
let p2: u16 = c.de()?;
match_points = Some((p1, p2));
} else {
let p1: u8 = c.de()?;
let p2: u8 = c.de()?;
match_points = Some((p1.into(), p2.into()));
}
if flags.contains(
ComponentFlags::WE_HAVE_A_SCALE
| ComponentFlags::WE_HAVE_AN_X_AND_Y_SCALE
| ComponentFlags::WE_HAVE_A_TWO_BY_TWO,
) {
return Err(DeserializationError(
"Simon is a lazy programmer".to_string(),
));
}
} else {
// signed xy values
if flags.contains(ComponentFlags::ARG_1_AND_2_ARE_WORDS) {
x_offset = c.de()?;
y_offset = c.de()?;
} else {
let x_off_u8: u8 = c.de()?;
let y_off_u8: u8 = c.de()?;
x_offset = x_off_u8.into();
y_offset = y_off_u8.into();
}
}
let mut x_scale = 1.0_f64;
let mut scale01 = 0.0_f64;
let mut scale10 = 0.0_f64;
let mut y_scale = 1.0_f64;
if flags.contains(ComponentFlags::WE_HAVE_A_SCALE) {
x_scale = read_f64_from_f2dot14(c)?;
y_scale = x_scale;
} else if flags.contains(ComponentFlags::WE_HAVE_AN_X_AND_Y_SCALE) {
x_scale = read_f64_from_f2dot14(c)?;
y_scale = read_f64_from_f2dot14(c)?;
} else if flags.contains(ComponentFlags::WE_HAVE_A_TWO_BY_TWO) {
x_scale = read_f64_from_f2dot14(c)?;
scale01 = read_f64_from_f2dot14(c)?;
scale10 = read_f64_from_f2dot14(c)?;
y_scale = read_f64_from_f2dot14(c)?;
}
let transformation = Affine::new([
x_scale,
scale01,
scale10,
y_scale,
x_offset.into(),
y_offset.into(),
]);
Ok(Component {
glyph_index,
transformation,
match_points,
flags,
})
}
}