Coverage Report

Created: 2026-10-28 07:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fontations/write-fonts/generated/generated_ift.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::ift::{
9
    EntryFormatFlags, GlyphKeyedFlags, PatchMapFieldPresenceFlags, TablePatchFlags,
10
};
11
12
impl FontWrite for PatchMapFieldPresenceFlags {
13
0
    fn write_into(&self, writer: &mut TableWriter) {
14
0
        writer.write_slice(&self.bits().to_be_bytes())
15
0
    }
16
}
17
18
/// [Patch Map Table](https://w3c.github.io/IFT/Overview.html#patch-map-table)
19
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
20
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21
pub struct IftPatchMap {
22
    /// Format identifier: format = 2
23
    pub format: u8,
24
    pub field_flags: PatchMapFieldPresenceFlags,
25
    /// Unique ID that identifies compatible patches.
26
    pub compatibility_id: CompatibilityId,
27
    /// Patch format number for patches referenced by this mapping.
28
    pub default_patch_format: u8,
29
    pub entry_count: Uint24,
30
    pub entries: OffsetMarker<MappingEntries, WIDTH_32>,
31
    pub entry_id_string_data: NullableOffsetMarker<IdStringData, WIDTH_32>,
32
    pub url_template_length: u16,
33
    pub url_template: Vec<u8>,
34
    pub cff_charstrings_offset: Option<u32>,
35
    pub cff2_charstrings_offset: Option<u32>,
36
}
37
38
impl IftPatchMap {
39
    /// Construct a new `IftPatchMap`
40
    #[allow(clippy::too_many_arguments)]
41
0
    pub fn new(
42
0
        format: u8,
43
0
        field_flags: PatchMapFieldPresenceFlags,
44
0
        compatibility_id: CompatibilityId,
45
0
        default_patch_format: u8,
46
0
        entry_count: Uint24,
47
0
        entries: MappingEntries,
48
0
        entry_id_string_data: Option<IdStringData>,
49
0
        url_template_length: u16,
50
0
        url_template: Vec<u8>,
51
0
    ) -> Self {
52
0
        Self {
53
0
            format,
54
0
            field_flags,
55
0
            compatibility_id,
56
0
            default_patch_format,
57
0
            entry_count,
58
0
            entries: entries.into(),
59
0
            entry_id_string_data: entry_id_string_data.into(),
60
0
            url_template_length,
61
0
            url_template,
62
0
            ..Default::default()
63
0
        }
64
0
    }
65
}
66
67
impl FontWrite for IftPatchMap {
68
    #[allow(clippy::unnecessary_cast)]
69
0
    fn write_into(&self, writer: &mut TableWriter) {
70
0
        self.format.write_into(writer);
71
0
        (0 as u8).write_into(writer);
72
0
        (0 as u8).write_into(writer);
73
0
        (0 as u8).write_into(writer);
74
0
        self.field_flags.write_into(writer);
75
0
        self.compatibility_id.write_into(writer);
76
0
        self.default_patch_format.write_into(writer);
77
0
        self.entry_count.write_into(writer);
78
0
        self.entries.write_into(writer);
79
0
        self.entry_id_string_data.write_into(writer);
80
0
        self.url_template_length.write_into(writer);
81
0
        self.url_template.write_into(writer);
82
0
        self.field_flags
83
0
            .contains(PatchMapFieldPresenceFlags::CFF_CHARSTRINGS_OFFSET)
84
0
            .then(|| {
85
0
                self.cff_charstrings_offset
86
0
                    .as_ref()
87
0
                    .expect("missing conditional field should have failed validation")
88
0
                    .write_into(writer)
89
0
            });
90
0
        self.field_flags
91
0
            .contains(PatchMapFieldPresenceFlags::CFF2_CHARSTRINGS_OFFSET)
92
0
            .then(|| {
93
0
                self.cff2_charstrings_offset
94
0
                    .as_ref()
95
0
                    .expect("missing conditional field should have failed validation")
96
0
                    .write_into(writer)
97
0
            });
98
0
    }
99
0
    fn table_type(&self) -> TableType {
100
0
        TableType::Named("IftPatchMap")
101
0
    }
102
}
103
104
impl Validate for IftPatchMap {
105
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
106
0
        ctx.in_table("IftPatchMap", |ctx| {
107
0
            ctx.in_field("entries", |ctx| {
108
0
                self.entries.validate_impl(ctx);
109
0
            });
110
0
            ctx.in_field("entry_id_string_data", |ctx| {
111
0
                self.entry_id_string_data.validate_impl(ctx);
112
0
            });
113
0
            ctx.in_field("url_template", |ctx| {
114
0
                if self.url_template.len() > to_usize(u16::MAX) {
115
0
                    ctx.report("array exceeds max length");
116
0
                }
117
0
            });
118
0
            ctx.in_field("cff_charstrings_offset", |ctx| {
119
0
                if !(self
120
0
                    .field_flags
121
0
                    .contains(PatchMapFieldPresenceFlags::CFF_CHARSTRINGS_OFFSET))
122
0
                    && self.cff_charstrings_offset.is_some()
123
                {
124
0
                    ctx.report(
125
                        "'cff_charstrings_offset' is present but CFF_CHARSTRINGS_OFFSET not set",
126
                    )
127
0
                }
128
0
                if (self
129
0
                    .field_flags
130
0
                    .contains(PatchMapFieldPresenceFlags::CFF_CHARSTRINGS_OFFSET))
131
0
                    && self.cff_charstrings_offset.is_none()
132
                {
133
0
                    ctx.report("CFF_CHARSTRINGS_OFFSET is set but 'cff_charstrings_offset' is None")
134
0
                }
135
0
            });
136
0
            ctx.in_field("cff2_charstrings_offset", |ctx| {
137
0
                if !(self
138
0
                    .field_flags
139
0
                    .contains(PatchMapFieldPresenceFlags::CFF2_CHARSTRINGS_OFFSET))
140
0
                    && self.cff2_charstrings_offset.is_some()
141
                {
142
0
                    ctx.report(
143
                        "'cff2_charstrings_offset' is present but CFF2_CHARSTRINGS_OFFSET not set",
144
                    )
145
0
                }
146
0
                if (self
147
0
                    .field_flags
148
0
                    .contains(PatchMapFieldPresenceFlags::CFF2_CHARSTRINGS_OFFSET))
149
0
                    && self.cff2_charstrings_offset.is_none()
150
                {
151
0
                    ctx.report(
152
                        "CFF2_CHARSTRINGS_OFFSET is set but 'cff2_charstrings_offset' is None",
153
                    )
154
0
                }
155
0
            });
156
0
        })
157
0
    }
