1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8pub use read_fonts::tables::ift::{
9 EntryFormatFlags, GlyphKeyedFlags, PatchMapFieldPresenceFlags, TablePatchFlags,
10};
11
12#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub enum Ift {
15 Format1(PatchMapFormat1),
16 Format2(PatchMapFormat2),
17}
18
19impl Ift {
20 #[allow(clippy::too_many_arguments)]
22 pub fn format_1(
23 field_flags: PatchMapFieldPresenceFlags,
24 compatibility_id: CompatibilityId,
25 max_entry_index: u16,
26 max_glyph_map_entry_index: u16,
27 glyph_count: Uint24,
28 glyph_map: GlyphMap,
29 feature_map: Option<FeatureMap>,
30 applied_entries_bitmap: Vec<u8>,
31 url_template_length: u16,
32 url_template: Vec<u8>,
33 patch_format: u8,
34 ) -> Self {
35 Self::Format1(PatchMapFormat1::new(
36 field_flags,
37 compatibility_id,
38 max_entry_index,
39 max_glyph_map_entry_index,
40 glyph_count,
41 glyph_map,
42 feature_map,
43 applied_entries_bitmap,
44 url_template_length,
45 url_template,
46 patch_format,
47 ))
48 }
49
50 #[allow(clippy::too_many_arguments)]
52 pub fn format_2(
53 field_flags: PatchMapFieldPresenceFlags,
54 compatibility_id: CompatibilityId,
55 default_patch_format: u8,
56 entry_count: Uint24,
57 entries: MappingEntries,
58 entry_id_string_data: Option<IdStringData>,
59 url_template_length: u16,
60 url_template: Vec<u8>,
61 ) -> Self {
62 Self::Format2(PatchMapFormat2::new(
63 field_flags,
64 compatibility_id,
65 default_patch_format,
66 entry_count,
67 entries,
68 entry_id_string_data,
69 url_template_length,
70 url_template,
71 ))
72 }
73}
74
75impl Default for Ift {
76 fn default() -> Self {
77 Self::Format1(Default::default())
78 }
79}
80
81impl FontWrite for Ift {
82 fn write_into(&self, writer: &mut TableWriter) {
83 match self {
84 Self::Format1(item) => item.write_into(writer),
85 Self::Format2(item) => item.write_into(writer),
86 }
87 }
88 fn table_type(&self) -> TableType {
89 match self {
90 Self::Format1(item) => item.table_type(),
91 Self::Format2(item) => item.table_type(),
92 }
93 }
94}
95
96impl Validate for Ift {
97 fn validate_impl(&self, ctx: &mut ValidationCtx) {
98 match self {
99 Self::Format1(item) => item.validate_impl(ctx),
100 Self::Format2(item) => item.validate_impl(ctx),
101 }
102 }
103}
104
105impl FromObjRef<read_fonts::tables::ift::Ift<'_>> for Ift {
106 fn from_obj_ref(obj: &read_fonts::tables::ift::Ift, _: FontData) -> Self {
107 use read_fonts::tables::ift::Ift as ObjRefType;
108 match obj {
109 ObjRefType::Format1(item) => Ift::Format1(item.to_owned_table()),
110 ObjRefType::Format2(item) => Ift::Format2(item.to_owned_table()),
111 }
112 }
113}
114
115impl FromTableRef<read_fonts::tables::ift::Ift<'_>> for Ift {}
116
117impl<'a> FontRead<'a> for Ift {
118 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
119 <read_fonts::tables::ift::Ift as FontRead>::read(data).map(|x| x.to_owned_table())
120 }
121}
122
123impl From<PatchMapFormat1> for Ift {
124 fn from(src: PatchMapFormat1) -> Ift {
125 Ift::Format1(src)
126 }
127}
128
129impl From<PatchMapFormat2> for Ift {
130 fn from(src: PatchMapFormat2) -> Ift {
131 Ift::Format2(src)
132 }
133}
134
135impl FontWrite for PatchMapFieldPresenceFlags {
136 fn write_into(&self, writer: &mut TableWriter) {
137 writer.write_slice(&self.bits().to_be_bytes())
138 }
139}
140
141#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
143#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
144pub struct PatchMapFormat1 {
145 pub field_flags: PatchMapFieldPresenceFlags,
146 pub compatibility_id: CompatibilityId,
148 pub max_entry_index: u16,
150 pub max_glyph_map_entry_index: u16,
152 pub glyph_count: Uint24,
153 pub glyph_map: OffsetMarker<GlyphMap, WIDTH_32>,
155 pub feature_map: NullableOffsetMarker<FeatureMap, WIDTH_32>,
157 pub applied_entries_bitmap: Vec<u8>,
158 pub url_template_length: u16,
159 pub url_template: Vec<u8>,
160 pub patch_format: u8,
162 pub cff_charstrings_offset: Option<u32>,
163 pub cff2_charstrings_offset: Option<u32>,
164}
165
166impl PatchMapFormat1 {
167 #[allow(clippy::too_many_arguments)]
169 pub fn new(
170 field_flags: PatchMapFieldPresenceFlags,
171 compatibility_id: CompatibilityId,
172 max_entry_index: u16,
173 max_glyph_map_entry_index: u16,
174 glyph_count: Uint24,
175 glyph_map: GlyphMap,
176 feature_map: Option<FeatureMap>,
177 applied_entries_bitmap: Vec<u8>,
178 url_template_length: u16,
179 url_template: Vec<u8>,
180 patch_format: u8,
181 ) -> Self {
182 Self {
183 field_flags,
184 compatibility_id,
185 max_entry_index,
186 max_glyph_map_entry_index,
187 glyph_count,
188 glyph_map: glyph_map.into(),
189 feature_map: feature_map.into(),
190 applied_entries_bitmap,
191 url_template_length,
192 url_template,
193 patch_format,
194 ..Default::default()
195 }
196 }
197}
198
199impl FontWrite for PatchMapFormat1 {
200 #[allow(clippy::unnecessary_cast)]
201 fn write_into(&self, writer: &mut TableWriter) {
202 (1 as u8).write_into(writer);
203 (0 as u8).write_into(writer);
204 (0 as u8).write_into(writer);
205 (0 as u8).write_into(writer);
206 self.field_flags.write_into(writer);
207 self.compatibility_id.write_into(writer);
208 self.max_entry_index.write_into(writer);
209 self.max_glyph_map_entry_index.write_into(writer);
210 self.glyph_count.write_into(writer);
211 self.glyph_map.write_into(writer);
212 self.feature_map.write_into(writer);
213 self.applied_entries_bitmap.write_into(writer);
214 self.url_template_length.write_into(writer);
215 self.url_template.write_into(writer);
216 self.patch_format.write_into(writer);
217 self.field_flags
218 .contains(PatchMapFieldPresenceFlags::CFF_CHARSTRINGS_OFFSET)
219 .then(|| {
220 self.cff_charstrings_offset
221 .as_ref()
222 .expect("missing conditional field should have failed validation")
223 .write_into(writer)
224 });
225 self.field_flags
226 .contains(PatchMapFieldPresenceFlags::CFF2_CHARSTRINGS_OFFSET)
227 .then(|| {
228 self.cff2_charstrings_offset
229 .as_ref()
230 .expect("missing conditional field should have failed validation")
231 .write_into(writer)
232 });
233 }
234 fn table_type(&self) -> TableType {
235 TableType::Named("PatchMapFormat1")
236 }
237}
238
239impl Validate for PatchMapFormat1 {
240 fn validate_impl(&self, ctx: &mut ValidationCtx) {
241 ctx.in_table("PatchMapFormat1", |ctx| {
242 ctx.in_field("glyph_map", |ctx| {
243 self.glyph_map.validate_impl(ctx);
244 });
245 ctx.in_field("feature_map", |ctx| {
246 self.feature_map.validate_impl(ctx);
247 });
248 ctx.in_field("url_template", |ctx| {
249 if self.url_template.len() > (u16::MAX as usize) {
250 ctx.report("array exceeds max length");
251 }
252 });
253 ctx.in_field("cff_charstrings_offset", |ctx| {
254 if !(self
255 .field_flags
256 .contains(PatchMapFieldPresenceFlags::CFF_CHARSTRINGS_OFFSET))
257 && self.cff_charstrings_offset.is_some()
258 {
259 ctx.report(
260 "'cff_charstrings_offset' is present but CFF_CHARSTRINGS_OFFSET not set",
261 )
262 }
263 if (self
264 .field_flags
265 .contains(PatchMapFieldPresenceFlags::CFF_CHARSTRINGS_OFFSET))
266 && self.cff_charstrings_offset.is_none()
267 {
268 ctx.report("CFF_CHARSTRINGS_OFFSET is set but 'cff_charstrings_offset' is None")
269 }
270 });
271 ctx.in_field("cff2_charstrings_offset", |ctx| {
272 if !(self
273 .field_flags
274 .contains(PatchMapFieldPresenceFlags::CFF2_CHARSTRINGS_OFFSET))
275 && self.cff2_charstrings_offset.is_some()
276 {
277 ctx.report(
278 "'cff2_charstrings_offset' is present but CFF2_CHARSTRINGS_OFFSET not set",
279 )
280 }
281 if (self
282 .field_flags
283 .contains(PatchMapFieldPresenceFlags::CFF2_CHARSTRINGS_OFFSET))
284 && self.cff2_charstrings_offset.is_none()
285 {
286 ctx.report(
287 "CFF2_CHARSTRINGS_OFFSET is set but 'cff2_charstrings_offset' is None",
288 )
289 }
290 });
291 })
292 }
293}
294
295impl<'a> FromObjRef<read_fonts::tables::ift::PatchMapFormat1<'a>> for PatchMapFormat1 {
296 fn from_obj_ref(obj: &read_fonts::tables::ift::PatchMapFormat1<'a>, _: FontData) -> Self {
297 let offset_data = obj.offset_data();
298 PatchMapFormat1 {
299 field_flags: obj.field_flags(),
300 compatibility_id: obj.compatibility_id(),
301 max_entry_index: obj.max_entry_index(),
302 max_glyph_map_entry_index: obj.max_glyph_map_entry_index(),
303 glyph_count: obj.glyph_count(),
304 glyph_map: obj.glyph_map().to_owned_table(),
305 feature_map: obj.feature_map().to_owned_table(),
306 applied_entries_bitmap: obj.applied_entries_bitmap().to_owned_obj(offset_data),
307 url_template_length: obj.url_template_length(),
308 url_template: obj.url_template().to_owned_obj(offset_data),
309 patch_format: obj.patch_format(),
310 cff_charstrings_offset: obj.cff_charstrings_offset(),
311 cff2_charstrings_offset: obj.cff2_charstrings_offset(),
312 }
313 }
314}
315
316#[allow(clippy::needless_lifetimes)]
317impl<'a> FromTableRef<read_fonts::tables::ift::PatchMapFormat1<'a>> for PatchMapFormat1 {}
318
319impl<'a> FontRead<'a> for PatchMapFormat1 {
320 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
321 <read_fonts::tables::ift::PatchMapFormat1 as FontRead>::read(data)
322 .map(|x| x.to_owned_table())
323 }
324}
325
326#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
327#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
328pub struct GlyphMap {
329 pub first_mapped_glyph: u16,
330}
331
332impl GlyphMap {
333 pub fn new(first_mapped_glyph: u16) -> Self {
335 Self { first_mapped_glyph }
336 }
337}
338
339impl FontWrite for GlyphMap {
340 #[allow(clippy::unnecessary_cast)]
341 fn write_into(&self, writer: &mut TableWriter) {
342 self.first_mapped_glyph.write_into(writer);
343 }
344 fn table_type(&self) -> TableType {
345 TableType::Named("GlyphMap")
346 }
347}
348
349impl Validate for GlyphMap {
350 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
351}
352
353impl<'a> FromObjRef<read_fonts::tables::ift::GlyphMap<'a>> for GlyphMap {
354 fn from_obj_ref(obj: &read_fonts::tables::ift::GlyphMap<'a>, _: FontData) -> Self {
355 let offset_data = obj.offset_data();
356 GlyphMap {
357 first_mapped_glyph: obj.first_mapped_glyph(),
358 }
359 }
360}
361
362#[allow(clippy::needless_lifetimes)]
363impl<'a> FromTableRef<read_fonts::tables::ift::GlyphMap<'a>> for GlyphMap {}
364
365#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
366#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
367pub struct FeatureMap {
368 pub feature_count: u16,
369 pub entry_map_data: Vec<u8>,
370}
371
372impl FeatureMap {
373 pub fn new(feature_count: u16, entry_map_data: Vec<u8>) -> Self {
375 Self {
376 feature_count,
377 entry_map_data,
378 }
379 }
380}
381
382impl FontWrite for FeatureMap {
383 #[allow(clippy::unnecessary_cast)]
384 fn write_into(&self, writer: &mut TableWriter) {
385 self.feature_count.write_into(writer);
386 self.entry_map_data.write_into(writer);
387 }
388 fn table_type(&self) -> TableType {
389 TableType::Named("FeatureMap")
390 }
391}
392
393impl Validate for FeatureMap {
394 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
395}
396
397impl<'a> FromObjRef<read_fonts::tables::ift::FeatureMap<'a>> for FeatureMap {
398 fn from_obj_ref(obj: &read_fonts::tables::ift::FeatureMap<'a>, _: FontData) -> Self {
399 let offset_data = obj.offset_data();
400 FeatureMap {
401 feature_count: obj.feature_count(),
402 entry_map_data: obj.entry_map_data().to_owned_obj(offset_data),
403 }
404 }
405}
406
407#[allow(clippy::needless_lifetimes)]
408impl<'a> FromTableRef<read_fonts::tables::ift::FeatureMap<'a>> for FeatureMap {}
409
410#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
411#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
412pub struct FeatureRecord {
413 pub feature_tag: Tag,
414}
415
416impl FeatureRecord {
417 pub fn new(feature_tag: Tag) -> Self {
419 Self { feature_tag }
420 }
421}
422
423impl FontWrite for FeatureRecord {
424 #[allow(clippy::unnecessary_cast)]
425 fn write_into(&self, writer: &mut TableWriter) {
426 self.feature_tag.write_into(writer);
427 }
428 fn table_type(&self) -> TableType {
429 TableType::Named("FeatureRecord")
430 }
431}
432
433impl Validate for FeatureRecord {
434 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
435}
436
437impl FromObjRef<read_fonts::tables::ift::FeatureRecord> for FeatureRecord {
438 fn from_obj_ref(obj: &read_fonts::tables::ift::FeatureRecord, offset_data: FontData) -> Self {
439 FeatureRecord {
440 feature_tag: obj.feature_tag(),
441 }
442 }
443}
444
445#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
446#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
447pub struct EntryMapRecord {}
448
449impl EntryMapRecord {
450 pub fn new() -> Self {
452 Self {}
453 }
454}
455
456impl FontWrite for EntryMapRecord {
457 #[allow(clippy::unnecessary_cast)]
458 fn write_into(&self, writer: &mut TableWriter) {}
459 fn table_type(&self) -> TableType {
460 TableType::Named("EntryMapRecord")
461 }
462}
463
464impl Validate for EntryMapRecord {
465 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
466}
467
468impl FromObjRef<read_fonts::tables::ift::EntryMapRecord> for EntryMapRecord {
469 fn from_obj_ref(obj: &read_fonts::tables::ift::EntryMapRecord, offset_data: FontData) -> Self {
470 EntryMapRecord {}
471 }
472}
473
474#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
476#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
477pub struct PatchMapFormat2 {
478 pub field_flags: PatchMapFieldPresenceFlags,
479 pub compatibility_id: CompatibilityId,
481 pub default_patch_format: u8,
483 pub entry_count: Uint24,
484 pub entries: OffsetMarker<MappingEntries, WIDTH_32>,
485 pub entry_id_string_data: NullableOffsetMarker<IdStringData, WIDTH_32>,
486 pub url_template_length: u16,
487 pub url_template: Vec<u8>,
488 pub cff_charstrings_offset: Option<u32>,
489 pub cff2_charstrings_offset: Option<u32>,
490}
491
492impl PatchMapFormat2 {
493 #[allow(clippy::too_many_arguments)]
495 pub fn new(
496 field_flags: PatchMapFieldPresenceFlags,
497 compatibility_id: CompatibilityId,
498 default_patch_format: u8,
499 entry_count: Uint24,
500 entries: MappingEntries,
501 entry_id_string_data: Option<IdStringData>,
502 url_template_length: u16,
503 url_template: Vec<u8>,
504 ) -> Self {
505 Self {
506 field_flags,
507 compatibility_id,
508 default_patch_format,
509 entry_count,
510 entries: entries.into(),
511 entry_id_string_data: entry_id_string_data.into(),
512 url_template_length,
513 url_template,
514 ..Default::default()
515 }
516 }
517}
518
519impl FontWrite for PatchMapFormat2 {
520 #[allow(clippy::unnecessary_cast)]
521 fn write_into(&self, writer: &mut TableWriter) {
522 (2 as u8).write_into(writer);
523 (0 as u8).write_into(writer);
524 (0 as u8).write_into(writer);
525 (0 as u8).write_into(writer);
526 self.field_flags.write_into(writer);
527 self.compatibility_id.write_into(writer);
528 self.default_patch_format.write_into(writer);
529 self.entry_count.write_into(writer);
530 self.entries.write_into(writer);
531 self.entry_id_string_data.write_into(writer);
532 self.url_template_length.write_into(writer);
533 self.url_template.write_into(writer);
534 self.field_flags
535 .contains(PatchMapFieldPresenceFlags::CFF_CHARSTRINGS_OFFSET)
536 .then(|| {
537 self.cff_charstrings_offset
538 .as_ref()
539 .expect("missing conditional field should have failed validation")
540 .write_into(writer)
541 });
542 self.field_flags
543 .contains(PatchMapFieldPresenceFlags::CFF2_CHARSTRINGS_OFFSET)
544 .then(|| {
545 self.cff2_charstrings_offset
546 .as_ref()
547 .expect("missing conditional field should have failed validation")
548 .write_into(writer)
549 });
550 }
551 fn table_type(&self) -> TableType {
552 TableType::Named("PatchMapFormat2")
553 }
554}
555
556impl Validate for PatchMapFormat2 {
557 fn validate_impl(&self, ctx: &mut ValidationCtx) {
558 ctx.in_table("PatchMapFormat2", |ctx| {
559 ctx.in_field("entries", |ctx| {
560 self.entries.validate_impl(ctx);
561 });
562 ctx.in_field("entry_id_string_data", |ctx| {
563 self.entry_id_string_data.validate_impl(ctx);
564 });
565 ctx.in_field("url_template", |ctx| {
566 if self.url_template.len() > (u16::MAX as usize) {
567 ctx.report("array exceeds max length");
568 }
569 });
570 ctx.in_field("cff_charstrings_offset", |ctx| {
571 if !(self
572 .field_flags
573 .contains(PatchMapFieldPresenceFlags::CFF_CHARSTRINGS_OFFSET))
574 && self.cff_charstrings_offset.is_some()
575 {
576 ctx.report(
577 "'cff_charstrings_offset' is present but CFF_CHARSTRINGS_OFFSET not set",
578 )
579 }
580 if (self
581 .field_flags
582 .contains(PatchMapFieldPresenceFlags::CFF_CHARSTRINGS_OFFSET))
583 && self.cff_charstrings_offset.is_none()
584 {
585 ctx.report("CFF_CHARSTRINGS_OFFSET is set but 'cff_charstrings_offset' is None")
586 }
587 });
588 ctx.in_field("cff2_charstrings_offset", |ctx| {
589 if !(self
590 .field_flags
591 .contains(PatchMapFieldPresenceFlags::CFF2_CHARSTRINGS_OFFSET))
592 && self.cff2_charstrings_offset.is_some()
593 {
594 ctx.report(
595 "'cff2_charstrings_offset' is present but CFF2_CHARSTRINGS_OFFSET not set",
596 )
597 }
598 if (self
599 .field_flags
600 .contains(PatchMapFieldPresenceFlags::CFF2_CHARSTRINGS_OFFSET))
601 && self.cff2_charstrings_offset.is_none()
602 {
603 ctx.report(
604 "CFF2_CHARSTRINGS_OFFSET is set but 'cff2_charstrings_offset' is None",
605 )
606 }
607 });
608 })
609 }
610}
611
612impl<'a> FromObjRef<read_fonts::tables::ift::PatchMapFormat2<'a>> for PatchMapFormat2 {
613 fn from_obj_ref(obj: &read_fonts::tables::ift::PatchMapFormat2<'a>, _: FontData) -> Self {
614 let offset_data = obj.offset_data();
615 PatchMapFormat2 {
616 field_flags: obj.field_flags(),
617 compatibility_id: obj.compatibility_id(),
618 default_patch_format: obj.default_patch_format(),
619 entry_count: obj.entry_count(),
620 entries: obj.entries().to_owned_table(),
621 entry_id_string_data: obj.entry_id_string_data().to_owned_table(),
622 url_template_length: obj.url_template_length(),
623 url_template: obj.url_template().to_owned_obj(offset_data),
624 cff_charstrings_offset: obj.cff_charstrings_offset(),
625 cff2_charstrings_offset: obj.cff2_charstrings_offset(),
626 }
627 }
628}
629
630#[allow(clippy::needless_lifetimes)]
631impl<'a> FromTableRef<read_fonts::tables::ift::PatchMapFormat2<'a>> for PatchMapFormat2 {}
632
633impl<'a> FontRead<'a> for PatchMapFormat2 {
634 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
635 <read_fonts::tables::ift::PatchMapFormat2 as FontRead>::read(data)
636 .map(|x| x.to_owned_table())
637 }
638}
639
640#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
641#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
642pub struct MappingEntries {
643 pub entry_data: Vec<u8>,
644}
645
646impl MappingEntries {
647 pub fn new(entry_data: Vec<u8>) -> Self {
649 Self { entry_data }
650 }
651}
652
653impl FontWrite for MappingEntries {
654 fn write_into(&self, writer: &mut TableWriter) {
655 self.entry_data.write_into(writer);
656 }
657 fn table_type(&self) -> TableType {
658 TableType::Named("MappingEntries")
659 }
660}
661
662impl Validate for MappingEntries {
663 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
664}
665
666impl<'a> FromObjRef<read_fonts::tables::ift::MappingEntries<'a>> for MappingEntries {
667 fn from_obj_ref(obj: &read_fonts::tables::ift::MappingEntries<'a>, _: FontData) -> Self {
668 let offset_data = obj.offset_data();
669 MappingEntries {
670 entry_data: obj.entry_data().to_owned_obj(offset_data),
671 }
672 }
673}
674
675#[allow(clippy::needless_lifetimes)]
676impl<'a> FromTableRef<read_fonts::tables::ift::MappingEntries<'a>> for MappingEntries {}
677
678impl<'a> FontRead<'a> for MappingEntries {
679 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
680 <read_fonts::tables::ift::MappingEntries as FontRead>::read(data)
681 .map(|x| x.to_owned_table())
682 }
683}
684
685#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
686#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
687pub struct EntryData {
688 pub format_flags: EntryFormatFlags,
689 pub feature_count: Option<u8>,
690 pub feature_tags: Option<Vec<Tag>>,
691 pub design_space_count: Option<u16>,
692 pub design_space_segments: Option<Vec<DesignSpaceSegment>>,
693 pub child_indices: Option<Vec<Uint24>>,
694 pub trailing_data: Vec<u8>,
695}
696
697impl EntryData {
698 pub fn new(format_flags: EntryFormatFlags, trailing_data: Vec<u8>) -> Self {
700 Self {
701 format_flags,
702 trailing_data,
703 ..Default::default()
704 }
705 }
706}
707
708impl FontWrite for EntryData {
709 #[allow(clippy::unnecessary_cast)]
710 fn write_into(&self, writer: &mut TableWriter) {
711 self.format_flags.write_into(writer);
712 self.format_flags
713 .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE)
714 .then(|| {
715 self.feature_count
716 .as_ref()
717 .expect("missing conditional field should have failed validation")
718 .write_into(writer)
719 });
720 self.format_flags
721 .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE)
722 .then(|| {
723 self.feature_tags
724 .as_ref()
725 .expect("missing conditional field should have failed validation")
726 .write_into(writer)
727 });
728 self.format_flags
729 .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE)
730 .then(|| {
731 self.design_space_count
732 .as_ref()
733 .expect("missing conditional field should have failed validation")
734 .write_into(writer)
735 });
736 self.format_flags
737 .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE)
738 .then(|| {
739 self.design_space_segments
740 .as_ref()
741 .expect("missing conditional field should have failed validation")
742 .write_into(writer)
743 });
744 self.format_flags
745 .contains(EntryFormatFlags::CHILD_INDICES)
746 .then(|| {
747 self.child_indices
748 .as_ref()
749 .expect("missing conditional field should have failed validation")
750 .write_into(writer)
751 });
752 self.trailing_data.write_into(writer);
753 }
754 fn table_type(&self) -> TableType {
755 TableType::Named("EntryData")
756 }
757}
758
759impl Validate for EntryData {
760 fn validate_impl(&self, ctx: &mut ValidationCtx) {
761 ctx.in_table("EntryData", |ctx| {
762 ctx.in_field("feature_count", |ctx| {
763 if !(self
764 .format_flags
765 .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE))
766 && self.feature_count.is_some()
767 {
768 ctx.report("'feature_count' is present but FEATURES_AND_DESIGN_SPACE not set")
769 }
770 if (self
771 .format_flags
772 .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE))
773 && self.feature_count.is_none()
774 {
775 ctx.report("FEATURES_AND_DESIGN_SPACE is set but 'feature_count' is None")
776 }
777 });
778 ctx.in_field("feature_tags", |ctx| {
779 if !(self
780 .format_flags
781 .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE))
782 && self.feature_tags.is_some()
783 {
784 ctx.report("'feature_tags' is present but FEATURES_AND_DESIGN_SPACE not set")
785 }
786 if (self
787 .format_flags
788 .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE))
789 && self.feature_tags.is_none()
790 {
791 ctx.report("FEATURES_AND_DESIGN_SPACE is set but 'feature_tags' is None")
792 }
793 if self.feature_tags.is_some()
794 && self.feature_tags.as_ref().unwrap().len() > (u8::MAX as usize)
795 {
796 ctx.report("array exceeds max length");
797 }
798 });
799 ctx.in_field("design_space_count", |ctx| {
800 if !(self
801 .format_flags
802 .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE))
803 && self.design_space_count.is_some()
804 {
805 ctx.report(
806 "'design_space_count' is present but FEATURES_AND_DESIGN_SPACE not set",
807 )
808 }
809 if (self
810 .format_flags
811 .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE))
812 && self.design_space_count.is_none()
813 {
814 ctx.report("FEATURES_AND_DESIGN_SPACE is set but 'design_space_count' is None")
815 }
816 });
817 ctx.in_field("design_space_segments", |ctx| {
818 if !(self
819 .format_flags
820 .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE))
821 && self.design_space_segments.is_some()
822 {
823 ctx.report(
824 "'design_space_segments' is present but FEATURES_AND_DESIGN_SPACE not set",
825 )
826 }
827 if (self
828 .format_flags
829 .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE))
830 && self.design_space_segments.is_none()
831 {
832 ctx.report(
833 "FEATURES_AND_DESIGN_SPACE is set but 'design_space_segments' is None",
834 )
835 }
836 if self.design_space_segments.is_some()
837 && self.design_space_segments.as_ref().unwrap().len() > (u16::MAX as usize)
838 {
839 ctx.report("array exceeds max length");
840 }
841 self.design_space_segments.validate_impl(ctx);
842 });
843 ctx.in_field("child_indices", |ctx| {
844 if !(self.format_flags.contains(EntryFormatFlags::CHILD_INDICES))
845 && self.child_indices.is_some()
846 {
847 ctx.report("'child_indices' is present but CHILD_INDICES not set")
848 }
849 if (self.format_flags.contains(EntryFormatFlags::CHILD_INDICES))
850 && self.child_indices.is_none()
851 {
852 ctx.report("CHILD_INDICES is set but 'child_indices' is None")
853 }
854 });
855 })
856 }
857}
858
859impl<'a> FromObjRef<read_fonts::tables::ift::EntryData<'a>> for EntryData {
860 fn from_obj_ref(obj: &read_fonts::tables::ift::EntryData<'a>, _: FontData) -> Self {
861 let offset_data = obj.offset_data();
862 EntryData {
863 format_flags: obj.format_flags(),
864 feature_count: obj.feature_count(),
865 feature_tags: obj.feature_tags().to_owned_obj(offset_data),
866 design_space_count: obj.design_space_count(),
867 design_space_segments: obj.design_space_segments().to_owned_obj(offset_data),
868 child_indices: obj.child_indices().to_owned_obj(offset_data),
869 trailing_data: obj.trailing_data().to_owned_obj(offset_data),
870 }
871 }
872}
873
874#[allow(clippy::needless_lifetimes)]
875impl<'a> FromTableRef<read_fonts::tables::ift::EntryData<'a>> for EntryData {}
876
877impl<'a> FontRead<'a> for EntryData {
878 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
879 <read_fonts::tables::ift::EntryData as FontRead>::read(data).map(|x| x.to_owned_table())
880 }
881}
882
883impl FontWrite for EntryFormatFlags {
884 fn write_into(&self, writer: &mut TableWriter) {
885 writer.write_slice(&self.bits().to_be_bytes())
886 }
887}
888
889#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
890#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
891pub struct DesignSpaceSegment {
892 pub axis_tag: Tag,
893 pub start: Fixed,
894 pub end: Fixed,
895}
896
897impl DesignSpaceSegment {
898 pub fn new(axis_tag: Tag, start: Fixed, end: Fixed) -> Self {
900 Self {
901 axis_tag,
902 start,
903 end,
904 }
905 }
906}
907
908impl FontWrite for DesignSpaceSegment {
909 fn write_into(&self, writer: &mut TableWriter) {
910 self.axis_tag.write_into(writer);
911 self.start.write_into(writer);
912 self.end.write_into(writer);
913 }
914 fn table_type(&self) -> TableType {
915 TableType::Named("DesignSpaceSegment")
916 }
917}
918
919impl Validate for DesignSpaceSegment {
920 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
921}
922
923impl FromObjRef<read_fonts::tables::ift::DesignSpaceSegment> for DesignSpaceSegment {
924 fn from_obj_ref(obj: &read_fonts::tables::ift::DesignSpaceSegment, _: FontData) -> Self {
925 DesignSpaceSegment {
926 axis_tag: obj.axis_tag(),
927 start: obj.start(),
928 end: obj.end(),
929 }
930 }
931}
932
933#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
934#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
935pub struct IdStringData {
936 pub id_data: Vec<u8>,
937}
938
939impl IdStringData {
940 pub fn new(id_data: Vec<u8>) -> Self {
942 Self { id_data }
943 }
944}
945
946impl FontWrite for IdStringData {
947 fn write_into(&self, writer: &mut TableWriter) {
948 self.id_data.write_into(writer);
949 }
950 fn table_type(&self) -> TableType {
951 TableType::Named("IdStringData")
952 }
953}
954
955impl Validate for IdStringData {
956 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
957}
958
959impl<'a> FromObjRef<read_fonts::tables::ift::IdStringData<'a>> for IdStringData {
960 fn from_obj_ref(obj: &read_fonts::tables::ift::IdStringData<'a>, _: FontData) -> Self {
961 let offset_data = obj.offset_data();
962 IdStringData {
963 id_data: obj.id_data().to_owned_obj(offset_data),
964 }
965 }
966}
967
968#[allow(clippy::needless_lifetimes)]
969impl<'a> FromTableRef<read_fonts::tables::ift::IdStringData<'a>> for IdStringData {}
970
971impl<'a> FontRead<'a> for IdStringData {
972 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
973 <read_fonts::tables::ift::IdStringData as FontRead>::read(data).map(|x| x.to_owned_table())
974 }
975}
976
977#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
979#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
980pub struct TableKeyedPatch {
981 pub format: Tag,
982 pub compatibility_id: CompatibilityId,
984 pub patches_count: u16,
985 pub patches: Vec<OffsetMarker<TablePatch, WIDTH_32>>,
986}
987
988impl TableKeyedPatch {
989 pub fn new(
991 format: Tag,
992 compatibility_id: CompatibilityId,
993 patches_count: u16,
994 patches: Vec<TablePatch>,
995 ) -> Self {
996 Self {
997 format,
998 compatibility_id,
999 patches_count,
1000 patches: patches.into_iter().map(Into::into).collect(),
1001 }
1002 }
1003}
1004
1005impl FontWrite for TableKeyedPatch {
1006 #[allow(clippy::unnecessary_cast)]
1007 fn write_into(&self, writer: &mut TableWriter) {
1008 self.format.write_into(writer);
1009 (0 as u32).write_into(writer);
1010 self.compatibility_id.write_into(writer);
1011 self.patches_count.write_into(writer);
1012 self.patches.write_into(writer);
1013 }
1014 fn table_type(&self) -> TableType {
1015 TableType::Named("TableKeyedPatch")
1016 }
1017}
1018
1019impl Validate for TableKeyedPatch {
1020 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1021 ctx.in_table("TableKeyedPatch", |ctx| {
1022 ctx.in_field("patches", |ctx| {
1023 self.patches.validate_impl(ctx);
1024 });
1025 })
1026 }
1027}
1028
1029impl<'a> FromObjRef<read_fonts::tables::ift::TableKeyedPatch<'a>> for TableKeyedPatch {
1030 fn from_obj_ref(obj: &read_fonts::tables::ift::TableKeyedPatch<'a>, _: FontData) -> Self {
1031 TableKeyedPatch {
1032 format: obj.format(),
1033 compatibility_id: obj.compatibility_id(),
1034 patches_count: obj.patches_count(),
1035 patches: obj.patches().to_owned_table(),
1036 }
1037 }
1038}
1039
1040#[allow(clippy::needless_lifetimes)]
1041impl<'a> FromTableRef<read_fonts::tables::ift::TableKeyedPatch<'a>> for TableKeyedPatch {}
1042
1043impl<'a> FontRead<'a> for TableKeyedPatch {
1044 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1045 <read_fonts::tables::ift::TableKeyedPatch as FontRead>::read(data)
1046 .map(|x| x.to_owned_table())
1047 }
1048}
1049
1050#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1052#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1053pub struct TablePatch {
1054 pub tag: Tag,
1055 pub flags: TablePatchFlags,
1056 pub max_uncompressed_length: u32,
1057 pub brotli_stream: Vec<u8>,
1058}
1059
1060impl TablePatch {
1061 pub fn new(
1063 tag: Tag,
1064 flags: TablePatchFlags,
1065 max_uncompressed_length: u32,
1066 brotli_stream: Vec<u8>,
1067 ) -> Self {
1068 Self {
1069 tag,
1070 flags,
1071 max_uncompressed_length,
1072 brotli_stream,
1073 }
1074 }
1075}
1076
1077impl FontWrite for TablePatch {
1078 fn write_into(&self, writer: &mut TableWriter) {
1079 self.tag.write_into(writer);
1080 self.flags.write_into(writer);
1081 self.max_uncompressed_length.write_into(writer);
1082 self.brotli_stream.write_into(writer);
1083 }
1084 fn table_type(&self) -> TableType {
1085 TableType::Named("TablePatch")
1086 }
1087}
1088
1089impl Validate for TablePatch {
1090 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
1091}
1092
1093impl<'a> FromObjRef<read_fonts::tables::ift::TablePatch<'a>> for TablePatch {
1094 fn from_obj_ref(obj: &read_fonts::tables::ift::TablePatch<'a>, _: FontData) -> Self {
1095 let offset_data = obj.offset_data();
1096 TablePatch {
1097 tag: obj.tag(),
1098 flags: obj.flags(),
1099 max_uncompressed_length: obj.max_uncompressed_length(),
1100 brotli_stream: obj.brotli_stream().to_owned_obj(offset_data),
1101 }
1102 }
1103}
1104
1105#[allow(clippy::needless_lifetimes)]
1106impl<'a> FromTableRef<read_fonts::tables::ift::TablePatch<'a>> for TablePatch {}
1107
1108impl<'a> FontRead<'a> for TablePatch {
1109 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1110 <read_fonts::tables::ift::TablePatch as FontRead>::read(data).map(|x| x.to_owned_table())
1111 }
1112}
1113
1114impl FontWrite for TablePatchFlags {
1115 fn write_into(&self, writer: &mut TableWriter) {
1116 writer.write_slice(&self.bits().to_be_bytes())
1117 }
1118}
1119
1120#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1122#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1123pub struct GlyphKeyedPatch {
1124 pub format: Tag,
1125 pub flags: GlyphKeyedFlags,
1126 pub compatibility_id: CompatibilityId,
1127 pub max_uncompressed_length: u32,
1128 pub brotli_stream: Vec<u8>,
1129}
1130
1131impl GlyphKeyedPatch {
1132 pub fn new(
1134 format: Tag,
1135 flags: GlyphKeyedFlags,
1136 compatibility_id: CompatibilityId,
1137 max_uncompressed_length: u32,
1138 brotli_stream: Vec<u8>,
1139 ) -> Self {
1140 Self {
1141 format,
1142 flags,
1143 compatibility_id,
1144 max_uncompressed_length,
1145 brotli_stream,
1146 }
1147 }
1148}
1149
1150impl FontWrite for GlyphKeyedPatch {
1151 #[allow(clippy::unnecessary_cast)]
1152 fn write_into(&self, writer: &mut TableWriter) {
1153 self.format.write_into(writer);
1154 (0 as u32).write_into(writer);
1155 self.flags.write_into(writer);
1156 self.compatibility_id.write_into(writer);
1157 self.max_uncompressed_length.write_into(writer);
1158 self.brotli_stream.write_into(writer);
1159 }
1160 fn table_type(&self) -> TableType {
1161 TableType::Named("GlyphKeyedPatch")
1162 }
1163}
1164
1165impl Validate for GlyphKeyedPatch {
1166 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
1167}
1168
1169impl<'a> FromObjRef<read_fonts::tables::ift::GlyphKeyedPatch<'a>> for GlyphKeyedPatch {
1170 fn from_obj_ref(obj: &read_fonts::tables::ift::GlyphKeyedPatch<'a>, _: FontData) -> Self {
1171 let offset_data = obj.offset_data();
1172 GlyphKeyedPatch {
1173 format: obj.format(),
1174 flags: obj.flags(),
1175 compatibility_id: obj.compatibility_id(),
1176 max_uncompressed_length: obj.max_uncompressed_length(),
1177 brotli_stream: obj.brotli_stream().to_owned_obj(offset_data),
1178 }
1179 }
1180}
1181
1182#[allow(clippy::needless_lifetimes)]
1183impl<'a> FromTableRef<read_fonts::tables::ift::GlyphKeyedPatch<'a>> for GlyphKeyedPatch {}
1184
1185impl<'a> FontRead<'a> for GlyphKeyedPatch {
1186 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1187 <read_fonts::tables::ift::GlyphKeyedPatch as FontRead>::read(data)
1188 .map(|x| x.to_owned_table())
1189 }
1190}
1191
1192impl FontWrite for GlyphKeyedFlags {
1193 fn write_into(&self, writer: &mut TableWriter) {
1194 writer.write_slice(&self.bits().to_be_bytes())
1195 }
1196}
1197
1198#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1200#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1201pub struct GlyphPatches {
1202 pub glyph_count: u32,
1203 pub table_count: u8,
1204 pub tables: Vec<Tag>,
1205 pub glyph_data: Vec<OffsetMarker<GlyphData, WIDTH_32>>,
1206}
1207
1208impl GlyphPatches {
1209 pub fn new(
1211 glyph_count: u32,
1212 table_count: u8,
1213 tables: Vec<Tag>,
1214 glyph_data: Vec<GlyphData>,
1215 ) -> Self {
1216 Self {
1217 glyph_count,
1218 table_count,
1219 tables,
1220 glyph_data: glyph_data.into_iter().map(Into::into).collect(),
1221 }
1222 }
1223}
1224
1225impl FontWrite for GlyphPatches {
1226 #[allow(clippy::unnecessary_cast)]
1227 fn write_into(&self, writer: &mut TableWriter) {
1228 self.glyph_count.write_into(writer);
1229 self.table_count.write_into(writer);
1230 self.tables.write_into(writer);
1231 self.glyph_data.write_into(writer);
1232 }
1233 fn table_type(&self) -> TableType {
1234 TableType::Named("GlyphPatches")
1235 }
1236}
1237
1238impl Validate for GlyphPatches {
1239 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1240 ctx.in_table("GlyphPatches", |ctx| {
1241 ctx.in_field("tables", |ctx| {
1242 if self.tables.len() > (u8::MAX as usize) {
1243 ctx.report("array exceeds max length");
1244 }
1245 });
1246 ctx.in_field("glyph_data", |ctx| {
1247 self.glyph_data.validate_impl(ctx);
1248 });
1249 })
1250 }
1251}
1252
1253impl<'a> FromObjRef<read_fonts::tables::ift::GlyphPatches<'a>> for GlyphPatches {
1254 fn from_obj_ref(obj: &read_fonts::tables::ift::GlyphPatches<'a>, _: FontData) -> Self {
1255 let offset_data = obj.offset_data();
1256 GlyphPatches {
1257 glyph_count: obj.glyph_count(),
1258 table_count: obj.table_count(),
1259 tables: obj.tables().to_owned_obj(offset_data),
1260 glyph_data: obj.glyph_data().to_owned_table(),
1261 }
1262 }
1263}
1264
1265#[allow(clippy::needless_lifetimes)]
1266impl<'a> FromTableRef<read_fonts::tables::ift::GlyphPatches<'a>> for GlyphPatches {}
1267
1268#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1269#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1270pub struct GlyphData {
1271 pub data: Vec<u8>,
1272}
1273
1274impl GlyphData {
1275 pub fn new(data: Vec<u8>) -> Self {
1277 Self { data }
1278 }
1279}
1280
1281impl FontWrite for GlyphData {
1282 fn write_into(&self, writer: &mut TableWriter) {
1283 self.data.write_into(writer);
1284 }
1285 fn table_type(&self) -> TableType {
1286 TableType::Named("GlyphData")
1287 }
1288}
1289
1290impl Validate for GlyphData {
1291 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
1292}
1293
1294impl<'a> FromObjRef<read_fonts::tables::ift::GlyphData<'a>> for GlyphData {
1295 fn from_obj_ref(obj: &read_fonts::tables::ift::GlyphData<'a>, _: FontData) -> Self {
1296 let offset_data = obj.offset_data();
1297 GlyphData {
1298 data: obj.data().to_owned_obj(offset_data),
1299 }
1300 }
1301}
1302
1303#[allow(clippy::needless_lifetimes)]
1304impl<'a> FromTableRef<read_fonts::tables::ift::GlyphData<'a>> for GlyphData {}
1305
1306impl<'a> FontRead<'a> for GlyphData {
1307 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1308 <read_fonts::tables::ift::GlyphData as FontRead>::read(data).map(|x| x.to_owned_table())
1309 }
1310}