1use std::borrow::Cow;
2
3#[derive(Debug, Clone, Copy, Default, PartialEq)]
5pub struct Vector {
6 pub x: f32,
8 pub y: f32,
10}
11
12#[derive(Debug, Clone, Copy, Default, PartialEq)]
14pub struct BBox {
15 pub llx: f32,
17 pub lly: f32,
19 pub urx: f32,
21 pub ury: f32,
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum Direction {
28 Zero,
30 One,
32}
33
34impl Direction {
35 #[must_use]
37 pub const fn index(self) -> usize {
38 match self {
39 Self::Zero => 0,
40 Self::One => 1,
41 }
42 }
43}
44
45#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
47pub enum MetricsSets {
48 #[default]
50 Zero,
51 One,
53 Both,
55}
56
57#[derive(Debug, Clone, Copy, Default, PartialEq)]
59pub struct DirectionMetrics {
60 pub underline_position: Option<f32>,
62 pub underline_thickness: Option<f32>,
64 pub italic_angle: Option<f32>,
66 pub char_width: Option<Vector>,
68 pub is_fixed_pitch: Option<bool>,
70}
71
72impl DirectionMetrics {
73 #[must_use]
75 pub fn fixed_pitch(&self) -> bool {
76 self.is_fixed_pitch
77 .unwrap_or_else(|| self.char_width.is_some())
78 }
79}
80
81#[derive(Debug, Clone, PartialEq, Eq)]
84pub enum CharacterCode<'a> {
85 Decimal(i32),
87 Hex(Cow<'a, str>),
89}
90
91impl CharacterCode<'_> {
92 #[must_use]
94 pub fn as_u32(&self) -> Option<u32> {
95 match self {
96 Self::Decimal(code) => u32::try_from(*code).ok(),
97 Self::Hex(digits) => u32::from_str_radix(digits, 16).ok(),
98 }
99 }
100
101 #[must_use]
103 pub fn into_owned(self) -> CharacterCode<'static> {
104 match self {
105 Self::Decimal(code) => CharacterCode::Decimal(code),
106 Self::Hex(digits) => CharacterCode::Hex(Cow::Owned(digits.into_owned())),
107 }
108 }
109}
110
111#[derive(Debug, Clone, PartialEq, Eq)]
113pub struct Ligature<'a> {
114 pub successor: Cow<'a, str>,
116 pub ligature: Cow<'a, str>,
118}
119
120impl Ligature<'_> {
121 #[must_use]
123 pub fn into_owned(self) -> Ligature<'static> {
124 Ligature {
125 successor: Cow::Owned(self.successor.into_owned()),
126 ligature: Cow::Owned(self.ligature.into_owned()),
127 }
128 }
129}
130
131#[derive(Debug, Clone, PartialEq)]
133pub struct CharacterMetric<'a> {
134 pub code: CharacterCode<'a>,
136 pub name: Option<Cow<'a, str>>,
138 pub advances: [Option<Vector>; 2],
140 pub bbox: Option<BBox>,
142 pub v_vector: Option<Vector>,
144 pub ligatures: Cow<'a, [Ligature<'a>]>,
146}
147
148impl CharacterMetric<'_> {
149 #[must_use]
151 pub fn into_owned(self) -> CharacterMetric<'static> {
152 CharacterMetric {
153 code: self.code.into_owned(),
154 name: self.name.map(|name| Cow::Owned(name.into_owned())),
155 advances: self.advances,
156 bbox: self.bbox,
157 v_vector: self.v_vector,
158 ligatures: Cow::Owned(
159 self.ligatures
160 .into_owned()
161 .into_iter()
162 .map(Ligature::into_owned)
163 .collect(),
164 ),
165 }
166 }
167}
168
169#[derive(Debug, Clone, PartialEq, Eq)]
171pub enum KerningOperands<'a> {
172 Names {
174 left: Cow<'a, str>,
176 right: Cow<'a, str>,
178 },
179 Hex {
181 left: Cow<'a, str>,
183 right: Cow<'a, str>,
185 },
186}
187
188impl KerningOperands<'_> {
189 #[must_use]
191 pub fn into_owned(self) -> KerningOperands<'static> {
192 match self {
193 Self::Names { left, right } => KerningOperands::Names {
194 left: Cow::Owned(left.into_owned()),
195 right: Cow::Owned(right.into_owned()),
196 },
197 Self::Hex { left, right } => KerningOperands::Hex {
198 left: Cow::Owned(left.into_owned()),
199 right: Cow::Owned(right.into_owned()),
200 },
201 }
202 }
203}
204
205#[derive(Debug, Clone, PartialEq)]
207pub struct KerningPair<'a> {
208 pub operands: KerningOperands<'a>,
210 pub adjustment: Vector,
212 pub direction: Direction,
214}
215
216impl KerningPair<'_> {
217 #[must_use]
219 pub fn into_owned(self) -> KerningPair<'static> {
220 KerningPair {
221 operands: self.operands.into_owned(),
222 adjustment: self.adjustment,
223 direction: self.direction,
224 }
225 }
226}
227
228#[derive(Debug, Clone, Copy, PartialEq)]
230pub struct TrackKern {
231 pub degree: i32,
233 pub min_point_size: f32,
235 pub min_kern: f32,
237 pub max_point_size: f32,
239 pub max_kern: f32,
241}
242
243#[derive(Debug, Clone, PartialEq)]
245pub struct CompositeComponent<'a> {
246 pub name: Cow<'a, str>,
248 pub offset: Vector,
250}
251
252impl CompositeComponent<'_> {
253 #[must_use]
255 pub fn into_owned(self) -> CompositeComponent<'static> {
256 CompositeComponent {
257 name: Cow::Owned(self.name.into_owned()),
258 offset: self.offset,
259 }
260 }
261}
262
263#[derive(Debug, Clone, PartialEq)]
265pub struct Composite<'a> {
266 pub name: Cow<'a, str>,
268 pub components: Cow<'a, [CompositeComponent<'a>]>,
270}
271
272impl Composite<'_> {
273 #[must_use]
275 pub fn into_owned(self) -> Composite<'static> {
276 Composite {
277 name: Cow::Owned(self.name.into_owned()),
278 components: Cow::Owned(
279 self.components
280 .into_owned()
281 .into_iter()
282 .map(CompositeComponent::into_owned)
283 .collect(),
284 ),
285 }
286 }
287}
288
289#[derive(Debug, Clone, Copy, PartialEq, Eq)]
291pub enum RecordContext {
292 Font,
294 Direction(MetricsSets),
296 CharacterMetrics,
298 Character(usize),
300 KernData,
302 KernPairs(Direction),
304 TrackKern,
306 Composites,
308 Composite(usize),
310}
311
312#[derive(Debug, Clone, PartialEq, Eq)]
314pub struct SourceRecord<'a> {
315 pub line: usize,
317 pub context: RecordContext,
319 pub keyword: Cow<'a, str>,
321 pub value: Cow<'a, str>,
323}
324
325impl SourceRecord<'_> {
326 #[must_use]
328 pub fn into_owned(self) -> SourceRecord<'static> {
329 SourceRecord {
330 line: self.line,
331 context: self.context,
332 keyword: Cow::Owned(self.keyword.into_owned()),
333 value: Cow::Owned(self.value.into_owned()),
334 }
335 }
336}
337
338#[derive(Debug, Clone, Default, PartialEq)]
340pub struct FontMetrics<'a> {
341 pub afm_version: Cow<'a, str>,
343 pub font_name: Cow<'a, str>,
345 pub font_bbox: BBox,
347 pub metrics_sets: Option<MetricsSets>,
349 pub full_name: Option<Cow<'a, str>>,
351 pub family_name: Option<Cow<'a, str>>,
353 pub weight: Option<Cow<'a, str>>,
355 pub version: Option<Cow<'a, str>>,
357 pub notice: Option<Cow<'a, str>>,
359 pub encoding_scheme: Option<Cow<'a, str>>,
361 pub character_set: Option<Cow<'a, str>>,
363 pub mapping_scheme: Option<u32>,
365 pub esc_char: Option<u8>,
367 pub characters: Option<u32>,
369 pub is_base_font: Option<bool>,
371 pub is_cid_font: Option<bool>,
373 pub v_vector: Option<Vector>,
375 pub is_fixed_v: Option<bool>,
377 pub cap_height: Option<f32>,
379 pub x_height: Option<f32>,
381 pub ascender: Option<f32>,
383 pub descender: Option<f32>,
385 pub std_hw: Option<f32>,
387 pub std_vw: Option<f32>,
389 pub directions: [DirectionMetrics; 2],
391 pub character_metrics: Cow<'a, [CharacterMetric<'a>]>,
393 pub kerning_pairs: Cow<'a, [KerningPair<'a>]>,
395 pub track_kerns: Cow<'a, [TrackKern]>,
397 pub composites: Cow<'a, [Composite<'a>]>,
399 pub source_records: Cow<'a, [SourceRecord<'a>]>,
401}
402
403pub type OwnedFontMetrics = FontMetrics<'static>;
405
406impl FontMetrics<'_> {
407 #[must_use]
409 pub const fn direction(&self, direction: Direction) -> &DirectionMetrics {
410 &self.directions[direction.index()]
411 }
412
413 #[must_use]
416 pub fn advance(&self, character: &CharacterMetric<'_>, direction: Direction) -> Option<Vector> {
417 character.advances[direction.index()].or_else(|| self.direction(direction).char_width)
418 }
419
420 #[must_use]
422 pub fn vertical_origin(&self, character: &CharacterMetric<'_>) -> Option<Vector> {
423 character.v_vector.or(self.v_vector)
424 }
425
426 #[must_use]
428 pub fn fixed_v(&self) -> bool {
429 self.is_fixed_v.unwrap_or_else(|| self.v_vector.is_some())
430 }
431
432 #[must_use]
434 pub fn into_owned(self) -> OwnedFontMetrics {
435 FontMetrics {
436 afm_version: Cow::Owned(self.afm_version.into_owned()),
437 font_name: Cow::Owned(self.font_name.into_owned()),
438 font_bbox: self.font_bbox,
439 metrics_sets: self.metrics_sets,
440 full_name: self.full_name.map(|value| Cow::Owned(value.into_owned())),
441 family_name: self.family_name.map(|value| Cow::Owned(value.into_owned())),
442 weight: self.weight.map(|value| Cow::Owned(value.into_owned())),
443 version: self.version.map(|value| Cow::Owned(value.into_owned())),
444 notice: self.notice.map(|value| Cow::Owned(value.into_owned())),
445 encoding_scheme: self
446 .encoding_scheme
447 .map(|value| Cow::Owned(value.into_owned())),
448 character_set: self
449 .character_set
450 .map(|value| Cow::Owned(value.into_owned())),
451 mapping_scheme: self.mapping_scheme,
452 esc_char: self.esc_char,
453 characters: self.characters,
454 is_base_font: self.is_base_font,
455 is_cid_font: self.is_cid_font,
456 v_vector: self.v_vector,
457 is_fixed_v: self.is_fixed_v,
458 cap_height: self.cap_height,
459 x_height: self.x_height,
460 ascender: self.ascender,
461 descender: self.descender,
462 std_hw: self.std_hw,
463 std_vw: self.std_vw,
464 directions: self.directions,
465 character_metrics: Cow::Owned(
466 self.character_metrics
467 .into_owned()
468 .into_iter()
469 .map(CharacterMetric::into_owned)
470 .collect(),
471 ),
472 kerning_pairs: Cow::Owned(
473 self.kerning_pairs
474 .into_owned()
475 .into_iter()
476 .map(KerningPair::into_owned)
477 .collect(),
478 ),
479 track_kerns: Cow::Owned(self.track_kerns.into_owned()),
480 composites: Cow::Owned(
481 self.composites
482 .into_owned()
483 .into_iter()
484 .map(Composite::into_owned)
485 .collect(),
486 ),
487 source_records: Cow::Owned(
488 self.source_records
489 .into_owned()
490 .into_iter()
491 .map(SourceRecord::into_owned)
492 .collect(),
493 ),
494 }
495 }
496}