158
}
159
160
impl<'a> FromObjRef<read_fonts::tables::ift::IftPatchMap<'a>> for IftPatchMap {
161
0
    fn from_obj_ref(obj: &read_fonts::tables::ift::IftPatchMap<'a>, _: FontData) -> Self {
162
0
        let offset_data = obj.offset_data();
163
0
        IftPatchMap {
164
0
            format: obj.format(),
165
0
            field_flags: obj.field_flags(),
166
0
            compatibility_id: obj.compatibility_id(),
167
0
            default_patch_format: obj.default_patch_format(),
168
0
            entry_count: obj.entry_count(),
169
0
            entries: obj.entries().to_owned_table(),
170
0
            entry_id_string_data: obj.entry_id_string_data().to_owned_table(),
171
0
            url_template_length: obj.url_template_length(),
172
0
            url_template: obj.url_template().to_owned_obj(offset_data),
173
0
            cff_charstrings_offset: obj.cff_charstrings_offset(),
174
0
            cff2_charstrings_offset: obj.cff2_charstrings_offset(),
175
0
        }
176
0
    }
177
}
178
179
#[allow(clippy::needless_lifetimes)]
180
impl<'a> FromTableRef<read_fonts::tables::ift::IftPatchMap<'a>> for IftPatchMap {}
181
182
impl ReadArgs for IftPatchMap {
183
    type Args = ();
184
}
185
186
impl<'a> FontRead<'a> for IftPatchMap {
187
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
188
0
        <read_fonts::tables::ift::IftPatchMap as FontRead>::read(data).map(|x| x.to_owned_table())
189
0
    }
