Coverage Report

Created: 2025-11-16 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fontations/write-fonts/generated/generated_gpos.rs
Line
Count
Source
1
// THIS FILE IS AUTOGENERATED.
2
// Any changes to this file will be overwritten.
3
// For more information about how codegen works, see font-codegen/README.md
4
5
#[allow(unused_imports)]
6
use crate::codegen_prelude::*;
7
8
pub use read_fonts::tables::gpos::ValueFormat;
9
10
/// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1)
11
/// [GPOS Version 1.0](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#gpos-header)
12
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
13
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14
pub struct Gpos {
15
    /// Offset to ScriptList table, from beginning of GPOS table
16
    pub script_list: OffsetMarker<ScriptList>,
17
    /// Offset to FeatureList table, from beginning of GPOS table
18
    pub feature_list: OffsetMarker<FeatureList>,
19
    /// Offset to LookupList table, from beginning of GPOS table
20
    pub lookup_list: OffsetMarker<PositionLookupList>,
21
    pub feature_variations: NullableOffsetMarker<FeatureVariations, WIDTH_32>,
22
}
23
24
impl Gpos {
25
    /// Construct a new `Gpos`
26
0
    pub fn new(
27
0
        script_list: ScriptList,
28
0
        feature_list: FeatureList,
29
0
        lookup_list: PositionLookupList,
30
0
    ) -> Self {
31
0
        Self {
32
0
            script_list: script_list.into(),
33
0
            feature_list: feature_list.into(),
34
0
            lookup_list: lookup_list.into(),
35
0
            ..Default::default()
36
0
        }
37
0
    }
38
}
39
40
impl FontWrite for Gpos {
41
    #[allow(clippy::unnecessary_cast)]
42
0
    fn write_into(&self, writer: &mut TableWriter) {
43
0
        let version = self.compute_version() as MajorMinor;
44
0
        version.write_into(writer);
45
0
        self.script_list.write_into(writer);
46
0
        self.feature_list.write_into(writer);
47
0
        self.lookup_list.write_into(writer);
48
0
        version
49
0
            .compatible((1u16, 1u16))
50
0
            .then(|| self.feature_variations.write_into(writer));
51
0
    }
52
0
    fn table_type(&self) -> TableType {
53
0
        TableType::TopLevel(Gpos::TAG)
54
0
    }
55
}
56
57
impl Validate for Gpos {
58
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
59
0
        ctx.in_table("Gpos", |ctx| {
60
0
            ctx.in_field("script_list", |ctx| {
61
0
                self.script_list.validate_impl(ctx);
62
0
            });
63
0
            ctx.in_field("feature_list", |ctx| {
64
0
                self.feature_list.validate_impl(ctx);
65
0
            });
66
0
            ctx.in_field("lookup_list", |ctx| {
67
0
                self.lookup_list.validate_impl(ctx);
68
0
            });
69
0
            ctx.in_field("feature_variations", |ctx| {
70
0
                self.feature_variations.validate_impl(ctx);
71
0
            });
72
0
        })
73
0
    }
74
}
75
76
impl TopLevelTable for Gpos {
77
    const TAG: Tag = Tag::new(b"GPOS");
78
}
79
80
impl<'a> FromObjRef<read_fonts::tables::gpos::Gpos<'a>> for Gpos {
81
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::Gpos<'a>, _: FontData) -> Self {
82
0
        Gpos {
83
0
            script_list: obj.script_list().to_owned_table(),
84
0
            feature_list: obj.feature_list().to_owned_table(),
85
0
            lookup_list: obj.lookup_list().to_owned_table(),
86
0
            feature_variations: obj.feature_variations().to_owned_table(),
87
0
        }
88
0
    }
89
}
90
91
#[allow(clippy::needless_lifetimes)]
92
impl<'a> FromTableRef<read_fonts::tables::gpos::Gpos<'a>> for Gpos {}
93
94
impl<'a> FontRead<'a> for Gpos {
95
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
96
0
        <read_fonts::tables::gpos::Gpos as FontRead>::read(data).map(|x| x.to_owned_table())
97
0
    }
98
}
99
100
/// A [GPOS Lookup](https://learn.microsoft.com/en-us/typography/opentype/spec/gpos#gsubLookupTypeEnum) subtable.
101
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
102
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
103
pub enum PositionLookup {
104
    Single(Lookup<SinglePos>),
105
    Pair(Lookup<PairPos>),
106
    Cursive(Lookup<CursivePosFormat1>),
107
    MarkToBase(Lookup<MarkBasePosFormat1>),
108
    MarkToLig(Lookup<MarkLigPosFormat1>),
109
    MarkToMark(Lookup<MarkMarkPosFormat1>),
110
    Contextual(Lookup<PositionSequenceContext>),
111
    ChainContextual(Lookup<PositionChainContext>),
112
    Extension(Lookup<ExtensionSubtable>),
113
}
114
115
impl Default for PositionLookup {
116
0
    fn default() -> Self {
117
0
        Self::Single(Default::default())
118
0
    }
119
}
120
121
impl FontWrite for PositionLookup {
122
0
    fn write_into(&self, writer: &mut TableWriter) {
123
0
        match self {
124
0
            Self::Single(table) => table.write_into(writer),
125
0
            Self::Pair(table) => table.write_into(writer),
126
0
            Self::Cursive(table) => table.write_into(writer),
127
0
            Self::MarkToBase(table) => table.write_into(writer),
128
0
            Self::MarkToLig(table) => table.write_into(writer),
129
0
            Self::MarkToMark(table) => table.write_into(writer),
130
0
            Self::Contextual(table) => table.write_into(writer),
131
0
            Self::ChainContextual(table) => table.write_into(writer),
132
0
            Self::Extension(table) => table.write_into(writer),
133
        }
134
0
    }
135
0
    fn table_type(&self) -> TableType {
136
0
        match self {
137
0
            Self::Single(table) => table.table_type(),
138
0
            Self::Pair(table) => table.table_type(),
139
0
            Self::Cursive(table) => table.table_type(),
140
0
            Self::MarkToBase(table) => table.table_type(),
141
0
            Self::MarkToLig(table) => table.table_type(),
142
0
            Self::MarkToMark(table) => table.table_type(),
143
0
            Self::Contextual(table) => table.table_type(),
144
0
            Self::ChainContextual(table) => table.table_type(),
145
0
            Self::Extension(table) => table.table_type(),
146
        }
147
0
    }
148
}
149
150
impl Validate for PositionLookup {
151
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
152
0
        match self {
153
0
            Self::Single(table) => table.validate_impl(ctx),
154
0
            Self::Pair(table) => table.validate_impl(ctx),
155
0
            Self::Cursive(table) => table.validate_impl(ctx),
156
0
            Self::MarkToBase(table) => table.validate_impl(ctx),
157
0
            Self::MarkToLig(table) => table.validate_impl(ctx),
158
0
            Self::MarkToMark(table) => table.validate_impl(ctx),
159
0
            Self::Contextual(table) => table.validate_impl(ctx),
160
0
            Self::ChainContextual(table) => table.validate_impl(ctx),
161
0
            Self::Extension(table) => table.validate_impl(ctx),
162
        }
163
0
    }
164
}
165
166
impl FromObjRef<read_fonts::tables::gpos::PositionLookup<'_>> for PositionLookup {
167
0
    fn from_obj_ref(from: &read_fonts::tables::gpos::PositionLookup<'_>, data: FontData) -> Self {
168
0
        match from {
169
0
            read_fonts::tables::gpos::PositionLookup::Single(table) => {
170
0
                Self::Single(table.to_owned_obj(data))
171
            }
172
0
            read_fonts::tables::gpos::PositionLookup::Pair(table) => {
173
0
                Self::Pair(table.to_owned_obj(data))
174
            }
175
0
            read_fonts::tables::gpos::PositionLookup::Cursive(table) => {
176
0
                Self::Cursive(table.to_owned_obj(data))
177
            }
178
0
            read_fonts::tables::gpos::PositionLookup::MarkToBase(table) => {
179
0
                Self::MarkToBase(table.to_owned_obj(data))
180
            }
181
0
            read_fonts::tables::gpos::PositionLookup::MarkToLig(table) => {
182
0
                Self::MarkToLig(table.to_owned_obj(data))
183
            }
184
0
            read_fonts::tables::gpos::PositionLookup::MarkToMark(table) => {
185
0
                Self::MarkToMark(table.to_owned_obj(data))
186
            }
187
0
            read_fonts::tables::gpos::PositionLookup::Contextual(table) => {
188
0
                Self::Contextual(table.to_owned_obj(data))
189
            }
190
0
            read_fonts::tables::gpos::PositionLookup::ChainContextual(table) => {
191
0
                Self::ChainContextual(table.to_owned_obj(data))
192
            }
193
0
            read_fonts::tables::gpos::PositionLookup::Extension(table) => {
194
0
                Self::Extension(table.to_owned_obj(data))
195
            }
196
        }
197
0
    }
198
}
199
200
impl FromTableRef<read_fonts::tables::gpos::PositionLookup<'_>> for PositionLookup {}
201
202
impl From<Lookup<SinglePos>> for PositionLookup {
203
0
    fn from(src: Lookup<SinglePos>) -> PositionLookup {
204
0
        PositionLookup::Single(src)
205
0
    }
206
}
207
208
impl From<Lookup<PairPos>> for PositionLookup {
209
0
    fn from(src: Lookup<PairPos>) -> PositionLookup {
210
0
        PositionLookup::Pair(src)
211
0
    }
212
}
213
214
impl From<Lookup<CursivePosFormat1>> for PositionLookup {
215
0
    fn from(src: Lookup<CursivePosFormat1>) -> PositionLookup {
216
0
        PositionLookup::Cursive(src)
217
0
    }
218
}
219
220
impl From<Lookup<MarkBasePosFormat1>> for PositionLookup {
221
0
    fn from(src: Lookup<MarkBasePosFormat1>) -> PositionLookup {
222
0
        PositionLookup::MarkToBase(src)
223
0
    }
224
}
225
226
impl From<Lookup<MarkLigPosFormat1>> for PositionLookup {
227
0
    fn from(src: Lookup<MarkLigPosFormat1>) -> PositionLookup {
228
0
        PositionLookup::MarkToLig(src)
229
0
    }
230
}
231
232
impl From<Lookup<MarkMarkPosFormat1>> for PositionLookup {
233
0
    fn from(src: Lookup<MarkMarkPosFormat1>) -> PositionLookup {
234
0
        PositionLookup::MarkToMark(src)
235
0
    }
236
}
237
238
impl From<Lookup<PositionSequenceContext>> for PositionLookup {
239
0
    fn from(src: Lookup<PositionSequenceContext>) -> PositionLookup {
240
0
        PositionLookup::Contextual(src)
241
0
    }
242
}
243
244
impl From<Lookup<PositionChainContext>> for PositionLookup {
245
0
    fn from(src: Lookup<PositionChainContext>) -> PositionLookup {
246
0
        PositionLookup::ChainContextual(src)
247
0
    }
248
}
249
250
impl From<Lookup<ExtensionSubtable>> for PositionLookup {
251
0
    fn from(src: Lookup<ExtensionSubtable>) -> PositionLookup {
252
0
        PositionLookup::Extension(src)
253
0
    }
254
}
255
256
impl FontWrite for ValueFormat {
257
0
    fn write_into(&self, writer: &mut TableWriter) {
258
0
        writer.write_slice(&self.bits().to_be_bytes())
259
0
    }
260
}
261
262
/// [Anchor Tables](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#anchor-tables)
263
/// position one glyph with respect to another.
264
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
265
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
266
pub enum AnchorTable {
267
    Format1(AnchorFormat1),
268
    Format2(AnchorFormat2),
269
    Format3(AnchorFormat3),
270
}
271
272
impl AnchorTable {
273
    /// Construct a new `AnchorFormat1` subtable
274
0
    pub fn format_1(x_coordinate: i16, y_coordinate: i16) -> Self {
275
0
        Self::Format1(AnchorFormat1::new(x_coordinate, y_coordinate))
276
0
    }
277
278
    /// Construct a new `AnchorFormat2` subtable
279
0
    pub fn format_2(x_coordinate: i16, y_coordinate: i16, anchor_point: u16) -> Self {
280
0
        Self::Format2(AnchorFormat2::new(x_coordinate, y_coordinate, anchor_point))
281
0
    }
282
283
    /// Construct a new `AnchorFormat3` subtable
284
0
    pub fn format_3(
285
0
        x_coordinate: i16,
286
0
        y_coordinate: i16,
287
0
        x_device: Option<DeviceOrVariationIndex>,
288
0
        y_device: Option<DeviceOrVariationIndex>,
289
0
    ) -> Self {
290
0
        Self::Format3(AnchorFormat3::new(
291
0
            x_coordinate,
292
0
            y_coordinate,
293
0
            x_device,
294
0
            y_device,
295
0
        ))
296
0
    }
297
}
298
299
impl Default for AnchorTable {
300
0
    fn default() -> Self {
301
0
        Self::Format1(Default::default())
302
0
    }
303
}
304
305
impl FontWrite for AnchorTable {
306
0
    fn write_into(&self, writer: &mut TableWriter) {
307
0
        match self {
308
0
            Self::Format1(item) => item.write_into(writer),
309
0
            Self::Format2(item) => item.write_into(writer),
310
0
            Self::Format3(item) => item.write_into(writer),
311
        }
312
0
    }
313
0
    fn table_type(&self) -> TableType {
314
0
        match self {
315
0
            Self::Format1(item) => item.table_type(),
316
0
            Self::Format2(item) => item.table_type(),
317
0
            Self::Format3(item) => item.table_type(),
318
        }
319
0
    }
320
}
321
322
impl Validate for AnchorTable {
323
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
324
0
        match self {
325
0
            Self::Format1(item) => item.validate_impl(ctx),
326
0
            Self::Format2(item) => item.validate_impl(ctx),
327
0
            Self::Format3(item) => item.validate_impl(ctx),
328
        }
329
0
    }
