#[allow(unused_imports)]
use crate::codegen_prelude::*;
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct GsubMarker {
feature_variations_offset_byte_start: Option<usize>,
}
impl GsubMarker {
pub fn version_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + MajorMinor::RAW_BYTE_LEN
}
pub fn script_list_offset_byte_range(&self) -> Range<usize> {
let start = self.version_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn feature_list_offset_byte_range(&self) -> Range<usize> {
let start = self.script_list_offset_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn lookup_list_offset_byte_range(&self) -> Range<usize> {
let start = self.feature_list_offset_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn feature_variations_offset_byte_range(&self) -> Option<Range<usize>> {
let start = self.feature_variations_offset_byte_start?;
Some(start..start + Offset32::RAW_BYTE_LEN)
}
}
impl TopLevelTable for Gsub<'_> {
const TAG: Tag = Tag::new(b"GSUB");
}
impl<'a> FontRead<'a> for Gsub<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let version: MajorMinor = cursor.read()?;
cursor.advance::<Offset16>();
cursor.advance::<Offset16>();
cursor.advance::<Offset16>();
let feature_variations_offset_byte_start = version
.compatible((1u16, 1u16))
.then(|| cursor.position())
.transpose()?;
version
.compatible((1u16, 1u16))
.then(|| cursor.advance::<Offset32>());
cursor.finish(GsubMarker {
feature_variations_offset_byte_start,
})
}
}
pub type Gsub<'a> = TableRef<'a, GsubMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> Gsub<'a> {
pub fn version(&self) -> MajorMinor {
let range = self.shape.version_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn script_list_offset(&self) -> Offset16 {
let range = self.shape.script_list_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn script_list(&self) -> Result<ScriptList<'a>, ReadError> {
let data = self.data;
self.script_list_offset().resolve(data)
}
pub fn feature_list_offset(&self) -> Offset16 {
let range = self.shape.feature_list_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn feature_list(&self) -> Result<FeatureList<'a>, ReadError> {
let data = self.data;
self.feature_list_offset().resolve(data)
}
pub fn lookup_list_offset(&self) -> Offset16 {
let range = self.shape.lookup_list_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn lookup_list(&self) -> Result<SubstitutionLookupList<'a>, ReadError> {
let data = self.data;
self.lookup_list_offset().resolve(data)
}
pub fn feature_variations_offset(&self) -> Option<Nullable<Offset32>> {
let range = self.shape.feature_variations_offset_byte_range()?;
Some(self.data.read_at(range.start).unwrap())
}
pub fn feature_variations(&self) -> Option<Result<FeatureVariations<'a>, ReadError>> {
let data = self.data;
self.feature_variations_offset().map(|x| x.resolve(data))?
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Gsub<'a> {
fn type_name(&self) -> &str {
"Gsub"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
let version = self.version();
match idx {
0usize => Some(Field::new("version", self.version())),
1usize => Some(Field::new(
"script_list_offset",
FieldType::offset(self.script_list_offset(), self.script_list()),
)),
2usize => Some(Field::new(
"feature_list_offset",
FieldType::offset(self.feature_list_offset(), self.feature_list()),
)),
3usize => Some(Field::new(
"lookup_list_offset",
FieldType::offset(self.lookup_list_offset(), self.lookup_list()),
)),
4usize if version.compatible((1u16, 1u16)) => Some(Field::new(
"feature_variations_offset",
FieldType::offset(
self.feature_variations_offset().unwrap(),
self.feature_variations(),
),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for Gsub<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
pub enum SubstitutionLookup<'a> {
Single(Lookup<'a, SingleSubst<'a>>),
Multiple(Lookup<'a, MultipleSubstFormat1<'a>>),
Alternate(Lookup<'a, AlternateSubstFormat1<'a>>),
Ligature(Lookup<'a, LigatureSubstFormat1<'a>>),
Contextual(Lookup<'a, SubstitutionSequenceContext<'a>>),
ChainContextual(Lookup<'a, SubstitutionChainContext<'a>>),
Extension(Lookup<'a, ExtensionSubtable<'a>>),
Reverse(Lookup<'a, ReverseChainSingleSubstFormat1<'a>>),
}
impl<'a> FontRead<'a> for SubstitutionLookup<'a> {
fn read(bytes: FontData<'a>) -> Result<Self, ReadError> {
let untyped = Lookup::read(bytes)?;
match untyped.lookup_type() {
1 => Ok(SubstitutionLookup::Single(untyped.into_concrete())),
2 => Ok(SubstitutionLookup::Multiple(untyped.into_concrete())),
3 => Ok(SubstitutionLookup::Alternate(untyped.into_concrete())),
4 => Ok(SubstitutionLookup::Ligature(untyped.into_concrete())),
5 => Ok(SubstitutionLookup::Contextual(untyped.into_concrete())),
6 => Ok(SubstitutionLookup::ChainContextual(untyped.into_concrete())),
7 => Ok(SubstitutionLookup::Extension(untyped.into_concrete())),
8 => Ok(SubstitutionLookup::Reverse(untyped.into_concrete())),
other => Err(ReadError::InvalidFormat(other.into())),
}
}
}
impl<'a> SubstitutionLookup<'a> {
#[allow(dead_code)]
pub(crate) fn of_unit_type(&self) -> Lookup<'a, ()> {
match self {
SubstitutionLookup::Single(inner) => inner.of_unit_type(),
SubstitutionLookup::Multiple(inner) => inner.of_unit_type(),
SubstitutionLookup::Alternate(inner) => inner.of_unit_type(),
SubstitutionLookup::Ligature(inner) => inner.of_unit_type(),
SubstitutionLookup::Contextual(inner) => inner.of_unit_type(),
SubstitutionLookup::ChainContextual(inner) => inner.of_unit_type(),
SubstitutionLookup::Extension(inner) => inner.of_unit_type(),
SubstitutionLookup::Reverse(inner) => inner.of_unit_type(),
}
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SubstitutionLookup<'a> {
fn dyn_inner(&self) -> &(dyn SomeTable<'a> + 'a) {
match self {
SubstitutionLookup::Single(table) => table,
SubstitutionLookup::Multiple(table) => table,
SubstitutionLookup::Alternate(table) => table,
SubstitutionLookup::Ligature(table) => table,
SubstitutionLookup::Contextual(table) => table,
SubstitutionLookup::ChainContextual(table) => table,
SubstitutionLookup::Extension(table) => table,
SubstitutionLookup::Reverse(table) => table,
}
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for SubstitutionLookup<'a> {
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
self.dyn_inner().get_field(idx)
}
fn type_name(&self) -> &str {
self.dyn_inner().type_name()
}
}
#[cfg(feature = "experimental_traverse")]
impl std::fmt::Debug for SubstitutionLookup<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.dyn_inner().fmt(f)
}
}
#[derive(Clone)]
pub enum SingleSubst<'a> {
Format1(SingleSubstFormat1<'a>),
Format2(SingleSubstFormat2<'a>),
}
impl<'a> SingleSubst<'a> {
pub fn offset_data(&self) -> FontData<'a> {
match self {
Self::Format1(item) => item.offset_data(),
Self::Format2(item) => item.offset_data(),
}
}
pub fn subst_format(&self) -> u16 {
match self {
Self::Format1(item) => item.subst_format(),
Self::Format2(item) => item.subst_format(),
}
}
pub fn coverage_offset(&self) -> Offset16 {
match self {
Self::Format1(item) => item.coverage_offset(),
Self::Format2(item) => item.coverage_offset(),
}
}
}
impl<'a> FontRead<'a> for SingleSubst<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let format: u16 = data.read_at(0usize)?;
match format {
SingleSubstFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
SingleSubstFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
other => Err(ReadError::InvalidFormat(other.into())),
}
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SingleSubst<'a> {
fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
match self {
Self::Format1(table) => table,
Self::Format2(table) => table,
}
}
}
#[cfg(feature = "experimental_traverse")]
impl std::fmt::Debug for SingleSubst<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.dyn_inner().fmt(f)
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for SingleSubst<'a> {
fn type_name(&self) -> &str {
self.dyn_inner().type_name()
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
self.dyn_inner().get_field(idx)
}
}
impl Format<u16> for SingleSubstFormat1Marker {
const FORMAT: u16 = 1;
}
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct SingleSubstFormat1Marker {}
impl SingleSubstFormat1Marker {
pub fn subst_format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn coverage_offset_byte_range(&self) -> Range<usize> {
let start = self.subst_format_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn delta_glyph_id_byte_range(&self) -> Range<usize> {
let start = self.coverage_offset_byte_range().end;
start..start + i16::RAW_BYTE_LEN
}
}
impl<'a> FontRead<'a> for SingleSubstFormat1<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<Offset16>();
cursor.advance::<i16>();
cursor.finish(SingleSubstFormat1Marker {})
}
}
pub type SingleSubstFormat1<'a> = TableRef<'a, SingleSubstFormat1Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> SingleSubstFormat1<'a> {
pub fn subst_format(&self) -> u16 {
let range = self.shape.subst_format_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn coverage_offset(&self) -> Offset16 {
let range = self.shape.coverage_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
let data = self.data;
self.coverage_offset().resolve(data)
}
pub fn delta_glyph_id(&self) -> i16 {
let range = self.shape.delta_glyph_id_byte_range();
self.data.read_at(range.start).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for SingleSubstFormat1<'a> {
fn type_name(&self) -> &str {
"SingleSubstFormat1"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("subst_format", self.subst_format())),
1usize => Some(Field::new(
"coverage_offset",
FieldType::offset(self.coverage_offset(), self.coverage()),
)),
2usize => Some(Field::new("delta_glyph_id", self.delta_glyph_id())),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for SingleSubstFormat1<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for SingleSubstFormat2Marker {
const FORMAT: u16 = 2;
}
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct SingleSubstFormat2Marker {
substitute_glyph_ids_byte_len: usize,
}
impl SingleSubstFormat2Marker {
pub fn subst_format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn coverage_offset_byte_range(&self) -> Range<usize> {
let start = self.subst_format_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn glyph_count_byte_range(&self) -> Range<usize> {
let start = self.coverage_offset_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn substitute_glyph_ids_byte_range(&self) -> Range<usize> {
let start = self.glyph_count_byte_range().end;
start..start + self.substitute_glyph_ids_byte_len
}
}
impl<'a> FontRead<'a> for SingleSubstFormat2<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<Offset16>();
let glyph_count: u16 = cursor.read()?;
let substitute_glyph_ids_byte_len = (glyph_count as usize)
.checked_mul(GlyphId16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(substitute_glyph_ids_byte_len);
cursor.finish(SingleSubstFormat2Marker {
substitute_glyph_ids_byte_len,
})
}
}
pub type SingleSubstFormat2<'a> = TableRef<'a, SingleSubstFormat2Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> SingleSubstFormat2<'a> {
pub fn subst_format(&self) -> u16 {
let range = self.shape.subst_format_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn coverage_offset(&self) -> Offset16 {
let range = self.shape.coverage_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
let data = self.data;
self.coverage_offset().resolve(data)
}
pub fn glyph_count(&self) -> u16 {
let range = self.shape.glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn substitute_glyph_ids(&self) -> &'a [BigEndian<GlyphId16>] {
let range = self.shape.substitute_glyph_ids_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for SingleSubstFormat2<'a> {
fn type_name(&self) -> &str {
"SingleSubstFormat2"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("subst_format", self.subst_format())),
1usize => Some(Field::new(
"coverage_offset",
FieldType::offset(self.coverage_offset(), self.coverage()),
)),
2usize => Some(Field::new("glyph_count", self.glyph_count())),
3usize => Some(Field::new(
"substitute_glyph_ids",
self.substitute_glyph_ids(),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for SingleSubstFormat2<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for MultipleSubstFormat1Marker {
const FORMAT: u16 = 1;
}
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct MultipleSubstFormat1Marker {
sequence_offsets_byte_len: usize,
}
impl MultipleSubstFormat1Marker {
pub fn subst_format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn coverage_offset_byte_range(&self) -> Range<usize> {
let start = self.subst_format_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn sequence_count_byte_range(&self) -> Range<usize> {
let start = self.coverage_offset_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn sequence_offsets_byte_range(&self) -> Range<usize> {
let start = self.sequence_count_byte_range().end;
start..start + self.sequence_offsets_byte_len
}
}
impl<'a> FontRead<'a> for MultipleSubstFormat1<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<Offset16>();
let sequence_count: u16 = cursor.read()?;
let sequence_offsets_byte_len = (sequence_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(sequence_offsets_byte_len);
cursor.finish(MultipleSubstFormat1Marker {
sequence_offsets_byte_len,
})
}
}
pub type MultipleSubstFormat1<'a> = TableRef<'a, MultipleSubstFormat1Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> MultipleSubstFormat1<'a> {
pub fn subst_format(&self) -> u16 {
let range = self.shape.subst_format_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn coverage_offset(&self) -> Offset16 {
let range = self.shape.coverage_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
let data = self.data;
self.coverage_offset().resolve(data)
}
pub fn sequence_count(&self) -> u16 {
let range = self.shape.sequence_count_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn sequence_offsets(&self) -> &'a [BigEndian<Offset16>] {
let range = self.shape.sequence_offsets_byte_range();
self.data.read_array(range).unwrap()
}
pub fn sequences(&self) -> ArrayOfOffsets<'a, Sequence<'a>, Offset16> {
let data = self.data;
let offsets = self.sequence_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for MultipleSubstFormat1<'a> {
fn type_name(&self) -> &str {
"MultipleSubstFormat1"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("subst_format", self.subst_format())),
1usize => Some(Field::new(
"coverage_offset",
FieldType::offset(self.coverage_offset(), self.coverage()),
)),
2usize => Some(Field::new("sequence_count", self.sequence_count())),
3usize => Some({
let data = self.data;
Field::new(
"sequence_offsets",
FieldType::array_of_offsets(
better_type_name::<Sequence>(),
self.sequence_offsets(),
move |off| {
let target = off.get().resolve::<Sequence>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for MultipleSubstFormat1<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct SequenceMarker {
substitute_glyph_ids_byte_len: usize,
}
impl SequenceMarker {
pub fn glyph_count_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn substitute_glyph_ids_byte_range(&self) -> Range<usize> {
let start = self.glyph_count_byte_range().end;
start..start + self.substitute_glyph_ids_byte_len
}
}
impl<'a> FontRead<'a> for Sequence<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let glyph_count: u16 = cursor.read()?;
let substitute_glyph_ids_byte_len = (glyph_count as usize)
.checked_mul(GlyphId16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(substitute_glyph_ids_byte_len);
cursor.finish(SequenceMarker {
substitute_glyph_ids_byte_len,
})
}
}
pub type Sequence<'a> = TableRef<'a, SequenceMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> Sequence<'a> {
pub fn glyph_count(&self) -> u16 {
let range = self.shape.glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn substitute_glyph_ids(&self) -> &'a [BigEndian<GlyphId16>] {
let range = self.shape.substitute_glyph_ids_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Sequence<'a> {
fn type_name(&self) -> &str {
"Sequence"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("glyph_count", self.glyph_count())),
1usize => Some(Field::new(
"substitute_glyph_ids",
self.substitute_glyph_ids(),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for Sequence<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for AlternateSubstFormat1Marker {
const FORMAT: u16 = 1;
}
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct AlternateSubstFormat1Marker {
alternate_set_offsets_byte_len: usize,
}
impl AlternateSubstFormat1Marker {
pub fn subst_format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn coverage_offset_byte_range(&self) -> Range<usize> {
let start = self.subst_format_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn alternate_set_count_byte_range(&self) -> Range<usize> {
let start = self.coverage_offset_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn alternate_set_offsets_byte_range(&self) -> Range<usize> {
let start = self.alternate_set_count_byte_range().end;
start..start + self.alternate_set_offsets_byte_len
}
}
impl<'a> FontRead<'a> for AlternateSubstFormat1<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<Offset16>();
let alternate_set_count: u16 = cursor.read()?;
let alternate_set_offsets_byte_len = (alternate_set_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(alternate_set_offsets_byte_len);
cursor.finish(AlternateSubstFormat1Marker {
alternate_set_offsets_byte_len,
})
}
}
pub type AlternateSubstFormat1<'a> = TableRef<'a, AlternateSubstFormat1Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> AlternateSubstFormat1<'a> {
pub fn subst_format(&self) -> u16 {
let range = self.shape.subst_format_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn coverage_offset(&self) -> Offset16 {
let range = self.shape.coverage_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
let data = self.data;
self.coverage_offset().resolve(data)
}
pub fn alternate_set_count(&self) -> u16 {
let range = self.shape.alternate_set_count_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn alternate_set_offsets(&self) -> &'a [BigEndian<Offset16>] {
let range = self.shape.alternate_set_offsets_byte_range();
self.data.read_array(range).unwrap()
}
pub fn alternate_sets(&self) -> ArrayOfOffsets<'a, AlternateSet<'a>, Offset16> {
let data = self.data;
let offsets = self.alternate_set_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for AlternateSubstFormat1<'a> {
fn type_name(&self) -> &str {
"AlternateSubstFormat1"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("subst_format", self.subst_format())),
1usize => Some(Field::new(
"coverage_offset",
FieldType::offset(self.coverage_offset(), self.coverage()),
)),
2usize => Some(Field::new(
"alternate_set_count",
self.alternate_set_count(),
)),
3usize => Some({
let data = self.data;
Field::new(
"alternate_set_offsets",
FieldType::array_of_offsets(
better_type_name::<AlternateSet>(),
self.alternate_set_offsets(),
move |off| {
let target = off.get().resolve::<AlternateSet>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for AlternateSubstFormat1<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct AlternateSetMarker {
alternate_glyph_ids_byte_len: usize,
}
impl AlternateSetMarker {
pub fn glyph_count_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn alternate_glyph_ids_byte_range(&self) -> Range<usize> {
let start = self.glyph_count_byte_range().end;
start..start + self.alternate_glyph_ids_byte_len
}
}
impl<'a> FontRead<'a> for AlternateSet<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let glyph_count: u16 = cursor.read()?;
let alternate_glyph_ids_byte_len = (glyph_count as usize)
.checked_mul(GlyphId16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(alternate_glyph_ids_byte_len);
cursor.finish(AlternateSetMarker {
alternate_glyph_ids_byte_len,
})
}
}
pub type AlternateSet<'a> = TableRef<'a, AlternateSetMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> AlternateSet<'a> {
pub fn glyph_count(&self) -> u16 {
let range = self.shape.glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn alternate_glyph_ids(&self) -> &'a [BigEndian<GlyphId16>] {
let range = self.shape.alternate_glyph_ids_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for AlternateSet<'a> {
fn type_name(&self) -> &str {
"AlternateSet"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("glyph_count", self.glyph_count())),
1usize => Some(Field::new(
"alternate_glyph_ids",
self.alternate_glyph_ids(),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for AlternateSet<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for LigatureSubstFormat1Marker {
const FORMAT: u16 = 1;
}
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct LigatureSubstFormat1Marker {
ligature_set_offsets_byte_len: usize,
}
impl LigatureSubstFormat1Marker {
pub fn subst_format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn coverage_offset_byte_range(&self) -> Range<usize> {
let start = self.subst_format_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn ligature_set_count_byte_range(&self) -> Range<usize> {
let start = self.coverage_offset_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn ligature_set_offsets_byte_range(&self) -> Range<usize> {
let start = self.ligature_set_count_byte_range().end;
start..start + self.ligature_set_offsets_byte_len
}
}
impl<'a> FontRead<'a> for LigatureSubstFormat1<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<Offset16>();
let ligature_set_count: u16 = cursor.read()?;
let ligature_set_offsets_byte_len = (ligature_set_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(ligature_set_offsets_byte_len);
cursor.finish(LigatureSubstFormat1Marker {
ligature_set_offsets_byte_len,
})
}
}
pub type LigatureSubstFormat1<'a> = TableRef<'a, LigatureSubstFormat1Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> LigatureSubstFormat1<'a> {
pub fn subst_format(&self) -> u16 {
let range = self.shape.subst_format_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn coverage_offset(&self) -> Offset16 {
let range = self.shape.coverage_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
let data = self.data;
self.coverage_offset().resolve(data)
}
pub fn ligature_set_count(&self) -> u16 {
let range = self.shape.ligature_set_count_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn ligature_set_offsets(&self) -> &'a [BigEndian<Offset16>] {
let range = self.shape.ligature_set_offsets_byte_range();
self.data.read_array(range).unwrap()
}
pub fn ligature_sets(&self) -> ArrayOfOffsets<'a, LigatureSet<'a>, Offset16> {
let data = self.data;
let offsets = self.ligature_set_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for LigatureSubstFormat1<'a> {
fn type_name(&self) -> &str {
"LigatureSubstFormat1"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("subst_format", self.subst_format())),
1usize => Some(Field::new(
"coverage_offset",
FieldType::offset(self.coverage_offset(), self.coverage()),
)),
2usize => Some(Field::new("ligature_set_count", self.ligature_set_count())),
3usize => Some({
let data = self.data;
Field::new(
"ligature_set_offsets",
FieldType::array_of_offsets(
better_type_name::<LigatureSet>(),
self.ligature_set_offsets(),
move |off| {
let target = off.get().resolve::<LigatureSet>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for LigatureSubstFormat1<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct LigatureSetMarker {
ligature_offsets_byte_len: usize,
}
impl LigatureSetMarker {
pub fn ligature_count_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn ligature_offsets_byte_range(&self) -> Range<usize> {
let start = self.ligature_count_byte_range().end;
start..start + self.ligature_offsets_byte_len
}
}
impl<'a> FontRead<'a> for LigatureSet<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let ligature_count: u16 = cursor.read()?;
let ligature_offsets_byte_len = (ligature_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(ligature_offsets_byte_len);
cursor.finish(LigatureSetMarker {
ligature_offsets_byte_len,
})
}
}
pub type LigatureSet<'a> = TableRef<'a, LigatureSetMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> LigatureSet<'a> {
pub fn ligature_count(&self) -> u16 {
let range = self.shape.ligature_count_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn ligature_offsets(&self) -> &'a [BigEndian<Offset16>] {
let range = self.shape.ligature_offsets_byte_range();
self.data.read_array(range).unwrap()
}
pub fn ligatures(&self) -> ArrayOfOffsets<'a, Ligature<'a>, Offset16> {
let data = self.data;
let offsets = self.ligature_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for LigatureSet<'a> {
fn type_name(&self) -> &str {
"LigatureSet"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("ligature_count", self.ligature_count())),
1usize => Some({
let data = self.data;
Field::new(
"ligature_offsets",
FieldType::array_of_offsets(
better_type_name::<Ligature>(),
self.ligature_offsets(),
move |off| {
let target = off.get().resolve::<Ligature>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for LigatureSet<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct LigatureMarker {
component_glyph_ids_byte_len: usize,
}
impl LigatureMarker {
pub fn ligature_glyph_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + GlyphId16::RAW_BYTE_LEN
}
pub fn component_count_byte_range(&self) -> Range<usize> {
let start = self.ligature_glyph_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn component_glyph_ids_byte_range(&self) -> Range<usize> {
let start = self.component_count_byte_range().end;
start..start + self.component_glyph_ids_byte_len
}
}
impl<'a> FontRead<'a> for Ligature<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<GlyphId16>();
let component_count: u16 = cursor.read()?;
let component_glyph_ids_byte_len = (transforms::subtract(component_count, 1_usize))
.checked_mul(GlyphId16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(component_glyph_ids_byte_len);
cursor.finish(LigatureMarker {
component_glyph_ids_byte_len,
})
}
}
pub type Ligature<'a> = TableRef<'a, LigatureMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> Ligature<'a> {
pub fn ligature_glyph(&self) -> GlyphId16 {
let range = self.shape.ligature_glyph_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn component_count(&self) -> u16 {
let range = self.shape.component_count_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn component_glyph_ids(&self) -> &'a [BigEndian<GlyphId16>] {
let range = self.shape.component_glyph_ids_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Ligature<'a> {
fn type_name(&self) -> &str {
"Ligature"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("ligature_glyph", self.ligature_glyph())),
1usize => Some(Field::new("component_count", self.component_count())),
2usize => Some(Field::new(
"component_glyph_ids",
self.component_glyph_ids(),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for Ligature<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for ExtensionSubstFormat1Marker {
const FORMAT: u16 = 1;
}
#[derive(Debug)]
#[doc(hidden)]
pub struct ExtensionSubstFormat1Marker<T = ()> {
offset_type: std::marker::PhantomData<*const T>,
}
impl<T> ExtensionSubstFormat1Marker<T> {
pub fn subst_format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn extension_lookup_type_byte_range(&self) -> Range<usize> {
let start = self.subst_format_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn extension_offset_byte_range(&self) -> Range<usize> {
let start = self.extension_lookup_type_byte_range().end;
start..start + Offset32::RAW_BYTE_LEN
}
}
impl<T> Clone for ExtensionSubstFormat1Marker<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for ExtensionSubstFormat1Marker<T> {}
impl<'a, T> FontRead<'a> for ExtensionSubstFormat1<'a, T> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<u16>();
cursor.advance::<Offset32>();
cursor.finish(ExtensionSubstFormat1Marker {
offset_type: std::marker::PhantomData,
})
}
}
impl<'a> ExtensionSubstFormat1<'a, ()> {
#[allow(dead_code)]
pub(crate) fn into_concrete<T>(self) -> ExtensionSubstFormat1<'a, T> {
let TableRef { data, .. } = self;
TableRef {
shape: ExtensionSubstFormat1Marker {
offset_type: std::marker::PhantomData,
},
data,
}
}
}
impl<'a, T> ExtensionSubstFormat1<'a, T> {
#[allow(dead_code)]
pub(crate) fn of_unit_type(&self) -> ExtensionSubstFormat1<'a, ()> {
let TableRef { data, .. } = self;
TableRef {
shape: ExtensionSubstFormat1Marker {
offset_type: std::marker::PhantomData,
},
data: *data,
}
}
}
pub type ExtensionSubstFormat1<'a, T> = TableRef<'a, ExtensionSubstFormat1Marker<T>>;
#[allow(clippy::needless_lifetimes)]
impl<'a, T> ExtensionSubstFormat1<'a, T> {
pub fn subst_format(&self) -> u16 {
let range = self.shape.subst_format_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn extension_lookup_type(&self) -> u16 {
let range = self.shape.extension_lookup_type_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn extension_offset(&self) -> Offset32 {
let range = self.shape.extension_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn extension(&self) -> Result<T, ReadError>
where
T: FontRead<'a>,
{
let data = self.data;
self.extension_offset().resolve(data)
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> SomeTable<'a> for ExtensionSubstFormat1<'a, T> {
fn type_name(&self) -> &str {
"ExtensionSubstFormat1"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("subst_format", self.subst_format())),
1usize => Some(Field::new(
"extension_lookup_type",
self.extension_lookup_type(),
)),
2usize => Some(Field::new(
"extension_offset",
FieldType::offset(self.extension_offset(), self.extension()),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> std::fmt::Debug for ExtensionSubstFormat1<'a, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
pub enum ExtensionSubtable<'a> {
Single(ExtensionSubstFormat1<'a, SingleSubst<'a>>),
Multiple(ExtensionSubstFormat1<'a, MultipleSubstFormat1<'a>>),
Alternate(ExtensionSubstFormat1<'a, AlternateSubstFormat1<'a>>),
Ligature(ExtensionSubstFormat1<'a, LigatureSubstFormat1<'a>>),
Contextual(ExtensionSubstFormat1<'a, SubstitutionSequenceContext<'a>>),
ChainContextual(ExtensionSubstFormat1<'a, SubstitutionChainContext<'a>>),
Reverse(ExtensionSubstFormat1<'a, ReverseChainSingleSubstFormat1<'a>>),
}
impl<'a> FontRead<'a> for ExtensionSubtable<'a> {
fn read(bytes: FontData<'a>) -> Result<Self, ReadError> {
let untyped = ExtensionSubstFormat1::read(bytes)?;
match untyped.extension_lookup_type() {
1 => Ok(ExtensionSubtable::Single(untyped.into_concrete())),
2 => Ok(ExtensionSubtable::Multiple(untyped.into_concrete())),
3 => Ok(ExtensionSubtable::Alternate(untyped.into_concrete())),
4 => Ok(ExtensionSubtable::Ligature(untyped.into_concrete())),
5 => Ok(ExtensionSubtable::Contextual(untyped.into_concrete())),
6 => Ok(ExtensionSubtable::ChainContextual(untyped.into_concrete())),
8 => Ok(ExtensionSubtable::Reverse(untyped.into_concrete())),
other => Err(ReadError::InvalidFormat(other.into())),
}
}
}
impl<'a> ExtensionSubtable<'a> {
#[allow(dead_code)]
pub(crate) fn of_unit_type(&self) -> ExtensionSubstFormat1<'a, ()> {
match self {
ExtensionSubtable::Single(inner) => inner.of_unit_type(),
ExtensionSubtable::Multiple(inner) => inner.of_unit_type(),
ExtensionSubtable::Alternate(inner) => inner.of_unit_type(),
ExtensionSubtable::Ligature(inner) => inner.of_unit_type(),
ExtensionSubtable::Contextual(inner) => inner.of_unit_type(),
ExtensionSubtable::ChainContextual(inner) => inner.of_unit_type(),
ExtensionSubtable::Reverse(inner) => inner.of_unit_type(),
}
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> ExtensionSubtable<'a> {
fn dyn_inner(&self) -> &(dyn SomeTable<'a> + 'a) {
match self {
ExtensionSubtable::Single(table) => table,
ExtensionSubtable::Multiple(table) => table,
ExtensionSubtable::Alternate(table) => table,
ExtensionSubtable::Ligature(table) => table,
ExtensionSubtable::Contextual(table) => table,
ExtensionSubtable::ChainContextual(table) => table,
ExtensionSubtable::Reverse(table) => table,
}
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ExtensionSubtable<'a> {
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
self.dyn_inner().get_field(idx)
}
fn type_name(&self) -> &str {
self.dyn_inner().type_name()
}
}
#[cfg(feature = "experimental_traverse")]
impl std::fmt::Debug for ExtensionSubtable<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.dyn_inner().fmt(f)
}
}
impl Format<u16> for ReverseChainSingleSubstFormat1Marker {
const FORMAT: u16 = 1;
}
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ReverseChainSingleSubstFormat1Marker {
backtrack_coverage_offsets_byte_len: usize,
lookahead_coverage_offsets_byte_len: usize,
substitute_glyph_ids_byte_len: usize,
}
impl ReverseChainSingleSubstFormat1Marker {
pub fn subst_format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn coverage_offset_byte_range(&self) -> Range<usize> {
let start = self.subst_format_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
let start = self.coverage_offset_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn backtrack_coverage_offsets_byte_range(&self) -> Range<usize> {
let start = self.backtrack_glyph_count_byte_range().end;
start..start + self.backtrack_coverage_offsets_byte_len
}
pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
let start = self.backtrack_coverage_offsets_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn lookahead_coverage_offsets_byte_range(&self) -> Range<usize> {
let start = self.lookahead_glyph_count_byte_range().end;
start..start + self.lookahead_coverage_offsets_byte_len
}
pub fn glyph_count_byte_range(&self) -> Range<usize> {
let start = self.lookahead_coverage_offsets_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn substitute_glyph_ids_byte_range(&self) -> Range<usize> {
let start = self.glyph_count_byte_range().end;
start..start + self.substitute_glyph_ids_byte_len
}
}
impl<'a> FontRead<'a> for ReverseChainSingleSubstFormat1<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<Offset16>();
let backtrack_glyph_count: u16 = cursor.read()?;
let backtrack_coverage_offsets_byte_len = (backtrack_glyph_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(backtrack_coverage_offsets_byte_len);
let lookahead_glyph_count: u16 = cursor.read()?;
let lookahead_coverage_offsets_byte_len = (lookahead_glyph_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(lookahead_coverage_offsets_byte_len);
let glyph_count: u16 = cursor.read()?;
let substitute_glyph_ids_byte_len = (glyph_count as usize)
.checked_mul(GlyphId16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(substitute_glyph_ids_byte_len);
cursor.finish(ReverseChainSingleSubstFormat1Marker {
backtrack_coverage_offsets_byte_len,
lookahead_coverage_offsets_byte_len,
substitute_glyph_ids_byte_len,
})
}
}
pub type ReverseChainSingleSubstFormat1<'a> = TableRef<'a, ReverseChainSingleSubstFormat1Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ReverseChainSingleSubstFormat1<'a> {
pub fn subst_format(&self) -> u16 {
let range = self.shape.subst_format_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn coverage_offset(&self) -> Offset16 {
let range = self.shape.coverage_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
let data = self.data;
self.coverage_offset().resolve(data)
}
pub fn backtrack_glyph_count(&self) -> u16 {
let range = self.shape.backtrack_glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn backtrack_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
let range = self.shape.backtrack_coverage_offsets_byte_range();
self.data.read_array(range).unwrap()
}
pub fn backtrack_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
let data = self.data;
let offsets = self.backtrack_coverage_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
pub fn lookahead_glyph_count(&self) -> u16 {
let range = self.shape.lookahead_glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn lookahead_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
let range = self.shape.lookahead_coverage_offsets_byte_range();
self.data.read_array(range).unwrap()
}
pub fn lookahead_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
let data = self.data;
let offsets = self.lookahead_coverage_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
pub fn glyph_count(&self) -> u16 {
let range = self.shape.glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn substitute_glyph_ids(&self) -> &'a [BigEndian<GlyphId16>] {
let range = self.shape.substitute_glyph_ids_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ReverseChainSingleSubstFormat1<'a> {
fn type_name(&self) -> &str {
"ReverseChainSingleSubstFormat1"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("subst_format", self.subst_format())),
1usize => Some(Field::new(
"coverage_offset",
FieldType::offset(self.coverage_offset(), self.coverage()),
)),
2usize => Some(Field::new(
"backtrack_glyph_count",
self.backtrack_glyph_count(),
)),
3usize => Some({
let data = self.data;
Field::new(
"backtrack_coverage_offsets",
FieldType::array_of_offsets(
better_type_name::<CoverageTable>(),
self.backtrack_coverage_offsets(),
move |off| {
let target = off.get().resolve::<CoverageTable>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
4usize => Some(Field::new(
"lookahead_glyph_count",
self.lookahead_glyph_count(),
)),
5usize => Some({
let data = self.data;
Field::new(
"lookahead_coverage_offsets",
FieldType::array_of_offsets(
better_type_name::<CoverageTable>(),
self.lookahead_coverage_offsets(),
move |off| {
let target = off.get().resolve::<CoverageTable>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
6usize => Some(Field::new("glyph_count", self.glyph_count())),
7usize => Some(Field::new(
"substitute_glyph_ids",
self.substitute_glyph_ids(),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ReverseChainSingleSubstFormat1<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}