190
}
191
192
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
193
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
194
pub struct MappingEntries {
195
    pub entry_data: Vec<u8>,
196
}
197
198
impl MappingEntries {
199
    /// Construct a new `MappingEntries`
200
0
    pub fn new(entry_data: Vec<u8>) -> Self {
201
0
        Self { entry_data }
202
0
    }
203
}
204
205
impl FontWrite for MappingEntries {
206
0
    fn write_into(&self, writer: &mut TableWriter) {
207
0
        self.entry_data.write_into(writer);
208
0
    }
209
0
    fn table_type(&self) -> TableType {
210
0
        TableType::Named("MappingEntries")
211
0
    }
212
}
213
214
impl Validate for MappingEntries {
215
0
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
216
}
217
218
impl<'a> FromObjRef<read_fonts::tables::ift::MappingEntries<'a>> for MappingEntries {
219
0
    fn from_obj_ref(obj: &read_fonts::tables::ift::MappingEntries<'a>, _: FontData) -> Self {
220
0
        let offset_data = obj.offset_data();
221
0
        MappingEntries {
222
0
            entry_data: obj.entry_data().to_owned_obj(offset_data),
223
0
        }
224
0
    }
225
}
226
227
#[allow(clippy::needless_lifetimes)]
228
impl<'a> FromTableRef<read_fonts::tables::ift::MappingEntries<'a>> for MappingEntries {}
229
230
impl ReadArgs for MappingEntries {
231
    type Args = ();
232
}
233
234
impl<'a> FontRead<'a> for MappingEntries {
235
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
236
0
        <read_fonts::tables::ift::MappingEntries as FontRead>::read(data)
237
0
            .map(|x| x.to_owned_table())
238
0
    }
239
}
240
241
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
242
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
243
pub struct EntryData {
244
    pub format_flags: EntryFormatFlags,
245
    pub feature_count: Option<u8>,
246
    pub feature_tags: Option<Vec<Tag>>,
247
    pub design_space_count: Option<u16>,
248
    pub design_space_segments: Option<Vec<DesignSpaceSegment>>,
249
    pub child_indices: Option<Vec<Uint24>>,
250
    pub trailing_data: Vec<u8>,
251
}
252
253
impl EntryData {
254
    /// Construct a new `EntryData`
255
0
    pub fn new(format_flags: EntryFormatFlags, trailing_data: Vec<u8>) -> Self {
256
0
        Self {
257
0
            format_flags,
258
0
            trailing_data,
259
0
            ..Default::default()
260
0
        }
261
0
    }
262
}
263
264
impl FontWrite for EntryData {
265
    #[allow(clippy::unnecessary_cast)]
266
0
    fn write_into(&self, writer: &mut TableWriter) {
267
0
        self.format_flags.write_into(writer);
268
0
        self.format_flags
269
0
            .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE)
270
0
            .then(|| {
271
0
                self.feature_count
272
0
                    .as_ref()
273
0
                    .expect("missing conditional field should have failed validation")
274
0
                    .write_into(writer)
275
0
            });
276
0
        self.format_flags
277
0
            .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE)
278
0
            .then(|| {
279
0
                self.feature_tags
280
0
                    .as_ref()
281
0
                    .expect("missing conditional field should have failed validation")
282
0
                    .write_into(writer)
283
0
            });
284
0
        self.format_flags
285
0
            .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE)
286
0
            .then(|| {
287
0
                self.design_space_count
288
0
                    .as_ref()
289
0
                    .expect("missing conditional field should have failed validation")
290
0
                    .write_into(writer)
291
0
            });
292
0
        self.format_flags
293
0
            .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE)
294
0
            .then(|| {
295
0
                self.design_space_segments
296
0
                    .as_ref()
297
0
                    .expect("missing conditional field should have failed validation")
298
0
                    .write_into(writer)
299
0
            });
300
0
        self.format_flags
301
0
            .contains(EntryFormatFlags::CHILD_INDICES)
302
0
            .then(|| {
303
0
                self.child_indices
304
0
                    .as_ref()
305
0
                    .expect("missing conditional field should have failed validation")
306
0
                    .write_into(writer)
307
0
            });
308
0
        self.trailing_data.write_into(writer);
309
0
    }
310
0
    fn table_type(&self) -> TableType {
311
0
        TableType::Named("EntryData")
312
0
    }