330
}
331
332
impl FromObjRef<read_fonts::tables::gpos::AnchorTable<'_>> for AnchorTable {
333
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::AnchorTable, _: FontData) -> Self {
334
        use read_fonts::tables::gpos::AnchorTable as ObjRefType;
335
0
        match obj {
336
0
            ObjRefType::Format1(item) => AnchorTable::Format1(item.to_owned_table()),
337
0
            ObjRefType::Format2(item) => AnchorTable::Format2(item.to_owned_table()),
338
0
            ObjRefType::Format3(item) => AnchorTable::Format3(item.to_owned_table()),
339
        }
340
0
    }
341
}
342
343
impl FromTableRef<read_fonts::tables::gpos::AnchorTable<'_>> for AnchorTable {}
344
345
impl<'a> FontRead<'a> for AnchorTable {
346
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
347
0
        <read_fonts::tables::gpos::AnchorTable as FontRead>::read(data).map(|x| x.to_owned_table())
348
0
    }
349
}
350
351
impl From<AnchorFormat1> for AnchorTable {
352
0
    fn from(src: AnchorFormat1) -> AnchorTable {
353
0
        AnchorTable::Format1(src)
354
0
    }
355
}
356
357
impl From<AnchorFormat2> for AnchorTable {
358
0
    fn from(src: AnchorFormat2) -> AnchorTable {
359
0
        AnchorTable::Format2(src)
360
0
    }
361
}
362
363
impl From<AnchorFormat3> for AnchorTable {
364
0
    fn from(src: AnchorFormat3) -> AnchorTable {
365
0
        AnchorTable::Format3(src)
366
0
    }
367
}
368
369
/// [Anchor Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#anchor-table-format-1-design-units): Design Units
370
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
371
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
372
pub struct AnchorFormat1 {
373
    /// Horizontal value, in design units
374
    pub x_coordinate: i16,
375
    /// Vertical value, in design units
376
    pub y_coordinate: i16,
377
}
378
379
impl AnchorFormat1 {
380
    /// Construct a new `AnchorFormat1`
381
0
    pub fn new(x_coordinate: i16, y_coordinate: i16) -> Self {
382
0
        Self {
383
0
            x_coordinate,
384
0
            y_coordinate,
385
0
        }
386
0
    }
387
}
388
389
impl FontWrite for AnchorFormat1 {
390
    #[allow(clippy::unnecessary_cast)]
391
0
    fn write_into(&self, writer: &mut TableWriter) {
392
0
        (1 as u16).write_into(writer);
393
0
        self.x_coordinate.write_into(writer);
394
0
        self.y_coordinate.write_into(writer);
395
0
    }
396
0
    fn table_type(&self) -> TableType {
397
0
        TableType::Named("AnchorFormat1")
398
0
    }
399
}
400
401
impl Validate for AnchorFormat1 {
402
0
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
403
}
404
405
impl<'a> FromObjRef<read_fonts::tables::gpos::AnchorFormat1<'a>> for AnchorFormat1 {
406
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::AnchorFormat1<'a>, _: FontData) -> Self {
407
0
        AnchorFormat1 {
408
0
            x_coordinate: obj.x_coordinate(),
409
0
            y_coordinate: obj.y_coordinate(),
410
0
        }
411
0
    }
412
}
413
414
#[allow(clippy::needless_lifetimes)]
415
impl<'a> FromTableRef<read_fonts::tables::gpos::AnchorFormat1<'a>> for AnchorFormat1 {}
416
417
impl<'a> FontRead<'a> for AnchorFormat1 {
418
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
419
0
        <read_fonts::tables::gpos::AnchorFormat1 as FontRead>::read(data)
420
0
            .map(|x| x.to_owned_table())
421
0
    }
422
}
423
424
/// [Anchor Table Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#anchor-table-format-2-design-units-plus-contour-point): Design Units Plus Contour Point
425
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
426
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
427
pub struct AnchorFormat2 {
428
    /// Horizontal value, in design units
429
    pub x_coordinate: i16,
430
    /// Vertical value, in design units
431
    pub y_coordinate: i16,
432
    /// Index to glyph contour point
433
    pub anchor_point: u16,
434
}
435
436
impl AnchorFormat2 {
437
    /// Construct a new `AnchorFormat2`
438
0
    pub fn new(x_coordinate: i16, y_coordinate: i16, anchor_point: u16) -> Self {
439
0
        Self {
440
0
            x_coordinate,
441
0
            y_coordinate,
442
0
            anchor_point,
443
0
        }
444
0
    }
445
}
446
447
impl FontWrite for AnchorFormat2 {
448
    #[allow(clippy::unnecessary_cast)]
449
0
    fn write_into(&self, writer: &mut TableWriter) {
450
0
        (2 as u16).write_into(writer);
451
0
        self.x_coordinate.write_into(writer);
452
0
        self.y_coordinate.write_into(writer);
453
0
        self.anchor_point.write_into(writer);
454
0
    }
455
0
    fn table_type(&self) -> TableType {
456
0
        TableType::Named("AnchorFormat2")
457
0
    }
458
}
459
460
impl Validate for AnchorFormat2 {
461
0
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
462
}
463
464
impl<'a> FromObjRef<read_fonts::tables::gpos::AnchorFormat2<'a>> for AnchorFormat2 {
465
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::AnchorFormat2<'a>, _: FontData) -> Self {
466
0
        AnchorFormat2 {
467
0
            x_coordinate: obj.x_coordinate(),
468
0
            y_coordinate: obj.y_coordinate(),
469
0
            anchor_point: obj.anchor_point(),
470
0
        }
471
0
    }
472
}
473
474
#[allow(clippy::needless_lifetimes)]
475
impl<'a> FromTableRef<read_fonts::tables::gpos::AnchorFormat2<'a>> for AnchorFormat2 {}
476
477
impl<'a> FontRead<'a> for AnchorFormat2 {
478
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
479
0
        <read_fonts::tables::gpos::AnchorFormat2 as FontRead>::read(data)
480
0
            .map(|x| x.to_owned_table())
481
0
    }
482
}
483
484
/// [Anchor Table Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#anchor-table-format-3-design-units-plus-device-or-variationindex-tables): Design Units Plus Device or VariationIndex Tables
485
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
486
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
487
pub struct AnchorFormat3 {
488
    /// Horizontal value, in design units
489
    pub x_coordinate: i16,
490
    /// Vertical value, in design units
491
    pub y_coordinate: i16,
492
    /// Offset to Device table (non-variable font) / VariationIndex
493
    /// table (variable font) for X coordinate, from beginning of
494
    /// Anchor table (may be NULL)
495
    pub x_device: NullableOffsetMarker<DeviceOrVariationIndex>,
496
    /// Offset to Device table (non-variable font) / VariationIndex
497
    /// table (variable font) for Y coordinate, from beginning of
498
    /// Anchor table (may be NULL)
499
    pub y_device: NullableOffsetMarker<DeviceOrVariationIndex>,
500
}
501
502
impl AnchorFormat3 {
503
    /// Construct a new `AnchorFormat3`
504
0
    pub fn new(
505
0
        x_coordinate: i16,
506
0
        y_coordinate: i16,
507
0
        x_device: Option<DeviceOrVariationIndex>,
508
0
        y_device: Option<DeviceOrVariationIndex>,
509
0
    ) -> Self {
510
0
        Self {
511
0
            x_coordinate,
512
0
            y_coordinate,
513
0
            x_device: x_device.into(),
514
0
            y_device: y_device.into(),
515
0
        }
516
0
    }
517
}
518
519
impl FontWrite for AnchorFormat3 {
520
    #[allow(clippy::unnecessary_cast)]
521
0
    fn write_into(&self, writer: &mut TableWriter) {
522
0
        (3 as u16).write_into(writer);
523
0
        self.x_coordinate.write_into(writer);
524
0
        self.y_coordinate.write_into(writer);
525
0
        self.x_device.write_into(writer);
526
0
        self.y_device.write_into(writer);
527
0
    }
528
0
    fn table_type(&self) -> TableType {
529
0
        TableType::Named("AnchorFormat3")
530
0
    }
531
}
532
533
impl Validate for AnchorFormat3 {
534
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
535
0
        ctx.in_table("AnchorFormat3", |ctx| {
536
0
            ctx.in_field("x_device", |ctx| {
537
0
                self.x_device.validate_impl(ctx);
538
0
            });
539
0
            ctx.in_field("y_device", |ctx| {
540
0
                self.y_device.validate_impl(ctx);
541
0
            });
542
0
        })
543
0
    }
544
}
545
546
impl<'a> FromObjRef<read_fonts::tables::gpos::AnchorFormat3<'a>> for AnchorFormat3 {
547
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::AnchorFormat3<'a>, _: FontData) -> Self {
548
0
        AnchorFormat3 {
549
0
            x_coordinate: obj.x_coordinate(),
550
0
            y_coordinate: obj.y_coordinate(),
551
0
            x_device: obj.x_device().to_owned_table(),
552
0
            y_device: obj.y_device().to_owned_table(),
553
0
        }
554
0
    }
555
}
556
557
#[allow(clippy::needless_lifetimes)]
558
impl<'a> FromTableRef<read_fonts::tables::gpos::AnchorFormat3<'a>> for AnchorFormat3 {}
559
560
impl<'a> FontRead<'a> for AnchorFormat3 {
561
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
562
0
        <read_fonts::tables::gpos::AnchorFormat3 as FontRead>::read(data)
563
0
            .map(|x| x.to_owned_table())
564
0
    }
565
}
566
567
/// [Mark Array Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#mark-array-table)
568
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
569
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
570
pub struct MarkArray {
571
    /// Array of MarkRecords, ordered by corresponding glyphs in the
572
    /// associated mark Coverage table.
573
    pub mark_records: Vec<MarkRecord>,
574
}
575
576
impl MarkArray {
577
    /// Construct a new `MarkArray`
578
0
    pub fn new(mark_records: Vec<MarkRecord>) -> Self {
579
0
        Self { mark_records }
580
0
    }
581
}
582
583
impl FontWrite for MarkArray {
584
    #[allow(clippy::unnecessary_cast)]
585
0
    fn write_into(&self, writer: &mut TableWriter) {
586
0
        (u16::try_from(array_len(&self.mark_records)).unwrap()).write_into(writer);
587
0
        self.mark_records.write_into(writer);
588
0
    }
589
0
    fn table_type(&self) -> TableType {
590
0
        TableType::Named("MarkArray")
591
0
    }
592
}
593
594
impl Validate for MarkArray {
595
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
596
0
        ctx.in_table("MarkArray", |ctx| {
597
0
            ctx.in_field("mark_records", |ctx| {
598
0
                if self.mark_records.len() > (u16::MAX as usize) {
599
0
                    ctx.report("array exceeds max length");
600
0
                }
601
0
                self.mark_records.validate_impl(ctx);
602
0
            });
603
0
        })
604
0
    }
605
}
606
607
impl<'a> FromObjRef<read_fonts::tables::gpos::MarkArray<'a>> for MarkArray {
608
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkArray<'a>, _: FontData) -> Self {
609
0
        let offset_data = obj.offset_data();
610
0
        MarkArray {
611
0
            mark_records: obj.mark_records().to_owned_obj(offset_data),
612
0
        }
613
0
    }
614
}
615
616
#[allow(clippy::needless_lifetimes)]
617
impl<'a> FromTableRef<read_fonts::tables::gpos::MarkArray<'a>> for MarkArray {}
618
619
impl<'a> FontRead<'a> for MarkArray {
620
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
621
0
        <read_fonts::tables::gpos::MarkArray as FontRead>::read(data).map(|x| x.to_owned_table())
622
0
    }
