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