313
}
314
315
impl Validate for EntryData {
316
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
317
0
        ctx.in_table("EntryData", |ctx| {
318
0
            ctx.in_field("feature_count", |ctx| {
319
0
                if !(self
320
0
                    .format_flags
321
0
                    .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE))
322
0
                    && self.feature_count.is_some()
323
                {
324
0
                    ctx.report("'feature_count' is present but FEATURES_AND_DESIGN_SPACE not set")
325
0
                }
326
0
                if (self
327
0
                    .format_flags
328
0
                    .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE))
329
0
                    && self.feature_count.is_none()
330
                {
331
0
                    ctx.report("FEATURES_AND_DESIGN_SPACE is set but 'feature_count' is None")
332
0
                }
333
0
            });
334
0
            ctx.in_field("feature_tags", |ctx| {
335
0
                if !(self
336
0
                    .format_flags
337
0
                    .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE))
338
0
                    && self.feature_tags.is_some()
339
                {
340
0
                    ctx.report("'feature_tags' is present but FEATURES_AND_DESIGN_SPACE not set")
341
0
                }
342
0
                if (self
343
0
                    .format_flags
344
0
                    .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE))
345
0
                    && self.feature_tags.is_none()
346
                {
347
0
                    ctx.report("FEATURES_AND_DESIGN_SPACE is set but 'feature_tags' is None")
348
0
                }
349
0
                if self.feature_tags.is_some()
350
0
                    && self.feature_tags.as_ref().unwrap().len() > to_usize(u8::MAX)
351
0
                {
352
0
                    ctx.report("array exceeds max length");
353
0
                }
354
0
            });
355
0
            ctx.in_field("design_space_count", |ctx| {
356
0
                if !(self
357
0
                    .format_flags
358
0
                    .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE))
359
0
                    && self.design_space_count.is_some()
360
                {
361
0
                    ctx.report(
362
                        "'design_space_count' is present but FEATURES_AND_DESIGN_SPACE not set",
363
                    )
364
0
                }
365
0
                if (self
366
0
                    .format_flags
367
0
                    .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE))
368
0
                    && self.design_space_count.is_none()
369
                {
370
0
                    ctx.report("FEATURES_AND_DESIGN_SPACE is set but 'design_space_count' is None")
371
0
                }
372
0
            });
373
0
            ctx.in_field("design_space_segments", |ctx| {
374
0
                if !(self
375
0
                    .format_flags
376
0
                    .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE))
377
0
                    && self.design_space_segments.is_some()
378
                {
379
0
                    ctx.report(
380
                        "'design_space_segments' is present but FEATURES_AND_DESIGN_SPACE not set",
381
                    )
382
0
                }
383
0
                if (self
384
0
                    .format_flags
385
0
                    .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE))
386
0
                    && self.design_space_segments.is_none()
387
                {
388
0
                    ctx.report(
389
                        "FEATURES_AND_DESIGN_SPACE is set but 'design_space_segments' is None",
390
                    )
391
0
                }
392
0
                if self.design_space_segments.is_some()
393
0
                    && self.design_space_segments.as_ref().unwrap().len() > to_usize(u16::MAX)
394
0
                {
395
0
                    ctx.report("array exceeds max length");
396
0
                }
397
0
                self.design_space_segments.validate_impl(ctx);
398
0
            });
399
0
            ctx.in_field("child_indices", |ctx| {
400
0
                if !(self.format_flags.contains(EntryFormatFlags::CHILD_INDICES))
401
0
                    && self.child_indices.is_some()
402
                {
403
0
                    ctx.report("'child_indices' is present but CHILD_INDICES not set")
404
0
                }
405
0
                if (self.format_flags.contains(EntryFormatFlags::CHILD_INDICES))
406
0
                    && self.child_indices.is_none()
407
                {
408
0
                    ctx.report("CHILD_INDICES is set but 'child_indices' is None")
409
0
                }
410
0
            });
411
0
        })
412
0
    }
413
}
414
415
impl<'a> FromObjRef<read_fonts::tables::ift::EntryData<'a>> for EntryData {
416
0
    fn from_obj_ref(obj: &read_fonts::tables::ift::EntryData<'a>, _: FontData) -> Self {
417
0
        let offset_data = obj.offset_data();
418
0
        EntryData {
419
0
            format_flags: obj.format_flags(),
420
0
            feature_count: obj.feature_count(),
421
0
            feature_tags: obj.feature_tags().to_owned_obj(offset_data),
422
0
            design_space_count: obj.design_space_count(),
423
0
            design_space_segments: obj.design_space_segments().to_owned_obj(offset_data),
424
0
            child_indices: obj.child_indices().to_owned_obj(offset_data),
425
0
            trailing_data: obj.trailing_data().to_owned_obj(offset_data),
426
0
        }
427
0
    }
428
}
429
430
#[allow(clippy::needless_lifetimes)]
431
impl<'a> FromTableRef<read_fonts::tables::ift::EntryData<'a>> for EntryData {}
432
433
impl ReadArgs for EntryData {
434
    type Args = ();
435
}
436
437
impl<'a> FontRead<'a> for EntryData {
438
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
439
0
        <read_fonts::tables::ift::EntryData as FontRead>::read(data).map(|x| x.to_owned_table())
440
0
    }
