1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct Gsub {
12 pub script_list: OffsetMarker<ScriptList>,
14 pub feature_list: OffsetMarker<FeatureList>,
16 pub lookup_list: OffsetMarker<SubstitutionLookupList>,
18 pub feature_variations: NullableOffsetMarker<FeatureVariations, WIDTH_32>,
21}
22
23impl Gsub {
24 pub fn new(
26 script_list: ScriptList,
27 feature_list: FeatureList,
28 lookup_list: SubstitutionLookupList,
29 ) -> Self {
30 Self {
31 script_list: script_list.into(),
32 feature_list: feature_list.into(),
33 lookup_list: lookup_list.into(),
34 ..Default::default()
35 }
36 }
37}
38
39impl FontWrite for Gsub {
40 #[allow(clippy::unnecessary_cast)]
41 fn write_into(&self, writer: &mut TableWriter) {
42 let version = self.compute_version() as MajorMinor;
43 version.write_into(writer);
44 self.script_list.write_into(writer);
45 self.feature_list.write_into(writer);
46 self.lookup_list.write_into(writer);
47 version
48 .compatible((1u16, 1u16))
49 .then(|| self.feature_variations.write_into(writer));
50 }
51 fn table_type(&self) -> TableType {
52 TableType::TopLevel(Gsub::TAG)
53 }
54}
55
56impl Validate for Gsub {
57 fn validate_impl(&self, ctx: &mut ValidationCtx) {
58 ctx.in_table("Gsub", |ctx| {
59 ctx.in_field("script_list", |ctx| {
60 self.script_list.validate_impl(ctx);
61 });
62 ctx.in_field("feature_list", |ctx| {
63 self.feature_list.validate_impl(ctx);
64 });
65 ctx.in_field("lookup_list", |ctx| {
66 self.lookup_list.validate_impl(ctx);
67 });
68 ctx.in_field("feature_variations", |ctx| {
69 self.feature_variations.validate_impl(ctx);
70 });
71 })
72 }
73}
74
75impl TopLevelTable for Gsub {
76 const TAG: Tag = Tag::new(b"GSUB");
77}
78
79impl<'a> FromObjRef<read_fonts::tables::gsub::Gsub<'a>> for Gsub {
80 fn from_obj_ref(obj: &read_fonts::tables::gsub::Gsub<'a>, _: FontData) -> Self {
81 Gsub {
82 script_list: obj.script_list().to_owned_table(),
83 feature_list: obj.feature_list().to_owned_table(),
84 lookup_list: obj.lookup_list().to_owned_table(),
85 feature_variations: obj.feature_variations().to_owned_table(),
86 }
87 }
88}
89
90#[allow(clippy::needless_lifetimes)]
91impl<'a> FromTableRef<read_fonts::tables::gsub::Gsub<'a>> for Gsub {}
92
93impl<'a> FontRead<'a> for Gsub {
94 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
95 <read_fonts::tables::gsub::Gsub as FontRead>::read(data).map(|x| x.to_owned_table())
96 }
97}
98
99#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
101#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
102pub enum SubstitutionLookup {
103 Single(Lookup<SingleSubst>),
104 Multiple(Lookup<MultipleSubstFormat1>),
105 Alternate(Lookup<AlternateSubstFormat1>),
106 Ligature(Lookup<LigatureSubstFormat1>),
107 Contextual(Lookup<SubstitutionSequenceContext>),
108 ChainContextual(Lookup<SubstitutionChainContext>),
109 Extension(Lookup<ExtensionSubtable>),
110 Reverse(Lookup<ReverseChainSingleSubstFormat1>),
111}
112
113impl Default for SubstitutionLookup {
114 fn default() -> Self {
115 Self::Single(Default::default())
116 }
117}
118
119impl FontWrite for SubstitutionLookup {
120 fn write_into(&self, writer: &mut TableWriter) {
121 match self {
122 Self::Single(table) => table.write_into(writer),
123 Self::Multiple(table) => table.write_into(writer),
124 Self::Alternate(table) => table.write_into(writer),
125 Self::Ligature(table) => table.write_into(writer),
126 Self::Contextual(table) => table.write_into(writer),
127 Self::ChainContextual(table) => table.write_into(writer),
128 Self::Extension(table) => table.write_into(writer),
129 Self::Reverse(table) => table.write_into(writer),
130 }
131 }
132 fn table_type(&self) -> TableType {
133 match self {
134 Self::Single(table) => table.table_type(),
135 Self::Multiple(table) => table.table_type(),
136 Self::Alternate(table) => table.table_type(),
137 Self::Ligature(table) => table.table_type(),
138 Self::Contextual(table) => table.table_type(),
139 Self::ChainContextual(table) => table.table_type(),
140 Self::Extension(table) => table.table_type(),
141 Self::Reverse(table) => table.table_type(),
142 }
143 }
144}
145
146impl Validate for SubstitutionLookup {
147 fn validate_impl(&self, ctx: &mut ValidationCtx) {
148 match self {
149 Self::Single(table) => table.validate_impl(ctx),
150 Self::Multiple(table) => table.validate_impl(ctx),
151 Self::Alternate(table) => table.validate_impl(ctx),
152 Self::Ligature(table) => table.validate_impl(ctx),
153 Self::Contextual(table) => table.validate_impl(ctx),
154 Self::ChainContextual(table) => table.validate_impl(ctx),
155 Self::Extension(table) => table.validate_impl(ctx),
156 Self::Reverse(table) => table.validate_impl(ctx),
157 }
158 }
159}
160
161impl FromObjRef<read_fonts::tables::gsub::SubstitutionLookup<'_>> for SubstitutionLookup {
162 fn from_obj_ref(
163 from: &read_fonts::tables::gsub::SubstitutionLookup<'_>,
164 data: FontData,
165 ) -> Self {
166 match from {
167 read_fonts::tables::gsub::SubstitutionLookup::Single(table) => {
168 Self::Single(table.to_owned_obj(data))
169 }
170 read_fonts::tables::gsub::SubstitutionLookup::Multiple(table) => {
171 Self::Multiple(table.to_owned_obj(data))
172 }
173 read_fonts::tables::gsub::SubstitutionLookup::Alternate(table) => {
174 Self::Alternate(table.to_owned_obj(data))
175 }
176 read_fonts::tables::gsub::SubstitutionLookup::Ligature(table) => {
177 Self::Ligature(table.to_owned_obj(data))
178 }
179 read_fonts::tables::gsub::SubstitutionLookup::Contextual(table) => {
180 Self::Contextual(table.to_owned_obj(data))
181 }
182 read_fonts::tables::gsub::SubstitutionLookup::ChainContextual(table) => {
183 Self::ChainContextual(table.to_owned_obj(data))
184 }
185 read_fonts::tables::gsub::SubstitutionLookup::Extension(table) => {
186 Self::Extension(table.to_owned_obj(data))
187 }
188 read_fonts::tables::gsub::SubstitutionLookup::Reverse(table) => {
189 Self::Reverse(table.to_owned_obj(data))
190 }
191 }
192 }
193}
194
195impl FromTableRef<read_fonts::tables::gsub::SubstitutionLookup<'_>> for SubstitutionLookup {}
196
197impl From<Lookup<SingleSubst>> for SubstitutionLookup {
198 fn from(src: Lookup<SingleSubst>) -> SubstitutionLookup {
199 SubstitutionLookup::Single(src)
200 }
201}
202
203impl From<Lookup<MultipleSubstFormat1>> for SubstitutionLookup {
204 fn from(src: Lookup<MultipleSubstFormat1>) -> SubstitutionLookup {
205 SubstitutionLookup::Multiple(src)
206 }
207}
208
209impl From<Lookup<AlternateSubstFormat1>> for SubstitutionLookup {
210 fn from(src: Lookup<AlternateSubstFormat1>) -> SubstitutionLookup {
211 SubstitutionLookup::Alternate(src)
212 }
213}
214
215impl From<Lookup<LigatureSubstFormat1>> for SubstitutionLookup {
216 fn from(src: Lookup<LigatureSubstFormat1>) -> SubstitutionLookup {
217 SubstitutionLookup::Ligature(src)
218 }
219}
220
221impl From<Lookup<SubstitutionSequenceContext>> for SubstitutionLookup {
222 fn from(src: Lookup<SubstitutionSequenceContext>) -> SubstitutionLookup {
223 SubstitutionLookup::Contextual(src)
224 }
225}
226
227impl From<Lookup<SubstitutionChainContext>> for SubstitutionLookup {
228 fn from(src: Lookup<SubstitutionChainContext>) -> SubstitutionLookup {
229 SubstitutionLookup::ChainContextual(src)
230 }
231}
232
233impl From<Lookup<ExtensionSubtable>> for SubstitutionLookup {
234 fn from(src: Lookup<ExtensionSubtable>) -> SubstitutionLookup {
235 SubstitutionLookup::Extension(src)
236 }
237}
238
239impl From<Lookup<ReverseChainSingleSubstFormat1>> for SubstitutionLookup {
240 fn from(src: Lookup<ReverseChainSingleSubstFormat1>) -> SubstitutionLookup {
241 SubstitutionLookup::Reverse(src)
242 }
243}
244
245#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
247#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
248pub enum SingleSubst {
249 Format1(SingleSubstFormat1),
250 Format2(SingleSubstFormat2),
251}
252
253impl SingleSubst {
254 pub fn format_1(coverage: CoverageTable, delta_glyph_id: i16) -> Self {
256 Self::Format1(SingleSubstFormat1::new(coverage, delta_glyph_id))
257 }
258
259 pub fn format_2(coverage: CoverageTable, substitute_glyph_ids: Vec<GlyphId16>) -> Self {
261 Self::Format2(SingleSubstFormat2::new(coverage, substitute_glyph_ids))
262 }
263}
264
265impl Default for SingleSubst {
266 fn default() -> Self {
267 Self::Format1(Default::default())
268 }
269}
270
271impl FontWrite for SingleSubst {
272 fn write_into(&self, writer: &mut TableWriter) {
273 match self {
274 Self::Format1(item) => item.write_into(writer),
275 Self::Format2(item) => item.write_into(writer),
276 }
277 }
278 fn table_type(&self) -> TableType {
279 match self {
280 Self::Format1(item) => item.table_type(),
281 Self::Format2(item) => item.table_type(),
282 }
283 }
284}
285
286impl Validate for SingleSubst {
287 fn validate_impl(&self, ctx: &mut ValidationCtx) {
288 match self {
289 Self::Format1(item) => item.validate_impl(ctx),
290 Self::Format2(item) => item.validate_impl(ctx),
291 }
292 }
293}
294
295impl FromObjRef<read_fonts::tables::gsub::SingleSubst<'_>> for SingleSubst {
296 fn from_obj_ref(obj: &read_fonts::tables::gsub::SingleSubst, _: FontData) -> Self {
297 use read_fonts::tables::gsub::SingleSubst as ObjRefType;
298 match obj {
299 ObjRefType::Format1(item) => SingleSubst::Format1(item.to_owned_table()),
300 ObjRefType::Format2(item) => SingleSubst::Format2(item.to_owned_table()),
301 }
302 }
303}
304
305impl FromTableRef<read_fonts::tables::gsub::SingleSubst<'_>> for SingleSubst {}
306
307impl<'a> FontRead<'a> for SingleSubst {
308 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
309 <read_fonts::tables::gsub::SingleSubst as FontRead>::read(data).map(|x| x.to_owned_table())
310 }
311}
312
313impl From<SingleSubstFormat1> for SingleSubst {
314 fn from(src: SingleSubstFormat1) -> SingleSubst {
315 SingleSubst::Format1(src)
316 }
317}
318
319impl From<SingleSubstFormat2> for SingleSubst {
320 fn from(src: SingleSubstFormat2) -> SingleSubst {
321 SingleSubst::Format2(src)
322 }
323}
324
325#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
327#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
328pub struct SingleSubstFormat1 {
329 pub coverage: OffsetMarker<CoverageTable>,
332 pub delta_glyph_id: i16,
334}
335
336impl SingleSubstFormat1 {
337 pub fn new(coverage: CoverageTable, delta_glyph_id: i16) -> Self {
339 Self {
340 coverage: coverage.into(),
341 delta_glyph_id,
342 }
343 }
344}
345
346impl FontWrite for SingleSubstFormat1 {
347 #[allow(clippy::unnecessary_cast)]
348 fn write_into(&self, writer: &mut TableWriter) {
349 (1 as u16).write_into(writer);
350 self.coverage.write_into(writer);
351 self.delta_glyph_id.write_into(writer);
352 }
353 fn table_type(&self) -> TableType {
354 TableType::Named("SingleSubstFormat1")
355 }
356}
357
358impl Validate for SingleSubstFormat1 {
359 fn validate_impl(&self, ctx: &mut ValidationCtx) {
360 ctx.in_table("SingleSubstFormat1", |ctx| {
361 ctx.in_field("coverage", |ctx| {
362 self.coverage.validate_impl(ctx);
363 });
364 })
365 }
366}
367
368impl<'a> FromObjRef<read_fonts::tables::gsub::SingleSubstFormat1<'a>> for SingleSubstFormat1 {
369 fn from_obj_ref(obj: &read_fonts::tables::gsub::SingleSubstFormat1<'a>, _: FontData) -> Self {
370 SingleSubstFormat1 {
371 coverage: obj.coverage().to_owned_table(),
372 delta_glyph_id: obj.delta_glyph_id(),
373 }
374 }
375}
376
377#[allow(clippy::needless_lifetimes)]
378impl<'a> FromTableRef<read_fonts::tables::gsub::SingleSubstFormat1<'a>> for SingleSubstFormat1 {}
379
380impl<'a> FontRead<'a> for SingleSubstFormat1 {
381 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
382 <read_fonts::tables::gsub::SingleSubstFormat1 as FontRead>::read(data)
383 .map(|x| x.to_owned_table())
384 }
385}
386
387#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
389#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
390pub struct SingleSubstFormat2 {
391 pub coverage: OffsetMarker<CoverageTable>,
394 pub substitute_glyph_ids: Vec<GlyphId16>,
396}
397
398impl SingleSubstFormat2 {
399 pub fn new(coverage: CoverageTable, substitute_glyph_ids: Vec<GlyphId16>) -> Self {
401 Self {
402 coverage: coverage.into(),
403 substitute_glyph_ids,
404 }
405 }
406}
407
408impl FontWrite for SingleSubstFormat2 {
409 #[allow(clippy::unnecessary_cast)]
410 fn write_into(&self, writer: &mut TableWriter) {
411 (2 as u16).write_into(writer);
412 self.coverage.write_into(writer);
413 (u16::try_from(array_len(&self.substitute_glyph_ids)).unwrap()).write_into(writer);
414 self.substitute_glyph_ids.write_into(writer);
415 }
416 fn table_type(&self) -> TableType {
417 TableType::Named("SingleSubstFormat2")
418 }
419}
420
421impl Validate for SingleSubstFormat2 {
422 fn validate_impl(&self, ctx: &mut ValidationCtx) {
423 ctx.in_table("SingleSubstFormat2", |ctx| {
424 ctx.in_field("coverage", |ctx| {
425 self.coverage.validate_impl(ctx);
426 });
427 ctx.in_field("substitute_glyph_ids", |ctx| {
428 if self.substitute_glyph_ids.len() > (u16::MAX as usize) {
429 ctx.report("array exceeds max length");
430 }
431 });
432 })
433 }
434}
435
436impl<'a> FromObjRef<read_fonts::tables::gsub::SingleSubstFormat2<'a>> for SingleSubstFormat2 {
437 fn from_obj_ref(obj: &read_fonts::tables::gsub::SingleSubstFormat2<'a>, _: FontData) -> Self {
438 let offset_data = obj.offset_data();
439 SingleSubstFormat2 {
440 coverage: obj.coverage().to_owned_table(),
441 substitute_glyph_ids: obj.substitute_glyph_ids().to_owned_obj(offset_data),
442 }
443 }
444}
445
446#[allow(clippy::needless_lifetimes)]
447impl<'a> FromTableRef<read_fonts::tables::gsub::SingleSubstFormat2<'a>> for SingleSubstFormat2 {}
448
449impl<'a> FontRead<'a> for SingleSubstFormat2 {
450 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
451 <read_fonts::tables::gsub::SingleSubstFormat2 as FontRead>::read(data)
452 .map(|x| x.to_owned_table())
453 }
454}
455
456#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
458#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
459pub struct MultipleSubstFormat1 {
460 pub coverage: OffsetMarker<CoverageTable>,
463 pub sequences: Vec<OffsetMarker<Sequence>>,
466}
467
468impl MultipleSubstFormat1 {
469 pub fn new(coverage: CoverageTable, sequences: Vec<Sequence>) -> Self {
471 Self {
472 coverage: coverage.into(),
473 sequences: sequences.into_iter().map(Into::into).collect(),
474 }
475 }
476}
477
478impl FontWrite for MultipleSubstFormat1 {
479 #[allow(clippy::unnecessary_cast)]
480 fn write_into(&self, writer: &mut TableWriter) {
481 (1 as u16).write_into(writer);
482 self.coverage.write_into(writer);
483 (u16::try_from(array_len(&self.sequences)).unwrap()).write_into(writer);
484 self.sequences.write_into(writer);
485 }
486 fn table_type(&self) -> TableType {
487 TableType::Named("MultipleSubstFormat1")
488 }
489}
490
491impl Validate for MultipleSubstFormat1 {
492 fn validate_impl(&self, ctx: &mut ValidationCtx) {
493 ctx.in_table("MultipleSubstFormat1", |ctx| {
494 ctx.in_field("coverage", |ctx| {
495 self.coverage.validate_impl(ctx);
496 });
497 ctx.in_field("sequences", |ctx| {
498 if self.sequences.len() > (u16::MAX as usize) {
499 ctx.report("array exceeds max length");
500 }
501 self.sequences.validate_impl(ctx);
502 });
503 })
504 }
505}
506
507impl<'a> FromObjRef<read_fonts::tables::gsub::MultipleSubstFormat1<'a>> for MultipleSubstFormat1 {
508 fn from_obj_ref(obj: &read_fonts::tables::gsub::MultipleSubstFormat1<'a>, _: FontData) -> Self {
509 MultipleSubstFormat1 {
510 coverage: obj.coverage().to_owned_table(),
511 sequences: obj.sequences().to_owned_table(),
512 }
513 }
514}
515
516#[allow(clippy::needless_lifetimes)]
517impl<'a> FromTableRef<read_fonts::tables::gsub::MultipleSubstFormat1<'a>> for MultipleSubstFormat1 {}
518
519impl<'a> FontRead<'a> for MultipleSubstFormat1 {
520 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
521 <read_fonts::tables::gsub::MultipleSubstFormat1 as FontRead>::read(data)
522 .map(|x| x.to_owned_table())
523 }
524}
525
526#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
528#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
529pub struct Sequence {
530 pub substitute_glyph_ids: Vec<GlyphId16>,
532}
533
534impl Sequence {
535 pub fn new(substitute_glyph_ids: Vec<GlyphId16>) -> Self {
537 Self {
538 substitute_glyph_ids,
539 }
540 }
541}
542
543impl FontWrite for Sequence {
544 #[allow(clippy::unnecessary_cast)]
545 fn write_into(&self, writer: &mut TableWriter) {
546 (u16::try_from(array_len(&self.substitute_glyph_ids)).unwrap()).write_into(writer);
547 self.substitute_glyph_ids.write_into(writer);
548 }
549 fn table_type(&self) -> TableType {
550 TableType::Named("Sequence")
551 }
552}
553
554impl Validate for Sequence {
555 fn validate_impl(&self, ctx: &mut ValidationCtx) {
556 ctx.in_table("Sequence", |ctx| {
557 ctx.in_field("substitute_glyph_ids", |ctx| {
558 if self.substitute_glyph_ids.len() > (u16::MAX as usize) {
559 ctx.report("array exceeds max length");
560 }
561 });
562 })
563 }
564}
565
566impl<'a> FromObjRef<read_fonts::tables::gsub::Sequence<'a>> for Sequence {
567 fn from_obj_ref(obj: &read_fonts::tables::gsub::Sequence<'a>, _: FontData) -> Self {
568 let offset_data = obj.offset_data();
569 Sequence {
570 substitute_glyph_ids: obj.substitute_glyph_ids().to_owned_obj(offset_data),
571 }
572 }
573}
574
575#[allow(clippy::needless_lifetimes)]
576impl<'a> FromTableRef<read_fonts::tables::gsub::Sequence<'a>> for Sequence {}
577
578impl<'a> FontRead<'a> for Sequence {
579 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
580 <read_fonts::tables::gsub::Sequence as FontRead>::read(data).map(|x| x.to_owned_table())
581 }
582}
583
584#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
586#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
587pub struct AlternateSubstFormat1 {
588 pub coverage: OffsetMarker<CoverageTable>,
591 pub alternate_sets: Vec<OffsetMarker<AlternateSet>>,
594}
595
596impl AlternateSubstFormat1 {
597 pub fn new(coverage: CoverageTable, alternate_sets: Vec<AlternateSet>) -> Self {
599 Self {
600 coverage: coverage.into(),
601 alternate_sets: alternate_sets.into_iter().map(Into::into).collect(),
602 }
603 }
604}
605
606impl FontWrite for AlternateSubstFormat1 {
607 #[allow(clippy::unnecessary_cast)]
608 fn write_into(&self, writer: &mut TableWriter) {
609 (1 as u16).write_into(writer);
610 self.coverage.write_into(writer);
611 (u16::try_from(array_len(&self.alternate_sets)).unwrap()).write_into(writer);
612 self.alternate_sets.write_into(writer);
613 }
614 fn table_type(&self) -> TableType {
615 TableType::Named("AlternateSubstFormat1")
616 }
617}
618
619impl Validate for AlternateSubstFormat1 {
620 fn validate_impl(&self, ctx: &mut ValidationCtx) {
621 ctx.in_table("AlternateSubstFormat1", |ctx| {
622 ctx.in_field("coverage", |ctx| {
623 self.coverage.validate_impl(ctx);
624 });
625 ctx.in_field("alternate_sets", |ctx| {
626 if self.alternate_sets.len() > (u16::MAX as usize) {
627 ctx.report("array exceeds max length");
628 }
629 self.alternate_sets.validate_impl(ctx);
630 });
631 })
632 }
633}
634
635impl<'a> FromObjRef<read_fonts::tables::gsub::AlternateSubstFormat1<'a>> for AlternateSubstFormat1 {
636 fn from_obj_ref(
637 obj: &read_fonts::tables::gsub::AlternateSubstFormat1<'a>,
638 _: FontData,
639 ) -> Self {
640 AlternateSubstFormat1 {
641 coverage: obj.coverage().to_owned_table(),
642 alternate_sets: obj.alternate_sets().to_owned_table(),
643 }
644 }
645}
646
647#[allow(clippy::needless_lifetimes)]
648impl<'a> FromTableRef<read_fonts::tables::gsub::AlternateSubstFormat1<'a>>
649 for AlternateSubstFormat1
650{
651}
652
653impl<'a> FontRead<'a> for AlternateSubstFormat1 {
654 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
655 <read_fonts::tables::gsub::AlternateSubstFormat1 as FontRead>::read(data)
656 .map(|x| x.to_owned_table())
657 }
658}
659
660#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
662#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
663pub struct AlternateSet {
664 pub alternate_glyph_ids: Vec<GlyphId16>,
666}
667
668impl AlternateSet {
669 pub fn new(alternate_glyph_ids: Vec<GlyphId16>) -> Self {
671 Self {
672 alternate_glyph_ids,
673 }
674 }
675}
676
677impl FontWrite for AlternateSet {
678 #[allow(clippy::unnecessary_cast)]
679 fn write_into(&self, writer: &mut TableWriter) {
680 (u16::try_from(array_len(&self.alternate_glyph_ids)).unwrap()).write_into(writer);
681 self.alternate_glyph_ids.write_into(writer);
682 }
683 fn table_type(&self) -> TableType {
684 TableType::Named("AlternateSet")
685 }
686}
687
688impl Validate for AlternateSet {
689 fn validate_impl(&self, ctx: &mut ValidationCtx) {
690 ctx.in_table("AlternateSet", |ctx| {
691 ctx.in_field("alternate_glyph_ids", |ctx| {
692 if self.alternate_glyph_ids.len() > (u16::MAX as usize) {
693 ctx.report("array exceeds max length");
694 }
695 });
696 })
697 }
698}
699
700impl<'a> FromObjRef<read_fonts::tables::gsub::AlternateSet<'a>> for AlternateSet {
701 fn from_obj_ref(obj: &read_fonts::tables::gsub::AlternateSet<'a>, _: FontData) -> Self {
702 let offset_data = obj.offset_data();
703 AlternateSet {
704 alternate_glyph_ids: obj.alternate_glyph_ids().to_owned_obj(offset_data),
705 }
706 }
707}
708
709#[allow(clippy::needless_lifetimes)]
710impl<'a> FromTableRef<read_fonts::tables::gsub::AlternateSet<'a>> for AlternateSet {}
711
712impl<'a> FontRead<'a> for AlternateSet {
713 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
714 <read_fonts::tables::gsub::AlternateSet as FontRead>::read(data).map(|x| x.to_owned_table())
715 }
716}
717
718#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
720#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
721pub struct LigatureSubstFormat1 {
722 pub coverage: OffsetMarker<CoverageTable>,
725 pub ligature_sets: Vec<OffsetMarker<LigatureSet>>,
728}
729
730impl LigatureSubstFormat1 {
731 pub fn new(coverage: CoverageTable, ligature_sets: Vec<LigatureSet>) -> Self {
733 Self {
734 coverage: coverage.into(),
735 ligature_sets: ligature_sets.into_iter().map(Into::into).collect(),
736 }
737 }
738}
739
740impl FontWrite for LigatureSubstFormat1 {
741 #[allow(clippy::unnecessary_cast)]
742 fn write_into(&self, writer: &mut TableWriter) {
743 (1 as u16).write_into(writer);
744 self.coverage.write_into(writer);
745 (u16::try_from(array_len(&self.ligature_sets)).unwrap()).write_into(writer);
746 self.ligature_sets.write_into(writer);
747 }
748 fn table_type(&self) -> TableType {
749 TableType::Named("LigatureSubstFormat1")
750 }
751}
752
753impl Validate for LigatureSubstFormat1 {
754 fn validate_impl(&self, ctx: &mut ValidationCtx) {
755 ctx.in_table("LigatureSubstFormat1", |ctx| {
756 ctx.in_field("coverage", |ctx| {
757 self.coverage.validate_impl(ctx);
758 });
759 ctx.in_field("ligature_sets", |ctx| {
760 if self.ligature_sets.len() > (u16::MAX as usize) {
761 ctx.report("array exceeds max length");
762 }
763 self.ligature_sets.validate_impl(ctx);
764 });
765 })
766 }
767}
768
769impl<'a> FromObjRef<read_fonts::tables::gsub::LigatureSubstFormat1<'a>> for LigatureSubstFormat1 {
770 fn from_obj_ref(obj: &read_fonts::tables::gsub::LigatureSubstFormat1<'a>, _: FontData) -> Self {
771 LigatureSubstFormat1 {
772 coverage: obj.coverage().to_owned_table(),
773 ligature_sets: obj.ligature_sets().to_owned_table(),
774 }
775 }
776}
777
778#[allow(clippy::needless_lifetimes)]
779impl<'a> FromTableRef<read_fonts::tables::gsub::LigatureSubstFormat1<'a>> for LigatureSubstFormat1 {}
780
781impl<'a> FontRead<'a> for LigatureSubstFormat1 {
782 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
783 <read_fonts::tables::gsub::LigatureSubstFormat1 as FontRead>::read(data)
784 .map(|x| x.to_owned_table())
785 }
786}
787
788#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
790#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
791pub struct LigatureSet {
792 pub ligatures: Vec<OffsetMarker<Ligature>>,
795}
796
797impl LigatureSet {
798 pub fn new(ligatures: Vec<Ligature>) -> Self {
800 Self {
801 ligatures: ligatures.into_iter().map(Into::into).collect(),
802 }
803 }
804}
805
806impl FontWrite for LigatureSet {
807 #[allow(clippy::unnecessary_cast)]
808 fn write_into(&self, writer: &mut TableWriter) {
809 (u16::try_from(array_len(&self.ligatures)).unwrap()).write_into(writer);
810 self.ligatures.write_into(writer);
811 }
812 fn table_type(&self) -> TableType {
813 TableType::Named("LigatureSet")
814 }
815}
816
817impl Validate for LigatureSet {
818 fn validate_impl(&self, ctx: &mut ValidationCtx) {
819 ctx.in_table("LigatureSet", |ctx| {
820 ctx.in_field("ligatures", |ctx| {
821 if self.ligatures.len() > (u16::MAX as usize) {
822 ctx.report("array exceeds max length");
823 }
824 self.ligatures.validate_impl(ctx);
825 });
826 })
827 }
828}
829
830impl<'a> FromObjRef<read_fonts::tables::gsub::LigatureSet<'a>> for LigatureSet {
831 fn from_obj_ref(obj: &read_fonts::tables::gsub::LigatureSet<'a>, _: FontData) -> Self {
832 LigatureSet {
833 ligatures: obj.ligatures().to_owned_table(),
834 }
835 }
836}
837
838#[allow(clippy::needless_lifetimes)]
839impl<'a> FromTableRef<read_fonts::tables::gsub::LigatureSet<'a>> for LigatureSet {}
840
841impl<'a> FontRead<'a> for LigatureSet {
842 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
843 <read_fonts::tables::gsub::LigatureSet as FontRead>::read(data).map(|x| x.to_owned_table())
844 }
845}
846
847#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
849#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
850pub struct Ligature {
851 pub ligature_glyph: GlyphId16,
853 pub component_glyph_ids: Vec<GlyphId16>,
856}
857
858impl Ligature {
859 pub fn new(ligature_glyph: GlyphId16, component_glyph_ids: Vec<GlyphId16>) -> Self {
861 Self {
862 ligature_glyph,
863 component_glyph_ids,
864 }
865 }
866}
867
868impl FontWrite for Ligature {
869 #[allow(clippy::unnecessary_cast)]
870 fn write_into(&self, writer: &mut TableWriter) {
871 self.ligature_glyph.write_into(writer);
872 (u16::try_from(plus_one(&self.component_glyph_ids.len())).unwrap()).write_into(writer);
873 self.component_glyph_ids.write_into(writer);
874 }
875 fn table_type(&self) -> TableType {
876 TableType::Named("Ligature")
877 }
878}
879
880impl Validate for Ligature {
881 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
882}
883
884impl<'a> FromObjRef<read_fonts::tables::gsub::Ligature<'a>> for Ligature {
885 fn from_obj_ref(obj: &read_fonts::tables::gsub::Ligature<'a>, _: FontData) -> Self {
886 let offset_data = obj.offset_data();
887 Ligature {
888 ligature_glyph: obj.ligature_glyph(),
889 component_glyph_ids: obj.component_glyph_ids().to_owned_obj(offset_data),
890 }
891 }
892}
893
894#[allow(clippy::needless_lifetimes)]
895impl<'a> FromTableRef<read_fonts::tables::gsub::Ligature<'a>> for Ligature {}
896
897impl<'a> FontRead<'a> for Ligature {
898 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
899 <read_fonts::tables::gsub::Ligature as FontRead>::read(data).map(|x| x.to_owned_table())
900 }
901}
902
903#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
905#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
906pub struct ExtensionSubstFormat1<T> {
907 pub extension_lookup_type: u16,
910 pub extension: OffsetMarker<T, WIDTH_32>,
914}
915
916impl<T: Default> ExtensionSubstFormat1<T> {
917 pub fn new(extension_lookup_type: u16, extension: T) -> Self {
919 Self {
920 extension_lookup_type,
921 extension: extension.into(),
922 }
923 }
924}
925
926impl<T: Validate> Validate for ExtensionSubstFormat1<T> {
927 fn validate_impl(&self, ctx: &mut ValidationCtx) {
928 ctx.in_table("ExtensionSubstFormat1", |ctx| {
929 ctx.in_field("extension", |ctx| {
930 self.extension.validate_impl(ctx);
931 });
932 })
933 }
934}
935
936impl<'a, T, U> FromObjRef<read_fonts::tables::gsub::ExtensionSubstFormat1<'a, U>>
937 for ExtensionSubstFormat1<T>
938where
939 U: FontRead<'a>,
940 T: FromTableRef<U> + Default + 'static,
941{
942 fn from_obj_ref(
943 obj: &read_fonts::tables::gsub::ExtensionSubstFormat1<'a, U>,
944 _: FontData,
945 ) -> Self {
946 ExtensionSubstFormat1 {
947 extension_lookup_type: obj.extension_lookup_type(),
948 extension: obj.extension().to_owned_table(),
949 }
950 }
951}
952
953#[allow(clippy::needless_lifetimes)]
954impl<'a, T, U> FromTableRef<read_fonts::tables::gsub::ExtensionSubstFormat1<'a, U>>
955 for ExtensionSubstFormat1<T>
956where
957 U: FontRead<'a>,
958 T: FromTableRef<U> + Default + 'static,
959{
960}
961
962#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
964#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
965pub enum ExtensionSubtable {
966 Single(ExtensionSubstFormat1<SingleSubst>),
967 Multiple(ExtensionSubstFormat1<MultipleSubstFormat1>),
968 Alternate(ExtensionSubstFormat1<AlternateSubstFormat1>),
969 Ligature(ExtensionSubstFormat1<LigatureSubstFormat1>),
970 Contextual(ExtensionSubstFormat1<SubstitutionSequenceContext>),
971 ChainContextual(ExtensionSubstFormat1<SubstitutionChainContext>),
972 Reverse(ExtensionSubstFormat1<ReverseChainSingleSubstFormat1>),
973}
974
975impl Default for ExtensionSubtable {
976 fn default() -> Self {
977 Self::Single(Default::default())
978 }
979}
980
981impl FontWrite for ExtensionSubtable {
982 fn write_into(&self, writer: &mut TableWriter) {
983 match self {
984 Self::Single(table) => table.write_into(writer),
985 Self::Multiple(table) => table.write_into(writer),
986 Self::Alternate(table) => table.write_into(writer),
987 Self::Ligature(table) => table.write_into(writer),
988 Self::Contextual(table) => table.write_into(writer),
989 Self::ChainContextual(table) => table.write_into(writer),
990 Self::Reverse(table) => table.write_into(writer),
991 }
992 }
993 fn table_type(&self) -> TableType {
994 match self {
995 Self::Single(table) => table.table_type(),
996 Self::Multiple(table) => table.table_type(),
997 Self::Alternate(table) => table.table_type(),
998 Self::Ligature(table) => table.table_type(),
999 Self::Contextual(table) => table.table_type(),
1000 Self::ChainContextual(table) => table.table_type(),
1001 Self::Reverse(table) => table.table_type(),
1002 }
1003 }
1004}
1005
1006impl Validate for ExtensionSubtable {
1007 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1008 match self {
1009 Self::Single(table) => table.validate_impl(ctx),
1010 Self::Multiple(table) => table.validate_impl(ctx),
1011 Self::Alternate(table) => table.validate_impl(ctx),
1012 Self::Ligature(table) => table.validate_impl(ctx),
1013 Self::Contextual(table) => table.validate_impl(ctx),
1014 Self::ChainContextual(table) => table.validate_impl(ctx),
1015 Self::Reverse(table) => table.validate_impl(ctx),
1016 }
1017 }
1018}
1019
1020impl FromObjRef<read_fonts::tables::gsub::ExtensionSubtable<'_>> for ExtensionSubtable {
1021 fn from_obj_ref(
1022 from: &read_fonts::tables::gsub::ExtensionSubtable<'_>,
1023 data: FontData,
1024 ) -> Self {
1025 match from {
1026 read_fonts::tables::gsub::ExtensionSubtable::Single(table) => {
1027 Self::Single(table.to_owned_obj(data))
1028 }
1029 read_fonts::tables::gsub::ExtensionSubtable::Multiple(table) => {
1030 Self::Multiple(table.to_owned_obj(data))
1031 }
1032 read_fonts::tables::gsub::ExtensionSubtable::Alternate(table) => {
1033 Self::Alternate(table.to_owned_obj(data))
1034 }
1035 read_fonts::tables::gsub::ExtensionSubtable::Ligature(table) => {
1036 Self::Ligature(table.to_owned_obj(data))
1037 }
1038 read_fonts::tables::gsub::ExtensionSubtable::Contextual(table) => {
1039 Self::Contextual(table.to_owned_obj(data))
1040 }
1041 read_fonts::tables::gsub::ExtensionSubtable::ChainContextual(table) => {
1042 Self::ChainContextual(table.to_owned_obj(data))
1043 }
1044 read_fonts::tables::gsub::ExtensionSubtable::Reverse(table) => {
1045 Self::Reverse(table.to_owned_obj(data))
1046 }
1047 }
1048 }
1049}
1050
1051impl FromTableRef<read_fonts::tables::gsub::ExtensionSubtable<'_>> for ExtensionSubtable {}
1052
1053impl From<ExtensionSubstFormat1<SingleSubst>> for ExtensionSubtable {
1054 fn from(src: ExtensionSubstFormat1<SingleSubst>) -> ExtensionSubtable {
1055 ExtensionSubtable::Single(src)
1056 }
1057}
1058
1059impl From<ExtensionSubstFormat1<MultipleSubstFormat1>> for ExtensionSubtable {
1060 fn from(src: ExtensionSubstFormat1<MultipleSubstFormat1>) -> ExtensionSubtable {
1061 ExtensionSubtable::Multiple(src)
1062 }
1063}
1064
1065impl From<ExtensionSubstFormat1<AlternateSubstFormat1>> for ExtensionSubtable {
1066 fn from(src: ExtensionSubstFormat1<AlternateSubstFormat1>) -> ExtensionSubtable {
1067 ExtensionSubtable::Alternate(src)
1068 }
1069}
1070
1071impl From<ExtensionSubstFormat1<LigatureSubstFormat1>> for ExtensionSubtable {
1072 fn from(src: ExtensionSubstFormat1<LigatureSubstFormat1>) -> ExtensionSubtable {
1073 ExtensionSubtable::Ligature(src)
1074 }
1075}
1076
1077impl From<ExtensionSubstFormat1<SubstitutionSequenceContext>> for ExtensionSubtable {
1078 fn from(src: ExtensionSubstFormat1<SubstitutionSequenceContext>) -> ExtensionSubtable {
1079 ExtensionSubtable::Contextual(src)
1080 }
1081}
1082
1083impl From<ExtensionSubstFormat1<SubstitutionChainContext>> for ExtensionSubtable {
1084 fn from(src: ExtensionSubstFormat1<SubstitutionChainContext>) -> ExtensionSubtable {
1085 ExtensionSubtable::ChainContextual(src)
1086 }
1087}
1088
1089impl From<ExtensionSubstFormat1<ReverseChainSingleSubstFormat1>> for ExtensionSubtable {
1090 fn from(src: ExtensionSubstFormat1<ReverseChainSingleSubstFormat1>) -> ExtensionSubtable {
1091 ExtensionSubtable::Reverse(src)
1092 }
1093}
1094
1095#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1097#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1098pub struct ReverseChainSingleSubstFormat1 {
1099 pub coverage: OffsetMarker<CoverageTable>,
1102 pub backtrack_coverages: Vec<OffsetMarker<CoverageTable>>,
1105 pub lookahead_coverages: Vec<OffsetMarker<CoverageTable>>,
1108 pub substitute_glyph_ids: Vec<GlyphId16>,
1110}
1111
1112impl ReverseChainSingleSubstFormat1 {
1113 pub fn new(
1115 coverage: CoverageTable,
1116 backtrack_coverages: Vec<CoverageTable>,
1117 lookahead_coverages: Vec<CoverageTable>,
1118 substitute_glyph_ids: Vec<GlyphId16>,
1119 ) -> Self {
1120 Self {
1121 coverage: coverage.into(),
1122 backtrack_coverages: backtrack_coverages.into_iter().map(Into::into).collect(),
1123 lookahead_coverages: lookahead_coverages.into_iter().map(Into::into).collect(),
1124 substitute_glyph_ids,
1125 }
1126 }
1127}
1128
1129impl FontWrite for ReverseChainSingleSubstFormat1 {
1130 #[allow(clippy::unnecessary_cast)]
1131 fn write_into(&self, writer: &mut TableWriter) {
1132 (1 as u16).write_into(writer);
1133 self.coverage.write_into(writer);
1134 (u16::try_from(array_len(&self.backtrack_coverages)).unwrap()).write_into(writer);
1135 self.backtrack_coverages.write_into(writer);
1136 (u16::try_from(array_len(&self.lookahead_coverages)).unwrap()).write_into(writer);
1137 self.lookahead_coverages.write_into(writer);
1138 (u16::try_from(array_len(&self.substitute_glyph_ids)).unwrap()).write_into(writer);
1139 self.substitute_glyph_ids.write_into(writer);
1140 }
1141 fn table_type(&self) -> TableType {
1142 TableType::Named("ReverseChainSingleSubstFormat1")
1143 }
1144}
1145
1146impl Validate for ReverseChainSingleSubstFormat1 {
1147 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1148 ctx.in_table("ReverseChainSingleSubstFormat1", |ctx| {
1149 ctx.in_field("coverage", |ctx| {
1150 self.coverage.validate_impl(ctx);
1151 });
1152 ctx.in_field("backtrack_coverages", |ctx| {
1153 if self.backtrack_coverages.len() > (u16::MAX as usize) {
1154 ctx.report("array exceeds max length");
1155 }
1156 self.backtrack_coverages.validate_impl(ctx);
1157 });
1158 ctx.in_field("lookahead_coverages", |ctx| {
1159 if self.lookahead_coverages.len() > (u16::MAX as usize) {
1160 ctx.report("array exceeds max length");
1161 }
1162 self.lookahead_coverages.validate_impl(ctx);
1163 });
1164 ctx.in_field("substitute_glyph_ids", |ctx| {
1165 if self.substitute_glyph_ids.len() > (u16::MAX as usize) {
1166 ctx.report("array exceeds max length");
1167 }
1168 });
1169 })
1170 }
1171}
1172
1173impl<'a> FromObjRef<read_fonts::tables::gsub::ReverseChainSingleSubstFormat1<'a>>
1174 for ReverseChainSingleSubstFormat1
1175{
1176 fn from_obj_ref(
1177 obj: &read_fonts::tables::gsub::ReverseChainSingleSubstFormat1<'a>,
1178 _: FontData,
1179 ) -> Self {
1180 let offset_data = obj.offset_data();
1181 ReverseChainSingleSubstFormat1 {
1182 coverage: obj.coverage().to_owned_table(),
1183 backtrack_coverages: obj.backtrack_coverages().to_owned_table(),
1184 lookahead_coverages: obj.lookahead_coverages().to_owned_table(),
1185 substitute_glyph_ids: obj.substitute_glyph_ids().to_owned_obj(offset_data),
1186 }
1187 }
1188}
1189
1190#[allow(clippy::needless_lifetimes)]
1191impl<'a> FromTableRef<read_fonts::tables::gsub::ReverseChainSingleSubstFormat1<'a>>
1192 for ReverseChainSingleSubstFormat1
1193{
1194}
1195
1196impl<'a> FontRead<'a> for ReverseChainSingleSubstFormat1 {
1197 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1198 <read_fonts::tables::gsub::ReverseChainSingleSubstFormat1 as FontRead>::read(data)
1199 .map(|x| x.to_owned_table())
1200 }
1201}