| // THIS FILE IS AUTOGENERATED. |
| // Any changes to this file will be overwritten. |
| // For more information about how codegen works, see font-codegen/README.md |
| |
| #[allow(unused_imports)] |
| use crate::codegen_prelude::*; |
| |
| pub use read_fonts::tables::gpos::ValueFormat; |
| |
| /// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1) |
| /// [GPOS Version 1.0](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#gpos-header) |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct Gpos { |
| /// Offset to ScriptList table, from beginning of GPOS table |
| pub script_list: OffsetMarker<ScriptList>, |
| /// Offset to FeatureList table, from beginning of GPOS table |
| pub feature_list: OffsetMarker<FeatureList>, |
| /// Offset to LookupList table, from beginning of GPOS table |
| pub lookup_list: OffsetMarker<PositionLookupList>, |
| pub feature_variations: NullableOffsetMarker<FeatureVariations, WIDTH_32>, |
| } |
| |
| impl Gpos { |
| /// Construct a new `Gpos` |
| pub fn new( |
| script_list: ScriptList, |
| feature_list: FeatureList, |
| lookup_list: PositionLookupList, |
| ) -> Self { |
| Self { |
| script_list: script_list.into(), |
| feature_list: feature_list.into(), |
| lookup_list: lookup_list.into(), |
| ..Default::default() |
| } |
| } |
| } |
| |
| impl FontWrite for Gpos { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| let version = self.compute_version() as MajorMinor; |
| version.write_into(writer); |
| self.script_list.write_into(writer); |
| self.feature_list.write_into(writer); |
| self.lookup_list.write_into(writer); |
| version |
| .compatible((1u16, 1u16)) |
| .then(|| self.feature_variations.write_into(writer)); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::TopLevel(Gpos::TAG) |
| } |
| } |
| |
| impl Validate for Gpos { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("Gpos", |ctx| { |
| ctx.in_field("script_list", |ctx| { |
| self.script_list.validate_impl(ctx); |
| }); |
| ctx.in_field("feature_list", |ctx| { |
| self.feature_list.validate_impl(ctx); |
| }); |
| ctx.in_field("lookup_list", |ctx| { |
| self.lookup_list.validate_impl(ctx); |
| }); |
| ctx.in_field("feature_variations", |ctx| { |
| self.feature_variations.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl TopLevelTable for Gpos { |
| const TAG: Tag = Tag::new(b"GPOS"); |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::Gpos<'a>> for Gpos { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::Gpos<'a>, _: FontData) -> Self { |
| Gpos { |
| script_list: obj.script_list().to_owned_table(), |
| feature_list: obj.feature_list().to_owned_table(), |
| lookup_list: obj.lookup_list().to_owned_table(), |
| feature_variations: obj.feature_variations().to_owned_table(), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::Gpos<'a>> for Gpos {} |
| |
| impl<'a> FontRead<'a> for Gpos { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| <read_fonts::tables::gpos::Gpos as FontRead>::read(data).map(|x| x.to_owned_table()) |
| } |
| } |
| |
| /// A [GPOS Lookup](https://learn.microsoft.com/en-us/typography/opentype/spec/gpos#gsubLookupTypeEnum) subtable. |
| #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub enum PositionLookup { |
| Single(Lookup<SinglePos>), |
| Pair(Lookup<PairPos>), |
| Cursive(Lookup<CursivePosFormat1>), |
| MarkToBase(Lookup<MarkBasePosFormat1>), |
| MarkToLig(Lookup<MarkLigPosFormat1>), |
| MarkToMark(Lookup<MarkMarkPosFormat1>), |
| Contextual(Lookup<PositionSequenceContext>), |
| ChainContextual(Lookup<PositionChainContext>), |
| Extension(Lookup<ExtensionSubtable>), |
| } |
| |
| impl Default for PositionLookup { |
| fn default() -> Self { |
| Self::Single(Default::default()) |
| } |
| } |
| |
| impl FontWrite for PositionLookup { |
| fn write_into(&self, writer: &mut TableWriter) { |
| match self { |
| Self::Single(table) => table.write_into(writer), |
| Self::Pair(table) => table.write_into(writer), |
| Self::Cursive(table) => table.write_into(writer), |
| Self::MarkToBase(table) => table.write_into(writer), |
| Self::MarkToLig(table) => table.write_into(writer), |
| Self::MarkToMark(table) => table.write_into(writer), |
| Self::Contextual(table) => table.write_into(writer), |
| Self::ChainContextual(table) => table.write_into(writer), |
| Self::Extension(table) => table.write_into(writer), |
| } |
| } |
| fn table_type(&self) -> TableType { |
| match self { |
| Self::Single(table) => table.table_type(), |
| Self::Pair(table) => table.table_type(), |
| Self::Cursive(table) => table.table_type(), |
| Self::MarkToBase(table) => table.table_type(), |
| Self::MarkToLig(table) => table.table_type(), |
| Self::MarkToMark(table) => table.table_type(), |
| Self::Contextual(table) => table.table_type(), |
| Self::ChainContextual(table) => table.table_type(), |
| Self::Extension(table) => table.table_type(), |
| } |
| } |
| } |
| |
| impl Validate for PositionLookup { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| match self { |
| Self::Single(table) => table.validate_impl(ctx), |
| Self::Pair(table) => table.validate_impl(ctx), |
| Self::Cursive(table) => table.validate_impl(ctx), |
| Self::MarkToBase(table) => table.validate_impl(ctx), |
| Self::MarkToLig(table) => table.validate_impl(ctx), |
| Self::MarkToMark(table) => table.validate_impl(ctx), |
| Self::Contextual(table) => table.validate_impl(ctx), |
| Self::ChainContextual(table) => table.validate_impl(ctx), |
| Self::Extension(table) => table.validate_impl(ctx), |
| } |
| } |
| } |
| |
| impl FromObjRef<read_fonts::tables::gpos::PositionLookup<'_>> for PositionLookup { |
| fn from_obj_ref(from: &read_fonts::tables::gpos::PositionLookup<'_>, data: FontData) -> Self { |
| match from { |
| read_fonts::tables::gpos::PositionLookup::Single(table) => { |
| Self::Single(table.to_owned_obj(data)) |
| } |
| read_fonts::tables::gpos::PositionLookup::Pair(table) => { |
| Self::Pair(table.to_owned_obj(data)) |
| } |
| read_fonts::tables::gpos::PositionLookup::Cursive(table) => { |
| Self::Cursive(table.to_owned_obj(data)) |
| } |
| read_fonts::tables::gpos::PositionLookup::MarkToBase(table) => { |
| Self::MarkToBase(table.to_owned_obj(data)) |
| } |
| read_fonts::tables::gpos::PositionLookup::MarkToLig(table) => { |
| Self::MarkToLig(table.to_owned_obj(data)) |
| } |
| read_fonts::tables::gpos::PositionLookup::MarkToMark(table) => { |
| Self::MarkToMark(table.to_owned_obj(data)) |
| } |
| read_fonts::tables::gpos::PositionLookup::Contextual(table) => { |
| Self::Contextual(table.to_owned_obj(data)) |
| } |
| read_fonts::tables::gpos::PositionLookup::ChainContextual(table) => { |
| Self::ChainContextual(table.to_owned_obj(data)) |
| } |
| read_fonts::tables::gpos::PositionLookup::Extension(table) => { |
| Self::Extension(table.to_owned_obj(data)) |
| } |
| } |
| } |
| } |
| |
| impl FromTableRef<read_fonts::tables::gpos::PositionLookup<'_>> for PositionLookup {} |
| |
| impl From<Lookup<SinglePos>> for PositionLookup { |
| fn from(src: Lookup<SinglePos>) -> PositionLookup { |
| PositionLookup::Single(src) |
| } |
| } |
| |
| impl From<Lookup<PairPos>> for PositionLookup { |
| fn from(src: Lookup<PairPos>) -> PositionLookup { |
| PositionLookup::Pair(src) |
| } |
| } |
| |
| impl From<Lookup<CursivePosFormat1>> for PositionLookup { |
| fn from(src: Lookup<CursivePosFormat1>) -> PositionLookup { |
| PositionLookup::Cursive(src) |
| } |
| } |
| |
| impl From<Lookup<MarkBasePosFormat1>> for PositionLookup { |
| fn from(src: Lookup<MarkBasePosFormat1>) -> PositionLookup { |
| PositionLookup::MarkToBase(src) |
| } |
| } |
| |
| impl From<Lookup<MarkLigPosFormat1>> for PositionLookup { |
| fn from(src: Lookup<MarkLigPosFormat1>) -> PositionLookup { |
| PositionLookup::MarkToLig(src) |
| } |
| } |
| |
| impl From<Lookup<MarkMarkPosFormat1>> for PositionLookup { |
| fn from(src: Lookup<MarkMarkPosFormat1>) -> PositionLookup { |
| PositionLookup::MarkToMark(src) |
| } |
| } |
| |
| impl From<Lookup<PositionSequenceContext>> for PositionLookup { |
| fn from(src: Lookup<PositionSequenceContext>) -> PositionLookup { |
| PositionLookup::Contextual(src) |
| } |
| } |
| |
| impl From<Lookup<PositionChainContext>> for PositionLookup { |
| fn from(src: Lookup<PositionChainContext>) -> PositionLookup { |
| PositionLookup::ChainContextual(src) |
| } |
| } |
| |
| impl From<Lookup<ExtensionSubtable>> for PositionLookup { |
| fn from(src: Lookup<ExtensionSubtable>) -> PositionLookup { |
| PositionLookup::Extension(src) |
| } |
| } |
| |
| impl FontWrite for ValueFormat { |
| fn write_into(&self, writer: &mut TableWriter) { |
| writer.write_slice(&self.bits().to_be_bytes()) |
| } |
| } |
| |
| /// [Anchor Tables](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#anchor-tables) |
| /// position one glyph with respect to another. |
| #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub enum AnchorTable { |
| Format1(AnchorFormat1), |
| Format2(AnchorFormat2), |
| Format3(AnchorFormat3), |
| } |
| |
| impl AnchorTable { |
| /// Construct a new `AnchorFormat1` subtable |
| pub fn format_1(x_coordinate: i16, y_coordinate: i16) -> Self { |
| Self::Format1(AnchorFormat1::new(x_coordinate, y_coordinate)) |
| } |
| |
| /// Construct a new `AnchorFormat2` subtable |
| pub fn format_2(x_coordinate: i16, y_coordinate: i16, anchor_point: u16) -> Self { |
| Self::Format2(AnchorFormat2::new(x_coordinate, y_coordinate, anchor_point)) |
| } |
| |
| /// Construct a new `AnchorFormat3` subtable |
| pub fn format_3( |
| x_coordinate: i16, |
| y_coordinate: i16, |
| x_device: Option<DeviceOrVariationIndex>, |
| y_device: Option<DeviceOrVariationIndex>, |
| ) -> Self { |
| Self::Format3(AnchorFormat3::new( |
| x_coordinate, |
| y_coordinate, |
| x_device, |
| y_device, |
| )) |
| } |
| } |
| |
| impl Default for AnchorTable { |
| fn default() -> Self { |
| Self::Format1(Default::default()) |
| } |
| } |
| |
| impl FontWrite for AnchorTable { |
| fn write_into(&self, writer: &mut TableWriter) { |
| match self { |
| Self::Format1(item) => item.write_into(writer), |
| Self::Format2(item) => item.write_into(writer), |
| Self::Format3(item) => item.write_into(writer), |
| } |
| } |
| fn table_type(&self) -> TableType { |
| match self { |
| Self::Format1(item) => item.table_type(), |
| Self::Format2(item) => item.table_type(), |
| Self::Format3(item) => item.table_type(), |
| } |
| } |
| } |
| |
| impl Validate for AnchorTable { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| match self { |
| Self::Format1(item) => item.validate_impl(ctx), |
| Self::Format2(item) => item.validate_impl(ctx), |
| Self::Format3(item) => item.validate_impl(ctx), |
| } |
| } |
| } |
| |
| impl FromObjRef<read_fonts::tables::gpos::AnchorTable<'_>> for AnchorTable { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::AnchorTable, _: FontData) -> Self { |
| use read_fonts::tables::gpos::AnchorTable as ObjRefType; |
| match obj { |
| ObjRefType::Format1(item) => AnchorTable::Format1(item.to_owned_table()), |
| ObjRefType::Format2(item) => AnchorTable::Format2(item.to_owned_table()), |
| ObjRefType::Format3(item) => AnchorTable::Format3(item.to_owned_table()), |
| } |
| } |
| } |
| |
| impl FromTableRef<read_fonts::tables::gpos::AnchorTable<'_>> for AnchorTable {} |
| |
| impl<'a> FontRead<'a> for AnchorTable { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| <read_fonts::tables::gpos::AnchorTable as FontRead>::read(data).map(|x| x.to_owned_table()) |
| } |
| } |
| |
| impl From<AnchorFormat1> for AnchorTable { |
| fn from(src: AnchorFormat1) -> AnchorTable { |
| AnchorTable::Format1(src) |
| } |
| } |
| |
| impl From<AnchorFormat2> for AnchorTable { |
| fn from(src: AnchorFormat2) -> AnchorTable { |
| AnchorTable::Format2(src) |
| } |
| } |
| |
| impl From<AnchorFormat3> for AnchorTable { |
| fn from(src: AnchorFormat3) -> AnchorTable { |
| AnchorTable::Format3(src) |
| } |
| } |
| |
| /// [Anchor Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#anchor-table-format-1-design-units): Design Units |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct AnchorFormat1 { |
| /// Horizontal value, in design units |
| pub x_coordinate: i16, |
| /// Vertical value, in design units |
| pub y_coordinate: i16, |
| } |
| |
| impl AnchorFormat1 { |
| /// Construct a new `AnchorFormat1` |
| pub fn new(x_coordinate: i16, y_coordinate: i16) -> Self { |
| Self { |
| x_coordinate, |
| y_coordinate, |
| } |
| } |
| } |
| |
| impl FontWrite for AnchorFormat1 { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (1 as u16).write_into(writer); |
| self.x_coordinate.write_into(writer); |
| self.y_coordinate.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("AnchorFormat1") |
| } |
| } |
| |
| impl Validate for AnchorFormat1 { |
| fn validate_impl(&self, _ctx: &mut ValidationCtx) {} |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::AnchorFormat1<'a>> for AnchorFormat1 { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::AnchorFormat1<'a>, _: FontData) -> Self { |
| AnchorFormat1 { |
| x_coordinate: obj.x_coordinate(), |
| y_coordinate: obj.y_coordinate(), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::AnchorFormat1<'a>> for AnchorFormat1 {} |
| |
| impl<'a> FontRead<'a> for AnchorFormat1 { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| <read_fonts::tables::gpos::AnchorFormat1 as FontRead>::read(data) |
| .map(|x| x.to_owned_table()) |
| } |
| } |
| |
| /// [Anchor Table Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#anchor-table-format-2-design-units-plus-contour-point): Design Units Plus Contour Point |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct AnchorFormat2 { |
| /// Horizontal value, in design units |
| pub x_coordinate: i16, |
| /// Vertical value, in design units |
| pub y_coordinate: i16, |
| /// Index to glyph contour point |
| pub anchor_point: u16, |
| } |
| |
| impl AnchorFormat2 { |
| /// Construct a new `AnchorFormat2` |
| pub fn new(x_coordinate: i16, y_coordinate: i16, anchor_point: u16) -> Self { |
| Self { |
| x_coordinate, |
| y_coordinate, |
| anchor_point, |
| } |
| } |
| } |
| |
| impl FontWrite for AnchorFormat2 { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (2 as u16).write_into(writer); |
| self.x_coordinate.write_into(writer); |
| self.y_coordinate.write_into(writer); |
| self.anchor_point.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("AnchorFormat2") |
| } |
| } |
| |
| impl Validate for AnchorFormat2 { |
| fn validate_impl(&self, _ctx: &mut ValidationCtx) {} |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::AnchorFormat2<'a>> for AnchorFormat2 { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::AnchorFormat2<'a>, _: FontData) -> Self { |
| AnchorFormat2 { |
| x_coordinate: obj.x_coordinate(), |
| y_coordinate: obj.y_coordinate(), |
| anchor_point: obj.anchor_point(), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::AnchorFormat2<'a>> for AnchorFormat2 {} |
| |
| impl<'a> FontRead<'a> for AnchorFormat2 { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| <read_fonts::tables::gpos::AnchorFormat2 as FontRead>::read(data) |
| .map(|x| x.to_owned_table()) |
| } |
| } |
| |
| /// [Anchor Table Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#anchor-table-format-3-design-units-plus-device-or-variationindex-tables): Design Units Plus Device or VariationIndex Tables |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct AnchorFormat3 { |
| /// Horizontal value, in design units |
| pub x_coordinate: i16, |
| /// Vertical value, in design units |
| pub y_coordinate: i16, |
| /// Offset to Device table (non-variable font) / VariationIndex |
| /// table (variable font) for X coordinate, from beginning of |
| /// Anchor table (may be NULL) |
| pub x_device: NullableOffsetMarker<DeviceOrVariationIndex>, |
| /// Offset to Device table (non-variable font) / VariationIndex |
| /// table (variable font) for Y coordinate, from beginning of |
| /// Anchor table (may be NULL) |
| pub y_device: NullableOffsetMarker<DeviceOrVariationIndex>, |
| } |
| |
| impl AnchorFormat3 { |
| /// Construct a new `AnchorFormat3` |
| pub fn new( |
| x_coordinate: i16, |
| y_coordinate: i16, |
| x_device: Option<DeviceOrVariationIndex>, |
| y_device: Option<DeviceOrVariationIndex>, |
| ) -> Self { |
| Self { |
| x_coordinate, |
| y_coordinate, |
| x_device: x_device.into(), |
| y_device: y_device.into(), |
| } |
| } |
| } |
| |
| impl FontWrite for AnchorFormat3 { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (3 as u16).write_into(writer); |
| self.x_coordinate.write_into(writer); |
| self.y_coordinate.write_into(writer); |
| self.x_device.write_into(writer); |
| self.y_device.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("AnchorFormat3") |
| } |
| } |
| |
| impl Validate for AnchorFormat3 { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("AnchorFormat3", |ctx| { |
| ctx.in_field("x_device", |ctx| { |
| self.x_device.validate_impl(ctx); |
| }); |
| ctx.in_field("y_device", |ctx| { |
| self.y_device.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::AnchorFormat3<'a>> for AnchorFormat3 { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::AnchorFormat3<'a>, _: FontData) -> Self { |
| AnchorFormat3 { |
| x_coordinate: obj.x_coordinate(), |
| y_coordinate: obj.y_coordinate(), |
| x_device: obj.x_device().to_owned_table(), |
| y_device: obj.y_device().to_owned_table(), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::AnchorFormat3<'a>> for AnchorFormat3 {} |
| |
| impl<'a> FontRead<'a> for AnchorFormat3 { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| <read_fonts::tables::gpos::AnchorFormat3 as FontRead>::read(data) |
| .map(|x| x.to_owned_table()) |
| } |
| } |
| |
| /// [Mark Array Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#mark-array-table) |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct MarkArray { |
| /// Array of MarkRecords, ordered by corresponding glyphs in the |
| /// associated mark Coverage table. |
| pub mark_records: Vec<MarkRecord>, |
| } |
| |
| impl MarkArray { |
| /// Construct a new `MarkArray` |
| pub fn new(mark_records: Vec<MarkRecord>) -> Self { |
| Self { mark_records } |
| } |
| } |
| |
| impl FontWrite for MarkArray { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (u16::try_from(array_len(&self.mark_records)).unwrap()).write_into(writer); |
| self.mark_records.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("MarkArray") |
| } |
| } |
| |
| impl Validate for MarkArray { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("MarkArray", |ctx| { |
| ctx.in_field("mark_records", |ctx| { |
| if self.mark_records.len() > (u16::MAX as usize) { |
| ctx.report("array exceeds max length"); |
| } |
| self.mark_records.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::MarkArray<'a>> for MarkArray { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkArray<'a>, _: FontData) -> Self { |
| let offset_data = obj.offset_data(); |
| MarkArray { |
| mark_records: obj.mark_records().to_owned_obj(offset_data), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::MarkArray<'a>> for MarkArray {} |
| |
| impl<'a> FontRead<'a> for MarkArray { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| <read_fonts::tables::gpos::MarkArray as FontRead>::read(data).map(|x| x.to_owned_table()) |
| } |
| } |
| |
| /// Part of [MarkArray] |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct MarkRecord { |
| /// Class defined for the associated mark. |
| pub mark_class: u16, |
| /// Offset to Anchor table, from beginning of MarkArray table. |
| pub mark_anchor: OffsetMarker<AnchorTable>, |
| } |
| |
| impl MarkRecord { |
| /// Construct a new `MarkRecord` |
| pub fn new(mark_class: u16, mark_anchor: AnchorTable) -> Self { |
| Self { |
| mark_class, |
| mark_anchor: mark_anchor.into(), |
| } |
| } |
| } |
| |
| impl FontWrite for MarkRecord { |
| fn write_into(&self, writer: &mut TableWriter) { |
| self.mark_class.write_into(writer); |
| self.mark_anchor.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("MarkRecord") |
| } |
| } |
| |
| impl Validate for MarkRecord { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("MarkRecord", |ctx| { |
| ctx.in_field("mark_anchor", |ctx| { |
| self.mark_anchor.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl FromObjRef<read_fonts::tables::gpos::MarkRecord> for MarkRecord { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkRecord, offset_data: FontData) -> Self { |
| MarkRecord { |
| mark_class: obj.mark_class(), |
| mark_anchor: obj.mark_anchor(offset_data).to_owned_table(), |
| } |
| } |
| } |
| |
| /// [Lookup Type 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#lookup-type-1-single-adjustment-positioning-subtable): Single Adjustment Positioning Subtable |
| #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub enum SinglePos { |
| Format1(SinglePosFormat1), |
| Format2(SinglePosFormat2), |
| } |
| |
| impl SinglePos { |
| /// Construct a new `SinglePosFormat1` subtable |
| pub fn format_1(coverage: CoverageTable, value_record: ValueRecord) -> Self { |
| Self::Format1(SinglePosFormat1::new(coverage, value_record)) |
| } |
| |
| /// Construct a new `SinglePosFormat2` subtable |
| pub fn format_2(coverage: CoverageTable, value_records: Vec<ValueRecord>) -> Self { |
| Self::Format2(SinglePosFormat2::new(coverage, value_records)) |
| } |
| } |
| |
| impl Default for SinglePos { |
| fn default() -> Self { |
| Self::Format1(Default::default()) |
| } |
| } |
| |
| impl FontWrite for SinglePos { |
| fn write_into(&self, writer: &mut TableWriter) { |
| match self { |
| Self::Format1(item) => item.write_into(writer), |
| Self::Format2(item) => item.write_into(writer), |
| } |
| } |
| fn table_type(&self) -> TableType { |
| match self { |
| Self::Format1(item) => item.table_type(), |
| Self::Format2(item) => item.table_type(), |
| } |
| } |
| } |
| |
| impl Validate for SinglePos { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| match self { |
| Self::Format1(item) => item.validate_impl(ctx), |
| Self::Format2(item) => item.validate_impl(ctx), |
| } |
| } |
| } |
| |
| impl FromObjRef<read_fonts::tables::gpos::SinglePos<'_>> for SinglePos { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::SinglePos, _: FontData) -> Self { |
| use read_fonts::tables::gpos::SinglePos as ObjRefType; |
| match obj { |
| ObjRefType::Format1(item) => SinglePos::Format1(item.to_owned_table()), |
| ObjRefType::Format2(item) => SinglePos::Format2(item.to_owned_table()), |
| } |
| } |
| } |
| |
| impl FromTableRef<read_fonts::tables::gpos::SinglePos<'_>> for SinglePos {} |
| |
| impl<'a> FontRead<'a> for SinglePos { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| <read_fonts::tables::gpos::SinglePos as FontRead>::read(data).map(|x| x.to_owned_table()) |
| } |
| } |
| |
| impl From<SinglePosFormat1> for SinglePos { |
| fn from(src: SinglePosFormat1) -> SinglePos { |
| SinglePos::Format1(src) |
| } |
| } |
| |
| impl From<SinglePosFormat2> for SinglePos { |
| fn from(src: SinglePosFormat2) -> SinglePos { |
| SinglePos::Format2(src) |
| } |
| } |
| |
| /// [Single Adjustment Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#single-adjustment-positioning-format-1-single-positioning-value): Single Positioning Value |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct SinglePosFormat1 { |
| /// Offset to Coverage table, from beginning of SinglePos subtable. |
| pub coverage: OffsetMarker<CoverageTable>, |
| /// Defines positioning value(s) — applied to all glyphs in the |
| /// Coverage table. |
| pub value_record: ValueRecord, |
| } |
| |
| impl SinglePosFormat1 { |
| /// Construct a new `SinglePosFormat1` |
| pub fn new(coverage: CoverageTable, value_record: ValueRecord) -> Self { |
| Self { |
| coverage: coverage.into(), |
| value_record, |
| } |
| } |
| } |
| |
| impl FontWrite for SinglePosFormat1 { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (1 as u16).write_into(writer); |
| self.coverage.write_into(writer); |
| (self.compute_value_format() as ValueFormat).write_into(writer); |
| self.value_record.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("SinglePosFormat1") |
| } |
| } |
| |
| impl Validate for SinglePosFormat1 { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("SinglePosFormat1", |ctx| { |
| ctx.in_field("coverage", |ctx| { |
| self.coverage.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::SinglePosFormat1<'a>> for SinglePosFormat1 { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::SinglePosFormat1<'a>, _: FontData) -> Self { |
| let offset_data = obj.offset_data(); |
| SinglePosFormat1 { |
| coverage: obj.coverage().to_owned_table(), |
| value_record: obj.value_record().to_owned_obj(offset_data), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::SinglePosFormat1<'a>> for SinglePosFormat1 {} |
| |
| impl<'a> FontRead<'a> for SinglePosFormat1 { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| <read_fonts::tables::gpos::SinglePosFormat1 as FontRead>::read(data) |
| .map(|x| x.to_owned_table()) |
| } |
| } |
| |
| /// [Single Adjustment Positioning Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#single-adjustment-positioning-format-2-array-of-positioning-values): Array of Positioning Values |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct SinglePosFormat2 { |
| /// Offset to Coverage table, from beginning of SinglePos subtable. |
| pub coverage: OffsetMarker<CoverageTable>, |
| /// Array of ValueRecords — positioning values applied to glyphs. |
| pub value_records: Vec<ValueRecord>, |
| } |
| |
| impl SinglePosFormat2 { |
| /// Construct a new `SinglePosFormat2` |
| pub fn new(coverage: CoverageTable, value_records: Vec<ValueRecord>) -> Self { |
| Self { |
| coverage: coverage.into(), |
| value_records, |
| } |
| } |
| } |
| |
| impl FontWrite for SinglePosFormat2 { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (2 as u16).write_into(writer); |
| self.coverage.write_into(writer); |
| (self.compute_value_format() as ValueFormat).write_into(writer); |
| (u16::try_from(array_len(&self.value_records)).unwrap()).write_into(writer); |
| self.value_records.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("SinglePosFormat2") |
| } |
| } |
| |
| impl Validate for SinglePosFormat2 { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("SinglePosFormat2", |ctx| { |
| ctx.in_field("coverage", |ctx| { |
| self.coverage.validate_impl(ctx); |
| }); |
| ctx.in_field("value_records", |ctx| { |
| if self.value_records.len() > (u16::MAX as usize) { |
| ctx.report("array exceeds max length"); |
| } |
| self.value_records.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::SinglePosFormat2<'a>> for SinglePosFormat2 { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::SinglePosFormat2<'a>, _: FontData) -> Self { |
| let offset_data = obj.offset_data(); |
| SinglePosFormat2 { |
| coverage: obj.coverage().to_owned_table(), |
| value_records: obj |
| .value_records() |
| .iter() |
| .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok()) |
| .collect(), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::SinglePosFormat2<'a>> for SinglePosFormat2 {} |
| |
| impl<'a> FontRead<'a> for SinglePosFormat2 { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| <read_fonts::tables::gpos::SinglePosFormat2 as FontRead>::read(data) |
| .map(|x| x.to_owned_table()) |
| } |
| } |
| |
| /// [Lookup Type 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#lookup-type-1-single-adjustment-positioning-subtable): Single Adjustment Positioning Subtable |
| #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub enum PairPos { |
| Format1(PairPosFormat1), |
| Format2(PairPosFormat2), |
| } |
| |
| impl PairPos { |
| /// Construct a new `PairPosFormat1` subtable |
| pub fn format_1(coverage: CoverageTable, pair_sets: Vec<PairSet>) -> Self { |
| Self::Format1(PairPosFormat1::new(coverage, pair_sets)) |
| } |
| |
| /// Construct a new `PairPosFormat2` subtable |
| pub fn format_2( |
| coverage: CoverageTable, |
| class_def1: ClassDef, |
| class_def2: ClassDef, |
| class1_records: Vec<Class1Record>, |
| ) -> Self { |
| Self::Format2(PairPosFormat2::new( |
| coverage, |
| class_def1, |
| class_def2, |
| class1_records, |
| )) |
| } |
| } |
| |
| impl Default for PairPos { |
| fn default() -> Self { |
| Self::Format1(Default::default()) |
| } |
| } |
| |
| impl FontWrite for PairPos { |
| fn write_into(&self, writer: &mut TableWriter) { |
| match self { |
| Self::Format1(item) => item.write_into(writer), |
| Self::Format2(item) => item.write_into(writer), |
| } |
| } |
| fn table_type(&self) -> TableType { |
| match self { |
| Self::Format1(item) => item.table_type(), |
| Self::Format2(item) => item.table_type(), |
| } |
| } |
| } |
| |
| impl Validate for PairPos { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| match self { |
| Self::Format1(item) => item.validate_impl(ctx), |
| Self::Format2(item) => item.validate_impl(ctx), |
| } |
| } |
| } |
| |
| impl FromObjRef<read_fonts::tables::gpos::PairPos<'_>> for PairPos { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::PairPos, _: FontData) -> Self { |
| use read_fonts::tables::gpos::PairPos as ObjRefType; |
| match obj { |
| ObjRefType::Format1(item) => PairPos::Format1(item.to_owned_table()), |
| ObjRefType::Format2(item) => PairPos::Format2(item.to_owned_table()), |
| } |
| } |
| } |
| |
| impl FromTableRef<read_fonts::tables::gpos::PairPos<'_>> for PairPos {} |
| |
| impl<'a> FontRead<'a> for PairPos { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| <read_fonts::tables::gpos::PairPos as FontRead>::read(data).map(|x| x.to_owned_table()) |
| } |
| } |
| |
| impl From<PairPosFormat1> for PairPos { |
| fn from(src: PairPosFormat1) -> PairPos { |
| PairPos::Format1(src) |
| } |
| } |
| |
| impl From<PairPosFormat2> for PairPos { |
| fn from(src: PairPosFormat2) -> PairPos { |
| PairPos::Format2(src) |
| } |
| } |
| |
| /// [Pair Adjustment Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#pair-adjustment-positioning-format-1-adjustments-for-glyph-pairs): Adjustments for Glyph Pairs |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct PairPosFormat1 { |
| /// Offset to Coverage table, from beginning of PairPos subtable. |
| pub coverage: OffsetMarker<CoverageTable>, |
| /// Array of offsets to PairSet tables. Offsets are from beginning |
| /// of PairPos subtable, ordered by Coverage Index. |
| pub pair_sets: Vec<OffsetMarker<PairSet>>, |
| } |
| |
| impl PairPosFormat1 { |
| /// Construct a new `PairPosFormat1` |
| pub fn new(coverage: CoverageTable, pair_sets: Vec<PairSet>) -> Self { |
| Self { |
| coverage: coverage.into(), |
| pair_sets: pair_sets.into_iter().map(Into::into).collect(), |
| } |
| } |
| } |
| |
| impl FontWrite for PairPosFormat1 { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (1 as u16).write_into(writer); |
| self.coverage.write_into(writer); |
| (self.compute_value_format1() as ValueFormat).write_into(writer); |
| (self.compute_value_format2() as ValueFormat).write_into(writer); |
| (u16::try_from(array_len(&self.pair_sets)).unwrap()).write_into(writer); |
| self.pair_sets.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("PairPosFormat1") |
| } |
| } |
| |
| impl Validate for PairPosFormat1 { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("PairPosFormat1", |ctx| { |
| ctx.in_field("coverage", |ctx| { |
| self.coverage.validate_impl(ctx); |
| }); |
| ctx.in_field("pair_sets", |ctx| { |
| if self.pair_sets.len() > (u16::MAX as usize) { |
| ctx.report("array exceeds max length"); |
| } |
| self.check_format_consistency(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::PairPosFormat1<'a>> for PairPosFormat1 { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::PairPosFormat1<'a>, _: FontData) -> Self { |
| PairPosFormat1 { |
| coverage: obj.coverage().to_owned_table(), |
| pair_sets: obj.pair_sets().to_owned_table(), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::PairPosFormat1<'a>> for PairPosFormat1 {} |
| |
| impl<'a> FontRead<'a> for PairPosFormat1 { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| <read_fonts::tables::gpos::PairPosFormat1 as FontRead>::read(data) |
| .map(|x| x.to_owned_table()) |
| } |
| } |
| |
| /// Part of [PairPosFormat1] |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct PairSet { |
| /// Array of PairValueRecords, ordered by glyph ID of the second |
| /// glyph. |
| pub pair_value_records: Vec<PairValueRecord>, |
| } |
| |
| impl PairSet { |
| /// Construct a new `PairSet` |
| pub fn new(pair_value_records: Vec<PairValueRecord>) -> Self { |
| Self { pair_value_records } |
| } |
| } |
| |
| impl FontWrite for PairSet { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (u16::try_from(array_len(&self.pair_value_records)).unwrap()).write_into(writer); |
| self.pair_value_records.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("PairSet") |
| } |
| } |
| |
| impl Validate for PairSet { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("PairSet", |ctx| { |
| ctx.in_field("pair_value_records", |ctx| { |
| if self.pair_value_records.len() > (u16::MAX as usize) { |
| ctx.report("array exceeds max length"); |
| } |
| self.pair_value_records.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::PairSet<'a>> for PairSet { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::PairSet<'a>, _: FontData) -> Self { |
| let offset_data = obj.offset_data(); |
| PairSet { |
| pair_value_records: obj |
| .pair_value_records() |
| .iter() |
| .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok()) |
| .collect(), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::PairSet<'a>> for PairSet {} |
| |
| /// Part of [PairSet] |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct PairValueRecord { |
| /// Glyph ID of second glyph in the pair (first glyph is listed in |
| /// the Coverage table). |
| pub second_glyph: GlyphId16, |
| /// Positioning data for the first glyph in the pair. |
| pub value_record1: ValueRecord, |
| /// Positioning data for the second glyph in the pair. |
| pub value_record2: ValueRecord, |
| } |
| |
| impl PairValueRecord { |
| /// Construct a new `PairValueRecord` |
| pub fn new( |
| second_glyph: GlyphId16, |
| value_record1: ValueRecord, |
| value_record2: ValueRecord, |
| ) -> Self { |
| Self { |
| second_glyph, |
| value_record1, |
| value_record2, |
| } |
| } |
| } |
| |
| impl FontWrite for PairValueRecord { |
| fn write_into(&self, writer: &mut TableWriter) { |
| self.second_glyph.write_into(writer); |
| self.value_record1.write_into(writer); |
| self.value_record2.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("PairValueRecord") |
| } |
| } |
| |
| impl Validate for PairValueRecord { |
| fn validate_impl(&self, _ctx: &mut ValidationCtx) {} |
| } |
| |
| impl FromObjRef<read_fonts::tables::gpos::PairValueRecord> for PairValueRecord { |
| fn from_obj_ref( |
| obj: &read_fonts::tables::gpos::PairValueRecord, |
| offset_data: FontData, |
| ) -> Self { |
| PairValueRecord { |
| second_glyph: obj.second_glyph(), |
| value_record1: obj.value_record1().to_owned_obj(offset_data), |
| value_record2: obj.value_record2().to_owned_obj(offset_data), |
| } |
| } |
| } |
| |
| /// [Pair Adjustment Positioning Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#pair-adjustment-positioning-format-2-class-pair-adjustment): Class Pair Adjustment |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct PairPosFormat2 { |
| /// Offset to Coverage table, from beginning of PairPos subtable. |
| pub coverage: OffsetMarker<CoverageTable>, |
| /// Offset to ClassDef table, from beginning of PairPos subtable |
| /// — for the first glyph of the pair. |
| pub class_def1: OffsetMarker<ClassDef>, |
| /// Offset to ClassDef table, from beginning of PairPos subtable |
| /// — for the second glyph of the pair. |
| pub class_def2: OffsetMarker<ClassDef>, |
| /// Array of Class1 records, ordered by classes in classDef1. |
| pub class1_records: Vec<Class1Record>, |
| } |
| |
| impl PairPosFormat2 { |
| /// Construct a new `PairPosFormat2` |
| pub fn new( |
| coverage: CoverageTable, |
| class_def1: ClassDef, |
| class_def2: ClassDef, |
| class1_records: Vec<Class1Record>, |
| ) -> Self { |
| Self { |
| coverage: coverage.into(), |
| class_def1: class_def1.into(), |
| class_def2: class_def2.into(), |
| class1_records, |
| } |
| } |
| } |
| |
| impl FontWrite for PairPosFormat2 { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (2 as u16).write_into(writer); |
| self.coverage.write_into(writer); |
| (self.compute_value_format1() as ValueFormat).write_into(writer); |
| (self.compute_value_format2() as ValueFormat).write_into(writer); |
| self.class_def1.write_into(writer); |
| self.class_def2.write_into(writer); |
| (self.compute_class1_count() as u16).write_into(writer); |
| (self.compute_class2_count() as u16).write_into(writer); |
| self.class1_records.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("PairPosFormat2") |
| } |
| } |
| |
| impl Validate for PairPosFormat2 { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("PairPosFormat2", |ctx| { |
| ctx.in_field("coverage", |ctx| { |
| self.coverage.validate_impl(ctx); |
| }); |
| ctx.in_field("class_def1", |ctx| { |
| self.class_def1.validate_impl(ctx); |
| }); |
| ctx.in_field("class_def2", |ctx| { |
| self.class_def2.validate_impl(ctx); |
| }); |
| ctx.in_field("class1_records", |ctx| { |
| if self.class1_records.len() > (u16::MAX as usize) { |
| ctx.report("array exceeds max length"); |
| } |
| self.class1_records.validate_impl(ctx); |
| }); |
| self.check_length_and_format_conformance(ctx); |
| }) |
| } |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::PairPosFormat2<'a>> for PairPosFormat2 { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::PairPosFormat2<'a>, _: FontData) -> Self { |
| let offset_data = obj.offset_data(); |
| PairPosFormat2 { |
| coverage: obj.coverage().to_owned_table(), |
| class_def1: obj.class_def1().to_owned_table(), |
| class_def2: obj.class_def2().to_owned_table(), |
| class1_records: obj |
| .class1_records() |
| .iter() |
| .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok()) |
| .collect(), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::PairPosFormat2<'a>> for PairPosFormat2 {} |
| |
| impl<'a> FontRead<'a> for PairPosFormat2 { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| <read_fonts::tables::gpos::PairPosFormat2 as FontRead>::read(data) |
| .map(|x| x.to_owned_table()) |
| } |
| } |
| |
| /// Part of [PairPosFormat2] |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct Class1Record { |
| /// Array of Class2 records, ordered by classes in classDef2. |
| pub class2_records: Vec<Class2Record>, |
| } |
| |
| impl Class1Record { |
| /// Construct a new `Class1Record` |
| pub fn new(class2_records: Vec<Class2Record>) -> Self { |
| Self { class2_records } |
| } |
| } |
| |
| impl FontWrite for Class1Record { |
| fn write_into(&self, writer: &mut TableWriter) { |
| self.class2_records.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("Class1Record") |
| } |
| } |
| |
| impl Validate for Class1Record { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("Class1Record", |ctx| { |
| ctx.in_field("class2_records", |ctx| { |
| if self.class2_records.len() > (u16::MAX as usize) { |
| ctx.report("array exceeds max length"); |
| } |
| self.class2_records.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl FromObjRef<read_fonts::tables::gpos::Class1Record<'_>> for Class1Record { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::Class1Record, offset_data: FontData) -> Self { |
| Class1Record { |
| class2_records: obj |
| .class2_records() |
| .iter() |
| .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok()) |
| .collect(), |
| } |
| } |
| } |
| |
| /// Part of [PairPosFormat2] |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct Class2Record { |
| /// Positioning for first glyph — empty if valueFormat1 = 0. |
| pub value_record1: ValueRecord, |
| /// Positioning for second glyph — empty if valueFormat2 = 0. |
| pub value_record2: ValueRecord, |
| } |
| |
| impl Class2Record { |
| /// Construct a new `Class2Record` |
| pub fn new(value_record1: ValueRecord, value_record2: ValueRecord) -> Self { |
| Self { |
| value_record1, |
| value_record2, |
| } |
| } |
| } |
| |
| impl FontWrite for Class2Record { |
| fn write_into(&self, writer: &mut TableWriter) { |
| self.value_record1.write_into(writer); |
| self.value_record2.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("Class2Record") |
| } |
| } |
| |
| impl Validate for Class2Record { |
| fn validate_impl(&self, _ctx: &mut ValidationCtx) {} |
| } |
| |
| impl FromObjRef<read_fonts::tables::gpos::Class2Record> for Class2Record { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::Class2Record, offset_data: FontData) -> Self { |
| Class2Record { |
| value_record1: obj.value_record1().to_owned_obj(offset_data), |
| value_record2: obj.value_record2().to_owned_obj(offset_data), |
| } |
| } |
| } |
| |
| /// [Cursive Attachment Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#cursive-attachment-positioning-format1-cursive-attachment): Cursvie attachment |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct CursivePosFormat1 { |
| /// Offset to Coverage table, from beginning of CursivePos subtable. |
| pub coverage: OffsetMarker<CoverageTable>, |
| /// Array of EntryExit records, in Coverage index order. |
| pub entry_exit_record: Vec<EntryExitRecord>, |
| } |
| |
| impl CursivePosFormat1 { |
| /// Construct a new `CursivePosFormat1` |
| pub fn new(coverage: CoverageTable, entry_exit_record: Vec<EntryExitRecord>) -> Self { |
| Self { |
| coverage: coverage.into(), |
| entry_exit_record, |
| } |
| } |
| } |
| |
| impl FontWrite for CursivePosFormat1 { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (1 as u16).write_into(writer); |
| self.coverage.write_into(writer); |
| (u16::try_from(array_len(&self.entry_exit_record)).unwrap()).write_into(writer); |
| self.entry_exit_record.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("CursivePosFormat1") |
| } |
| } |
| |
| impl Validate for CursivePosFormat1 { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("CursivePosFormat1", |ctx| { |
| ctx.in_field("coverage", |ctx| { |
| self.coverage.validate_impl(ctx); |
| }); |
| ctx.in_field("entry_exit_record", |ctx| { |
| if self.entry_exit_record.len() > (u16::MAX as usize) { |
| ctx.report("array exceeds max length"); |
| } |
| self.entry_exit_record.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::CursivePosFormat1<'a>> for CursivePosFormat1 { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::CursivePosFormat1<'a>, _: FontData) -> Self { |
| let offset_data = obj.offset_data(); |
| CursivePosFormat1 { |
| coverage: obj.coverage().to_owned_table(), |
| entry_exit_record: obj.entry_exit_record().to_owned_obj(offset_data), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::CursivePosFormat1<'a>> for CursivePosFormat1 {} |
| |
| impl<'a> FontRead<'a> for CursivePosFormat1 { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| <read_fonts::tables::gpos::CursivePosFormat1 as FontRead>::read(data) |
| .map(|x| x.to_owned_table()) |
| } |
| } |
| |
| /// Part of [CursivePosFormat1] |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct EntryExitRecord { |
| /// Offset to entryAnchor table, from beginning of CursivePos |
| /// subtable (may be NULL). |
| pub entry_anchor: NullableOffsetMarker<AnchorTable>, |
| /// Offset to exitAnchor table, from beginning of CursivePos |
| /// subtable (may be NULL). |
| pub exit_anchor: NullableOffsetMarker<AnchorTable>, |
| } |
| |
| impl EntryExitRecord { |
| /// Construct a new `EntryExitRecord` |
| pub fn new(entry_anchor: Option<AnchorTable>, exit_anchor: Option<AnchorTable>) -> Self { |
| Self { |
| entry_anchor: entry_anchor.into(), |
| exit_anchor: exit_anchor.into(), |
| } |
| } |
| } |
| |
| impl FontWrite for EntryExitRecord { |
| fn write_into(&self, writer: &mut TableWriter) { |
| self.entry_anchor.write_into(writer); |
| self.exit_anchor.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("EntryExitRecord") |
| } |
| } |
| |
| impl Validate for EntryExitRecord { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("EntryExitRecord", |ctx| { |
| ctx.in_field("entry_anchor", |ctx| { |
| self.entry_anchor.validate_impl(ctx); |
| }); |
| ctx.in_field("exit_anchor", |ctx| { |
| self.exit_anchor.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl FromObjRef<read_fonts::tables::gpos::EntryExitRecord> for EntryExitRecord { |
| fn from_obj_ref( |
| obj: &read_fonts::tables::gpos::EntryExitRecord, |
| offset_data: FontData, |
| ) -> Self { |
| EntryExitRecord { |
| entry_anchor: obj.entry_anchor(offset_data).to_owned_table(), |
| exit_anchor: obj.exit_anchor(offset_data).to_owned_table(), |
| } |
| } |
| } |
| |
| /// [Mark-to-Base Attachment Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#mark-to-base-attachment-positioning-format-1-mark-to-base-attachment-point): Mark-to-base Attachment Point |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct MarkBasePosFormat1 { |
| /// Offset to markCoverage table, from beginning of MarkBasePos |
| /// subtable. |
| pub mark_coverage: OffsetMarker<CoverageTable>, |
| /// Offset to baseCoverage table, from beginning of MarkBasePos |
| /// subtable. |
| pub base_coverage: OffsetMarker<CoverageTable>, |
| /// Offset to MarkArray table, from beginning of MarkBasePos |
| /// subtable. |
| pub mark_array: OffsetMarker<MarkArray>, |
| /// Offset to BaseArray table, from beginning of MarkBasePos |
| /// subtable. |
| pub base_array: OffsetMarker<BaseArray>, |
| } |
| |
| impl MarkBasePosFormat1 { |
| /// Construct a new `MarkBasePosFormat1` |
| pub fn new( |
| mark_coverage: CoverageTable, |
| base_coverage: CoverageTable, |
| mark_array: MarkArray, |
| base_array: BaseArray, |
| ) -> Self { |
| Self { |
| mark_coverage: mark_coverage.into(), |
| base_coverage: base_coverage.into(), |
| mark_array: mark_array.into(), |
| base_array: base_array.into(), |
| } |
| } |
| } |
| |
| impl FontWrite for MarkBasePosFormat1 { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (1 as u16).write_into(writer); |
| self.mark_coverage.write_into(writer); |
| self.base_coverage.write_into(writer); |
| (self.compute_mark_class_count() as u16).write_into(writer); |
| self.mark_array.write_into(writer); |
| self.base_array.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("MarkBasePosFormat1") |
| } |
| } |
| |
| impl Validate for MarkBasePosFormat1 { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("MarkBasePosFormat1", |ctx| { |
| ctx.in_field("mark_coverage", |ctx| { |
| self.mark_coverage.validate_impl(ctx); |
| }); |
| ctx.in_field("base_coverage", |ctx| { |
| self.base_coverage.validate_impl(ctx); |
| }); |
| ctx.in_field("mark_array", |ctx| { |
| self.mark_array.validate_impl(ctx); |
| }); |
| ctx.in_field("base_array", |ctx| { |
| self.base_array.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::MarkBasePosFormat1<'a>> for MarkBasePosFormat1 { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkBasePosFormat1<'a>, _: FontData) -> Self { |
| MarkBasePosFormat1 { |
| mark_coverage: obj.mark_coverage().to_owned_table(), |
| base_coverage: obj.base_coverage().to_owned_table(), |
| mark_array: obj.mark_array().to_owned_table(), |
| base_array: obj.base_array().to_owned_table(), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::MarkBasePosFormat1<'a>> for MarkBasePosFormat1 {} |
| |
| impl<'a> FontRead<'a> for MarkBasePosFormat1 { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| <read_fonts::tables::gpos::MarkBasePosFormat1 as FontRead>::read(data) |
| .map(|x| x.to_owned_table()) |
| } |
| } |
| |
| /// Part of [MarkBasePosFormat1] |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct BaseArray { |
| /// Array of BaseRecords, in order of baseCoverage Index. |
| pub base_records: Vec<BaseRecord>, |
| } |
| |
| impl BaseArray { |
| /// Construct a new `BaseArray` |
| pub fn new(base_records: Vec<BaseRecord>) -> Self { |
| Self { base_records } |
| } |
| } |
| |
| impl FontWrite for BaseArray { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (u16::try_from(array_len(&self.base_records)).unwrap()).write_into(writer); |
| self.base_records.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("BaseArray") |
| } |
| } |
| |
| impl Validate for BaseArray { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("BaseArray", |ctx| { |
| ctx.in_field("base_records", |ctx| { |
| if self.base_records.len() > (u16::MAX as usize) { |
| ctx.report("array exceeds max length"); |
| } |
| self.base_records.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::BaseArray<'a>> for BaseArray { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::BaseArray<'a>, _: FontData) -> Self { |
| let offset_data = obj.offset_data(); |
| BaseArray { |
| base_records: obj |
| .base_records() |
| .iter() |
| .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok()) |
| .collect(), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::BaseArray<'a>> for BaseArray {} |
| |
| /// Part of [BaseArray] |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct BaseRecord { |
| /// Array of offsets (one per mark class) to Anchor tables. Offsets |
| /// are from beginning of BaseArray table, ordered by class |
| /// (offsets may be NULL). |
| pub base_anchors: Vec<NullableOffsetMarker<AnchorTable>>, |
| } |
| |
| impl BaseRecord { |
| /// Construct a new `BaseRecord` |
| pub fn new(base_anchors: Vec<Option<AnchorTable>>) -> Self { |
| Self { |
| base_anchors: base_anchors.into_iter().map(Into::into).collect(), |
| } |
| } |
| } |
| |
| impl FontWrite for BaseRecord { |
| fn write_into(&self, writer: &mut TableWriter) { |
| self.base_anchors.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("BaseRecord") |
| } |
| } |
| |
| impl Validate for BaseRecord { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("BaseRecord", |ctx| { |
| ctx.in_field("base_anchors", |ctx| { |
| if self.base_anchors.len() > (u16::MAX as usize) { |
| ctx.report("array exceeds max length"); |
| } |
| self.base_anchors.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl FromObjRef<read_fonts::tables::gpos::BaseRecord<'_>> for BaseRecord { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::BaseRecord, offset_data: FontData) -> Self { |
| BaseRecord { |
| base_anchors: obj.base_anchors(offset_data).to_owned_table(), |
| } |
| } |
| } |
| |
| /// [Mark-to-Ligature Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#mark-to-ligature-attachment-positioning-format-1-mark-to-ligature-attachment): Mark-to-Ligature Attachment |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct MarkLigPosFormat1 { |
| /// Offset to markCoverage table, from beginning of MarkLigPos |
| /// subtable. |
| pub mark_coverage: OffsetMarker<CoverageTable>, |
| /// Offset to ligatureCoverage table, from beginning of MarkLigPos |
| /// subtable. |
| pub ligature_coverage: OffsetMarker<CoverageTable>, |
| /// Offset to MarkArray table, from beginning of MarkLigPos |
| /// subtable. |
| pub mark_array: OffsetMarker<MarkArray>, |
| /// Offset to LigatureArray table, from beginning of MarkLigPos |
| /// subtable. |
| pub ligature_array: OffsetMarker<LigatureArray>, |
| } |
| |
| impl MarkLigPosFormat1 { |
| /// Construct a new `MarkLigPosFormat1` |
| pub fn new( |
| mark_coverage: CoverageTable, |
| ligature_coverage: CoverageTable, |
| mark_array: MarkArray, |
| ligature_array: LigatureArray, |
| ) -> Self { |
| Self { |
| mark_coverage: mark_coverage.into(), |
| ligature_coverage: ligature_coverage.into(), |
| mark_array: mark_array.into(), |
| ligature_array: ligature_array.into(), |
| } |
| } |
| } |
| |
| impl FontWrite for MarkLigPosFormat1 { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (1 as u16).write_into(writer); |
| self.mark_coverage.write_into(writer); |
| self.ligature_coverage.write_into(writer); |
| (self.compute_mark_class_count() as u16).write_into(writer); |
| self.mark_array.write_into(writer); |
| self.ligature_array.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("MarkLigPosFormat1") |
| } |
| } |
| |
| impl Validate for MarkLigPosFormat1 { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("MarkLigPosFormat1", |ctx| { |
| ctx.in_field("mark_coverage", |ctx| { |
| self.mark_coverage.validate_impl(ctx); |
| }); |
| ctx.in_field("ligature_coverage", |ctx| { |
| self.ligature_coverage.validate_impl(ctx); |
| }); |
| ctx.in_field("mark_array", |ctx| { |
| self.mark_array.validate_impl(ctx); |
| }); |
| ctx.in_field("ligature_array", |ctx| { |
| self.ligature_array.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::MarkLigPosFormat1<'a>> for MarkLigPosFormat1 { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkLigPosFormat1<'a>, _: FontData) -> Self { |
| MarkLigPosFormat1 { |
| mark_coverage: obj.mark_coverage().to_owned_table(), |
| ligature_coverage: obj.ligature_coverage().to_owned_table(), |
| mark_array: obj.mark_array().to_owned_table(), |
| ligature_array: obj.ligature_array().to_owned_table(), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::MarkLigPosFormat1<'a>> for MarkLigPosFormat1 {} |
| |
| impl<'a> FontRead<'a> for MarkLigPosFormat1 { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| <read_fonts::tables::gpos::MarkLigPosFormat1 as FontRead>::read(data) |
| .map(|x| x.to_owned_table()) |
| } |
| } |
| |
| /// Part of [MarkLigPosFormat1] |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct LigatureArray { |
| /// Array of offsets to LigatureAttach tables. Offsets are from |
| /// beginning of LigatureArray table, ordered by ligatureCoverage |
| /// index. |
| pub ligature_attaches: Vec<OffsetMarker<LigatureAttach>>, |
| } |
| |
| impl LigatureArray { |
| /// Construct a new `LigatureArray` |
| pub fn new(ligature_attaches: Vec<LigatureAttach>) -> Self { |
| Self { |
| ligature_attaches: ligature_attaches.into_iter().map(Into::into).collect(), |
| } |
| } |
| } |
| |
| impl FontWrite for LigatureArray { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (u16::try_from(array_len(&self.ligature_attaches)).unwrap()).write_into(writer); |
| self.ligature_attaches.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("LigatureArray") |
| } |
| } |
| |
| impl Validate for LigatureArray { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("LigatureArray", |ctx| { |
| ctx.in_field("ligature_attaches", |ctx| { |
| if self.ligature_attaches.len() > (u16::MAX as usize) { |
| ctx.report("array exceeds max length"); |
| } |
| self.ligature_attaches.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::LigatureArray<'a>> for LigatureArray { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::LigatureArray<'a>, _: FontData) -> Self { |
| LigatureArray { |
| ligature_attaches: obj.ligature_attaches().to_owned_table(), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::LigatureArray<'a>> for LigatureArray {} |
| |
| /// Part of [MarkLigPosFormat1] |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct LigatureAttach { |
| /// Array of Component records, ordered in writing direction. |
| pub component_records: Vec<ComponentRecord>, |
| } |
| |
| impl LigatureAttach { |
| /// Construct a new `LigatureAttach` |
| pub fn new(component_records: Vec<ComponentRecord>) -> Self { |
| Self { component_records } |
| } |
| } |
| |
| impl FontWrite for LigatureAttach { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (u16::try_from(array_len(&self.component_records)).unwrap()).write_into(writer); |
| self.component_records.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("LigatureAttach") |
| } |
| } |
| |
| impl Validate for LigatureAttach { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("LigatureAttach", |ctx| { |
| ctx.in_field("component_records", |ctx| { |
| if self.component_records.len() > (u16::MAX as usize) { |
| ctx.report("array exceeds max length"); |
| } |
| self.component_records.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::LigatureAttach<'a>> for LigatureAttach { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::LigatureAttach<'a>, _: FontData) -> Self { |
| let offset_data = obj.offset_data(); |
| LigatureAttach { |
| component_records: obj |
| .component_records() |
| .iter() |
| .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok()) |
| .collect(), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::LigatureAttach<'a>> for LigatureAttach {} |
| |
| /// Part of [MarkLigPosFormat1] |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct ComponentRecord { |
| /// Array of offsets (one per class) to Anchor tables. Offsets are |
| /// from beginning of LigatureAttach table, ordered by class |
| /// (offsets may be NULL). |
| pub ligature_anchors: Vec<NullableOffsetMarker<AnchorTable>>, |
| } |
| |
| impl ComponentRecord { |
| /// Construct a new `ComponentRecord` |
| pub fn new(ligature_anchors: Vec<Option<AnchorTable>>) -> Self { |
| Self { |
| ligature_anchors: ligature_anchors.into_iter().map(Into::into).collect(), |
| } |
| } |
| } |
| |
| impl FontWrite for ComponentRecord { |
| fn write_into(&self, writer: &mut TableWriter) { |
| self.ligature_anchors.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("ComponentRecord") |
| } |
| } |
| |
| impl Validate for ComponentRecord { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("ComponentRecord", |ctx| { |
| ctx.in_field("ligature_anchors", |ctx| { |
| if self.ligature_anchors.len() > (u16::MAX as usize) { |
| ctx.report("array exceeds max length"); |
| } |
| self.ligature_anchors.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl FromObjRef<read_fonts::tables::gpos::ComponentRecord<'_>> for ComponentRecord { |
| fn from_obj_ref( |
| obj: &read_fonts::tables::gpos::ComponentRecord, |
| offset_data: FontData, |
| ) -> Self { |
| ComponentRecord { |
| ligature_anchors: obj.ligature_anchors(offset_data).to_owned_table(), |
| } |
| } |
| } |
| |
| /// [Mark-to-Mark Attachment Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#mark-to-mark-attachment-positioning-format-1-mark-to-mark-attachment): Mark-to-Mark Attachment |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct MarkMarkPosFormat1 { |
| /// Offset to Combining Mark Coverage table, from beginning of |
| /// MarkMarkPos subtable. |
| pub mark1_coverage: OffsetMarker<CoverageTable>, |
| /// Offset to Base Mark Coverage table, from beginning of |
| /// MarkMarkPos subtable. |
| pub mark2_coverage: OffsetMarker<CoverageTable>, |
| /// Offset to MarkArray table for mark1, from beginning of |
| /// MarkMarkPos subtable. |
| pub mark1_array: OffsetMarker<MarkArray>, |
| /// Offset to Mark2Array table for mark2, from beginning of |
| /// MarkMarkPos subtable. |
| pub mark2_array: OffsetMarker<Mark2Array>, |
| } |
| |
| impl MarkMarkPosFormat1 { |
| /// Construct a new `MarkMarkPosFormat1` |
| pub fn new( |
| mark1_coverage: CoverageTable, |
| mark2_coverage: CoverageTable, |
| mark1_array: MarkArray, |
| mark2_array: Mark2Array, |
| ) -> Self { |
| Self { |
| mark1_coverage: mark1_coverage.into(), |
| mark2_coverage: mark2_coverage.into(), |
| mark1_array: mark1_array.into(), |
| mark2_array: mark2_array.into(), |
| } |
| } |
| } |
| |
| impl FontWrite for MarkMarkPosFormat1 { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (1 as u16).write_into(writer); |
| self.mark1_coverage.write_into(writer); |
| self.mark2_coverage.write_into(writer); |
| (self.compute_mark_class_count() as u16).write_into(writer); |
| self.mark1_array.write_into(writer); |
| self.mark2_array.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("MarkMarkPosFormat1") |
| } |
| } |
| |
| impl Validate for MarkMarkPosFormat1 { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("MarkMarkPosFormat1", |ctx| { |
| ctx.in_field("mark1_coverage", |ctx| { |
| self.mark1_coverage.validate_impl(ctx); |
| }); |
| ctx.in_field("mark2_coverage", |ctx| { |
| self.mark2_coverage.validate_impl(ctx); |
| }); |
| ctx.in_field("mark1_array", |ctx| { |
| self.mark1_array.validate_impl(ctx); |
| }); |
| ctx.in_field("mark2_array", |ctx| { |
| self.mark2_array.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::MarkMarkPosFormat1<'a>> for MarkMarkPosFormat1 { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkMarkPosFormat1<'a>, _: FontData) -> Self { |
| MarkMarkPosFormat1 { |
| mark1_coverage: obj.mark1_coverage().to_owned_table(), |
| mark2_coverage: obj.mark2_coverage().to_owned_table(), |
| mark1_array: obj.mark1_array().to_owned_table(), |
| mark2_array: obj.mark2_array().to_owned_table(), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::MarkMarkPosFormat1<'a>> for MarkMarkPosFormat1 {} |
| |
| impl<'a> FontRead<'a> for MarkMarkPosFormat1 { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| <read_fonts::tables::gpos::MarkMarkPosFormat1 as FontRead>::read(data) |
| .map(|x| x.to_owned_table()) |
| } |
| } |
| |
| /// Part of [MarkMarkPosFormat1]Class2Record |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct Mark2Array { |
| /// Array of Mark2Records, in Coverage order. |
| pub mark2_records: Vec<Mark2Record>, |
| } |
| |
| impl Mark2Array { |
| /// Construct a new `Mark2Array` |
| pub fn new(mark2_records: Vec<Mark2Record>) -> Self { |
| Self { mark2_records } |
| } |
| } |
| |
| impl FontWrite for Mark2Array { |
| #[allow(clippy::unnecessary_cast)] |
| fn write_into(&self, writer: &mut TableWriter) { |
| (u16::try_from(array_len(&self.mark2_records)).unwrap()).write_into(writer); |
| self.mark2_records.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("Mark2Array") |
| } |
| } |
| |
| impl Validate for Mark2Array { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("Mark2Array", |ctx| { |
| ctx.in_field("mark2_records", |ctx| { |
| if self.mark2_records.len() > (u16::MAX as usize) { |
| ctx.report("array exceeds max length"); |
| } |
| self.mark2_records.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl<'a> FromObjRef<read_fonts::tables::gpos::Mark2Array<'a>> for Mark2Array { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::Mark2Array<'a>, _: FontData) -> Self { |
| let offset_data = obj.offset_data(); |
| Mark2Array { |
| mark2_records: obj |
| .mark2_records() |
| .iter() |
| .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok()) |
| .collect(), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FromTableRef<read_fonts::tables::gpos::Mark2Array<'a>> for Mark2Array {} |
| |
| /// Part of [MarkMarkPosFormat1] |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct Mark2Record { |
| /// Array of offsets (one per class) to Anchor tables. Offsets are |
| /// from beginning of Mark2Array table, in class order (offsets may |
| /// be NULL). |
| pub mark2_anchors: Vec<NullableOffsetMarker<AnchorTable>>, |
| } |
| |
| impl Mark2Record { |
| /// Construct a new `Mark2Record` |
| pub fn new(mark2_anchors: Vec<Option<AnchorTable>>) -> Self { |
| Self { |
| mark2_anchors: mark2_anchors.into_iter().map(Into::into).collect(), |
| } |
| } |
| } |
| |
| impl FontWrite for Mark2Record { |
| fn write_into(&self, writer: &mut TableWriter) { |
| self.mark2_anchors.write_into(writer); |
| } |
| fn table_type(&self) -> TableType { |
| TableType::Named("Mark2Record") |
| } |
| } |
| |
| impl Validate for Mark2Record { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("Mark2Record", |ctx| { |
| ctx.in_field("mark2_anchors", |ctx| { |
| if self.mark2_anchors.len() > (u16::MAX as usize) { |
| ctx.report("array exceeds max length"); |
| } |
| self.mark2_anchors.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl FromObjRef<read_fonts::tables::gpos::Mark2Record<'_>> for Mark2Record { |
| fn from_obj_ref(obj: &read_fonts::tables::gpos::Mark2Record, offset_data: FontData) -> Self { |
| Mark2Record { |
| mark2_anchors: obj.mark2_anchors(offset_data).to_owned_table(), |
| } |
| } |
| } |
| |
| /// [Extension Positioning Subtable Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#extension-positioning-subtable-format-1) |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct ExtensionPosFormat1<T> { |
| /// Lookup type of subtable referenced by extensionOffset (i.e. the |
| /// extension subtable). |
| pub extension_lookup_type: u16, |
| /// Offset to the extension subtable, of lookup type |
| /// extensionLookupType, relative to the start of the |
| /// ExtensionPosFormat1 subtable. |
| pub extension: OffsetMarker<T, WIDTH_32>, |
| } |
| |
| impl<T: Default> ExtensionPosFormat1<T> { |
| /// Construct a new `ExtensionPosFormat1` |
| pub fn new(extension_lookup_type: u16, extension: T) -> Self { |
| Self { |
| extension_lookup_type, |
| extension: extension.into(), |
| } |
| } |
| } |
| |
| impl<T: Validate> Validate for ExtensionPosFormat1<T> { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| ctx.in_table("ExtensionPosFormat1", |ctx| { |
| ctx.in_field("extension", |ctx| { |
| self.extension.validate_impl(ctx); |
| }); |
| }) |
| } |
| } |
| |
| impl<'a, T, U> FromObjRef<read_fonts::tables::gpos::ExtensionPosFormat1<'a, U>> |
| for ExtensionPosFormat1<T> |
| where |
| U: FontRead<'a>, |
| T: FromTableRef<U> + Default + 'static, |
| { |
| fn from_obj_ref( |
| obj: &read_fonts::tables::gpos::ExtensionPosFormat1<'a, U>, |
| _: FontData, |
| ) -> Self { |
| ExtensionPosFormat1 { |
| extension_lookup_type: obj.extension_lookup_type(), |
| extension: obj.extension().to_owned_table(), |
| } |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a, T, U> FromTableRef<read_fonts::tables::gpos::ExtensionPosFormat1<'a, U>> |
| for ExtensionPosFormat1<T> |
| where |
| U: FontRead<'a>, |
| T: FromTableRef<U> + Default + 'static, |
| { |
| } |
| |
| /// A [GPOS Extension Positioning](https://learn.microsoft.com/en-us/typography/opentype/spec/gpos#lookuptype-9-extension-positioning) subtable |
| #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub enum ExtensionSubtable { |
| Single(ExtensionPosFormat1<SinglePos>), |
| Pair(ExtensionPosFormat1<PairPos>), |
| Cursive(ExtensionPosFormat1<CursivePosFormat1>), |
| MarkToBase(ExtensionPosFormat1<MarkBasePosFormat1>), |
| MarkToLig(ExtensionPosFormat1<MarkLigPosFormat1>), |
| MarkToMark(ExtensionPosFormat1<MarkMarkPosFormat1>), |
| Contextual(ExtensionPosFormat1<PositionSequenceContext>), |
| ChainContextual(ExtensionPosFormat1<PositionChainContext>), |
| } |
| |
| impl Default for ExtensionSubtable { |
| fn default() -> Self { |
| Self::Single(Default::default()) |
| } |
| } |
| |
| impl FontWrite for ExtensionSubtable { |
| fn write_into(&self, writer: &mut TableWriter) { |
| match self { |
| Self::Single(table) => table.write_into(writer), |
| Self::Pair(table) => table.write_into(writer), |
| Self::Cursive(table) => table.write_into(writer), |
| Self::MarkToBase(table) => table.write_into(writer), |
| Self::MarkToLig(table) => table.write_into(writer), |
| Self::MarkToMark(table) => table.write_into(writer), |
| Self::Contextual(table) => table.write_into(writer), |
| Self::ChainContextual(table) => table.write_into(writer), |
| } |
| } |
| fn table_type(&self) -> TableType { |
| match self { |
| Self::Single(table) => table.table_type(), |
| Self::Pair(table) => table.table_type(), |
| Self::Cursive(table) => table.table_type(), |
| Self::MarkToBase(table) => table.table_type(), |
| Self::MarkToLig(table) => table.table_type(), |
| Self::MarkToMark(table) => table.table_type(), |
| Self::Contextual(table) => table.table_type(), |
| Self::ChainContextual(table) => table.table_type(), |
| } |
| } |
| } |
| |
| impl Validate for ExtensionSubtable { |
| fn validate_impl(&self, ctx: &mut ValidationCtx) { |
| match self { |
| Self::Single(table) => table.validate_impl(ctx), |
| Self::Pair(table) => table.validate_impl(ctx), |
| Self::Cursive(table) => table.validate_impl(ctx), |
| Self::MarkToBase(table) => table.validate_impl(ctx), |
| Self::MarkToLig(table) => table.validate_impl(ctx), |
| Self::MarkToMark(table) => table.validate_impl(ctx), |
| Self::Contextual(table) => table.validate_impl(ctx), |
| Self::ChainContextual(table) => table.validate_impl(ctx), |
| } |
| } |
| } |
| |
| impl FromObjRef<read_fonts::tables::gpos::ExtensionSubtable<'_>> for ExtensionSubtable { |
| fn from_obj_ref( |
| from: &read_fonts::tables::gpos::ExtensionSubtable<'_>, |
| data: FontData, |
| ) -> Self { |
| match from { |
| read_fonts::tables::gpos::ExtensionSubtable::Single(table) => { |
| Self::Single(table.to_owned_obj(data)) |
| } |
| read_fonts::tables::gpos::ExtensionSubtable::Pair(table) => { |
| Self::Pair(table.to_owned_obj(data)) |
| } |
| read_fonts::tables::gpos::ExtensionSubtable::Cursive(table) => { |
| Self::Cursive(table.to_owned_obj(data)) |
| } |
| read_fonts::tables::gpos::ExtensionSubtable::MarkToBase(table) => { |
| Self::MarkToBase(table.to_owned_obj(data)) |
| } |
| read_fonts::tables::gpos::ExtensionSubtable::MarkToLig(table) => { |
| Self::MarkToLig(table.to_owned_obj(data)) |
| } |
| read_fonts::tables::gpos::ExtensionSubtable::MarkToMark(table) => { |
| Self::MarkToMark(table.to_owned_obj(data)) |
| } |
| read_fonts::tables::gpos::ExtensionSubtable::Contextual(table) => { |
| Self::Contextual(table.to_owned_obj(data)) |
| } |
| read_fonts::tables::gpos::ExtensionSubtable::ChainContextual(table) => { |
| Self::ChainContextual(table.to_owned_obj(data)) |
| } |
| } |
| } |
| } |
| |
| impl FromTableRef<read_fonts::tables::gpos::ExtensionSubtable<'_>> for ExtensionSubtable {} |
| |
| impl From<ExtensionPosFormat1<SinglePos>> for ExtensionSubtable { |
| fn from(src: ExtensionPosFormat1<SinglePos>) -> ExtensionSubtable { |
| ExtensionSubtable::Single(src) |
| } |
| } |
| |
| impl From<ExtensionPosFormat1<PairPos>> for ExtensionSubtable { |
| fn from(src: ExtensionPosFormat1<PairPos>) -> ExtensionSubtable { |
| ExtensionSubtable::Pair(src) |
| } |
| } |
| |
| impl From<ExtensionPosFormat1<CursivePosFormat1>> for ExtensionSubtable { |
| fn from(src: ExtensionPosFormat1<CursivePosFormat1>) -> ExtensionSubtable { |
| ExtensionSubtable::Cursive(src) |
| } |
| } |
| |
| impl From<ExtensionPosFormat1<MarkBasePosFormat1>> for ExtensionSubtable { |
| fn from(src: ExtensionPosFormat1<MarkBasePosFormat1>) -> ExtensionSubtable { |
| ExtensionSubtable::MarkToBase(src) |
| } |
| } |
| |
| impl From<ExtensionPosFormat1<MarkLigPosFormat1>> for ExtensionSubtable { |
| fn from(src: ExtensionPosFormat1<MarkLigPosFormat1>) -> ExtensionSubtable { |
| ExtensionSubtable::MarkToLig(src) |
| } |
| } |
| |
| impl From<ExtensionPosFormat1<MarkMarkPosFormat1>> for ExtensionSubtable { |
| fn from(src: ExtensionPosFormat1<MarkMarkPosFormat1>) -> ExtensionSubtable { |
| ExtensionSubtable::MarkToMark(src) |
| } |
| } |
| |
| impl From<ExtensionPosFormat1<PositionSequenceContext>> for ExtensionSubtable { |
| fn from(src: ExtensionPosFormat1<PositionSequenceContext>) -> ExtensionSubtable { |
| ExtensionSubtable::Contextual(src) |
| } |
| } |
| |
| impl From<ExtensionPosFormat1<PositionChainContext>> for ExtensionSubtable { |
| fn from(src: ExtensionPosFormat1<PositionChainContext>) -> ExtensionSubtable { |
| ExtensionSubtable::ChainContextual(src) |
| } |
| } |