441
}
442
443
impl FontWrite for EntryFormatFlags {
444
0
    fn write_into(&self, writer: &mut TableWriter) {
445
0
        writer.write_slice(&self.bits().to_be_bytes())
446
0
    }
447
}
448
449
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
450
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
451
pub struct DesignSpaceSegment {
452
    pub axis_tag: Tag,
453
    pub start: Fixed,
454
    pub end: Fixed,
455
}
456
457
impl DesignSpaceSegment {
458
    /// Construct a new `DesignSpaceSegment`
459
0
    pub fn new(axis_tag: Tag, start: Fixed, end: Fixed) -> Self {
460
0
        Self {
461
0
            axis_tag,
462
0
            start,
463
0
            end,
464
0
        }
465
0
    }
466
}
467
468
impl FontWrite for DesignSpaceSegment {
469
0
    fn write_into(&self, writer: &mut TableWriter) {
470
0
        self.axis_tag.write_into(writer);
471
0
        self.start.write_into(writer);
472
0
        self.end.write_into(writer);
473
0
    }
474
0
    fn table_type(&self) -> TableType {
475
0
        TableType::Named("DesignSpaceSegment")
476
0
    }
477
}
478
479
impl Validate for DesignSpaceSegment {
480
0
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
481
}
482
483
impl FromObjRef<read_fonts::tables::ift::DesignSpaceSegment> for DesignSpaceSegment {
484
0
    fn from_obj_ref(obj: &read_fonts::tables::ift::DesignSpaceSegment, _: FontData) -> Self {
485
0
        DesignSpaceSegment {
486
0
            axis_tag: obj.axis_tag(),
487
0
            start: obj.start(),
488
0
            end: obj.end(),
489
0
        }
490
0
    }
491
}
492
493
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
494
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
495
pub struct IdStringData {
496
    pub id_data: Vec<u8>,
497
}
498
499
impl IdStringData {
500
    /// Construct a new `IdStringData`
501
0
    pub fn new(id_data: Vec<u8>) -> Self {
502
0
        Self { id_data }
503
0
    }
504
}
505
506
impl FontWrite for IdStringData {
507
0
    fn write_into(&self, writer: &mut TableWriter) {
508
0
        self.id_data.write_into(writer);
509
0
    }
510
0
    fn table_type(&self) -> TableType {
511
0
        TableType::Named("IdStringData")
512
0
    }
513
}
514
515
impl Validate for IdStringData {
516
0
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
517
}
518
519
impl<'a> FromObjRef<read_fonts::tables::ift::IdStringData<'a>> for IdStringData {
520
0
    fn from_obj_ref(obj: &read_fonts::tables::ift::IdStringData<'a>, _: FontData) -> Self {
521
0
        let offset_data = obj.offset_data();
522
0
        IdStringData {
523
0
            id_data: obj.id_data().to_owned_obj(offset_data),
524
0
        }
525
0
    }
526
}
527
528
#[allow(clippy::needless_lifetimes)]
529
impl<'a> FromTableRef<read_fonts::tables::ift::IdStringData<'a>> for IdStringData {}
530
531
impl ReadArgs for IdStringData {
532
    type Args = ();
533
}
534
535
impl<'a> FontRead<'a> for IdStringData {
536
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
537
0
        <read_fonts::tables::ift::IdStringData as FontRead>::read(data).map(|x| x.to_owned_table())
538
0
    }
