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