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