539
}
540
541
/// [Table Keyed Patch](https://w3c.github.io/IFT/Overview.html#table-keyed)
542
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
543
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
544
pub struct TableKeyedPatch {
545
    pub format: Tag,
546
    /// Unique ID that identifies compatible patches.
547
    pub compatibility_id: CompatibilityId,
548
    pub patches_count: u16,
549
    pub patches: Vec<OffsetMarker<TablePatch, WIDTH_32>>,
550
}
551
552
impl TableKeyedPatch {
553
    /// Construct a new `TableKeyedPatch`
554
0
    pub fn new(
555
0
        format: Tag,
556
0
        compatibility_id: CompatibilityId,
557
0
        patches_count: u16,
558
0
        patches: Vec<TablePatch>,
559
0
    ) -> Self {
560
0
        Self {
561
0
            format,
562
0
            compatibility_id,
563
0
            patches_count,
564
0
            patches: patches.into_iter().map(Into::into).collect(),
565
0
        }
566
0
    }
567
}
568
569
impl FontWrite for TableKeyedPatch {
570
    #[allow(clippy::unnecessary_cast)]
571
0
    fn write_into(&self, writer: &mut TableWriter) {
572
0
        self.format.write_into(writer);
573
0
        (0 as u32).write_into(writer);
574
0
        self.compatibility_id.write_into(writer);
575
0
        self.patches_count.write_into(writer);
576
0
        self.patches.write_into(writer);
577
0
    }
578
0
    fn table_type(&self) -> TableType {
579
0
        TableType::Named("TableKeyedPatch")
580
0
    }
581
}
582
583
impl Validate for TableKeyedPatch {
584
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
585
0
        ctx.in_table("TableKeyedPatch", |ctx| {
586
0
            ctx.in_field("patches", |ctx| {
587
0
                self.patches.validate_impl(ctx);
588
0
            });
589
0
        })
590
0
    }
591
}
592
593
impl<'a> FromObjRef<read_fonts::tables::ift::TableKeyedPatch<'a>> for TableKeyedPatch {
594
0
    fn from_obj_ref(obj: &read_fonts::tables::ift::TableKeyedPatch<'a>, _: FontData) -> Self {
595
0
        TableKeyedPatch {
596
0
            format: obj.format(),
597
0
            compatibility_id: obj.compatibility_id(),
598
0
            patches_count: obj.patches_count(),
599
0
            patches: obj.patches().to_owned_table(),
600
0
        }
601
0
    }
602
}
603
604
#[allow(clippy::needless_lifetimes)]
605
impl<'a> FromTableRef<read_fonts::tables::ift::TableKeyedPatch<'a>> for TableKeyedPatch {}
606
607
impl ReadArgs for TableKeyedPatch {
608
    type Args = ();
609
}
610
611
impl<'a> FontRead<'a> for TableKeyedPatch {
612
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
613
0
        <read_fonts::tables::ift::TableKeyedPatch as FontRead>::read(data)
614
0
            .map(|x| x.to_owned_table())
615
0
    }
616
}
617
618
/// [TablePatch](https://w3c.github.io/IFT/Overview.html#tablepatch)
619
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
620
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
621
pub struct TablePatch {
622
    pub tag: Tag,
623
    pub flags: TablePatchFlags,
624
    pub max_uncompressed_length: u32,
625
    pub brotli_stream: Vec<u8>,
626
}
627
628
impl TablePatch {
629
    /// Construct a new `TablePatch`
630
0
    pub fn new(
631
0
        tag: Tag,
632
0
        flags: TablePatchFlags,
633
0
        max_uncompressed_length: u32,
634
0
        brotli_stream: Vec<u8>,
635
0
    ) -> Self {
636
0
        Self {
637
0
            tag,
638
0
            flags,
639
0
            max_uncompressed_length,
640
0
            brotli_stream,
641
0
        }
642
0
    }
643
}
644
645
impl FontWrite for TablePatch {
646
0
    fn write_into(&self, writer: &mut TableWriter) {
647
0
        self.tag.write_into(writer);
648
0
        self.flags.write_into(writer);
649
0
        self.max_uncompressed_length.write_into(writer);
650
0
        self.brotli_stream.write_into(writer);
651
0
    }
652
0
    fn table_type(&self) -> TableType {
653
0
        TableType::Named("TablePatch")
654
0
    }
655
}
656
657
impl Validate for TablePatch {
658
0
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
659
}
660
661
impl<'a> FromObjRef<read_fonts::tables::ift::TablePatch<'a>> for TablePatch {
662
0
    fn from_obj_ref(obj: &read_fonts::tables::ift::TablePatch<'a>, _: FontData) -> Self {
663
0
        let offset_data = obj.offset_data();
664
0
        TablePatch {
665
0
            tag: obj.tag(),
666
0
            flags: obj.flags(),
667
0
            max_uncompressed_length: obj.max_uncompressed_length(),
668
0
            brotli_stream: obj.brotli_stream().to_owned_obj(offset_data),
669
0
        }
670
0
    }
671
}
672
673
#[allow(clippy::needless_lifetimes)]
674
impl<'a> FromTableRef<read_fonts::tables::ift::TablePatch<'a>> for TablePatch {}
675
676
impl ReadArgs for TablePatch {
677
    type Args = ();
678
}
679
680
impl<'a> FontRead<'a> for TablePatch {
681
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
682
0
        <read_fonts::tables::ift::TablePatch as FontRead>::read(data).map(|x| x.to_owned_table())
683
0
    }
