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