623
}
624
625
/// Part of [MarkArray]
626
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
627
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
628
pub struct MarkRecord {
629
    /// Class defined for the associated mark.
630
    pub mark_class: u16,
631
    /// Offset to Anchor table, from beginning of MarkArray table.
632
    pub mark_anchor: OffsetMarker<AnchorTable>,
633
}
634
635
impl MarkRecord {
636
    /// Construct a new `MarkRecord`
637
0
    pub fn new(mark_class: u16, mark_anchor: AnchorTable) -> Self {
638
0
        Self {
639
0
            mark_class,
640
0
            mark_anchor: mark_anchor.into(),
641
0
        }
642
0
    }
643
}
644
645
impl FontWrite for MarkRecord {
646
0
    fn write_into(&self, writer: &mut TableWriter) {
647
0
        self.mark_class.write_into(writer);
648
0
        self.mark_anchor.write_into(writer);
649
0
    }
650
0
    fn table_type(&self) -> TableType {
651
0
        TableType::Named("MarkRecord")
652
0
    }
653
}
654
655
impl Validate for MarkRecord {
656
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
657
0
        ctx.in_table("MarkRecord", |ctx| {
658
0
            ctx.in_field("mark_anchor", |ctx| {
659
0
                self.mark_anchor.validate_impl(ctx);
660
0
            });
661
0
        })
662
0
    }
663
}
664
665
impl FromObjRef<read_fonts::tables::gpos::MarkRecord> for MarkRecord {
666
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkRecord, offset_data: FontData) -> Self {
667
0
        MarkRecord {
668
0
            mark_class: obj.mark_class(),
669
0
            mark_anchor: obj.mark_anchor(offset_data).to_owned_table(),
670
0
        }
671
0
    }
672
}
673
674
/// [Lookup Type 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#lookup-type-1-single-adjustment-positioning-subtable): Single Adjustment Positioning Subtable
675
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
676
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
677
pub enum SinglePos {
678
    Format1(SinglePosFormat1),
679
    Format2(SinglePosFormat2),
680
}
681
682
impl SinglePos {
683
    /// Construct a new `SinglePosFormat1` subtable
684
0
    pub fn format_1(coverage: CoverageTable, value_record: ValueRecord) -> Self {
685
0
        Self::Format1(SinglePosFormat1::new(coverage, value_record))
686
0
    }
687
688
    /// Construct a new `SinglePosFormat2` subtable
689
0
    pub fn format_2(coverage: CoverageTable, value_records: Vec<ValueRecord>) -> Self {
690
0
        Self::Format2(SinglePosFormat2::new(coverage, value_records))
691
0
    }
692
}
693
694
impl Default for SinglePos {
695
0
    fn default() -> Self {
696
0
        Self::Format1(Default::default())
697
0
    }
698
}
699
700
impl FontWrite for SinglePos {
701
0
    fn write_into(&self, writer: &mut TableWriter) {
702
0
        match self {
703
0
            Self::Format1(item) => item.write_into(writer),
704
0
            Self::Format2(item) => item.write_into(writer),
705
        }
706
0
    }
707
0
    fn table_type(&self) -> TableType {
708
0
        match self {
709
0
            Self::Format1(item) => item.table_type(),
710
0
            Self::Format2(item) => item.table_type(),
711
        }
712
0
    }
713
}
714
715
impl Validate for SinglePos {
716
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
717
0
        match self {
718
0
            Self::Format1(item) => item.validate_impl(ctx),
719
0
            Self::Format2(item) => item.validate_impl(ctx),
720
        }
721
0
    }
722
}
723
724
impl FromObjRef<read_fonts::tables::gpos::SinglePos<'_>> for SinglePos {
725
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::SinglePos, _: FontData) -> Self {
726
        use read_fonts::tables::gpos::SinglePos as ObjRefType;
727
0
        match obj {
728
0
            ObjRefType::Format1(item) => SinglePos::Format1(item.to_owned_table()),
729
0
            ObjRefType::Format2(item) => SinglePos::Format2(item.to_owned_table()),
730
        }
731
0
    }
732
}
733
734
impl FromTableRef<read_fonts::tables::gpos::SinglePos<'_>> for SinglePos {}
735
736
impl<'a> FontRead<'a> for SinglePos {
737
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
738
0
        <read_fonts::tables::gpos::SinglePos as FontRead>::read(data).map(|x| x.to_owned_table())
739
0
    }
740
}
741
742
impl From<SinglePosFormat1> for SinglePos {
743
0
    fn from(src: SinglePosFormat1) -> SinglePos {
744
0
        SinglePos::Format1(src)
745
0
    }
746
}
747
748
impl From<SinglePosFormat2> for SinglePos {
749
0
    fn from(src: SinglePosFormat2) -> SinglePos {
750
0
        SinglePos::Format2(src)
751
0
    }
752
}
753
754
/// [Single Adjustment Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#single-adjustment-positioning-format-1-single-positioning-value): Single Positioning Value
755
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
756
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
757
pub struct SinglePosFormat1 {
758
    /// Offset to Coverage table, from beginning of SinglePos subtable.
759
    pub coverage: OffsetMarker<CoverageTable>,
760
    /// Defines positioning value(s) — applied to all glyphs in the
761
    /// Coverage table.
762
    pub value_record: ValueRecord,
763
}
764
765
impl SinglePosFormat1 {
766
    /// Construct a new `SinglePosFormat1`
767
0
    pub fn new(coverage: CoverageTable, value_record: ValueRecord) -> Self {
768
0
        Self {
769
0
            coverage: coverage.into(),
770
0
            value_record,
771
0
        }
772
0
    }
773
}
774
775
impl FontWrite for SinglePosFormat1 {
776
    #[allow(clippy::unnecessary_cast)]
777
0
    fn write_into(&self, writer: &mut TableWriter) {
778
0
        (1 as u16).write_into(writer);
779
0
        self.coverage.write_into(writer);
780
0
        (self.compute_value_format() as ValueFormat).write_into(writer);
781
0
        self.value_record.write_into(writer);
782
0
    }
783
0
    fn table_type(&self) -> TableType {
784
0
        TableType::Named("SinglePosFormat1")
785
0
    }
786
}
787
788
impl Validate for SinglePosFormat1 {
789
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
790
0
        ctx.in_table("SinglePosFormat1", |ctx| {
791
0
            ctx.in_field("coverage", |ctx| {
792
0
                self.coverage.validate_impl(ctx);
793
0
            });
794
0
        })
795
0
    }
796
}
797
798
impl<'a> FromObjRef<read_fonts::tables::gpos::SinglePosFormat1<'a>> for SinglePosFormat1 {
799
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::SinglePosFormat1<'a>, _: FontData) -> Self {
800
0
        let offset_data = obj.offset_data();
801
0
        SinglePosFormat1 {
802
0
            coverage: obj.coverage().to_owned_table(),
803
0
            value_record: obj.value_record().to_owned_obj(offset_data),
804
0
        }
805
0
    }
806
}
807
808
#[allow(clippy::needless_lifetimes)]
809
impl<'a> FromTableRef<read_fonts::tables::gpos::SinglePosFormat1<'a>> for SinglePosFormat1 {}
810
811
impl<'a> FontRead<'a> for SinglePosFormat1 {
812
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
813
0
        <read_fonts::tables::gpos::SinglePosFormat1 as FontRead>::read(data)
814
0
            .map(|x| x.to_owned_table())
815
0
    }
816
}
817
818
/// [Single Adjustment Positioning Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#single-adjustment-positioning-format-2-array-of-positioning-values): Array of Positioning Values
819
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
820
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
821
pub struct SinglePosFormat2 {
822
    /// Offset to Coverage table, from beginning of SinglePos subtable.
823
    pub coverage: OffsetMarker<CoverageTable>,
824
    /// Array of ValueRecords — positioning values applied to glyphs.
825
    pub value_records: Vec<ValueRecord>,
826
}
827
828
impl SinglePosFormat2 {
829
    /// Construct a new `SinglePosFormat2`
830
0
    pub fn new(coverage: CoverageTable, value_records: Vec<ValueRecord>) -> Self {
831
0
        Self {
832
0
            coverage: coverage.into(),
833
0
            value_records,
834
0
        }
835
0
    }
836
}
837
838
impl FontWrite for SinglePosFormat2 {
839
    #[allow(clippy::unnecessary_cast)]
840
0
    fn write_into(&self, writer: &mut TableWriter) {
841
0
        (2 as u16).write_into(writer);
842
0
        self.coverage.write_into(writer);
843
0
        (self.compute_value_format() as ValueFormat).write_into(writer);
844
0
        (u16::try_from(array_len(&self.value_records)).unwrap()).write_into(writer);
845
0
        self.value_records.write_into(writer);
846
0
    }
847
0
    fn table_type(&self) -> TableType {
848
0
        TableType::Named("SinglePosFormat2")
849
0
    }
850
}
851
852
impl Validate for SinglePosFormat2 {
853
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
854
0
        ctx.in_table("SinglePosFormat2", |ctx| {
855
0
            ctx.in_field("coverage", |ctx| {
856
0
                self.coverage.validate_impl(ctx);
857
0
            });
858
0
            ctx.in_field("value_records", |ctx| {
859
0
                if self.value_records.len() > (u16::MAX as usize) {
860
0
                    ctx.report("array exceeds max length");
861
0
                }
862
0
                self.value_records.validate_impl(ctx);
863
0
            });
864
0
        })
865
0
    }
866
}
867
868
impl<'a> FromObjRef<read_fonts::tables::gpos::SinglePosFormat2<'a>> for SinglePosFormat2 {
869
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::SinglePosFormat2<'a>, _: FontData) -> Self {
870
0
        let offset_data = obj.offset_data();
871
        SinglePosFormat2 {
872
0
            coverage: obj.coverage().to_owned_table(),
873
0
            value_records: obj
874
0
                .value_records()
875
0
                .iter()
876
0
                .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
877
0
                .collect(),
878
        }
879
0
    }
880
}
881
882
#[allow(clippy::needless_lifetimes)]
883
impl<'a> FromTableRef<read_fonts::tables::gpos::SinglePosFormat2<'a>> for SinglePosFormat2 {}
884
885
impl<'a> FontRead<'a> for SinglePosFormat2 {
886
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
887
0
        <read_fonts::tables::gpos::SinglePosFormat2 as FontRead>::read(data)
888
0
            .map(|x| x.to_owned_table())
889
0
    }
890
}
891
892
/// [Lookup Type 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#lookup-type-1-single-adjustment-positioning-subtable): Single Adjustment Positioning Subtable
893
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
894
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
895
pub enum PairPos {
896
    Format1(PairPosFormat1),
897
    Format2(PairPosFormat2),
898
}
899
900
impl PairPos {
901
    /// Construct a new `PairPosFormat1` subtable
902
0
    pub fn format_1(coverage: CoverageTable, pair_sets: Vec<PairSet>) -> Self {
903
0
        Self::Format1(PairPosFormat1::new(coverage, pair_sets))
904
0
    }
905
906
    /// Construct a new `PairPosFormat2` subtable
907
0
    pub fn format_2(
908
0
        coverage: CoverageTable,
909
0
        class_def1: ClassDef,
910
0
        class_def2: ClassDef,
911
0
        class1_records: Vec<Class1Record>,
912
0
    ) -> Self {
913
0
        Self::Format2(PairPosFormat2::new(
914
0
            coverage,
915
0
            class_def1,
916
0
            class_def2,
917
0
            class1_records,
918
0
        ))
919
0
    }
920
}
921
922
impl Default for PairPos {
923
0
    fn default() -> Self {
924
0
        Self::Format1(Default::default())
925
0
    }
926
}
927
928
impl FontWrite for PairPos {
929
0
    fn write_into(&self, writer: &mut TableWriter) {
930
0
        match self {
931
0
            Self::Format1(item) => item.write_into(writer),
932
0
            Self::Format2(item) => item.write_into(writer),
933
        }
934
0
    }
935
0
    fn table_type(&self) -> TableType {
936
0
        match self {
937
0
            Self::Format1(item) => item.table_type(),
938
0
            Self::Format2(item) => item.table_type(),
939
        }
940
0
    }
941
}
942
943
impl Validate for PairPos {
944
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
945
0
        match self {
946
0
            Self::Format1(item) => item.validate_impl(ctx),
947
0
            Self::Format2(item) => item.validate_impl(ctx),
948
        }
949
0
    }
950
}
951
952
impl FromObjRef<read_fonts::tables::gpos::PairPos<'_>> for PairPos {
953
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::PairPos, _: FontData) -> Self {
954
        use read_fonts::tables::gpos::PairPos as ObjRefType;
955
0
        match obj {
956
0
            ObjRefType::Format1(item) => PairPos::Format1(item.to_owned_table()),
957
0
            ObjRefType::Format2(item) => PairPos::Format2(item.to_owned_table()),
958
        }
959
0
    }