684
}
685
686
impl FontWrite for TablePatchFlags {
687
0
    fn write_into(&self, writer: &mut TableWriter) {
688
0
        writer.write_slice(&self.bits().to_be_bytes())
689
0
    }
690
}
691
692
/// [Glyph Keyed Patch](https://w3c.github.io/IFT/Overview.html#glyph-keyed)
693
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
694
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
695
pub struct GlyphKeyedPatch {
696
    pub format: Tag,
697
    pub flags: GlyphKeyedFlags,
698
    pub compatibility_id: CompatibilityId,
699
    pub max_uncompressed_length: u32,
700
    pub brotli_stream: Vec<u8>,
701
}
702
703
impl GlyphKeyedPatch {
704
    /// Construct a new `GlyphKeyedPatch`
705
0
    pub fn new(
706
0
        format: Tag,
707
0
        flags: GlyphKeyedFlags,
708
0
        compatibility_id: CompatibilityId,
709
0
        max_uncompressed_length: u32,
710
0
        brotli_stream: Vec<u8>,
711
0
    ) -> Self {
712
0
        Self {
713
0
            format,
714
0
            flags,
715
0
            compatibility_id,
716
0
            max_uncompressed_length,
717
0
            brotli_stream,
718
0
        }
719
0
    }
720
}
721
722
impl FontWrite for GlyphKeyedPatch {
723
    #[allow(clippy::unnecessary_cast)]
724
0
    fn write_into(&self, writer: &mut TableWriter) {
725
0
        self.format.write_into(writer);
726
0
        (0 as u32).write_into(writer);
727
0
        self.flags.write_into(writer);
728
0
        self.compatibility_id.write_into(writer);
729
0
        self.max_uncompressed_length.write_into(writer);
730
0
        self.brotli_stream.write_into(writer);
731
0
    }
732
0
    fn table_type(&self) -> TableType {
733
0
        TableType::Named("GlyphKeyedPatch")
734
0
    }
735
}
736
737
impl Validate for GlyphKeyedPatch {
738
0
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
739
}
740
741
impl<'a> FromObjRef<read_fonts::tables::ift::GlyphKeyedPatch<'a>> for GlyphKeyedPatch {
742
0
    fn from_obj_ref(obj: &read_fonts::tables::ift::GlyphKeyedPatch<'a>, _: FontData) -> Self {
743
0
        let offset_data = obj.offset_data();
744
0
        GlyphKeyedPatch {
745
0
            format: obj.format(),
746
0
            flags: obj.flags(),
747
0
            compatibility_id: obj.compatibility_id(),
748
0
            max_uncompressed_length: obj.max_uncompressed_length(),
749
0
            brotli_stream: obj.brotli_stream().to_owned_obj(offset_data),
750
0
        }
751
0
    }
752
}
753
754
#[allow(clippy::needless_lifetimes)]
755
impl<'a> FromTableRef<read_fonts::tables::ift::GlyphKeyedPatch<'a>> for GlyphKeyedPatch {}
756
757
impl ReadArgs for GlyphKeyedPatch {
758
    type Args = ();
759
}
760
761
impl<'a> FontRead<'a> for GlyphKeyedPatch {
762
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
763
0
        <read_fonts::tables::ift::GlyphKeyedPatch as FontRead>::read(data)
764
0
            .map(|x| x.to_owned_table())
765
0
    }
