1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8pub use read_fonts::tables::gpos::ValueFormat;
9
10#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct Gpos {
15 pub script_list: OffsetMarker<ScriptList>,
17 pub feature_list: OffsetMarker<FeatureList>,
19 pub lookup_list: OffsetMarker<PositionLookupList>,
21 pub feature_variations: NullableOffsetMarker<FeatureVariations, WIDTH_32>,
22}
23
24impl Gpos {
25 pub fn new(
27 script_list: ScriptList,
28 feature_list: FeatureList,
29 lookup_list: PositionLookupList,
30 ) -> Self {
31 Self {
32 script_list: script_list.into(),
33 feature_list: feature_list.into(),
34 lookup_list: lookup_list.into(),
35 ..Default::default()
36 }
37 }
38}
39
40impl FontWrite for Gpos {
41 #[allow(clippy::unnecessary_cast)]
42 fn write_into(&self, writer: &mut TableWriter) {
43 let version = self.compute_version() as MajorMinor;
44 version.write_into(writer);
45 self.script_list.write_into(writer);
46 self.feature_list.write_into(writer);
47 self.lookup_list.write_into(writer);
48 version
49 .compatible((1u16, 1u16))
50 .then(|| self.feature_variations.write_into(writer));
51 }
52 fn table_type(&self) -> TableType {
53 TableType::TopLevel(Gpos::TAG)
54 }
55}
56
57impl Validate for Gpos {
58 fn validate_impl(&self, ctx: &mut ValidationCtx) {
59 ctx.in_table("Gpos", |ctx| {
60 ctx.in_field("script_list", |ctx| {
61 self.script_list.validate_impl(ctx);
62 });
63 ctx.in_field("feature_list", |ctx| {
64 self.feature_list.validate_impl(ctx);
65 });
66 ctx.in_field("lookup_list", |ctx| {
67 self.lookup_list.validate_impl(ctx);
68 });
69 ctx.in_field("feature_variations", |ctx| {
70 self.feature_variations.validate_impl(ctx);
71 });
72 })
73 }
74}
75
76impl TopLevelTable for Gpos {
77 const TAG: Tag = Tag::new(b"GPOS");
78}
79
80impl<'a> FromObjRef<read_fonts::tables::gpos::Gpos<'a>> for Gpos {
81 fn from_obj_ref(obj: &read_fonts::tables::gpos::Gpos<'a>, _: FontData) -> Self {
82 Gpos {
83 script_list: obj.script_list().to_owned_table(),
84 feature_list: obj.feature_list().to_owned_table(),
85 lookup_list: obj.lookup_list().to_owned_table(),
86 feature_variations: obj.feature_variations().to_owned_table(),
87 }
88 }
89}
90
91#[allow(clippy::needless_lifetimes)]
92impl<'a> FromTableRef<read_fonts::tables::gpos::Gpos<'a>> for Gpos {}
93
94impl ReadArgs for Gpos {
95 type Args = ();
96}
97
98impl<'a> FontRead<'a> for Gpos {
99 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
100 <read_fonts::tables::gpos::Gpos as FontRead>::read(data).map(|x| x.to_owned_table())
101 }
102}
103
104#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
106#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
107pub enum PositionLookup {
108 Single(Lookup<SinglePos>),
109 Pair(Lookup<PairPos>),
110 Cursive(Lookup<CursivePosFormat1>),
111 MarkToBase(Lookup<MarkBasePosFormat1>),
112 MarkToLig(Lookup<MarkLigPosFormat1>),
113 MarkToMark(Lookup<MarkMarkPosFormat1>),
114 Contextual(Lookup<PositionSequenceContext>),
115 ChainContextual(Lookup<PositionChainContext>),
116 Extension(Lookup<ExtensionSubtable>),
117}
118
119impl Default for PositionLookup {
120 fn default() -> Self {
121 Self::Single(Default::default())
122 }
123}
124
125impl FontWrite for PositionLookup {
126 fn write_into(&self, writer: &mut TableWriter) {
127 match self {
128 Self::Single(table) => table.write_into(writer),
129 Self::Pair(table) => table.write_into(writer),
130 Self::Cursive(table) => table.write_into(writer),
131 Self::MarkToBase(table) => table.write_into(writer),
132 Self::MarkToLig(table) => table.write_into(writer),
133 Self::MarkToMark(table) => table.write_into(writer),
134 Self::Contextual(table) => table.write_into(writer),
135 Self::ChainContextual(table) => table.write_into(writer),
136 Self::Extension(table) => table.write_into(writer),
137 }
138 }
139 fn table_type(&self) -> TableType {
140 match self {
141 Self::Single(table) => table.table_type(),
142 Self::Pair(table) => table.table_type(),
143 Self::Cursive(table) => table.table_type(),
144 Self::MarkToBase(table) => table.table_type(),
145 Self::MarkToLig(table) => table.table_type(),
146 Self::MarkToMark(table) => table.table_type(),
147 Self::Contextual(table) => table.table_type(),
148 Self::ChainContextual(table) => table.table_type(),
149 Self::Extension(table) => table.table_type(),
150 }
151 }
152}
153
154impl Validate for PositionLookup {
155 fn validate_impl(&self, ctx: &mut ValidationCtx) {
156 match self {
157 Self::Single(table) => table.validate_impl(ctx),
158 Self::Pair(table) => table.validate_impl(ctx),
159 Self::Cursive(table) => table.validate_impl(ctx),
160 Self::MarkToBase(table) => table.validate_impl(ctx),
161 Self::MarkToLig(table) => table.validate_impl(ctx),
162 Self::MarkToMark(table) => table.validate_impl(ctx),
163 Self::Contextual(table) => table.validate_impl(ctx),
164 Self::ChainContextual(table) => table.validate_impl(ctx),
165 Self::Extension(table) => table.validate_impl(ctx),
166 }
167 }
168}
169
170impl FromObjRef<read_fonts::tables::gpos::PositionLookup<'_>> for PositionLookup {
171 fn from_obj_ref(from: &read_fonts::tables::gpos::PositionLookup<'_>, data: FontData) -> Self {
172 match from {
173 read_fonts::tables::gpos::PositionLookup::Single(table) => {
174 Self::Single(table.to_owned_obj(data))
175 }
176 read_fonts::tables::gpos::PositionLookup::Pair(table) => {
177 Self::Pair(table.to_owned_obj(data))
178 }
179 read_fonts::tables::gpos::PositionLookup::Cursive(table) => {
180 Self::Cursive(table.to_owned_obj(data))
181 }
182 read_fonts::tables::gpos::PositionLookup::MarkToBase(table) => {
183 Self::MarkToBase(table.to_owned_obj(data))
184 }
185 read_fonts::tables::gpos::PositionLookup::MarkToLig(table) => {
186 Self::MarkToLig(table.to_owned_obj(data))
187 }
188 read_fonts::tables::gpos::PositionLookup::MarkToMark(table) => {
189 Self::MarkToMark(table.to_owned_obj(data))
190 }
191 read_fonts::tables::gpos::PositionLookup::Contextual(table) => {
192 Self::Contextual(table.to_owned_obj(data))
193 }
194 read_fonts::tables::gpos::PositionLookup::ChainContextual(table) => {
195 Self::ChainContextual(table.to_owned_obj(data))
196 }
197 read_fonts::tables::gpos::PositionLookup::Extension(table) => {
198 Self::Extension(table.to_owned_obj(data))
199 }
200 }
201 }
202}
203
204impl FromTableRef<read_fonts::tables::gpos::PositionLookup<'_>> for PositionLookup {}
205
206impl From<Lookup<SinglePos>> for PositionLookup {
207 fn from(src: Lookup<SinglePos>) -> PositionLookup {
208 PositionLookup::Single(src)
209 }
210}
211
212impl From<Lookup<PairPos>> for PositionLookup {
213 fn from(src: Lookup<PairPos>) -> PositionLookup {
214 PositionLookup::Pair(src)
215 }
216}
217
218impl From<Lookup<CursivePosFormat1>> for PositionLookup {
219 fn from(src: Lookup<CursivePosFormat1>) -> PositionLookup {
220 PositionLookup::Cursive(src)
221 }
222}
223
224impl From<Lookup<MarkBasePosFormat1>> for PositionLookup {
225 fn from(src: Lookup<MarkBasePosFormat1>) -> PositionLookup {
226 PositionLookup::MarkToBase(src)
227 }
228}
229
230impl From<Lookup<MarkLigPosFormat1>> for PositionLookup {
231 fn from(src: Lookup<MarkLigPosFormat1>) -> PositionLookup {
232 PositionLookup::MarkToLig(src)
233 }
234}
235
236impl From<Lookup<MarkMarkPosFormat1>> for PositionLookup {
237 fn from(src: Lookup<MarkMarkPosFormat1>) -> PositionLookup {
238 PositionLookup::MarkToMark(src)
239 }
240}
241
242impl From<Lookup<PositionSequenceContext>> for PositionLookup {
243 fn from(src: Lookup<PositionSequenceContext>) -> PositionLookup {
244 PositionLookup::Contextual(src)
245 }
246}
247
248impl From<Lookup<PositionChainContext>> for PositionLookup {
249 fn from(src: Lookup<PositionChainContext>) -> PositionLookup {
250 PositionLookup::ChainContextual(src)
251 }
252}
253
254impl From<Lookup<ExtensionSubtable>> for PositionLookup {
255 fn from(src: Lookup<ExtensionSubtable>) -> PositionLookup {
256 PositionLookup::Extension(src)
257 }
258}
259
260impl FontWrite for ValueFormat {
261 fn write_into(&self, writer: &mut TableWriter) {
262 writer.write_slice(&self.bits().to_be_bytes())
263 }
264}
265
266#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
269#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
270pub enum AnchorTable {
271 Format1(AnchorFormat1),
272 Format2(AnchorFormat2),
273 Format3(AnchorFormat3),
274}
275
276impl AnchorTable {
277 pub fn format_1(x_coordinate: i16, y_coordinate: i16) -> Self {
279 Self::Format1(AnchorFormat1::new(x_coordinate, y_coordinate))
280 }
281
282 pub fn format_2(x_coordinate: i16, y_coordinate: i16, anchor_point: u16) -> Self {
284 Self::Format2(AnchorFormat2::new(x_coordinate, y_coordinate, anchor_point))
285 }
286
287 pub fn format_3(
289 x_coordinate: i16,
290 y_coordinate: i16,
291 x_device: Option<DeviceOrVariationIndex>,
292 y_device: Option<DeviceOrVariationIndex>,
293 ) -> Self {
294 Self::Format3(AnchorFormat3::new(
295 x_coordinate,
296 y_coordinate,
297 x_device,
298 y_device,
299 ))
300 }
301}
302
303impl Default for AnchorTable {
304 fn default() -> Self {
305 Self::Format1(Default::default())
306 }
307}
308
309impl FontWrite for AnchorTable {
310 fn write_into(&self, writer: &mut TableWriter) {
311 match self {
312 Self::Format1(item) => item.write_into(writer),
313 Self::Format2(item) => item.write_into(writer),
314 Self::Format3(item) => item.write_into(writer),
315 }
316 }
317 fn table_type(&self) -> TableType {
318 match self {
319 Self::Format1(item) => item.table_type(),
320 Self::Format2(item) => item.table_type(),
321 Self::Format3(item) => item.table_type(),
322 }
323 }
324}
325
326impl Validate for AnchorTable {
327 fn validate_impl(&self, ctx: &mut ValidationCtx) {
328 match self {
329 Self::Format1(item) => item.validate_impl(ctx),
330 Self::Format2(item) => item.validate_impl(ctx),
331 Self::Format3(item) => item.validate_impl(ctx),
332 }
333 }
334}
335
336impl FromObjRef<read_fonts::tables::gpos::AnchorTable<'_>> for AnchorTable {
337 fn from_obj_ref(obj: &read_fonts::tables::gpos::AnchorTable, _: FontData) -> Self {
338 use read_fonts::tables::gpos::AnchorTable as ObjRefType;
339 match obj {
340 ObjRefType::Format1(item) => AnchorTable::Format1(item.to_owned_table()),
341 ObjRefType::Format2(item) => AnchorTable::Format2(item.to_owned_table()),
342 ObjRefType::Format3(item) => AnchorTable::Format3(item.to_owned_table()),
343 }
344 }
345}
346
347impl FromTableRef<read_fonts::tables::gpos::AnchorTable<'_>> for AnchorTable {}
348
349impl ReadArgs for AnchorTable {
350 type Args = ();
351}
352
353impl<'a> FontRead<'a> for AnchorTable {
354 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
355 <read_fonts::tables::gpos::AnchorTable as FontRead>::read(data).map(|x| x.to_owned_table())
356 }
357}
358
359impl From<AnchorFormat1> for AnchorTable {
360 fn from(src: AnchorFormat1) -> AnchorTable {
361 AnchorTable::Format1(src)
362 }
363}
364
365impl From<AnchorFormat2> for AnchorTable {
366 fn from(src: AnchorFormat2) -> AnchorTable {
367 AnchorTable::Format2(src)
368 }
369}
370
371impl From<AnchorFormat3> for AnchorTable {
372 fn from(src: AnchorFormat3) -> AnchorTable {
373 AnchorTable::Format3(src)
374 }
375}
376
377#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
379#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
380pub struct AnchorFormat1 {
381 pub x_coordinate: i16,
383 pub y_coordinate: i16,
385}
386
387impl AnchorFormat1 {
388 pub fn new(x_coordinate: i16, y_coordinate: i16) -> Self {
390 Self {
391 x_coordinate,
392 y_coordinate,
393 }
394 }
395}
396
397impl FontWrite for AnchorFormat1 {
398 #[allow(clippy::unnecessary_cast)]
399 fn write_into(&self, writer: &mut TableWriter) {
400 (1 as u16).write_into(writer);
401 self.x_coordinate.write_into(writer);
402 self.y_coordinate.write_into(writer);
403 }
404 fn table_type(&self) -> TableType {
405 TableType::Named("AnchorFormat1")
406 }
407}
408
409impl Validate for AnchorFormat1 {
410 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
411}
412
413impl<'a> FromObjRef<read_fonts::tables::gpos::AnchorFormat1<'a>> for AnchorFormat1 {
414 fn from_obj_ref(obj: &read_fonts::tables::gpos::AnchorFormat1<'a>, _: FontData) -> Self {
415 AnchorFormat1 {
416 x_coordinate: obj.x_coordinate(),
417 y_coordinate: obj.y_coordinate(),
418 }
419 }
420}
421
422#[allow(clippy::needless_lifetimes)]
423impl<'a> FromTableRef<read_fonts::tables::gpos::AnchorFormat1<'a>> for AnchorFormat1 {}
424
425impl ReadArgs for AnchorFormat1 {
426 type Args = ();
427}
428
429impl<'a> FontRead<'a> for AnchorFormat1 {
430 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
431 <read_fonts::tables::gpos::AnchorFormat1 as FontRead>::read(data)
432 .map(|x| x.to_owned_table())
433 }
434}
435
436#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
438#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
439pub struct AnchorFormat2 {
440 pub x_coordinate: i16,
442 pub y_coordinate: i16,
444 pub anchor_point: u16,
446}
447
448impl AnchorFormat2 {
449 pub fn new(x_coordinate: i16, y_coordinate: i16, anchor_point: u16) -> Self {
451 Self {
452 x_coordinate,
453 y_coordinate,
454 anchor_point,
455 }
456 }
457}
458
459impl FontWrite for AnchorFormat2 {
460 #[allow(clippy::unnecessary_cast)]
461 fn write_into(&self, writer: &mut TableWriter) {
462 (2 as u16).write_into(writer);
463 self.x_coordinate.write_into(writer);
464 self.y_coordinate.write_into(writer);
465 self.anchor_point.write_into(writer);
466 }
467 fn table_type(&self) -> TableType {
468 TableType::Named("AnchorFormat2")
469 }
470}
471
472impl Validate for AnchorFormat2 {
473 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
474}
475
476impl<'a> FromObjRef<read_fonts::tables::gpos::AnchorFormat2<'a>> for AnchorFormat2 {
477 fn from_obj_ref(obj: &read_fonts::tables::gpos::AnchorFormat2<'a>, _: FontData) -> Self {
478 AnchorFormat2 {
479 x_coordinate: obj.x_coordinate(),
480 y_coordinate: obj.y_coordinate(),
481 anchor_point: obj.anchor_point(),
482 }
483 }
484}
485
486#[allow(clippy::needless_lifetimes)]
487impl<'a> FromTableRef<read_fonts::tables::gpos::AnchorFormat2<'a>> for AnchorFormat2 {}
488
489impl ReadArgs for AnchorFormat2 {
490 type Args = ();
491}
492
493impl<'a> FontRead<'a> for AnchorFormat2 {
494 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
495 <read_fonts::tables::gpos::AnchorFormat2 as FontRead>::read(data)
496 .map(|x| x.to_owned_table())
497 }
498}
499
500#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
502#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
503pub struct AnchorFormat3 {
504 pub x_coordinate: i16,
506 pub y_coordinate: i16,
508 pub x_device: NullableOffsetMarker<DeviceOrVariationIndex>,
512 pub y_device: NullableOffsetMarker<DeviceOrVariationIndex>,
516}
517
518impl AnchorFormat3 {
519 pub fn new(
521 x_coordinate: i16,
522 y_coordinate: i16,
523 x_device: Option<DeviceOrVariationIndex>,
524 y_device: Option<DeviceOrVariationIndex>,
525 ) -> Self {
526 Self {
527 x_coordinate,
528 y_coordinate,
529 x_device: x_device.into(),
530 y_device: y_device.into(),
531 }
532 }
533}
534
535impl FontWrite for AnchorFormat3 {
536 #[allow(clippy::unnecessary_cast)]
537 fn write_into(&self, writer: &mut TableWriter) {
538 (3 as u16).write_into(writer);
539 self.x_coordinate.write_into(writer);
540 self.y_coordinate.write_into(writer);
541 self.x_device.write_into(writer);
542 self.y_device.write_into(writer);
543 }
544 fn table_type(&self) -> TableType {
545 TableType::Named("AnchorFormat3")
546 }
547}
548
549impl Validate for AnchorFormat3 {
550 fn validate_impl(&self, ctx: &mut ValidationCtx) {
551 ctx.in_table("AnchorFormat3", |ctx| {
552 ctx.in_field("x_device", |ctx| {
553 self.x_device.validate_impl(ctx);
554 });
555 ctx.in_field("y_device", |ctx| {
556 self.y_device.validate_impl(ctx);
557 });
558 })
559 }
560}
561
562impl<'a> FromObjRef<read_fonts::tables::gpos::AnchorFormat3<'a>> for AnchorFormat3 {
563 fn from_obj_ref(obj: &read_fonts::tables::gpos::AnchorFormat3<'a>, _: FontData) -> Self {
564 AnchorFormat3 {
565 x_coordinate: obj.x_coordinate(),
566 y_coordinate: obj.y_coordinate(),
567 x_device: obj.x_device().to_owned_table(),
568 y_device: obj.y_device().to_owned_table(),
569 }
570 }
571}
572
573#[allow(clippy::needless_lifetimes)]
574impl<'a> FromTableRef<read_fonts::tables::gpos::AnchorFormat3<'a>> for AnchorFormat3 {}
575
576impl ReadArgs for AnchorFormat3 {
577 type Args = ();
578}
579
580impl<'a> FontRead<'a> for AnchorFormat3 {
581 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
582 <read_fonts::tables::gpos::AnchorFormat3 as FontRead>::read(data)
583 .map(|x| x.to_owned_table())
584 }
585}
586
587#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
589#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
590pub struct MarkArray {
591 pub mark_records: Vec<MarkRecord>,
594}
595
596impl MarkArray {
597 pub fn new(mark_records: Vec<MarkRecord>) -> Self {
599 Self { mark_records }
600 }
601}
602
603impl FontWrite for MarkArray {
604 #[allow(clippy::unnecessary_cast)]
605 fn write_into(&self, writer: &mut TableWriter) {
606 (u16::try_from(array_len(&self.mark_records)).unwrap()).write_into(writer);
607 self.mark_records.write_into(writer);
608 }
609 fn table_type(&self) -> TableType {
610 TableType::Named("MarkArray")
611 }
612}
613
614impl Validate for MarkArray {
615 fn validate_impl(&self, ctx: &mut ValidationCtx) {
616 ctx.in_table("MarkArray", |ctx| {
617 ctx.in_field("mark_records", |ctx| {
618 if self.mark_records.len() > to_usize(u16::MAX) {
619 ctx.report("array exceeds max length");
620 }
621 self.mark_records.validate_impl(ctx);
622 });
623 })
624 }
625}
626
627impl<'a> FromObjRef<read_fonts::tables::gpos::MarkArray<'a>> for MarkArray {
628 fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkArray<'a>, _: FontData) -> Self {
629 let offset_data = obj.offset_data();
630 MarkArray {
631 mark_records: obj.mark_records().to_owned_obj(offset_data),
632 }
633 }
634}
635
636#[allow(clippy::needless_lifetimes)]
637impl<'a> FromTableRef<read_fonts::tables::gpos::MarkArray<'a>> for MarkArray {}
638
639impl ReadArgs for MarkArray {
640 type Args = ();
641}
642
643impl<'a> FontRead<'a> for MarkArray {
644 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
645 <read_fonts::tables::gpos::MarkArray as FontRead>::read(data).map(|x| x.to_owned_table())
646 }
647}
648
649#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
651#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
652pub struct MarkRecord {
653 pub mark_class: u16,
655 pub mark_anchor: OffsetMarker<AnchorTable>,
657}
658
659impl MarkRecord {
660 pub fn new(mark_class: u16, mark_anchor: AnchorTable) -> Self {
662 Self {
663 mark_class,
664 mark_anchor: mark_anchor.into(),
665 }
666 }
667}
668
669impl FontWrite for MarkRecord {
670 fn write_into(&self, writer: &mut TableWriter) {
671 self.mark_class.write_into(writer);
672 self.mark_anchor.write_into(writer);
673 }
674 fn table_type(&self) -> TableType {
675 TableType::Named("MarkRecord")
676 }
677}
678
679impl Validate for MarkRecord {
680 fn validate_impl(&self, ctx: &mut ValidationCtx) {
681 ctx.in_table("MarkRecord", |ctx| {
682 ctx.in_field("mark_anchor", |ctx| {
683 self.mark_anchor.validate_impl(ctx);
684 });
685 })
686 }
687}
688
689impl FromObjRef<read_fonts::tables::gpos::MarkRecord> for MarkRecord {
690 fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkRecord, offset_data: FontData) -> Self {
691 MarkRecord {
692 mark_class: obj.mark_class(),
693 mark_anchor: obj.mark_anchor(offset_data).to_owned_table(),
694 }
695 }
696}
697
698#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
700#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
701pub enum SinglePos {
702 Format1(SinglePosFormat1),
703 Format2(SinglePosFormat2),
704}
705
706impl SinglePos {
707 pub fn format_1(coverage: CoverageTable, value_record: ValueRecord) -> Self {
709 Self::Format1(SinglePosFormat1::new(coverage, value_record))
710 }
711
712 pub fn format_2(coverage: CoverageTable, value_records: Vec<ValueRecord>) -> Self {
714 Self::Format2(SinglePosFormat2::new(coverage, value_records))
715 }
716}
717
718impl Default for SinglePos {
719 fn default() -> Self {
720 Self::Format1(Default::default())
721 }
722}
723
724impl FontWrite for SinglePos {
725 fn write_into(&self, writer: &mut TableWriter) {
726 match self {
727 Self::Format1(item) => item.write_into(writer),
728 Self::Format2(item) => item.write_into(writer),
729 }
730 }
731 fn table_type(&self) -> TableType {
732 match self {
733 Self::Format1(item) => item.table_type(),
734 Self::Format2(item) => item.table_type(),
735 }
736 }
737}
738
739impl Validate for SinglePos {
740 fn validate_impl(&self, ctx: &mut ValidationCtx) {
741 match self {
742 Self::Format1(item) => item.validate_impl(ctx),
743 Self::Format2(item) => item.validate_impl(ctx),
744 }
745 }
746}
747
748impl FromObjRef<read_fonts::tables::gpos::SinglePos<'_>> for SinglePos {
749 fn from_obj_ref(obj: &read_fonts::tables::gpos::SinglePos, _: FontData) -> Self {
750 use read_fonts::tables::gpos::SinglePos as ObjRefType;
751 match obj {
752 ObjRefType::Format1(item) => SinglePos::Format1(item.to_owned_table()),
753 ObjRefType::Format2(item) => SinglePos::Format2(item.to_owned_table()),
754 }
755 }
756}
757
758impl FromTableRef<read_fonts::tables::gpos::SinglePos<'_>> for SinglePos {}
759
760impl ReadArgs for SinglePos {
761 type Args = ();
762}
763
764impl<'a> FontRead<'a> for SinglePos {
765 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
766 <read_fonts::tables::gpos::SinglePos as FontRead>::read(data).map(|x| x.to_owned_table())
767 }
768}
769
770impl From<SinglePosFormat1> for SinglePos {
771 fn from(src: SinglePosFormat1) -> SinglePos {
772 SinglePos::Format1(src)
773 }
774}
775
776impl From<SinglePosFormat2> for SinglePos {
777 fn from(src: SinglePosFormat2) -> SinglePos {
778 SinglePos::Format2(src)
779 }
780}
781
782#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
784#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
785pub struct SinglePosFormat1 {
786 pub coverage: OffsetMarker<CoverageTable>,
788 pub value_record: ValueRecord,
791}
792
793impl SinglePosFormat1 {
794 pub fn new(coverage: CoverageTable, value_record: ValueRecord) -> Self {
796 Self {
797 coverage: coverage.into(),
798 value_record,
799 }
800 }
801}
802
803impl FontWrite for SinglePosFormat1 {
804 #[allow(clippy::unnecessary_cast)]
805 fn write_into(&self, writer: &mut TableWriter) {
806 (1 as u16).write_into(writer);
807 self.coverage.write_into(writer);
808 (self.compute_value_format() as ValueFormat).write_into(writer);
809 self.value_record.write_into(writer);
810 }
811 fn table_type(&self) -> TableType {
812 TableType::Named("SinglePosFormat1")
813 }
814}
815
816impl Validate for SinglePosFormat1 {
817 fn validate_impl(&self, ctx: &mut ValidationCtx) {
818 ctx.in_table("SinglePosFormat1", |ctx| {
819 ctx.in_field("coverage", |ctx| {
820 self.coverage.validate_impl(ctx);
821 });
822 })
823 }
824}
825
826impl<'a> FromObjRef<read_fonts::tables::gpos::SinglePosFormat1<'a>> for SinglePosFormat1 {
827 fn from_obj_ref(obj: &read_fonts::tables::gpos::SinglePosFormat1<'a>, _: FontData) -> Self {
828 let offset_data = obj.offset_data();
829 SinglePosFormat1 {
830 coverage: obj.coverage().to_owned_table(),
831 value_record: obj.value_record().to_owned_obj(offset_data),
832 }
833 }
834}
835
836#[allow(clippy::needless_lifetimes)]
837impl<'a> FromTableRef<read_fonts::tables::gpos::SinglePosFormat1<'a>> for SinglePosFormat1 {}
838
839impl ReadArgs for SinglePosFormat1 {
840 type Args = ();
841}
842
843impl<'a> FontRead<'a> for SinglePosFormat1 {
844 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
845 <read_fonts::tables::gpos::SinglePosFormat1 as FontRead>::read(data)
846 .map(|x| x.to_owned_table())
847 }
848}
849
850#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
852#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
853pub struct SinglePosFormat2 {
854 pub coverage: OffsetMarker<CoverageTable>,
856 pub value_records: Vec<ValueRecord>,
858}
859
860impl SinglePosFormat2 {
861 pub fn new(coverage: CoverageTable, value_records: Vec<ValueRecord>) -> Self {
863 Self {
864 coverage: coverage.into(),
865 value_records,
866 }
867 }
868}
869
870impl FontWrite for SinglePosFormat2 {
871 #[allow(clippy::unnecessary_cast)]
872 fn write_into(&self, writer: &mut TableWriter) {
873 (2 as u16).write_into(writer);
874 self.coverage.write_into(writer);
875 (self.compute_value_format() as ValueFormat).write_into(writer);
876 (u16::try_from(array_len(&self.value_records)).unwrap()).write_into(writer);
877 self.value_records.write_into(writer);
878 }
879 fn table_type(&self) -> TableType {
880 TableType::Named("SinglePosFormat2")
881 }
882}
883
884impl Validate for SinglePosFormat2 {
885 fn validate_impl(&self, ctx: &mut ValidationCtx) {
886 ctx.in_table("SinglePosFormat2", |ctx| {
887 ctx.in_field("coverage", |ctx| {
888 self.coverage.validate_impl(ctx);
889 });
890 ctx.in_field("value_records", |ctx| {
891 if self.value_records.len() > to_usize(u16::MAX) {
892 ctx.report("array exceeds max length");
893 }
894 self.value_records.validate_impl(ctx);
895 });
896 })
897 }
898}
899
900impl<'a> FromObjRef<read_fonts::tables::gpos::SinglePosFormat2<'a>> for SinglePosFormat2 {
901 fn from_obj_ref(obj: &read_fonts::tables::gpos::SinglePosFormat2<'a>, _: FontData) -> Self {
902 let offset_data = obj.offset_data();
903 SinglePosFormat2 {
904 coverage: obj.coverage().to_owned_table(),
905 value_records: obj
906 .value_records()
907 .iter()
908 .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
909 .collect(),
910 }
911 }
912}
913
914#[allow(clippy::needless_lifetimes)]
915impl<'a> FromTableRef<read_fonts::tables::gpos::SinglePosFormat2<'a>> for SinglePosFormat2 {}
916
917impl ReadArgs for SinglePosFormat2 {
918 type Args = ();
919}
920
921impl<'a> FontRead<'a> for SinglePosFormat2 {
922 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
923 <read_fonts::tables::gpos::SinglePosFormat2 as FontRead>::read(data)
924 .map(|x| x.to_owned_table())
925 }
926}
927
928#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
930#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
931pub enum PairPos {
932 Format1(PairPosFormat1),
933 Format2(PairPosFormat2),
934}
935
936impl PairPos {
937 pub fn format_1(coverage: CoverageTable, pair_sets: Vec<PairSet>) -> Self {
939 Self::Format1(PairPosFormat1::new(coverage, pair_sets))
940 }
941
942 pub fn format_2(
944 coverage: CoverageTable,
945 class_def1: ClassDef,
946 class_def2: ClassDef,
947 class1_records: Vec<Class1Record>,
948 ) -> Self {
949 Self::Format2(PairPosFormat2::new(
950 coverage,
951 class_def1,
952 class_def2,
953 class1_records,
954 ))
955 }
956}
957
958impl Default for PairPos {
959 fn default() -> Self {
960 Self::Format1(Default::default())
961 }
962}
963
964impl FontWrite for PairPos {
965 fn write_into(&self, writer: &mut TableWriter) {
966 match self {
967 Self::Format1(item) => item.write_into(writer),
968 Self::Format2(item) => item.write_into(writer),
969 }
970 }
971 fn table_type(&self) -> TableType {
972 match self {
973 Self::Format1(item) => item.table_type(),
974 Self::Format2(item) => item.table_type(),
975 }
976 }
977}
978
979impl Validate for PairPos {
980 fn validate_impl(&self, ctx: &mut ValidationCtx) {
981 match self {
982 Self::Format1(item) => item.validate_impl(ctx),
983 Self::Format2(item) => item.validate_impl(ctx),
984 }
985 }
986}
987
988impl FromObjRef<read_fonts::tables::gpos::PairPos<'_>> for PairPos {
989 fn from_obj_ref(obj: &read_fonts::tables::gpos::PairPos, _: FontData) -> Self {
990 use read_fonts::tables::gpos::PairPos as ObjRefType;
991 match obj {
992 ObjRefType::Format1(item) => PairPos::Format1(item.to_owned_table()),
993 ObjRefType::Format2(item) => PairPos::Format2(item.to_owned_table()),
994 }
995 }
996}
997
998impl FromTableRef<read_fonts::tables::gpos::PairPos<'_>> for PairPos {}
999
1000impl ReadArgs for PairPos {
1001 type Args = ();
1002}
1003
1004impl<'a> FontRead<'a> for PairPos {
1005 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1006 <read_fonts::tables::gpos::PairPos as FontRead>::read(data).map(|x| x.to_owned_table())
1007 }
1008}
1009
1010impl From<PairPosFormat1> for PairPos {
1011 fn from(src: PairPosFormat1) -> PairPos {
1012 PairPos::Format1(src)
1013 }
1014}
1015
1016impl From<PairPosFormat2> for PairPos {
1017 fn from(src: PairPosFormat2) -> PairPos {
1018 PairPos::Format2(src)
1019 }
1020}
1021
1022#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1024#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1025pub struct PairPosFormat1 {
1026 pub coverage: OffsetMarker<CoverageTable>,
1028 pub pair_sets: Vec<OffsetMarker<PairSet>>,
1031}
1032
1033impl PairPosFormat1 {
1034 pub fn new(coverage: CoverageTable, pair_sets: Vec<PairSet>) -> Self {
1036 Self {
1037 coverage: coverage.into(),
1038 pair_sets: pair_sets.into_iter().map(Into::into).collect(),
1039 }
1040 }
1041}
1042
1043impl FontWrite for PairPosFormat1 {
1044 #[allow(clippy::unnecessary_cast)]
1045 fn write_into(&self, writer: &mut TableWriter) {
1046 (1 as u16).write_into(writer);
1047 self.coverage.write_into(writer);
1048 (self.compute_value_format1() as ValueFormat).write_into(writer);
1049 (self.compute_value_format2() as ValueFormat).write_into(writer);
1050 (u16::try_from(array_len(&self.pair_sets)).unwrap()).write_into(writer);
1051 self.pair_sets.write_into(writer);
1052 }
1053 fn table_type(&self) -> TableType {
1054 TableType::Named("PairPosFormat1")
1055 }
1056}
1057
1058impl Validate for PairPosFormat1 {
1059 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1060 ctx.in_table("PairPosFormat1", |ctx| {
1061 ctx.in_field("coverage", |ctx| {
1062 self.coverage.validate_impl(ctx);
1063 });
1064 ctx.in_field("pair_sets", |ctx| {
1065 if self.pair_sets.len() > to_usize(u16::MAX) {
1066 ctx.report("array exceeds max length");
1067 }
1068 self.check_format_consistency(ctx);
1069 });
1070 })
1071 }
1072}
1073
1074impl<'a> FromObjRef<read_fonts::tables::gpos::PairPosFormat1<'a>> for PairPosFormat1 {
1075 fn from_obj_ref(obj: &read_fonts::tables::gpos::PairPosFormat1<'a>, _: FontData) -> Self {
1076 PairPosFormat1 {
1077 coverage: obj.coverage().to_owned_table(),
1078 pair_sets: obj.pair_sets().to_owned_table(),
1079 }
1080 }
1081}
1082
1083#[allow(clippy::needless_lifetimes)]
1084impl<'a> FromTableRef<read_fonts::tables::gpos::PairPosFormat1<'a>> for PairPosFormat1 {}
1085
1086impl ReadArgs for PairPosFormat1 {
1087 type Args = ();
1088}
1089
1090impl<'a> FontRead<'a> for PairPosFormat1 {
1091 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1092 <read_fonts::tables::gpos::PairPosFormat1 as FontRead>::read(data)
1093 .map(|x| x.to_owned_table())
1094 }
1095}
1096
1097#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1099#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1100pub struct PairSet {
1101 pub pair_value_records: Vec<PairValueRecord>,
1104}
1105
1106impl PairSet {
1107 pub fn new(pair_value_records: Vec<PairValueRecord>) -> Self {
1109 Self { pair_value_records }
1110 }
1111}
1112
1113impl FontWrite for PairSet {
1114 #[allow(clippy::unnecessary_cast)]
1115 fn write_into(&self, writer: &mut TableWriter) {
1116 (u16::try_from(array_len(&self.pair_value_records)).unwrap()).write_into(writer);
1117 self.pair_value_records.write_into(writer);
1118 }
1119 fn table_type(&self) -> TableType {
1120 TableType::Named("PairSet")
1121 }
1122}
1123
1124impl Validate for PairSet {
1125 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1126 ctx.in_table("PairSet", |ctx| {
1127 ctx.in_field("pair_value_records", |ctx| {
1128 if self.pair_value_records.len() > to_usize(u16::MAX) {
1129 ctx.report("array exceeds max length");
1130 }
1131 self.pair_value_records.validate_impl(ctx);
1132 });
1133 })
1134 }
1135}
1136
1137impl<'a> FromObjRef<read_fonts::tables::gpos::PairSet<'a>> for PairSet {
1138 fn from_obj_ref(obj: &read_fonts::tables::gpos::PairSet<'a>, _: FontData) -> Self {
1139 let offset_data = obj.offset_data();
1140 PairSet {
1141 pair_value_records: obj
1142 .pair_value_records()
1143 .iter()
1144 .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
1145 .collect(),
1146 }
1147 }
1148}
1149
1150#[allow(clippy::needless_lifetimes)]
1151impl<'a> FromTableRef<read_fonts::tables::gpos::PairSet<'a>> for PairSet {}
1152
1153#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1155#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1156pub struct PairValueRecord {
1157 pub second_glyph: GlyphId16,
1160 pub value_record1: ValueRecord,
1162 pub value_record2: ValueRecord,
1164}
1165
1166impl PairValueRecord {
1167 pub fn new(
1169 second_glyph: GlyphId16,
1170 value_record1: ValueRecord,
1171 value_record2: ValueRecord,
1172 ) -> Self {
1173 Self {
1174 second_glyph,
1175 value_record1,
1176 value_record2,
1177 }
1178 }
1179}
1180
1181impl FontWrite for PairValueRecord {
1182 fn write_into(&self, writer: &mut TableWriter) {
1183 self.second_glyph.write_into(writer);
1184 self.value_record1.write_into(writer);
1185 self.value_record2.write_into(writer);
1186 }
1187 fn table_type(&self) -> TableType {
1188 TableType::Named("PairValueRecord")
1189 }
1190}
1191
1192impl Validate for PairValueRecord {
1193 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
1194}
1195
1196impl FromObjRef<read_fonts::tables::gpos::PairValueRecord> for PairValueRecord {
1197 fn from_obj_ref(
1198 obj: &read_fonts::tables::gpos::PairValueRecord,
1199 offset_data: FontData,
1200 ) -> Self {
1201 PairValueRecord {
1202 second_glyph: obj.second_glyph(),
1203 value_record1: obj.value_record1().to_owned_obj(offset_data),
1204 value_record2: obj.value_record2().to_owned_obj(offset_data),
1205 }
1206 }
1207}
1208
1209#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1211#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1212pub struct PairPosFormat2 {
1213 pub coverage: OffsetMarker<CoverageTable>,
1215 pub class_def1: OffsetMarker<ClassDef>,
1218 pub class_def2: OffsetMarker<ClassDef>,
1221 pub class1_records: Vec<Class1Record>,
1223}
1224
1225impl PairPosFormat2 {
1226 pub fn new(
1228 coverage: CoverageTable,
1229 class_def1: ClassDef,
1230 class_def2: ClassDef,
1231 class1_records: Vec<Class1Record>,
1232 ) -> Self {
1233 Self {
1234 coverage: coverage.into(),
1235 class_def1: class_def1.into(),
1236 class_def2: class_def2.into(),
1237 class1_records,
1238 }
1239 }
1240}
1241
1242impl FontWrite for PairPosFormat2 {
1243 #[allow(clippy::unnecessary_cast)]
1244 fn write_into(&self, writer: &mut TableWriter) {
1245 (2 as u16).write_into(writer);
1246 self.coverage.write_into(writer);
1247 (self.compute_value_format1() as ValueFormat).write_into(writer);
1248 (self.compute_value_format2() as ValueFormat).write_into(writer);
1249 self.class_def1.write_into(writer);
1250 self.class_def2.write_into(writer);
1251 (self.compute_class1_count() as u16).write_into(writer);
1252 (self.compute_class2_count() as u16).write_into(writer);
1253 self.class1_records.write_into(writer);
1254 }
1255 fn table_type(&self) -> TableType {
1256 TableType::Named("PairPosFormat2")
1257 }
1258}
1259
1260impl Validate for PairPosFormat2 {
1261 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1262 ctx.in_table("PairPosFormat2", |ctx| {
1263 ctx.in_field("coverage", |ctx| {
1264 self.coverage.validate_impl(ctx);
1265 });
1266 ctx.in_field("class_def1", |ctx| {
1267 self.class_def1.validate_impl(ctx);
1268 });
1269 ctx.in_field("class_def2", |ctx| {
1270 self.class_def2.validate_impl(ctx);
1271 });
1272 ctx.in_field("class1_records", |ctx| {
1273 if self.class1_records.len() > to_usize(u16::MAX) {
1274 ctx.report("array exceeds max length");
1275 }
1276 self.class1_records.validate_impl(ctx);
1277 });
1278 self.check_length_and_format_conformance(ctx);
1279 })
1280 }
1281}
1282
1283impl<'a> FromObjRef<read_fonts::tables::gpos::PairPosFormat2<'a>> for PairPosFormat2 {
1284 fn from_obj_ref(obj: &read_fonts::tables::gpos::PairPosFormat2<'a>, _: FontData) -> Self {
1285 let offset_data = obj.offset_data();
1286 PairPosFormat2 {
1287 coverage: obj.coverage().to_owned_table(),
1288 class_def1: obj.class_def1().to_owned_table(),
1289 class_def2: obj.class_def2().to_owned_table(),
1290 class1_records: obj
1291 .class1_records()
1292 .iter()
1293 .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
1294 .collect(),
1295 }
1296 }
1297}
1298
1299#[allow(clippy::needless_lifetimes)]
1300impl<'a> FromTableRef<read_fonts::tables::gpos::PairPosFormat2<'a>> for PairPosFormat2 {}
1301
1302impl ReadArgs for PairPosFormat2 {
1303 type Args = ();
1304}
1305
1306impl<'a> FontRead<'a> for PairPosFormat2 {
1307 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1308 <read_fonts::tables::gpos::PairPosFormat2 as FontRead>::read(data)
1309 .map(|x| x.to_owned_table())
1310 }
1311}
1312
1313#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1315#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1316pub struct Class1Record {
1317 pub class2_records: Vec<Class2Record>,
1319}
1320
1321impl Class1Record {
1322 pub fn new(class2_records: Vec<Class2Record>) -> Self {
1324 Self { class2_records }
1325 }
1326}
1327
1328impl FontWrite for Class1Record {
1329 fn write_into(&self, writer: &mut TableWriter) {
1330 self.class2_records.write_into(writer);
1331 }
1332 fn table_type(&self) -> TableType {
1333 TableType::Named("Class1Record")
1334 }
1335}
1336
1337impl Validate for Class1Record {
1338 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1339 ctx.in_table("Class1Record", |ctx| {
1340 ctx.in_field("class2_records", |ctx| {
1341 if self.class2_records.len() > to_usize(u16::MAX) {
1342 ctx.report("array exceeds max length");
1343 }
1344 self.class2_records.validate_impl(ctx);
1345 });
1346 })
1347 }
1348}
1349
1350impl FromObjRef<read_fonts::tables::gpos::Class1Record<'_>> for Class1Record {
1351 fn from_obj_ref(obj: &read_fonts::tables::gpos::Class1Record, offset_data: FontData) -> Self {
1352 Class1Record {
1353 class2_records: obj
1354 .class2_records()
1355 .iter()
1356 .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
1357 .collect(),
1358 }
1359 }
1360}
1361
1362#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1364#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1365pub struct Class2Record {
1366 pub value_record1: ValueRecord,
1368 pub value_record2: ValueRecord,
1370}
1371
1372impl Class2Record {
1373 pub fn new(value_record1: ValueRecord, value_record2: ValueRecord) -> Self {
1375 Self {
1376 value_record1,
1377 value_record2,
1378 }
1379 }
1380}
1381
1382impl FontWrite for Class2Record {
1383 fn write_into(&self, writer: &mut TableWriter) {
1384 self.value_record1.write_into(writer);
1385 self.value_record2.write_into(writer);
1386 }
1387 fn table_type(&self) -> TableType {
1388 TableType::Named("Class2Record")
1389 }
1390}
1391
1392impl Validate for Class2Record {
1393 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
1394}
1395
1396impl FromObjRef<read_fonts::tables::gpos::Class2Record> for Class2Record {
1397 fn from_obj_ref(obj: &read_fonts::tables::gpos::Class2Record, offset_data: FontData) -> Self {
1398 Class2Record {
1399 value_record1: obj.value_record1().to_owned_obj(offset_data),
1400 value_record2: obj.value_record2().to_owned_obj(offset_data),
1401 }
1402 }
1403}
1404
1405#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1407#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1408pub struct CursivePosFormat1 {
1409 pub coverage: OffsetMarker<CoverageTable>,
1411 pub entry_exit_record: Vec<EntryExitRecord>,
1413}
1414
1415impl CursivePosFormat1 {
1416 pub fn new(coverage: CoverageTable, entry_exit_record: Vec<EntryExitRecord>) -> Self {
1418 Self {
1419 coverage: coverage.into(),
1420 entry_exit_record,
1421 }
1422 }
1423}
1424
1425impl FontWrite for CursivePosFormat1 {
1426 #[allow(clippy::unnecessary_cast)]
1427 fn write_into(&self, writer: &mut TableWriter) {
1428 (1 as u16).write_into(writer);
1429 self.coverage.write_into(writer);
1430 (u16::try_from(array_len(&self.entry_exit_record)).unwrap()).write_into(writer);
1431 self.entry_exit_record.write_into(writer);
1432 }
1433 fn table_type(&self) -> TableType {
1434 TableType::Named("CursivePosFormat1")
1435 }
1436}
1437
1438impl Validate for CursivePosFormat1 {
1439 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1440 ctx.in_table("CursivePosFormat1", |ctx| {
1441 ctx.in_field("coverage", |ctx| {
1442 self.coverage.validate_impl(ctx);
1443 });
1444 ctx.in_field("entry_exit_record", |ctx| {
1445 if self.entry_exit_record.len() > to_usize(u16::MAX) {
1446 ctx.report("array exceeds max length");
1447 }
1448 self.entry_exit_record.validate_impl(ctx);
1449 });
1450 })
1451 }
1452}
1453
1454impl<'a> FromObjRef<read_fonts::tables::gpos::CursivePosFormat1<'a>> for CursivePosFormat1 {
1455 fn from_obj_ref(obj: &read_fonts::tables::gpos::CursivePosFormat1<'a>, _: FontData) -> Self {
1456 let offset_data = obj.offset_data();
1457 CursivePosFormat1 {
1458 coverage: obj.coverage().to_owned_table(),
1459 entry_exit_record: obj.entry_exit_record().to_owned_obj(offset_data),
1460 }
1461 }
1462}
1463
1464#[allow(clippy::needless_lifetimes)]
1465impl<'a> FromTableRef<read_fonts::tables::gpos::CursivePosFormat1<'a>> for CursivePosFormat1 {}
1466
1467impl ReadArgs for CursivePosFormat1 {
1468 type Args = ();
1469}
1470
1471impl<'a> FontRead<'a> for CursivePosFormat1 {
1472 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1473 <read_fonts::tables::gpos::CursivePosFormat1 as FontRead>::read(data)
1474 .map(|x| x.to_owned_table())
1475 }
1476}
1477
1478#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1480#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1481pub struct EntryExitRecord {
1482 pub entry_anchor: NullableOffsetMarker<AnchorTable>,
1485 pub exit_anchor: NullableOffsetMarker<AnchorTable>,
1488}
1489
1490impl EntryExitRecord {
1491 pub fn new(entry_anchor: Option<AnchorTable>, exit_anchor: Option<AnchorTable>) -> Self {
1493 Self {
1494 entry_anchor: entry_anchor.into(),
1495 exit_anchor: exit_anchor.into(),
1496 }
1497 }
1498}
1499
1500impl FontWrite for EntryExitRecord {
1501 fn write_into(&self, writer: &mut TableWriter) {
1502 self.entry_anchor.write_into(writer);
1503 self.exit_anchor.write_into(writer);
1504 }
1505 fn table_type(&self) -> TableType {
1506 TableType::Named("EntryExitRecord")
1507 }
1508}
1509
1510impl Validate for EntryExitRecord {
1511 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1512 ctx.in_table("EntryExitRecord", |ctx| {
1513 ctx.in_field("entry_anchor", |ctx| {
1514 self.entry_anchor.validate_impl(ctx);
1515 });
1516 ctx.in_field("exit_anchor", |ctx| {
1517 self.exit_anchor.validate_impl(ctx);
1518 });
1519 })
1520 }
1521}
1522
1523impl FromObjRef<read_fonts::tables::gpos::EntryExitRecord> for EntryExitRecord {
1524 fn from_obj_ref(
1525 obj: &read_fonts::tables::gpos::EntryExitRecord,
1526 offset_data: FontData,
1527 ) -> Self {
1528 EntryExitRecord {
1529 entry_anchor: obj.entry_anchor(offset_data).to_owned_table(),
1530 exit_anchor: obj.exit_anchor(offset_data).to_owned_table(),
1531 }
1532 }
1533}
1534
1535#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1537#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1538pub struct MarkBasePosFormat1 {
1539 pub mark_coverage: OffsetMarker<CoverageTable>,
1542 pub base_coverage: OffsetMarker<CoverageTable>,
1545 pub mark_array: OffsetMarker<MarkArray>,
1548 pub base_array: OffsetMarker<BaseArray>,
1551}
1552
1553impl MarkBasePosFormat1 {
1554 pub fn new(
1556 mark_coverage: CoverageTable,
1557 base_coverage: CoverageTable,
1558 mark_array: MarkArray,
1559 base_array: BaseArray,
1560 ) -> Self {
1561 Self {
1562 mark_coverage: mark_coverage.into(),
1563 base_coverage: base_coverage.into(),
1564 mark_array: mark_array.into(),
1565 base_array: base_array.into(),
1566 }
1567 }
1568}
1569
1570impl FontWrite for MarkBasePosFormat1 {
1571 #[allow(clippy::unnecessary_cast)]
1572 fn write_into(&self, writer: &mut TableWriter) {
1573 (1 as u16).write_into(writer);
1574 self.mark_coverage.write_into(writer);
1575 self.base_coverage.write_into(writer);
1576 (self.compute_mark_class_count() as u16).write_into(writer);
1577 self.mark_array.write_into(writer);
1578 self.base_array.write_into(writer);
1579 }
1580 fn table_type(&self) -> TableType {
1581 TableType::Named("MarkBasePosFormat1")
1582 }
1583}
1584
1585impl Validate for MarkBasePosFormat1 {
1586 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1587 ctx.in_table("MarkBasePosFormat1", |ctx| {
1588 ctx.in_field("mark_coverage", |ctx| {
1589 self.mark_coverage.validate_impl(ctx);
1590 });
1591 ctx.in_field("base_coverage", |ctx| {
1592 self.base_coverage.validate_impl(ctx);
1593 });
1594 ctx.in_field("mark_array", |ctx| {
1595 self.mark_array.validate_impl(ctx);
1596 });
1597 ctx.in_field("base_array", |ctx| {
1598 self.base_array.validate_impl(ctx);
1599 });
1600 })
1601 }
1602}
1603
1604impl<'a> FromObjRef<read_fonts::tables::gpos::MarkBasePosFormat1<'a>> for MarkBasePosFormat1 {
1605 fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkBasePosFormat1<'a>, _: FontData) -> Self {
1606 MarkBasePosFormat1 {
1607 mark_coverage: obj.mark_coverage().to_owned_table(),
1608 base_coverage: obj.base_coverage().to_owned_table(),
1609 mark_array: obj.mark_array().to_owned_table(),
1610 base_array: obj.base_array().to_owned_table(),
1611 }
1612 }
1613}
1614
1615#[allow(clippy::needless_lifetimes)]
1616impl<'a> FromTableRef<read_fonts::tables::gpos::MarkBasePosFormat1<'a>> for MarkBasePosFormat1 {}
1617
1618impl ReadArgs for MarkBasePosFormat1 {
1619 type Args = ();
1620}
1621
1622impl<'a> FontRead<'a> for MarkBasePosFormat1 {
1623 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1624 <read_fonts::tables::gpos::MarkBasePosFormat1 as FontRead>::read(data)
1625 .map(|x| x.to_owned_table())
1626 }
1627}
1628
1629#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1631#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1632pub struct BaseArray {
1633 pub base_records: Vec<BaseRecord>,
1635}
1636
1637impl BaseArray {
1638 pub fn new(base_records: Vec<BaseRecord>) -> Self {
1640 Self { base_records }
1641 }
1642}
1643
1644impl FontWrite for BaseArray {
1645 #[allow(clippy::unnecessary_cast)]
1646 fn write_into(&self, writer: &mut TableWriter) {
1647 (u16::try_from(array_len(&self.base_records)).unwrap()).write_into(writer);
1648 self.base_records.write_into(writer);
1649 }
1650 fn table_type(&self) -> TableType {
1651 TableType::Named("BaseArray")
1652 }
1653}
1654
1655impl Validate for BaseArray {
1656 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1657 ctx.in_table("BaseArray", |ctx| {
1658 ctx.in_field("base_records", |ctx| {
1659 if self.base_records.len() > to_usize(u16::MAX) {
1660 ctx.report("array exceeds max length");
1661 }
1662 self.base_records.validate_impl(ctx);
1663 });
1664 })
1665 }
1666}
1667
1668impl<'a> FromObjRef<read_fonts::tables::gpos::BaseArray<'a>> for BaseArray {
1669 fn from_obj_ref(obj: &read_fonts::tables::gpos::BaseArray<'a>, _: FontData) -> Self {
1670 let offset_data = obj.offset_data();
1671 BaseArray {
1672 base_records: obj
1673 .base_records()
1674 .iter()
1675 .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
1676 .collect(),
1677 }
1678 }
1679}
1680
1681#[allow(clippy::needless_lifetimes)]
1682impl<'a> FromTableRef<read_fonts::tables::gpos::BaseArray<'a>> for BaseArray {}
1683
1684#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1686#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1687pub struct BaseRecord {
1688 pub base_anchors: Vec<NullableOffsetMarker<AnchorTable>>,
1692}
1693
1694impl BaseRecord {
1695 pub fn new(base_anchors: Vec<Option<AnchorTable>>) -> Self {
1697 Self {
1698 base_anchors: base_anchors.into_iter().map(Into::into).collect(),
1699 }
1700 }
1701}
1702
1703impl FontWrite for BaseRecord {
1704 fn write_into(&self, writer: &mut TableWriter) {
1705 self.base_anchors.write_into(writer);
1706 }
1707 fn table_type(&self) -> TableType {
1708 TableType::Named("BaseRecord")
1709 }
1710}
1711
1712impl Validate for BaseRecord {
1713 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1714 ctx.in_table("BaseRecord", |ctx| {
1715 ctx.in_field("base_anchors", |ctx| {
1716 if self.base_anchors.len() > to_usize(u16::MAX) {
1717 ctx.report("array exceeds max length");
1718 }
1719 self.base_anchors.validate_impl(ctx);
1720 });
1721 })
1722 }
1723}
1724
1725impl FromObjRef<read_fonts::tables::gpos::BaseRecord<'_>> for BaseRecord {
1726 fn from_obj_ref(obj: &read_fonts::tables::gpos::BaseRecord, offset_data: FontData) -> Self {
1727 BaseRecord {
1728 base_anchors: obj.base_anchors(offset_data).to_owned_table(),
1729 }
1730 }
1731}
1732
1733#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1735#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1736pub struct MarkLigPosFormat1 {
1737 pub mark_coverage: OffsetMarker<CoverageTable>,
1740 pub ligature_coverage: OffsetMarker<CoverageTable>,
1743 pub mark_array: OffsetMarker<MarkArray>,
1746 pub ligature_array: OffsetMarker<LigatureArray>,
1749}
1750
1751impl MarkLigPosFormat1 {
1752 pub fn new(
1754 mark_coverage: CoverageTable,
1755 ligature_coverage: CoverageTable,
1756 mark_array: MarkArray,
1757 ligature_array: LigatureArray,
1758 ) -> Self {
1759 Self {
1760 mark_coverage: mark_coverage.into(),
1761 ligature_coverage: ligature_coverage.into(),
1762 mark_array: mark_array.into(),
1763 ligature_array: ligature_array.into(),
1764 }
1765 }
1766}
1767
1768impl FontWrite for MarkLigPosFormat1 {
1769 #[allow(clippy::unnecessary_cast)]
1770 fn write_into(&self, writer: &mut TableWriter) {
1771 (1 as u16).write_into(writer);
1772 self.mark_coverage.write_into(writer);
1773 self.ligature_coverage.write_into(writer);
1774 (self.compute_mark_class_count() as u16).write_into(writer);
1775 self.mark_array.write_into(writer);
1776 self.ligature_array.write_into(writer);
1777 }
1778 fn table_type(&self) -> TableType {
1779 TableType::Named("MarkLigPosFormat1")
1780 }
1781}
1782
1783impl Validate for MarkLigPosFormat1 {
1784 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1785 ctx.in_table("MarkLigPosFormat1", |ctx| {
1786 ctx.in_field("mark_coverage", |ctx| {
1787 self.mark_coverage.validate_impl(ctx);
1788 });
1789 ctx.in_field("ligature_coverage", |ctx| {
1790 self.ligature_coverage.validate_impl(ctx);
1791 });
1792 ctx.in_field("mark_array", |ctx| {
1793 self.mark_array.validate_impl(ctx);
1794 });
1795 ctx.in_field("ligature_array", |ctx| {
1796 self.ligature_array.validate_impl(ctx);
1797 });
1798 })
1799 }
1800}
1801
1802impl<'a> FromObjRef<read_fonts::tables::gpos::MarkLigPosFormat1<'a>> for MarkLigPosFormat1 {
1803 fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkLigPosFormat1<'a>, _: FontData) -> Self {
1804 MarkLigPosFormat1 {
1805 mark_coverage: obj.mark_coverage().to_owned_table(),
1806 ligature_coverage: obj.ligature_coverage().to_owned_table(),
1807 mark_array: obj.mark_array().to_owned_table(),
1808 ligature_array: obj.ligature_array().to_owned_table(),
1809 }
1810 }
1811}
1812
1813#[allow(clippy::needless_lifetimes)]
1814impl<'a> FromTableRef<read_fonts::tables::gpos::MarkLigPosFormat1<'a>> for MarkLigPosFormat1 {}
1815
1816impl ReadArgs for MarkLigPosFormat1 {
1817 type Args = ();
1818}
1819
1820impl<'a> FontRead<'a> for MarkLigPosFormat1 {
1821 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1822 <read_fonts::tables::gpos::MarkLigPosFormat1 as FontRead>::read(data)
1823 .map(|x| x.to_owned_table())
1824 }
1825}
1826
1827#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1829#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1830pub struct LigatureArray {
1831 pub ligature_attaches: Vec<OffsetMarker<LigatureAttach>>,
1835}
1836
1837impl LigatureArray {
1838 pub fn new(ligature_attaches: Vec<LigatureAttach>) -> Self {
1840 Self {
1841 ligature_attaches: ligature_attaches.into_iter().map(Into::into).collect(),
1842 }
1843 }
1844}
1845
1846impl FontWrite for LigatureArray {
1847 #[allow(clippy::unnecessary_cast)]
1848 fn write_into(&self, writer: &mut TableWriter) {
1849 (u16::try_from(array_len(&self.ligature_attaches)).unwrap()).write_into(writer);
1850 self.ligature_attaches.write_into(writer);
1851 }
1852 fn table_type(&self) -> TableType {
1853 TableType::Named("LigatureArray")
1854 }
1855}
1856
1857impl Validate for LigatureArray {
1858 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1859 ctx.in_table("LigatureArray", |ctx| {
1860 ctx.in_field("ligature_attaches", |ctx| {
1861 if self.ligature_attaches.len() > to_usize(u16::MAX) {
1862 ctx.report("array exceeds max length");
1863 }
1864 self.ligature_attaches.validate_impl(ctx);
1865 });
1866 })
1867 }
1868}
1869
1870impl<'a> FromObjRef<read_fonts::tables::gpos::LigatureArray<'a>> for LigatureArray {
1871 fn from_obj_ref(obj: &read_fonts::tables::gpos::LigatureArray<'a>, _: FontData) -> Self {
1872 LigatureArray {
1873 ligature_attaches: obj.ligature_attaches().to_owned_table(),
1874 }
1875 }
1876}
1877
1878#[allow(clippy::needless_lifetimes)]
1879impl<'a> FromTableRef<read_fonts::tables::gpos::LigatureArray<'a>> for LigatureArray {}
1880
1881#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1883#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1884pub struct LigatureAttach {
1885 pub component_records: Vec<ComponentRecord>,
1887}
1888
1889impl LigatureAttach {
1890 pub fn new(component_records: Vec<ComponentRecord>) -> Self {
1892 Self { component_records }
1893 }
1894}
1895
1896impl FontWrite for LigatureAttach {
1897 #[allow(clippy::unnecessary_cast)]
1898 fn write_into(&self, writer: &mut TableWriter) {
1899 (u16::try_from(array_len(&self.component_records)).unwrap()).write_into(writer);
1900 self.component_records.write_into(writer);
1901 }
1902 fn table_type(&self) -> TableType {
1903 TableType::Named("LigatureAttach")
1904 }
1905}
1906
1907impl Validate for LigatureAttach {
1908 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1909 ctx.in_table("LigatureAttach", |ctx| {
1910 ctx.in_field("component_records", |ctx| {
1911 if self.component_records.len() > to_usize(u16::MAX) {
1912 ctx.report("array exceeds max length");
1913 }
1914 self.component_records.validate_impl(ctx);
1915 });
1916 })
1917 }
1918}
1919
1920impl<'a> FromObjRef<read_fonts::tables::gpos::LigatureAttach<'a>> for LigatureAttach {
1921 fn from_obj_ref(obj: &read_fonts::tables::gpos::LigatureAttach<'a>, _: FontData) -> Self {
1922 let offset_data = obj.offset_data();
1923 LigatureAttach {
1924 component_records: obj
1925 .component_records()
1926 .iter()
1927 .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
1928 .collect(),
1929 }
1930 }
1931}
1932
1933#[allow(clippy::needless_lifetimes)]
1934impl<'a> FromTableRef<read_fonts::tables::gpos::LigatureAttach<'a>> for LigatureAttach {}
1935
1936#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1938#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1939pub struct ComponentRecord {
1940 pub ligature_anchors: Vec<NullableOffsetMarker<AnchorTable>>,
1944}
1945
1946impl ComponentRecord {
1947 pub fn new(ligature_anchors: Vec<Option<AnchorTable>>) -> Self {
1949 Self {
1950 ligature_anchors: ligature_anchors.into_iter().map(Into::into).collect(),
1951 }
1952 }
1953}
1954
1955impl FontWrite for ComponentRecord {
1956 fn write_into(&self, writer: &mut TableWriter) {
1957 self.ligature_anchors.write_into(writer);
1958 }
1959 fn table_type(&self) -> TableType {
1960 TableType::Named("ComponentRecord")
1961 }
1962}
1963
1964impl Validate for ComponentRecord {
1965 fn validate_impl(&self, ctx: &mut ValidationCtx) {
1966 ctx.in_table("ComponentRecord", |ctx| {
1967 ctx.in_field("ligature_anchors", |ctx| {
1968 if self.ligature_anchors.len() > to_usize(u16::MAX) {
1969 ctx.report("array exceeds max length");
1970 }
1971 self.ligature_anchors.validate_impl(ctx);
1972 });
1973 })
1974 }
1975}
1976
1977impl FromObjRef<read_fonts::tables::gpos::ComponentRecord<'_>> for ComponentRecord {
1978 fn from_obj_ref(
1979 obj: &read_fonts::tables::gpos::ComponentRecord,
1980 offset_data: FontData,
1981 ) -> Self {
1982 ComponentRecord {
1983 ligature_anchors: obj.ligature_anchors(offset_data).to_owned_table(),
1984 }
1985 }
1986}
1987
1988#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1990#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1991pub struct MarkMarkPosFormat1 {
1992 pub mark1_coverage: OffsetMarker<CoverageTable>,
1995 pub mark2_coverage: OffsetMarker<CoverageTable>,
1998 pub mark1_array: OffsetMarker<MarkArray>,
2001 pub mark2_array: OffsetMarker<Mark2Array>,
2004}
2005
2006impl MarkMarkPosFormat1 {
2007 pub fn new(
2009 mark1_coverage: CoverageTable,
2010 mark2_coverage: CoverageTable,
2011 mark1_array: MarkArray,
2012 mark2_array: Mark2Array,
2013 ) -> Self {
2014 Self {
2015 mark1_coverage: mark1_coverage.into(),
2016 mark2_coverage: mark2_coverage.into(),
2017 mark1_array: mark1_array.into(),
2018 mark2_array: mark2_array.into(),
2019 }
2020 }
2021}
2022
2023impl FontWrite for MarkMarkPosFormat1 {
2024 #[allow(clippy::unnecessary_cast)]
2025 fn write_into(&self, writer: &mut TableWriter) {
2026 (1 as u16).write_into(writer);
2027 self.mark1_coverage.write_into(writer);
2028 self.mark2_coverage.write_into(writer);
2029 (self.compute_mark_class_count() as u16).write_into(writer);
2030 self.mark1_array.write_into(writer);
2031 self.mark2_array.write_into(writer);
2032 }
2033 fn table_type(&self) -> TableType {
2034 TableType::Named("MarkMarkPosFormat1")
2035 }
2036}
2037
2038impl Validate for MarkMarkPosFormat1 {
2039 fn validate_impl(&self, ctx: &mut ValidationCtx) {
2040 ctx.in_table("MarkMarkPosFormat1", |ctx| {
2041 ctx.in_field("mark1_coverage", |ctx| {
2042 self.mark1_coverage.validate_impl(ctx);
2043 });
2044 ctx.in_field("mark2_coverage", |ctx| {
2045 self.mark2_coverage.validate_impl(ctx);
2046 });
2047 ctx.in_field("mark1_array", |ctx| {
2048 self.mark1_array.validate_impl(ctx);
2049 });
2050 ctx.in_field("mark2_array", |ctx| {
2051 self.mark2_array.validate_impl(ctx);
2052 });
2053 })
2054 }
2055}
2056
2057impl<'a> FromObjRef<read_fonts::tables::gpos::MarkMarkPosFormat1<'a>> for MarkMarkPosFormat1 {
2058 fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkMarkPosFormat1<'a>, _: FontData) -> Self {
2059 MarkMarkPosFormat1 {
2060 mark1_coverage: obj.mark1_coverage().to_owned_table(),
2061 mark2_coverage: obj.mark2_coverage().to_owned_table(),
2062 mark1_array: obj.mark1_array().to_owned_table(),
2063 mark2_array: obj.mark2_array().to_owned_table(),
2064 }
2065 }
2066}
2067
2068#[allow(clippy::needless_lifetimes)]
2069impl<'a> FromTableRef<read_fonts::tables::gpos::MarkMarkPosFormat1<'a>> for MarkMarkPosFormat1 {}
2070
2071impl ReadArgs for MarkMarkPosFormat1 {
2072 type Args = ();
2073}
2074
2075impl<'a> FontRead<'a> for MarkMarkPosFormat1 {
2076 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2077 <read_fonts::tables::gpos::MarkMarkPosFormat1 as FontRead>::read(data)
2078 .map(|x| x.to_owned_table())
2079 }
2080}
2081
2082#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2084#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2085pub struct Mark2Array {
2086 pub mark2_records: Vec<Mark2Record>,
2088}
2089
2090impl Mark2Array {
2091 pub fn new(mark2_records: Vec<Mark2Record>) -> Self {
2093 Self { mark2_records }
2094 }
2095}
2096
2097impl FontWrite for Mark2Array {
2098 #[allow(clippy::unnecessary_cast)]
2099 fn write_into(&self, writer: &mut TableWriter) {
2100 (u16::try_from(array_len(&self.mark2_records)).unwrap()).write_into(writer);
2101 self.mark2_records.write_into(writer);
2102 }
2103 fn table_type(&self) -> TableType {
2104 TableType::Named("Mark2Array")
2105 }
2106}
2107
2108impl Validate for Mark2Array {
2109 fn validate_impl(&self, ctx: &mut ValidationCtx) {
2110 ctx.in_table("Mark2Array", |ctx| {
2111 ctx.in_field("mark2_records", |ctx| {
2112 if self.mark2_records.len() > to_usize(u16::MAX) {
2113 ctx.report("array exceeds max length");
2114 }
2115 self.mark2_records.validate_impl(ctx);
2116 });
2117 })
2118 }
2119}
2120
2121impl<'a> FromObjRef<read_fonts::tables::gpos::Mark2Array<'a>> for Mark2Array {
2122 fn from_obj_ref(obj: &read_fonts::tables::gpos::Mark2Array<'a>, _: FontData) -> Self {
2123 let offset_data = obj.offset_data();
2124 Mark2Array {
2125 mark2_records: obj
2126 .mark2_records()
2127 .iter()
2128 .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
2129 .collect(),
2130 }
2131 }
2132}
2133
2134#[allow(clippy::needless_lifetimes)]
2135impl<'a> FromTableRef<read_fonts::tables::gpos::Mark2Array<'a>> for Mark2Array {}
2136
2137#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2139#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2140pub struct Mark2Record {
2141 pub mark2_anchors: Vec<NullableOffsetMarker<AnchorTable>>,
2145}
2146
2147impl Mark2Record {
2148 pub fn new(mark2_anchors: Vec<Option<AnchorTable>>) -> Self {
2150 Self {
2151 mark2_anchors: mark2_anchors.into_iter().map(Into::into).collect(),
2152 }
2153 }
2154}
2155
2156impl FontWrite for Mark2Record {
2157 fn write_into(&self, writer: &mut TableWriter) {
2158 self.mark2_anchors.write_into(writer);
2159 }
2160 fn table_type(&self) -> TableType {
2161 TableType::Named("Mark2Record")
2162 }
2163}
2164
2165impl Validate for Mark2Record {
2166 fn validate_impl(&self, ctx: &mut ValidationCtx) {
2167 ctx.in_table("Mark2Record", |ctx| {
2168 ctx.in_field("mark2_anchors", |ctx| {
2169 if self.mark2_anchors.len() > to_usize(u16::MAX) {
2170 ctx.report("array exceeds max length");
2171 }
2172 self.mark2_anchors.validate_impl(ctx);
2173 });
2174 })
2175 }
2176}
2177
2178impl FromObjRef<read_fonts::tables::gpos::Mark2Record<'_>> for Mark2Record {
2179 fn from_obj_ref(obj: &read_fonts::tables::gpos::Mark2Record, offset_data: FontData) -> Self {
2180 Mark2Record {
2181 mark2_anchors: obj.mark2_anchors(offset_data).to_owned_table(),
2182 }
2183 }
2184}
2185
2186#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2188#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2189pub struct ExtensionPosFormat1<T> {
2190 pub extension_lookup_type: u16,
2193 pub extension: OffsetMarker<T, WIDTH_32>,
2197}
2198
2199impl<T: Default> ExtensionPosFormat1<T> {
2200 pub fn new(extension_lookup_type: u16, extension: T) -> Self {
2202 Self {
2203 extension_lookup_type,
2204 extension: extension.into(),
2205 }
2206 }
2207}
2208
2209impl<T: Validate> Validate for ExtensionPosFormat1<T> {
2210 fn validate_impl(&self, ctx: &mut ValidationCtx) {
2211 ctx.in_table("ExtensionPosFormat1", |ctx| {
2212 ctx.in_field("extension", |ctx| {
2213 self.extension.validate_impl(ctx);
2214 });
2215 })
2216 }
2217}
2218
2219impl<'a, T, U> FromObjRef<read_fonts::tables::gpos::ExtensionPosFormat1<'a, U>>
2220 for ExtensionPosFormat1<T>
2221where
2222 U: FontRead<'a, Args = ()>,
2223 T: FromTableRef<U> + Default + 'static,
2224{
2225 fn from_obj_ref(
2226 obj: &read_fonts::tables::gpos::ExtensionPosFormat1<'a, U>,
2227 _: FontData,
2228 ) -> Self {
2229 ExtensionPosFormat1 {
2230 extension_lookup_type: obj.extension_lookup_type(),
2231 extension: obj.extension().to_owned_table(),
2232 }
2233 }
2234}
2235
2236#[allow(clippy::needless_lifetimes)]
2237impl<'a, T, U> FromTableRef<read_fonts::tables::gpos::ExtensionPosFormat1<'a, U>>
2238 for ExtensionPosFormat1<T>
2239where
2240 U: FontRead<'a, Args = ()>,
2241 T: FromTableRef<U> + Default + 'static,
2242{
2243}
2244
2245#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
2247#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2248pub enum ExtensionSubtable {
2249 Single(ExtensionPosFormat1<SinglePos>),
2250 Pair(ExtensionPosFormat1<PairPos>),
2251 Cursive(ExtensionPosFormat1<CursivePosFormat1>),
2252 MarkToBase(ExtensionPosFormat1<MarkBasePosFormat1>),
2253 MarkToLig(ExtensionPosFormat1<MarkLigPosFormat1>),
2254 MarkToMark(ExtensionPosFormat1<MarkMarkPosFormat1>),
2255 Contextual(ExtensionPosFormat1<PositionSequenceContext>),
2256 ChainContextual(ExtensionPosFormat1<PositionChainContext>),
2257}
2258
2259impl Default for ExtensionSubtable {
2260 fn default() -> Self {
2261 Self::Single(Default::default())
2262 }
2263}
2264
2265impl FontWrite for ExtensionSubtable {
2266 fn write_into(&self, writer: &mut TableWriter) {
2267 match self {
2268 Self::Single(table) => table.write_into(writer),
2269 Self::Pair(table) => table.write_into(writer),
2270 Self::Cursive(table) => table.write_into(writer),
2271 Self::MarkToBase(table) => table.write_into(writer),
2272 Self::MarkToLig(table) => table.write_into(writer),
2273 Self::MarkToMark(table) => table.write_into(writer),
2274 Self::Contextual(table) => table.write_into(writer),
2275 Self::ChainContextual(table) => table.write_into(writer),
2276 }
2277 }
2278 fn table_type(&self) -> TableType {
2279 match self {
2280 Self::Single(table) => table.table_type(),
2281 Self::Pair(table) => table.table_type(),
2282 Self::Cursive(table) => table.table_type(),
2283 Self::MarkToBase(table) => table.table_type(),
2284 Self::MarkToLig(table) => table.table_type(),
2285 Self::MarkToMark(table) => table.table_type(),
2286 Self::Contextual(table) => table.table_type(),
2287 Self::ChainContextual(table) => table.table_type(),
2288 }
2289 }
2290}
2291
2292impl Validate for ExtensionSubtable {
2293 fn validate_impl(&self, ctx: &mut ValidationCtx) {
2294 match self {
2295 Self::Single(table) => table.validate_impl(ctx),
2296 Self::Pair(table) => table.validate_impl(ctx),
2297 Self::Cursive(table) => table.validate_impl(ctx),
2298 Self::MarkToBase(table) => table.validate_impl(ctx),
2299 Self::MarkToLig(table) => table.validate_impl(ctx),
2300 Self::MarkToMark(table) => table.validate_impl(ctx),
2301 Self::Contextual(table) => table.validate_impl(ctx),
2302 Self::ChainContextual(table) => table.validate_impl(ctx),
2303 }
2304 }
2305}
2306
2307impl FromObjRef<read_fonts::tables::gpos::ExtensionSubtable<'_>> for ExtensionSubtable {
2308 fn from_obj_ref(
2309 from: &read_fonts::tables::gpos::ExtensionSubtable<'_>,
2310 data: FontData,
2311 ) -> Self {
2312 match from {
2313 read_fonts::tables::gpos::ExtensionSubtable::Single(table) => {
2314 Self::Single(table.to_owned_obj(data))
2315 }
2316 read_fonts::tables::gpos::ExtensionSubtable::Pair(table) => {
2317 Self::Pair(table.to_owned_obj(data))
2318 }
2319 read_fonts::tables::gpos::ExtensionSubtable::Cursive(table) => {
2320 Self::Cursive(table.to_owned_obj(data))
2321 }
2322 read_fonts::tables::gpos::ExtensionSubtable::MarkToBase(table) => {
2323 Self::MarkToBase(table.to_owned_obj(data))
2324 }
2325 read_fonts::tables::gpos::ExtensionSubtable::MarkToLig(table) => {
2326 Self::MarkToLig(table.to_owned_obj(data))
2327 }
2328 read_fonts::tables::gpos::ExtensionSubtable::MarkToMark(table) => {
2329 Self::MarkToMark(table.to_owned_obj(data))
2330 }
2331 read_fonts::tables::gpos::ExtensionSubtable::Contextual(table) => {
2332 Self::Contextual(table.to_owned_obj(data))
2333 }
2334 read_fonts::tables::gpos::ExtensionSubtable::ChainContextual(table) => {
2335 Self::ChainContextual(table.to_owned_obj(data))
2336 }
2337 }
2338 }
2339}
2340
2341impl FromTableRef<read_fonts::tables::gpos::ExtensionSubtable<'_>> for ExtensionSubtable {}
2342
2343impl From<ExtensionPosFormat1<SinglePos>> for ExtensionSubtable {
2344 fn from(src: ExtensionPosFormat1<SinglePos>) -> ExtensionSubtable {
2345 ExtensionSubtable::Single(src)
2346 }
2347}
2348
2349impl From<ExtensionPosFormat1<PairPos>> for ExtensionSubtable {
2350 fn from(src: ExtensionPosFormat1<PairPos>) -> ExtensionSubtable {
2351 ExtensionSubtable::Pair(src)
2352 }
2353}
2354
2355impl From<ExtensionPosFormat1<CursivePosFormat1>> for ExtensionSubtable {
2356 fn from(src: ExtensionPosFormat1<CursivePosFormat1>) -> ExtensionSubtable {
2357 ExtensionSubtable::Cursive(src)
2358 }
2359}
2360
2361impl From<ExtensionPosFormat1<MarkBasePosFormat1>> for ExtensionSubtable {
2362 fn from(src: ExtensionPosFormat1<MarkBasePosFormat1>) -> ExtensionSubtable {
2363 ExtensionSubtable::MarkToBase(src)
2364 }
2365}
2366
2367impl From<ExtensionPosFormat1<MarkLigPosFormat1>> for ExtensionSubtable {
2368 fn from(src: ExtensionPosFormat1<MarkLigPosFormat1>) -> ExtensionSubtable {
2369 ExtensionSubtable::MarkToLig(src)
2370 }
2371}
2372
2373impl From<ExtensionPosFormat1<MarkMarkPosFormat1>> for ExtensionSubtable {
2374 fn from(src: ExtensionPosFormat1<MarkMarkPosFormat1>) -> ExtensionSubtable {
2375 ExtensionSubtable::MarkToMark(src)
2376 }
2377}
2378
2379impl From<ExtensionPosFormat1<PositionSequenceContext>> for ExtensionSubtable {
2380 fn from(src: ExtensionPosFormat1<PositionSequenceContext>) -> ExtensionSubtable {
2381 ExtensionSubtable::Contextual(src)
2382 }
2383}
2384
2385impl From<ExtensionPosFormat1<PositionChainContext>> for ExtensionSubtable {
2386 fn from(src: ExtensionPosFormat1<PositionChainContext>) -> ExtensionSubtable {
2387 ExtensionSubtable::ChainContextual(src)
2388 }
2389}