960
}
961
962
impl FromTableRef<read_fonts::tables::gpos::PairPos<'_>> for PairPos {}
963
964
impl<'a> FontRead<'a> for PairPos {
965
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
966
0
        <read_fonts::tables::gpos::PairPos as FontRead>::read(data).map(|x| x.to_owned_table())
967
0
    }
968
}
969
970
impl From<PairPosFormat1> for PairPos {
971
0
    fn from(src: PairPosFormat1) -> PairPos {
972
0
        PairPos::Format1(src)
973
0
    }
974
}
975
976
impl From<PairPosFormat2> for PairPos {
977
0
    fn from(src: PairPosFormat2) -> PairPos {
978
0
        PairPos::Format2(src)
979
0
    }
980
}
981
982
/// [Pair Adjustment Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#pair-adjustment-positioning-format-1-adjustments-for-glyph-pairs): Adjustments for Glyph Pairs
983
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
984
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
985
pub struct PairPosFormat1 {
986
    /// Offset to Coverage table, from beginning of PairPos subtable.
987
    pub coverage: OffsetMarker<CoverageTable>,
988
    /// Array of offsets to PairSet tables. Offsets are from beginning
989
    /// of PairPos subtable, ordered by Coverage Index.
990
    pub pair_sets: Vec<OffsetMarker<PairSet>>,
991
}
992
993
impl PairPosFormat1 {
994
    /// Construct a new `PairPosFormat1`
995
0
    pub fn new(coverage: CoverageTable, pair_sets: Vec<PairSet>) -> Self {
996
0
        Self {
997
0
            coverage: coverage.into(),
998
0
            pair_sets: pair_sets.into_iter().map(Into::into).collect(),
999
0
        }
1000
0
    }
1001
}
1002
1003
impl FontWrite for PairPosFormat1 {
1004
    #[allow(clippy::unnecessary_cast)]
1005
0
    fn write_into(&self, writer: &mut TableWriter) {
1006
0
        (1 as u16).write_into(writer);
1007
0
        self.coverage.write_into(writer);
1008
0
        (self.compute_value_format1() as ValueFormat).write_into(writer);
1009
0
        (self.compute_value_format2() as ValueFormat).write_into(writer);
1010
0
        (u16::try_from(array_len(&self.pair_sets)).unwrap()).write_into(writer);
1011
0
        self.pair_sets.write_into(writer);
1012
0
    }
1013
0
    fn table_type(&self) -> TableType {
1014
0
        TableType::Named("PairPosFormat1")
1015
0
    }
1016
}
1017
1018
impl Validate for PairPosFormat1 {
1019
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1020
0
        ctx.in_table("PairPosFormat1", |ctx| {
1021
0
            ctx.in_field("coverage", |ctx| {
1022
0
                self.coverage.validate_impl(ctx);
1023
0
            });
1024
0
            ctx.in_field("pair_sets", |ctx| {
1025
0
                if self.pair_sets.len() > (u16::MAX as usize) {
1026
0
                    ctx.report("array exceeds max length");
1027
0
                }
1028
0
                self.check_format_consistency(ctx);
1029
0
            });
1030
0
        })
1031
0
    }
1032
}
1033
1034
impl<'a> FromObjRef<read_fonts::tables::gpos::PairPosFormat1<'a>> for PairPosFormat1 {
1035
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::PairPosFormat1<'a>, _: FontData) -> Self {
1036
0
        PairPosFormat1 {
1037
0
            coverage: obj.coverage().to_owned_table(),
1038
0
            pair_sets: obj.pair_sets().to_owned_table(),
1039
0
        }
1040
0
    }
1041
}
1042
1043
#[allow(clippy::needless_lifetimes)]
1044
impl<'a> FromTableRef<read_fonts::tables::gpos::PairPosFormat1<'a>> for PairPosFormat1 {}
1045
1046
impl<'a> FontRead<'a> for PairPosFormat1 {
1047
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1048
0
        <read_fonts::tables::gpos::PairPosFormat1 as FontRead>::read(data)
1049
0
            .map(|x| x.to_owned_table())
1050
0
    }
1051
}
1052
1053
/// Part of [PairPosFormat1]
1054
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1055
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1056
pub struct PairSet {
1057
    /// Array of PairValueRecords, ordered by glyph ID of the second
1058
    /// glyph.
1059
    pub pair_value_records: Vec<PairValueRecord>,
1060
}
1061
1062
impl PairSet {
1063
    /// Construct a new `PairSet`
1064
0
    pub fn new(pair_value_records: Vec<PairValueRecord>) -> Self {
1065
0
        Self { pair_value_records }
1066
0
    }
1067
}
1068
1069
impl FontWrite for PairSet {
1070
    #[allow(clippy::unnecessary_cast)]
1071
0
    fn write_into(&self, writer: &mut TableWriter) {
1072
0
        (u16::try_from(array_len(&self.pair_value_records)).unwrap()).write_into(writer);
1073
0
        self.pair_value_records.write_into(writer);
1074
0
    }
1075
0
    fn table_type(&self) -> TableType {
1076
0
        TableType::Named("PairSet")
1077
0
    }
1078
}
1079
1080
impl Validate for PairSet {
1081
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1082
0
        ctx.in_table("PairSet", |ctx| {
1083
0
            ctx.in_field("pair_value_records", |ctx| {
1084
0
                if self.pair_value_records.len() > (u16::MAX as usize) {
1085
0
                    ctx.report("array exceeds max length");
1086
0
                }
1087
0
                self.pair_value_records.validate_impl(ctx);
1088
0
            });
1089
0
        })
1090
0
    }
1091
}
1092
1093
impl<'a> FromObjRef<read_fonts::tables::gpos::PairSet<'a>> for PairSet {
1094
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::PairSet<'a>, _: FontData) -> Self {
1095
0
        let offset_data = obj.offset_data();
1096
        PairSet {
1097
0
            pair_value_records: obj
1098
0
                .pair_value_records()
1099
0
                .iter()
1100
0
                .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
1101
0
                .collect(),
1102
        }
1103
0
    }
1104
}
1105
1106
#[allow(clippy::needless_lifetimes)]
1107
impl<'a> FromTableRef<read_fonts::tables::gpos::PairSet<'a>> for PairSet {}
1108
1109
/// Part of [PairSet]
1110
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1111
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1112
pub struct PairValueRecord {
1113
    /// Glyph ID of second glyph in the pair (first glyph is listed in
1114
    /// the Coverage table).
1115
    pub second_glyph: GlyphId16,
1116
    /// Positioning data for the first glyph in the pair.
1117
    pub value_record1: ValueRecord,
1118
    /// Positioning data for the second glyph in the pair.
1119
    pub value_record2: ValueRecord,
1120
}
1121
1122
impl PairValueRecord {
1123
    /// Construct a new `PairValueRecord`
1124
0
    pub fn new(
1125
0
        second_glyph: GlyphId16,
1126
0
        value_record1: ValueRecord,
1127
0
        value_record2: ValueRecord,
1128
0
    ) -> Self {
1129
0
        Self {
1130
0
            second_glyph,
1131
0
            value_record1,
1132
0
            value_record2,
1133
0
        }
1134
0
    }
1135
}
1136
1137
impl FontWrite for PairValueRecord {
1138
0
    fn write_into(&self, writer: &mut TableWriter) {
1139
0
        self.second_glyph.write_into(writer);
1140
0
        self.value_record1.write_into(writer);
1141
0
        self.value_record2.write_into(writer);
1142
0
    }
1143
0
    fn table_type(&self) -> TableType {
1144
0
        TableType::Named("PairValueRecord")
1145
0
    }
1146
}
1147
1148
impl Validate for PairValueRecord {
1149
0
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
1150
}
1151
1152
impl FromObjRef<read_fonts::tables::gpos::PairValueRecord> for PairValueRecord {
1153
0
    fn from_obj_ref(
1154
0
        obj: &read_fonts::tables::gpos::PairValueRecord,
1155
0
        offset_data: FontData,
1156
0
    ) -> Self {
1157
0
        PairValueRecord {
1158
0
            second_glyph: obj.second_glyph(),
1159
0
            value_record1: obj.value_record1().to_owned_obj(offset_data),
1160
0
            value_record2: obj.value_record2().to_owned_obj(offset_data),
1161
0
        }
1162
0
    }
1163
}
1164
1165
/// [Pair Adjustment Positioning Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#pair-adjustment-positioning-format-2-class-pair-adjustment): Class Pair Adjustment
1166
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1167
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1168
pub struct PairPosFormat2 {
1169
    /// Offset to Coverage table, from beginning of PairPos subtable.
1170
    pub coverage: OffsetMarker<CoverageTable>,
1171
    /// Offset to ClassDef table, from beginning of PairPos subtable
1172
    /// — for the first glyph of the pair.
1173
    pub class_def1: OffsetMarker<ClassDef>,
1174
    /// Offset to ClassDef table, from beginning of PairPos subtable
1175
    /// — for the second glyph of the pair.
1176
    pub class_def2: OffsetMarker<ClassDef>,
1177
    /// Array of Class1 records, ordered by classes in classDef1.
1178
    pub class1_records: Vec<Class1Record>,
1179
}
1180
1181
impl PairPosFormat2 {
1182
    /// Construct a new `PairPosFormat2`
1183
0
    pub fn new(
1184
0
        coverage: CoverageTable,
1185
0
        class_def1: ClassDef,
1186
0
        class_def2: ClassDef,
1187
0
        class1_records: Vec<Class1Record>,
1188
0
    ) -> Self {
1189
0
        Self {
1190
0
            coverage: coverage.into(),
1191
0
            class_def1: class_def1.into(),
1192
0
            class_def2: class_def2.into(),
1193
0
            class1_records,
1194
0
        }
1195
0
    }
1196
}
1197
1198
impl FontWrite for PairPosFormat2 {
1199
    #[allow(clippy::unnecessary_cast)]
1200
0
    fn write_into(&self, writer: &mut TableWriter) {
1201
0
        (2 as u16).write_into(writer);
1202
0
        self.coverage.write_into(writer);
1203
0
        (self.compute_value_format1() as ValueFormat).write_into(writer);
1204
0
        (self.compute_value_format2() as ValueFormat).write_into(writer);
1205
0
        self.class_def1.write_into(writer);
1206
0
        self.class_def2.write_into(writer);
1207
0
        (self.compute_class1_count() as u16).write_into(writer);
1208
0
        (self.compute_class2_count() as u16).write_into(writer);
1209
0
        self.class1_records.write_into(writer);
1210
0
    }
1211
0
    fn table_type(&self) -> TableType {
1212
0
        TableType::Named("PairPosFormat2")
1213
0
    }
1214
}
1215
1216
impl Validate for PairPosFormat2 {
1217
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1218
0
        ctx.in_table("PairPosFormat2", |ctx| {
1219
0
            ctx.in_field("coverage", |ctx| {
1220
0
                self.coverage.validate_impl(ctx);
1221
0
            });
1222
0
            ctx.in_field("class_def1", |ctx| {
1223
0
                self.class_def1.validate_impl(ctx);
1224
0
            });
1225
0
            ctx.in_field("class_def2", |ctx| {
1226
0
                self.class_def2.validate_impl(ctx);
1227
0
            });
1228
0
            ctx.in_field("class1_records", |ctx| {
1229
0
                if self.class1_records.len() > (u16::MAX as usize) {
1230
0
                    ctx.report("array exceeds max length");
1231
0
                }
1232
0
                self.class1_records.validate_impl(ctx);
1233
0
            });
1234
0
            self.check_length_and_format_conformance(ctx);
1235
0
        })
1236
0
    }
1237
}
1238
1239
impl<'a> FromObjRef<read_fonts::tables::gpos::PairPosFormat2<'a>> for PairPosFormat2 {
1240
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::PairPosFormat2<'a>, _: FontData) -> Self {
1241
0
        let offset_data = obj.offset_data();
1242
        PairPosFormat2 {
1243
0
            coverage: obj.coverage().to_owned_table(),
1244
0
            class_def1: obj.class_def1().to_owned_table(),
1245
0
            class_def2: obj.class_def2().to_owned_table(),
1246
0
            class1_records: obj
1247
0
                .class1_records()
1248
0
                .iter()
1249
0
                .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
1250
0
                .collect(),
1251
        }
1252
0
    }
1253
}
1254
1255
#[allow(clippy::needless_lifetimes)]
1256
impl<'a> FromTableRef<read_fonts::tables::gpos::PairPosFormat2<'a>> for PairPosFormat2 {}
1257
1258
impl<'a> FontRead<'a> for PairPosFormat2 {
1259
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1260
0
        <read_fonts::tables::gpos::PairPosFormat2 as FontRead>::read(data)
1261
0
            .map(|x| x.to_owned_table())
1262
0
    }