766
}
767
768
impl FontWrite for GlyphKeyedFlags {
769
0
    fn write_into(&self, writer: &mut TableWriter) {
770
0
        writer.write_slice(&self.bits().to_be_bytes())
771
0
    }
772
}
773
774
/// [GlyphPatches](https://w3c.github.io/IFT/Overview.html#glyphpatches)
775
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
776
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
777
pub struct GlyphPatches {
778
    pub glyph_count: u32,
779
    pub table_count: u8,
780
    pub tables: Vec<Tag>,
781
    pub glyph_data: Vec<OffsetMarker<GlyphData, WIDTH_32>>,
782
}
783
784
impl GlyphPatches {
785
    /// Construct a new `GlyphPatches`
786
0
    pub fn new(
787
0
        glyph_count: u32,
788
0
        table_count: u8,
789
0
        tables: Vec<Tag>,
790
0
        glyph_data: Vec<GlyphData>,
791
0
    ) -> Self {
792
0
        Self {
793
0
            glyph_count,
794
0
            table_count,
795
0
            tables,
796
0
            glyph_data: glyph_data.into_iter().map(Into::into).collect(),
797
0
        }
798
0
    }
799
}
800
801
impl FontWrite for GlyphPatches {
802
    #[allow(clippy::unnecessary_cast)]
803
0
    fn write_into(&self, writer: &mut TableWriter) {
804
0
        self.glyph_count.write_into(writer);
805
0
        self.table_count.write_into(writer);
806
0
        self.tables.write_into(writer);
807
0
        self.glyph_data.write_into(writer);
808
0
    }
809
0
    fn table_type(&self) -> TableType {
810
0
        TableType::Named("GlyphPatches")
811
0
    }
812
}
813
814
impl Validate for GlyphPatches {
815
0
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
816
0
        ctx.in_table("GlyphPatches", |ctx| {
817
0
            ctx.in_field("tables", |ctx| {
818
0
                if self.tables.len() > to_usize(u8::MAX) {
819
0
                    ctx.report("array exceeds max length");
820
0
                }
821
0
            });
822
0
            ctx.in_field("glyph_data", |ctx| {
823
0
                self.glyph_data.validate_impl(ctx);
824
0
            });
825
0
        })
826
0
    }
827
}
828
829
impl<'a> FromObjRef<read_fonts::tables::ift::GlyphPatches<'a>> for GlyphPatches {
830
0
    fn from_obj_ref(obj: &read_fonts::tables::ift::GlyphPatches<'a>, _: FontData) -> Self {
831
0
        let offset_data = obj.offset_data();
832
0
        GlyphPatches {
833
0
            glyph_count: obj.glyph_count(),
834
0
            table_count: obj.table_count(),
835
0
            tables: obj.tables().to_owned_obj(offset_data),
836
0
            glyph_data: obj.glyph_data().to_owned_table(),
837
0
        }
838
0
    }
839
}
840
841
#[allow(clippy::needless_lifetimes)]
842
impl<'a> FromTableRef<read_fonts::tables::ift::GlyphPatches<'a>> for GlyphPatches {}
843
844
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
845
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
846
pub struct GlyphData {
847
    pub data: Vec<u8>,
848
}
849
850
impl GlyphData {
851
    /// Construct a new `GlyphData`
852
0
    pub fn new(data: Vec<u8>) -> Self {
853
0
        Self { data }
854
0
    }
855
}
856
857
impl FontWrite for GlyphData {
858
0
    fn write_into(&self, writer: &mut TableWriter) {
859
0
        self.data.write_into(writer);
860
0
    }
861
0
    fn table_type(&self) -> TableType {
862
0
        TableType::Named("GlyphData")
863
0
    }
864
}
865
866
impl Validate for GlyphData {
867
0
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
868
}
869
870
impl<'a> FromObjRef<read_fonts::tables::ift::GlyphData<'a>> for GlyphData {
871
0
    fn from_obj_ref(obj: &read_fonts::tables::ift::GlyphData<'a>, _: FontData) -> Self {
872
0
        let offset_data = obj.offset_data();
873
0
        GlyphData {
874
0
            data: obj.data().to_owned_obj(offset_data),
875
0
        }
876
0
    }
877
}
878
879
#[allow(clippy::needless_lifetimes)]
880
impl<'a> FromTableRef<read_fonts::tables::ift::GlyphData<'a>> for GlyphData {}
881
882
impl ReadArgs for GlyphData {
883
    type Args = ();
884
}
885
886
impl<'a> FontRead<'a> for GlyphData {
887
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
888
0
        <read_fonts::tables::ift::GlyphData as FontRead>::read(data).map(|x| x.to_owned_table())
889
0
    }
890
}