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