1263
}
1264
1265
/// Part of [PairPosFormat2]
1266
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1267
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1268
pub struct Class1Record {
1269
    /// Array of Class2 records, ordered by classes in classDef2.
1270
    pub class2_records: Vec<Class2Record>,
1271
}
1272
1273
impl Class1Record {
1274
    /// Construct a new `Class1Record`
1275
0
    pub fn new(class2_records: Vec<Class2Record>) -> Self {
1276
0
        Self { class2_records }
1277
0
    }
1278
}
1279
1280
impl FontWrite for Class1Record {
1281
0
    fn write_into(&self, writer: &mut TableWriter) {
1282
0
        self.class2_records.write_into(writer);
1283
0
    }
1284
0
    fn table_type(&self) -> TableType {
1285
0
        TableType::Named("Class1Record")
1286
0
    }
1287
}
1288
1289
impl Validate for Class1Record {
1290
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1291
0
        ctx.in_table("Class1Record", |ctx| {
1292
0
            ctx.in_field("class2_records", |ctx| {
1293
0
                if self.class2_records.len() > (u16::MAX as usize) {
1294
0
                    ctx.report("array exceeds max length");
1295
0
                }
1296
0
                self.class2_records.validate_impl(ctx);
1297
0
            });
1298
0
        })
1299
0
    }
1300
}
1301
1302
impl FromObjRef<read_fonts::tables::gpos::Class1Record<'_>> for Class1Record {
1303
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::Class1Record, offset_data: FontData) -> Self {
1304
        Class1Record {
1305
0
            class2_records: obj
1306
0
                .class2_records()
1307
0
                .iter()
1308
0
                .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
1309
0
                .collect(),
1310
        }
1311
0
    }
1312
}
1313
1314
/// Part of [PairPosFormat2]
1315
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1316
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1317
pub struct Class2Record {
1318
    /// Positioning for first glyph — empty if valueFormat1 = 0.
1319
    pub value_record1: ValueRecord,
1320
    /// Positioning for second glyph — empty if valueFormat2 = 0.
1321
    pub value_record2: ValueRecord,
1322
}
1323
1324
impl Class2Record {
1325
    /// Construct a new `Class2Record`
1326
0
    pub fn new(value_record1: ValueRecord, value_record2: ValueRecord) -> Self {
1327
0
        Self {
1328
0
            value_record1,
1329
0
            value_record2,
1330
0
        }
1331
0
    }
1332
}
1333
1334
impl FontWrite for Class2Record {
1335
0
    fn write_into(&self, writer: &mut TableWriter) {
1336
0
        self.value_record1.write_into(writer);
1337
0
        self.value_record2.write_into(writer);
1338
0
    }
1339
0
    fn table_type(&self) -> TableType {
1340
0
        TableType::Named("Class2Record")
1341
0
    }
1342
}
1343
1344
impl Validate for Class2Record {
1345
0
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
1346
}
1347
1348
impl FromObjRef<read_fonts::tables::gpos::Class2Record> for Class2Record {
1349
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::Class2Record, offset_data: FontData) -> Self {
1350
0
        Class2Record {
1351
0
            value_record1: obj.value_record1().to_owned_obj(offset_data),
1352
0
            value_record2: obj.value_record2().to_owned_obj(offset_data),
1353
0
        }
1354
0
    }
1355
}
1356
1357
/// [Cursive Attachment Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#cursive-attachment-positioning-format1-cursive-attachment): Cursvie attachment
1358
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1359
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1360
pub struct CursivePosFormat1 {
1361
    /// Offset to Coverage table, from beginning of CursivePos subtable.
1362
    pub coverage: OffsetMarker<CoverageTable>,
1363
    /// Array of EntryExit records, in Coverage index order.
1364
    pub entry_exit_record: Vec<EntryExitRecord>,
1365
}
1366
1367
impl CursivePosFormat1 {
1368
    /// Construct a new `CursivePosFormat1`
1369
0
    pub fn new(coverage: CoverageTable, entry_exit_record: Vec<EntryExitRecord>) -> Self {
1370
0
        Self {
1371
0
            coverage: coverage.into(),
1372
0
            entry_exit_record,
1373
0
        }
1374
0
    }
1375
}
1376
1377
impl FontWrite for CursivePosFormat1 {
1378
    #[allow(clippy::unnecessary_cast)]
1379
0
    fn write_into(&self, writer: &mut TableWriter) {
1380
0
        (1 as u16).write_into(writer);
1381
0
        self.coverage.write_into(writer);
1382
0
        (u16::try_from(array_len(&self.entry_exit_record)).unwrap()).write_into(writer);
1383
0
        self.entry_exit_record.write_into(writer);
1384
0
    }
1385
0
    fn table_type(&self) -> TableType {
1386
0
        TableType::Named("CursivePosFormat1")
1387
0
    }
1388
}
1389
1390
impl Validate for CursivePosFormat1 {
1391
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1392
0
        ctx.in_table("CursivePosFormat1", |ctx| {
1393
0
            ctx.in_field("coverage", |ctx| {
1394
0
                self.coverage.validate_impl(ctx);
1395
0
            });
1396
0
            ctx.in_field("entry_exit_record", |ctx| {
1397
0
                if self.entry_exit_record.len() > (u16::MAX as usize) {
1398
0
                    ctx.report("array exceeds max length");
1399
0
                }
1400
0
                self.entry_exit_record.validate_impl(ctx);
1401
0
            });
1402
0
        })
1403
0
    }
1404
}
1405
1406
impl<'a> FromObjRef<read_fonts::tables::gpos::CursivePosFormat1<'a>> for CursivePosFormat1 {
1407
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::CursivePosFormat1<'a>, _: FontData) -> Self {
1408
0
        let offset_data = obj.offset_data();
1409
0
        CursivePosFormat1 {
1410
0
            coverage: obj.coverage().to_owned_table(),
1411
0
            entry_exit_record: obj.entry_exit_record().to_owned_obj(offset_data),
1412
0
        }
1413
0
    }
1414
}
1415
1416
#[allow(clippy::needless_lifetimes)]
1417
impl<'a> FromTableRef<read_fonts::tables::gpos::CursivePosFormat1<'a>> for CursivePosFormat1 {}
1418
1419
impl<'a> FontRead<'a> for CursivePosFormat1 {
1420
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1421
0
        <read_fonts::tables::gpos::CursivePosFormat1 as FontRead>::read(data)
1422
0
            .map(|x| x.to_owned_table())
1423
0
    }
1424
}
1425
1426
/// Part of [CursivePosFormat1]
1427
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1428
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1429
pub struct EntryExitRecord {
1430
    /// Offset to entryAnchor table, from beginning of CursivePos
1431
    /// subtable (may be NULL).
1432
    pub entry_anchor: NullableOffsetMarker<AnchorTable>,
1433
    /// Offset to exitAnchor table, from beginning of CursivePos
1434
    /// subtable (may be NULL).
1435
    pub exit_anchor: NullableOffsetMarker<AnchorTable>,
1436
}
1437
1438
impl EntryExitRecord {
1439
    /// Construct a new `EntryExitRecord`
1440
0
    pub fn new(entry_anchor: Option<AnchorTable>, exit_anchor: Option<AnchorTable>) -> Self {
1441
0
        Self {
1442
0
            entry_anchor: entry_anchor.into(),
1443
0
            exit_anchor: exit_anchor.into(),
1444
0
        }
1445
0
    }
1446
}
1447
1448
impl FontWrite for EntryExitRecord {
1449
0
    fn write_into(&self, writer: &mut TableWriter) {
1450
0
        self.entry_anchor.write_into(writer);
1451
0
        self.exit_anchor.write_into(writer);
1452
0
    }
1453
0
    fn table_type(&self) -> TableType {
1454
0
        TableType::Named("EntryExitRecord")
1455
0
    }
1456
}
1457
1458
impl Validate for EntryExitRecord {
1459
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1460
0
        ctx.in_table("EntryExitRecord", |ctx| {
1461
0
            ctx.in_field("entry_anchor", |ctx| {
1462
0
                self.entry_anchor.validate_impl(ctx);
1463
0
            });
1464
0
            ctx.in_field("exit_anchor", |ctx| {
1465
0
                self.exit_anchor.validate_impl(ctx);
1466
0
            });
1467
0
        })
1468
0
    }
1469
}
1470
1471
impl FromObjRef<read_fonts::tables::gpos::EntryExitRecord> for EntryExitRecord {
1472
0
    fn from_obj_ref(
1473
0
        obj: &read_fonts::tables::gpos::EntryExitRecord,
1474
0
        offset_data: FontData,
1475
0
    ) -> Self {
1476
0
        EntryExitRecord {
1477
0
            entry_anchor: obj.entry_anchor(offset_data).to_owned_table(),
1478
0
            exit_anchor: obj.exit_anchor(offset_data).to_owned_table(),
1479
0
        }
1480
0
    }
1481
}
1482
1483
/// [Mark-to-Base Attachment Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#mark-to-base-attachment-positioning-format-1-mark-to-base-attachment-point): Mark-to-base Attachment Point
1484
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1485
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1486
pub struct MarkBasePosFormat1 {
1487
    /// Offset to markCoverage table, from beginning of MarkBasePos
1488
    /// subtable.
1489
    pub mark_coverage: OffsetMarker<CoverageTable>,
1490
    /// Offset to baseCoverage table, from beginning of MarkBasePos
1491
    /// subtable.
1492
    pub base_coverage: OffsetMarker<CoverageTable>,
1493
    /// Offset to MarkArray table, from beginning of MarkBasePos
1494
    /// subtable.
1495
    pub mark_array: OffsetMarker<MarkArray>,
1496
    /// Offset to BaseArray table, from beginning of MarkBasePos
1497
    /// subtable.
1498
    pub base_array: OffsetMarker<BaseArray>,
1499
}
1500
1501
impl MarkBasePosFormat1 {
1502
    /// Construct a new `MarkBasePosFormat1`
1503
0
    pub fn new(
1504
0
        mark_coverage: CoverageTable,
1505
0
        base_coverage: CoverageTable,
1506
0
        mark_array: MarkArray,
1507
0
        base_array: BaseArray,
1508
0
    ) -> Self {
1509
0
        Self {
1510
0
            mark_coverage: mark_coverage.into(),
1511
0
            base_coverage: base_coverage.into(),
1512
0
            mark_array: mark_array.into(),
1513
0
            base_array: base_array.into(),
1514
0
        }
1515
0
    }
1516
}
1517
1518
impl FontWrite for MarkBasePosFormat1 {
1519
    #[allow(clippy::unnecessary_cast)]
1520
0
    fn write_into(&self, writer: &mut TableWriter) {
1521
0
        (1 as u16).write_into(writer);
1522
0
        self.mark_coverage.write_into(writer);
1523
0
        self.base_coverage.write_into(writer);
1524
0
        (self.compute_mark_class_count() as u16).write_into(writer);
1525
0
        self.mark_array.write_into(writer);
1526
0
        self.base_array.write_into(writer);
1527
0
    }
1528
0
    fn table_type(&self) -> TableType {
1529
0
        TableType::Named("MarkBasePosFormat1")
1530
0
    }
1531
}
1532
1533
impl Validate for MarkBasePosFormat1 {
1534
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1535
0
        ctx.in_table("MarkBasePosFormat1", |ctx| {
1536
0
            ctx.in_field("mark_coverage", |ctx| {
1537
0
                self.mark_coverage.validate_impl(ctx);
1538
0
            });
1539
0
            ctx.in_field("base_coverage", |ctx| {
1540
0
                self.base_coverage.validate_impl(ctx);
1541
0
            });
1542
0
            ctx.in_field("mark_array", |ctx| {
1543
0
                self.mark_array.validate_impl(ctx);
1544
0
            });
1545
0
            ctx.in_field("base_array", |ctx| {
1546
0
                self.base_array.validate_impl(ctx);
1547
0
            });
1548
0
        })
1549
0
    }
1550
}
1551
1552
impl<'a> FromObjRef<read_fonts::tables::gpos::MarkBasePosFormat1<'a>> for MarkBasePosFormat1 {
1553
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkBasePosFormat1<'a>, _: FontData) -> Self {
1554
0
        MarkBasePosFormat1 {
1555
0
            mark_coverage: obj.mark_coverage().to_owned_table(),
1556
0
            base_coverage: obj.base_coverage().to_owned_table(),
1557
0
            mark_array: obj.mark_array().to_owned_table(),
1558
0
            base_array: obj.base_array().to_owned_table(),
1559
0
        }
1560
0
    }
1561
}
1562
1563
#[allow(clippy::needless_lifetimes)]
1564
impl<'a> FromTableRef<read_fonts::tables::gpos::MarkBasePosFormat1<'a>> for MarkBasePosFormat1 {}
1565
1566
impl<'a> FontRead<'a> for MarkBasePosFormat1 {
1567
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1568
0
        <read_fonts::tables::gpos::MarkBasePosFormat1 as FontRead>::read(data)
1569
0
            .map(|x| x.to_owned_table())
1570
0
    }
