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