1571
}
1572
1573
/// Part of [MarkBasePosFormat1]
1574
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1575
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1576
pub struct BaseArray {
1577
    /// Array of BaseRecords, in order of baseCoverage Index.
1578
    pub base_records: Vec<BaseRecord>,
1579
}
1580
1581
impl BaseArray {
1582
    /// Construct a new `BaseArray`
1583
0
    pub fn new(base_records: Vec<BaseRecord>) -> Self {
1584
0
        Self { base_records }
1585
0
    }
1586
}
1587
1588
impl FontWrite for BaseArray {
1589
    #[allow(clippy::unnecessary_cast)]
1590
0
    fn write_into(&self, writer: &mut TableWriter) {
1591
0
        (u16::try_from(array_len(&self.base_records)).unwrap()).write_into(writer);
1592
0
        self.base_records.write_into(writer);
1593
0
    }
1594
0
    fn table_type(&self) -> TableType {
1595
0
        TableType::Named("BaseArray")
1596
0
    }
1597
}
1598
1599
impl Validate for BaseArray {
1600
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1601
0
        ctx.in_table("BaseArray", |ctx| {
1602
0
            ctx.in_field("base_records", |ctx| {
1603
0
                if self.base_records.len() > (u16::MAX as usize) {
1604
0
                    ctx.report("array exceeds max length");
1605
0
                }
1606
0
                self.base_records.validate_impl(ctx);
1607
0
            });
1608
0
        })
1609
0
    }
1610
}
1611
1612
impl<'a> FromObjRef<read_fonts::tables::gpos::BaseArray<'a>> for BaseArray {
1613
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::BaseArray<'a>, _: FontData) -> Self {
1614
0
        let offset_data = obj.offset_data();
1615
        BaseArray {
1616
0
            base_records: obj
1617
0
                .base_records()
1618
0
                .iter()
1619
0
                .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
1620
0
                .collect(),
1621
        }
1622
0
    }
1623
}
1624
1625
#[allow(clippy::needless_lifetimes)]
1626
impl<'a> FromTableRef<read_fonts::tables::gpos::BaseArray<'a>> for BaseArray {}
1627
1628
/// Part of [BaseArray]
1629
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1630
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1631
pub struct BaseRecord {
1632
    /// Array of offsets (one per mark class) to Anchor tables. Offsets
1633
    /// are from beginning of BaseArray table, ordered by class
1634
    /// (offsets may be NULL).
1635
    pub base_anchors: Vec<NullableOffsetMarker<AnchorTable>>,
1636
}
1637
1638
impl BaseRecord {
1639
    /// Construct a new `BaseRecord`
1640
0
    pub fn new(base_anchors: Vec<Option<AnchorTable>>) -> Self {
1641
0
        Self {
1642
0
            base_anchors: base_anchors.into_iter().map(Into::into).collect(),
1643
0
        }
1644
0
    }
1645
}
1646
1647
impl FontWrite for BaseRecord {
1648
0
    fn write_into(&self, writer: &mut TableWriter) {
1649
0
        self.base_anchors.write_into(writer);
1650
0
    }
1651
0
    fn table_type(&self) -> TableType {
1652
0
        TableType::Named("BaseRecord")
1653
0
    }
1654
}
1655
1656
impl Validate for BaseRecord {
1657
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1658
0
        ctx.in_table("BaseRecord", |ctx| {
1659
0
            ctx.in_field("base_anchors", |ctx| {
1660
0
                if self.base_anchors.len() > (u16::MAX as usize) {
1661
0
                    ctx.report("array exceeds max length");
1662
0
                }
1663
0
                self.base_anchors.validate_impl(ctx);
1664
0
            });
1665
0
        })
1666
0
    }
1667
}
1668
1669
impl FromObjRef<read_fonts::tables::gpos::BaseRecord<'_>> for BaseRecord {
1670
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::BaseRecord, offset_data: FontData) -> Self {
1671
0
        BaseRecord {
1672
0
            base_anchors: obj.base_anchors(offset_data).to_owned_table(),
1673
0
        }
1674
0
    }
1675
}
1676
1677
/// [Mark-to-Ligature Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#mark-to-ligature-attachment-positioning-format-1-mark-to-ligature-attachment): Mark-to-Ligature Attachment
1678
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1679
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1680
pub struct MarkLigPosFormat1 {
1681
    /// Offset to markCoverage table, from beginning of MarkLigPos
1682
    /// subtable.
1683
    pub mark_coverage: OffsetMarker<CoverageTable>,
1684
    /// Offset to ligatureCoverage table, from beginning of MarkLigPos
1685
    /// subtable.
1686
    pub ligature_coverage: OffsetMarker<CoverageTable>,
1687
    /// Offset to MarkArray table, from beginning of MarkLigPos
1688
    /// subtable.
1689
    pub mark_array: OffsetMarker<MarkArray>,
1690
    /// Offset to LigatureArray table, from beginning of MarkLigPos
1691
    /// subtable.
1692
    pub ligature_array: OffsetMarker<LigatureArray>,
1693
}
1694
1695
impl MarkLigPosFormat1 {
1696
    /// Construct a new `MarkLigPosFormat1`
1697
0
    pub fn new(
1698
0
        mark_coverage: CoverageTable,
1699
0
        ligature_coverage: CoverageTable,
1700
0
        mark_array: MarkArray,
1701
0
        ligature_array: LigatureArray,
1702
0
    ) -> Self {
1703
0
        Self {
1704
0
            mark_coverage: mark_coverage.into(),
1705
0
            ligature_coverage: ligature_coverage.into(),
1706
0
            mark_array: mark_array.into(),
1707
0
            ligature_array: ligature_array.into(),
1708
0
        }
1709
0
    }
1710
}
1711
1712
impl FontWrite for MarkLigPosFormat1 {
1713
    #[allow(clippy::unnecessary_cast)]
1714
0
    fn write_into(&self, writer: &mut TableWriter) {
1715
0
        (1 as u16).write_into(writer);
1716
0
        self.mark_coverage.write_into(writer);
1717
0
        self.ligature_coverage.write_into(writer);
1718
0
        (self.compute_mark_class_count() as u16).write_into(writer);
1719
0
        self.mark_array.write_into(writer);
1720
0
        self.ligature_array.write_into(writer);
1721
0
    }
1722
0
    fn table_type(&self) -> TableType {
1723
0
        TableType::Named("MarkLigPosFormat1")
1724
0
    }
1725
}
1726
1727
impl Validate for MarkLigPosFormat1 {
1728
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1729
0
        ctx.in_table("MarkLigPosFormat1", |ctx| {
1730
0
            ctx.in_field("mark_coverage", |ctx| {
1731
0
                self.mark_coverage.validate_impl(ctx);
1732
0
            });
1733
0
            ctx.in_field("ligature_coverage", |ctx| {
1734
0
                self.ligature_coverage.validate_impl(ctx);
1735
0
            });
1736
0
            ctx.in_field("mark_array", |ctx| {
1737
0
                self.mark_array.validate_impl(ctx);
1738
0
            });
1739
0
            ctx.in_field("ligature_array", |ctx| {
1740
0
                self.ligature_array.validate_impl(ctx);
1741
0
            });
1742
0
        })
1743
0
    }
1744
}
1745
1746
impl<'a> FromObjRef<read_fonts::tables::gpos::MarkLigPosFormat1<'a>> for MarkLigPosFormat1 {
1747
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkLigPosFormat1<'a>, _: FontData) -> Self {
1748
0
        MarkLigPosFormat1 {
1749
0
            mark_coverage: obj.mark_coverage().to_owned_table(),
1750
0
            ligature_coverage: obj.ligature_coverage().to_owned_table(),
1751
0
            mark_array: obj.mark_array().to_owned_table(),
1752
0
            ligature_array: obj.ligature_array().to_owned_table(),
1753
0
        }
1754
0
    }
1755
}
1756
1757
#[allow(clippy::needless_lifetimes)]
1758
impl<'a> FromTableRef<read_fonts::tables::gpos::MarkLigPosFormat1<'a>> for MarkLigPosFormat1 {}
1759
1760
impl<'a> FontRead<'a> for MarkLigPosFormat1 {
1761
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1762
0
        <read_fonts::tables::gpos::MarkLigPosFormat1 as FontRead>::read(data)
1763
0
            .map(|x| x.to_owned_table())
1764
0
    }
1765
}
1766
1767
/// Part of [MarkLigPosFormat1]
1768
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1769
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1770
pub struct LigatureArray {
1771
    /// Array of offsets to LigatureAttach tables. Offsets are from
1772
    /// beginning of LigatureArray table, ordered by ligatureCoverage
1773
    /// index.
1774
    pub ligature_attaches: Vec<OffsetMarker<LigatureAttach>>,
1775
}
1776
1777
impl LigatureArray {
1778
    /// Construct a new `LigatureArray`
1779
0
    pub fn new(ligature_attaches: Vec<LigatureAttach>) -> Self {
1780
0
        Self {
1781
0
            ligature_attaches: ligature_attaches.into_iter().map(Into::into).collect(),
1782
0
        }
1783
0
    }
1784
}
1785
1786
impl FontWrite for LigatureArray {
1787
    #[allow(clippy::unnecessary_cast)]
1788
0
    fn write_into(&self, writer: &mut TableWriter) {
1789
0
        (u16::try_from(array_len(&self.ligature_attaches)).unwrap()).write_into(writer);
1790
0
        self.ligature_attaches.write_into(writer);
1791
0
    }
1792
0
    fn table_type(&self) -> TableType {
1793
0
        TableType::Named("LigatureArray")
1794
0
    }
1795
}
1796
1797
impl Validate for LigatureArray {
1798
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1799
0
        ctx.in_table("LigatureArray", |ctx| {
1800
0
            ctx.in_field("ligature_attaches", |ctx| {
1801
0
                if self.ligature_attaches.len() > (u16::MAX as usize) {
1802
0
                    ctx.report("array exceeds max length");
1803
0
                }
1804
0
                self.ligature_attaches.validate_impl(ctx);
1805
0
            });
1806
0
        })
1807
0
    }
1808
}
1809
1810
impl<'a> FromObjRef<read_fonts::tables::gpos::LigatureArray<'a>> for LigatureArray {
1811
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::LigatureArray<'a>, _: FontData) -> Self {
1812
0
        LigatureArray {
1813
0
            ligature_attaches: obj.ligature_attaches().to_owned_table(),
1814
0
        }
1815
0
    }
1816
}
1817
1818
#[allow(clippy::needless_lifetimes)]
1819
impl<'a> FromTableRef<read_fonts::tables::gpos::LigatureArray<'a>> for LigatureArray {}
1820
1821
/// Part of [MarkLigPosFormat1]
1822
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1823
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1824
pub struct LigatureAttach {
1825
    /// Array of Component records, ordered in writing direction.
1826
    pub component_records: Vec<ComponentRecord>,
1827
}
1828
1829
impl LigatureAttach {
1830
    /// Construct a new `LigatureAttach`
1831
0
    pub fn new(component_records: Vec<ComponentRecord>) -> Self {
1832
0
        Self { component_records }
1833
0
    }
1834
}
1835
1836
impl FontWrite for LigatureAttach {
1837
    #[allow(clippy::unnecessary_cast)]
1838
0
    fn write_into(&self, writer: &mut TableWriter) {
1839
0
        (u16::try_from(array_len(&self.component_records)).unwrap()).write_into(writer);
1840
0
        self.component_records.write_into(writer);
1841
0
    }
1842
0
    fn table_type(&self) -> TableType {
1843
0
        TableType::Named("LigatureAttach")
1844
0
    }
1845
}
1846
1847
impl Validate for LigatureAttach {
1848
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1849
0
        ctx.in_table("LigatureAttach", |ctx| {
1850
0
            ctx.in_field("component_records", |ctx| {
1851
0
                if self.component_records.len() > (u16::MAX as usize) {
1852
0
                    ctx.report("array exceeds max length");
1853
0
                }
1854
0
                self.component_records.validate_impl(ctx);
1855
0
            });
1856
0
        })
1857
0
    }
1858
}
1859
1860
impl<'a> FromObjRef<read_fonts::tables::gpos::LigatureAttach<'a>> for LigatureAttach {
1861
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::LigatureAttach<'a>, _: FontData) -> Self {
1862
0
        let offset_data = obj.offset_data();
1863
        LigatureAttach {
1864
0
            component_records: obj
1865
0
                .component_records()
1866
0
                .iter()
1867
0
                .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
1868
0
                .collect(),
1869
        }
1870
0
    }
1871
}
1872
1873
#[allow(clippy::needless_lifetimes)]
1874
impl<'a> FromTableRef<read_fonts::tables::gpos::LigatureAttach<'a>> for LigatureAttach {}
1875
1876
/// Part of [MarkLigPosFormat1]
1877
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1878
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1879
pub struct ComponentRecord {
1880
    /// Array of offsets (one per class) to Anchor tables. Offsets are
1881
    /// from beginning of LigatureAttach table, ordered by class
1882
    /// (offsets may be NULL).
1883
    pub ligature_anchors: Vec<NullableOffsetMarker<AnchorTable>>,
1884
}
1885
1886
impl ComponentRecord {
1887
    /// Construct a new `ComponentRecord`
1888
0
    pub fn new(ligature_anchors: Vec<Option<AnchorTable>>) -> Self {
1889
0
        Self {
1890
0
            ligature_anchors: ligature_anchors.into_iter().map(Into::into).collect(),
1891
0
        }
1892
0
    }
1893
}
1894
1895
impl FontWrite for ComponentRecord {
1896
0
    fn write_into(&self, writer: &mut TableWriter) {
1897
0
        self.ligature_anchors.write_into(writer);
1898
0
    }
1899
0
    fn table_type(&self) -> TableType {
1900
0
        TableType::Named("ComponentRecord")
1901
0
    }
1902
}
1903
1904
impl Validate for ComponentRecord {
1905
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1906
0
        ctx.in_table("ComponentRecord", |ctx| {
1907
0
            ctx.in_field("ligature_anchors", |ctx| {
1908
0
                if self.ligature_anchors.len() > (u16::MAX as usize) {
1909
0
                    ctx.report("array exceeds max length");
1910
0
                }
1911
0
                self.ligature_anchors.validate_impl(ctx);
1912
0
            });
1913
0
        })
1914
0
    }
1915
}
1916
1917
impl FromObjRef<read_fonts::tables::gpos::ComponentRecord<'_>> for ComponentRecord {
1918
0
    fn from_obj_ref(
1919
0
        obj: &read_fonts::tables::gpos::ComponentRecord,
1920
0
        offset_data: FontData,
1921
0
    ) -> Self {
1922
0
        ComponentRecord {
1923
0
            ligature_anchors: obj.ligature_anchors(offset_data).to_owned_table(),
1924
0
        }
1925
0
    }
1926
}
1927
1928
/// [Mark-to-Mark Attachment Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#mark-to-mark-attachment-positioning-format-1-mark-to-mark-attachment): Mark-to-Mark Attachment
1929
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1930
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1931
pub struct MarkMarkPosFormat1 {
1932
    /// Offset to Combining Mark Coverage table, from beginning of
1933
    /// MarkMarkPos subtable.
1934
    pub mark1_coverage: OffsetMarker<CoverageTable>,
1935
    /// Offset to Base Mark Coverage table, from beginning of
1936
    /// MarkMarkPos subtable.
1937
    pub mark2_coverage: OffsetMarker<CoverageTable>,
1938
    /// Offset to MarkArray table for mark1, from beginning of
1939
    /// MarkMarkPos subtable.
1940
    pub mark1_array: OffsetMarker<MarkArray>,
1941
    /// Offset to Mark2Array table for mark2, from beginning of
1942
    /// MarkMarkPos subtable.
1943
    pub mark2_array: OffsetMarker<Mark2Array>,
1944
}
1945
1946
impl MarkMarkPosFormat1 {
1947
    /// Construct a new `MarkMarkPosFormat1`
1948
0
    pub fn new(
1949
0
        mark1_coverage: CoverageTable,
1950
0
        mark2_coverage: CoverageTable,
1951
0
        mark1_array: MarkArray,
1952
0
        mark2_array: Mark2Array,
1953
0
    ) -> Self {
1954
0
        Self {
1955
0
            mark1_coverage: mark1_coverage.into(),
1956
0
            mark2_coverage: mark2_coverage.into(),
1957
0
            mark1_array: mark1_array.into(),
1958
0
            mark2_array: mark2_array.into(),
1959
0
        }
1960
0
    }
1961
}
1962
1963
impl FontWrite for MarkMarkPosFormat1 {
1964
    #[allow(clippy::unnecessary_cast)]
1965
0
    fn write_into(&self, writer: &mut TableWriter) {
1966
0
        (1 as u16).write_into(writer);
1967
0
        self.mark1_coverage.write_into(writer);
1968
0
        self.mark2_coverage.write_into(writer);
1969
0
        (self.compute_mark_class_count() as u16).write_into(writer);
1970
0
        self.mark1_array.write_into(writer);
1971
0
        self.mark2_array.write_into(writer);
1972
0
    }
1973
0
    fn table_type(&self) -> TableType {
1974
0
        TableType::Named("MarkMarkPosFormat1")
1975
0
    }
1976
}
1977
1978
impl Validate for MarkMarkPosFormat1 {
1979
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1980
0
        ctx.in_table("MarkMarkPosFormat1", |ctx| {
1981
0
            ctx.in_field("mark1_coverage", |ctx| {
1982
0
                self.mark1_coverage.validate_impl(ctx);
1983
0
            });
1984
0
            ctx.in_field("mark2_coverage", |ctx| {
1985
0
                self.mark2_coverage.validate_impl(ctx);
1986
0
            });
1987
0
            ctx.in_field("mark1_array", |ctx| {
1988
0
                self.mark1_array.validate_impl(ctx);
1989
0
            });
1990
0
            ctx.in_field("mark2_array", |ctx| {
1991
0
                self.mark2_array.validate_impl(ctx);
1992
0
            });
1993
0
        })
1994
0
    }
1995
}
1996
1997
impl<'a> FromObjRef<read_fonts::tables::gpos::MarkMarkPosFormat1<'a>> for MarkMarkPosFormat1 {
1998
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkMarkPosFormat1<'a>, _: FontData) -> Self {
1999
0
        MarkMarkPosFormat1 {
2000
0
            mark1_coverage: obj.mark1_coverage().to_owned_table(),
2001
0
            mark2_coverage: obj.mark2_coverage().to_owned_table(),
2002
0
            mark1_array: obj.mark1_array().to_owned_table(),
2003
0
            mark2_array: obj.mark2_array().to_owned_table(),
2004
0
        }
2005
0
    }
2006
}
2007
2008
#[allow(clippy::needless_lifetimes)]
2009
impl<'a> FromTableRef<read_fonts::tables::gpos::MarkMarkPosFormat1<'a>> for MarkMarkPosFormat1 {}
2010
2011
impl<'a> FontRead<'a> for MarkMarkPosFormat1 {
2012
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2013
0
        <read_fonts::tables::gpos::MarkMarkPosFormat1 as FontRead>::read(data)
2014
0
            .map(|x| x.to_owned_table())
2015
0
    }
2016
}
2017
2018
/// Part of [MarkMarkPosFormat1]Class2Record
2019
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2020
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2021
pub struct Mark2Array {
2022
    /// Array of Mark2Records, in Coverage order.
2023
    pub mark2_records: Vec<Mark2Record>,
2024
}
2025
2026
impl Mark2Array {
2027
    /// Construct a new `Mark2Array`
2028
0
    pub fn new(mark2_records: Vec<Mark2Record>) -> Self {
2029
0
        Self { mark2_records }
2030
0
    }
2031
}
2032
2033
impl FontWrite for Mark2Array {
2034
    #[allow(clippy::unnecessary_cast)]
2035
0
    fn write_into(&self, writer: &mut TableWriter) {
2036
0
        (u16::try_from(array_len(&self.mark2_records)).unwrap()).write_into(writer);
2037
0
        self.mark2_records.write_into(writer);
2038
0
    }
2039
0
    fn table_type(&self) -> TableType {
2040
0
        TableType::Named("Mark2Array")
2041
0
    }
2042
}
2043
2044
impl Validate for Mark2Array {
2045
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2046
0
        ctx.in_table("Mark2Array", |ctx| {
2047
0
            ctx.in_field("mark2_records", |ctx| {
2048
0
                if self.mark2_records.len() > (u16::MAX as usize) {
2049
0
                    ctx.report("array exceeds max length");
2050
0
                }
2051
0
                self.mark2_records.validate_impl(ctx);
2052
0
            });
2053
0
        })
2054
0
    }
2055
}
2056
2057
impl<'a> FromObjRef<read_fonts::tables::gpos::Mark2Array<'a>> for Mark2Array {
2058
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::Mark2Array<'a>, _: FontData) -> Self {
2059
0
        let offset_data = obj.offset_data();
2060
        Mark2Array {
2061
0
            mark2_records: obj
2062
0
                .mark2_records()
2063
0
                .iter()
2064
0
                .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
2065
0
                .collect(),
2066
        }
2067
0
    }
2068
}
2069
2070
#[allow(clippy::needless_lifetimes)]
2071
impl<'a> FromTableRef<read_fonts::tables::gpos::Mark2Array<'a>> for Mark2Array {}
2072
2073
/// Part of [MarkMarkPosFormat1]
2074
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2075
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2076
pub struct Mark2Record {
2077
    /// Array of offsets (one per class) to Anchor tables. Offsets are
2078
    /// from beginning of Mark2Array table, in class order (offsets may
2079
    /// be NULL).
2080
    pub mark2_anchors: Vec<NullableOffsetMarker<AnchorTable>>,
2081
}
2082
2083
impl Mark2Record {
2084
    /// Construct a new `Mark2Record`
2085
0
    pub fn new(mark2_anchors: Vec<Option<AnchorTable>>) -> Self {
2086
0
        Self {
2087
0
            mark2_anchors: mark2_anchors.into_iter().map(Into::into).collect(),
2088
0
        }
2089
0
    }
2090
}
2091
2092
impl FontWrite for Mark2Record {
2093
0
    fn write_into(&self, writer: &mut TableWriter) {
2094
0
        self.mark2_anchors.write_into(writer);
2095
0
    }
2096
0
    fn table_type(&self) -> TableType {
2097
0
        TableType::Named("Mark2Record")
2098
0
    }
2099
}
2100
2101
impl Validate for Mark2Record {
2102
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2103
0
        ctx.in_table("Mark2Record", |ctx| {
2104
0
            ctx.in_field("mark2_anchors", |ctx| {
2105
0
                if self.mark2_anchors.len() > (u16::MAX as usize) {
2106
0
                    ctx.report("array exceeds max length");
2107
0
                }
2108
0
                self.mark2_anchors.validate_impl(ctx);
2109
0
            });
2110
0
        })
2111
0
    }
2112
}
2113
2114
impl FromObjRef<read_fonts::tables::gpos::Mark2Record<'_>> for Mark2Record {
2115
0
    fn from_obj_ref(obj: &read_fonts::tables::gpos::Mark2Record, offset_data: FontData) -> Self {
2116
0
        Mark2Record {
2117
0
            mark2_anchors: obj.mark2_anchors(offset_data).to_owned_table(),
2118
0
        }
2119
0
    }
2120
}
2121
2122
/// [Extension Positioning Subtable Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#extension-positioning-subtable-format-1)
2123
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2124
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2125
pub struct ExtensionPosFormat1<T> {
2126
    /// Lookup type of subtable referenced by extensionOffset (i.e. the
2127
    /// extension subtable).
2128
    pub extension_lookup_type: u16,
2129
    /// Offset to the extension subtable, of lookup type
2130
    /// extensionLookupType, relative to the start of the
2131
    /// ExtensionPosFormat1 subtable.
2132
    pub extension: OffsetMarker<T, WIDTH_32>,
2133
}
2134
2135
impl<T: Default> ExtensionPosFormat1<T> {
2136
    /// Construct a new `ExtensionPosFormat1`
2137
0
    pub fn new(extension_lookup_type: u16, extension: T) -> Self {
2138
0
        Self {
2139
0
            extension_lookup_type,
2140
0
            extension: extension.into(),
2141
0
        }
2142
0
    }
2143
}
2144
2145
impl<T: Validate> Validate for ExtensionPosFormat1<T> {
2146
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2147
0
        ctx.in_table("ExtensionPosFormat1", |ctx| {
2148
0
            ctx.in_field("extension", |ctx| {
2149
0
                self.extension.validate_impl(ctx);
2150
0
            });
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::CursivePosFormat1> as write_fonts::validate::Validate>::validate_impl::{closure#0}::{closure#0}
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::MarkLigPosFormat1> as write_fonts::validate::Validate>::validate_impl::{closure#0}::{closure#0}
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::MarkBasePosFormat1> as write_fonts::validate::Validate>::validate_impl::{closure#0}::{closure#0}
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::MarkMarkPosFormat1> as write_fonts::validate::Validate>::validate_impl::{closure#0}::{closure#0}
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::PositionChainContext> as write_fonts::validate::Validate>::validate_impl::{closure#0}::{closure#0}
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::PositionSequenceContext> as write_fonts::validate::Validate>::validate_impl::{closure#0}::{closure#0}
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::PairPos> as write_fonts::validate::Validate>::validate_impl::{closure#0}::{closure#0}
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::SinglePos> as write_fonts::validate::Validate>::validate_impl::{closure#0}::{closure#0}
2151
0
        })
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::CursivePosFormat1> as write_fonts::validate::Validate>::validate_impl::{closure#0}
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::MarkLigPosFormat1> as write_fonts::validate::Validate>::validate_impl::{closure#0}
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::MarkBasePosFormat1> as write_fonts::validate::Validate>::validate_impl::{closure#0}
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::MarkMarkPosFormat1> as write_fonts::validate::Validate>::validate_impl::{closure#0}
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::PositionChainContext> as write_fonts::validate::Validate>::validate_impl::{closure#0}
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::PositionSequenceContext> as write_fonts::validate::Validate>::validate_impl::{closure#0}
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::PairPos> as write_fonts::validate::Validate>::validate_impl::{closure#0}
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::SinglePos> as write_fonts::validate::Validate>::validate_impl::{closure#0}
2152
0
    }
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::CursivePosFormat1> as write_fonts::validate::Validate>::validate_impl
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::MarkLigPosFormat1> as write_fonts::validate::Validate>::validate_impl
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::MarkBasePosFormat1> as write_fonts::validate::Validate>::validate_impl
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::MarkMarkPosFormat1> as write_fonts::validate::Validate>::validate_impl
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::PositionChainContext> as write_fonts::validate::Validate>::validate_impl
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::PositionSequenceContext> as write_fonts::validate::Validate>::validate_impl
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::PairPos> as write_fonts::validate::Validate>::validate_impl
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::SinglePos> as write_fonts::validate::Validate>::validate_impl
2153
}
2154
2155
impl<'a, T, U> FromObjRef<read_fonts::tables::gpos::ExtensionPosFormat1<'a, U>>
2156
    for ExtensionPosFormat1<T>
2157
where
2158
    U: FontRead<'a>,
2159
    T: FromTableRef<U> + Default + 'static,
2160
{
2161
0
    fn from_obj_ref(
2162
0
        obj: &read_fonts::tables::gpos::ExtensionPosFormat1<'a, U>,
2163
0
        _: FontData,
2164
0
    ) -> Self {
2165
0
        ExtensionPosFormat1 {
2166
0
            extension_lookup_type: obj.extension_lookup_type(),
2167
0
            extension: obj.extension().to_owned_table(),
2168
0
        }
2169
0
    }
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::CursivePosFormat1> as write_fonts::from_obj::FromObjRef<read_fonts::table_ref::TableRef<read_fonts::tables::gpos::ExtensionPosFormat1Marker<read_fonts::table_ref::TableRef<read_fonts::tables::gpos::CursivePosFormat1Marker>>>>>::from_obj_ref
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::MarkLigPosFormat1> as write_fonts::from_obj::FromObjRef<read_fonts::table_ref::TableRef<read_fonts::tables::gpos::ExtensionPosFormat1Marker<read_fonts::table_ref::TableRef<read_fonts::tables::gpos::MarkLigPosFormat1Marker>>>>>::from_obj_ref
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::MarkBasePosFormat1> as write_fonts::from_obj::FromObjRef<read_fonts::table_ref::TableRef<read_fonts::tables::gpos::ExtensionPosFormat1Marker<read_fonts::table_ref::TableRef<read_fonts::tables::gpos::MarkBasePosFormat1Marker>>>>>::from_obj_ref
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::MarkMarkPosFormat1> as write_fonts::from_obj::FromObjRef<read_fonts::table_ref::TableRef<read_fonts::tables::gpos::ExtensionPosFormat1Marker<read_fonts::table_ref::TableRef<read_fonts::tables::gpos::MarkMarkPosFormat1Marker>>>>>::from_obj_ref
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::PositionChainContext> as write_fonts::from_obj::FromObjRef<read_fonts::table_ref::TableRef<read_fonts::tables::gpos::ExtensionPosFormat1Marker<read_fonts::tables::layout::ChainedSequenceContext>>>>::from_obj_ref
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::PositionSequenceContext> as write_fonts::from_obj::FromObjRef<read_fonts::table_ref::TableRef<read_fonts::tables::gpos::ExtensionPosFormat1Marker<read_fonts::tables::layout::SequenceContext>>>>::from_obj_ref
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::PairPos> as write_fonts::from_obj::FromObjRef<read_fonts::table_ref::TableRef<read_fonts::tables::gpos::ExtensionPosFormat1Marker<read_fonts::tables::gpos::PairPos>>>>::from_obj_ref
Unexecuted instantiation: <write_fonts::tables::gpos::ExtensionPosFormat1<write_fonts::tables::gpos::SinglePos> as write_fonts::from_obj::FromObjRef<read_fonts::table_ref::TableRef<read_fonts::tables::gpos::ExtensionPosFormat1Marker<read_fonts::tables::gpos::SinglePos>>>>::from_obj_ref
2170
}
2171
2172
#[allow(clippy::needless_lifetimes)]
2173
impl<'a, T, U> FromTableRef<read_fonts::tables::gpos::ExtensionPosFormat1<'a, U>>
2174
    for ExtensionPosFormat1<T>
2175
where
2176
    U: FontRead<'a>,
2177
    T: FromTableRef<U> + Default + 'static,
2178
{
2179
}
2180
2181
/// A [GPOS Extension Positioning](https://learn.microsoft.com/en-us/typography/opentype/spec/gpos#lookuptype-9-extension-positioning) subtable
2182
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
2183
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2184
pub enum ExtensionSubtable {
2185
    Single(ExtensionPosFormat1<SinglePos>),
2186
    Pair(ExtensionPosFormat1<PairPos>),
2187
    Cursive(ExtensionPosFormat1<CursivePosFormat1>),
2188
    MarkToBase(ExtensionPosFormat1<MarkBasePosFormat1>),
2189
    MarkToLig(ExtensionPosFormat1<MarkLigPosFormat1>),
2190
    MarkToMark(ExtensionPosFormat1<MarkMarkPosFormat1>),
2191
    Contextual(ExtensionPosFormat1<PositionSequenceContext>),
2192
    ChainContextual(ExtensionPosFormat1<PositionChainContext>),
2193
}
2194
2195
impl Default for ExtensionSubtable {
2196
0
    fn default() -> Self {
2197
0
        Self::Single(Default::default())
2198
0
    }
2199
}
2200
2201
impl FontWrite for ExtensionSubtable {
2202
0
    fn write_into(&self, writer: &mut TableWriter) {
2203
0
        match self {
2204
0
            Self::Single(table) => table.write_into(writer),
2205
0
            Self::Pair(table) => table.write_into(writer),
2206
0
            Self::Cursive(table) => table.write_into(writer),
2207
0
            Self::MarkToBase(table) => table.write_into(writer),
2208
0
            Self::MarkToLig(table) => table.write_into(writer),
2209
0
            Self::MarkToMark(table) => table.write_into(writer),
2210
0
            Self::Contextual(table) => table.write_into(writer),
2211
0
            Self::ChainContextual(table) => table.write_into(writer),
2212
        }
2213
0
    }
2214
0
    fn table_type(&self) -> TableType {
2215
0
        match self {
2216
0
            Self::Single(table) => table.table_type(),
2217
0
            Self::Pair(table) => table.table_type(),
2218
0
            Self::Cursive(table) => table.table_type(),
2219
0
            Self::MarkToBase(table) => table.table_type(),
2220
0
            Self::MarkToLig(table) => table.table_type(),
2221
0
            Self::MarkToMark(table) => table.table_type(),
2222
0
            Self::Contextual(table) => table.table_type(),
2223
0
            Self::ChainContextual(table) => table.table_type(),
2224
        }
2225
0
    }
2226
}
2227
2228
impl Validate for ExtensionSubtable {
2229
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2230
0
        match self {
2231
0
            Self::Single(table) => table.validate_impl(ctx),
2232
0
            Self::Pair(table) => table.validate_impl(ctx),
2233
0
            Self::Cursive(table) => table.validate_impl(ctx),
2234
0
            Self::MarkToBase(table) => table.validate_impl(ctx),
2235
0
            Self::MarkToLig(table) => table.validate_impl(ctx),
2236
0
            Self::MarkToMark(table) => table.validate_impl(ctx),
2237
0
            Self::Contextual(table) => table.validate_impl(ctx),
2238
0
            Self::ChainContextual(table) => table.validate_impl(ctx),
2239
        }
2240
0
    }
2241
}
2242
2243
impl FromObjRef<read_fonts::tables::gpos::ExtensionSubtable<'_>> for ExtensionSubtable {
2244
0
    fn from_obj_ref(
2245
0
        from: &read_fonts::tables::gpos::ExtensionSubtable<'_>,
2246
0
        data: FontData,
2247
0
    ) -> Self {
2248
0
        match from {
2249
0
            read_fonts::tables::gpos::ExtensionSubtable::Single(table) => {
2250
0
                Self::Single(table.to_owned_obj(data))
2251
            }
2252
0
            read_fonts::tables::gpos::ExtensionSubtable::Pair(table) => {
2253
0
                Self::Pair(table.to_owned_obj(data))
2254
            }
2255
0
            read_fonts::tables::gpos::ExtensionSubtable::Cursive(table) => {
2256
0
                Self::Cursive(table.to_owned_obj(data))
2257
            }
2258
0
            read_fonts::tables::gpos::ExtensionSubtable::MarkToBase(table) => {
2259
0
                Self::MarkToBase(table.to_owned_obj(data))
2260
            }
2261
0
            read_fonts::tables::gpos::ExtensionSubtable::MarkToLig(table) => {
2262
0
                Self::MarkToLig(table.to_owned_obj(data))
2263
            }
2264
0
            read_fonts::tables::gpos::ExtensionSubtable::MarkToMark(table) => {
2265
0
                Self::MarkToMark(table.to_owned_obj(data))
2266
            }
2267
0
            read_fonts::tables::gpos::ExtensionSubtable::Contextual(table) => {
2268
0
                Self::Contextual(table.to_owned_obj(data))
2269
            }
2270
0
            read_fonts::tables::gpos::ExtensionSubtable::ChainContextual(table) => {
2271
0
                Self::ChainContextual(table.to_owned_obj(data))
2272
            }
2273
        }
2274
0
    }
2275
}
2276
2277
impl FromTableRef<read_fonts::tables::gpos::ExtensionSubtable<'_>> for ExtensionSubtable {}
2278
2279
impl From<ExtensionPosFormat1<SinglePos>> for ExtensionSubtable {
2280
0
    fn from(src: ExtensionPosFormat1<SinglePos>) -> ExtensionSubtable {
2281
0
        ExtensionSubtable::Single(src)
2282
0
    }
2283
}
2284
2285
impl From<ExtensionPosFormat1<PairPos>> for ExtensionSubtable {
2286
0
    fn from(src: ExtensionPosFormat1<PairPos>) -> ExtensionSubtable {
2287
0
        ExtensionSubtable::Pair(src)
2288
0
    }
2289
}
2290
2291
impl From<ExtensionPosFormat1<CursivePosFormat1>> for ExtensionSubtable {
2292
0
    fn from(src: ExtensionPosFormat1<CursivePosFormat1>) -> ExtensionSubtable {
2293
0
        ExtensionSubtable::Cursive(src)
2294
0
    }
2295
}
2296
2297
impl From<ExtensionPosFormat1<MarkBasePosFormat1>> for ExtensionSubtable {
2298
0
    fn from(src: ExtensionPosFormat1<MarkBasePosFormat1>) -> ExtensionSubtable {
2299
0
        ExtensionSubtable::MarkToBase(src)
2300
0
    }
2301
}
2302
2303
impl From<ExtensionPosFormat1<MarkLigPosFormat1>> for ExtensionSubtable {
2304
0
    fn from(src: ExtensionPosFormat1<MarkLigPosFormat1>) -> ExtensionSubtable {
2305
0
        ExtensionSubtable::MarkToLig(src)
2306
0
    }
2307
}
2308
2309
impl From<ExtensionPosFormat1<MarkMarkPosFormat1>> for ExtensionSubtable {
2310
0
    fn from(src: ExtensionPosFormat1<MarkMarkPosFormat1>) -> ExtensionSubtable {
2311
0
        ExtensionSubtable::MarkToMark(src)
2312
0
    }
2313
}
2314
2315
impl From<ExtensionPosFormat1<PositionSequenceContext>> for ExtensionSubtable {
2316
0
    fn from(src: ExtensionPosFormat1<PositionSequenceContext>) -> ExtensionSubtable {
2317
0
        ExtensionSubtable::Contextual(src)
2318
0
    }
2319
}
2320
2321
impl From<ExtensionPosFormat1<PositionChainContext>> for ExtensionSubtable {
2322
0
    fn from(src: ExtensionPosFormat1<PositionChainContext>) -> ExtensionSubtable {
2323
0
        ExtensionSubtable::ChainContextual(src)
2324
0
    }
2325
}