Files
another-boids-in-rust/vendor/read-fonts/generated/generated_layout.rs

5736 lines
196 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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::*;
/// [Script List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ScriptListMarker {
script_records_byte_len: usize,
}
impl ScriptListMarker {
pub fn script_count_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn script_records_byte_range(&self) -> Range<usize> {
let start = self.script_count_byte_range().end;
start..start + self.script_records_byte_len
}
}
impl MinByteRange for ScriptListMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.script_records_byte_range().end
}
}
impl<'a> FontRead<'a> for ScriptList<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let script_count: u16 = cursor.read()?;
let script_records_byte_len = (script_count as usize)
.checked_mul(ScriptRecord::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(script_records_byte_len);
cursor.finish(ScriptListMarker {
script_records_byte_len,
})
}
}
/// [Script List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
pub type ScriptList<'a> = TableRef<'a, ScriptListMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ScriptList<'a> {
/// Number of ScriptRecords
pub fn script_count(&self) -> u16 {
let range = self.shape.script_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of ScriptRecords, listed alphabetically by script tag
pub fn script_records(&self) -> &'a [ScriptRecord] {
let range = self.shape.script_records_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ScriptList<'a> {
fn type_name(&self) -> &str {
"ScriptList"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("script_count", self.script_count())),
1usize => Some(Field::new(
"script_records",
traversal::FieldType::array_of_records(
stringify!(ScriptRecord),
self.script_records(),
self.offset_data(),
),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ScriptList<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// [Script Record](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct ScriptRecord {
/// 4-byte script tag identifier
pub script_tag: BigEndian<Tag>,
/// Offset to Script table, from beginning of ScriptList
pub script_offset: BigEndian<Offset16>,
}
impl ScriptRecord {
/// 4-byte script tag identifier
pub fn script_tag(&self) -> Tag {
self.script_tag.get()
}
/// Offset to Script table, from beginning of ScriptList
pub fn script_offset(&self) -> Offset16 {
self.script_offset.get()
}
/// Offset to Script table, from beginning of ScriptList
///
/// The `data` argument should be retrieved from the parent table
/// By calling its `offset_data` method.
pub fn script<'a>(&self, data: FontData<'a>) -> Result<Script<'a>, ReadError> {
self.script_offset().resolve(data)
}
}
impl FixedSize for ScriptRecord {
const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeRecord<'a> for ScriptRecord {
fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
RecordResolver {
name: "ScriptRecord",
get_field: Box::new(move |idx, _data| match idx {
0usize => Some(Field::new("script_tag", self.script_tag())),
1usize => Some(Field::new(
"script_offset",
FieldType::offset(self.script_offset(), self.script(_data)),
)),
_ => None,
}),
data,
}
}
}
/// [Script Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-table-and-language-system-record)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ScriptMarker {
lang_sys_records_byte_len: usize,
}
impl ScriptMarker {
pub fn default_lang_sys_offset_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn lang_sys_count_byte_range(&self) -> Range<usize> {
let start = self.default_lang_sys_offset_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn lang_sys_records_byte_range(&self) -> Range<usize> {
let start = self.lang_sys_count_byte_range().end;
start..start + self.lang_sys_records_byte_len
}
}
impl MinByteRange for ScriptMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.lang_sys_records_byte_range().end
}
}
impl<'a> FontRead<'a> for Script<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<Offset16>();
let lang_sys_count: u16 = cursor.read()?;
let lang_sys_records_byte_len = (lang_sys_count as usize)
.checked_mul(LangSysRecord::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(lang_sys_records_byte_len);
cursor.finish(ScriptMarker {
lang_sys_records_byte_len,
})
}
}
/// [Script Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-table-and-language-system-record)
pub type Script<'a> = TableRef<'a, ScriptMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> Script<'a> {
/// Offset to default LangSys table, from beginning of Script table
/// — may be NULL
pub fn default_lang_sys_offset(&self) -> Nullable<Offset16> {
let range = self.shape.default_lang_sys_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Attempt to resolve [`default_lang_sys_offset`][Self::default_lang_sys_offset].
pub fn default_lang_sys(&self) -> Option<Result<LangSys<'a>, ReadError>> {
let data = self.data;
self.default_lang_sys_offset().resolve(data)
}
/// Number of LangSysRecords for this script — excluding the
/// default LangSys
pub fn lang_sys_count(&self) -> u16 {
let range = self.shape.lang_sys_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of LangSysRecords, listed alphabetically by LangSys tag
pub fn lang_sys_records(&self) -> &'a [LangSysRecord] {
let range = self.shape.lang_sys_records_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Script<'a> {
fn type_name(&self) -> &str {
"Script"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new(
"default_lang_sys_offset",
FieldType::offset(self.default_lang_sys_offset(), self.default_lang_sys()),
)),
1usize => Some(Field::new("lang_sys_count", self.lang_sys_count())),
2usize => Some(Field::new(
"lang_sys_records",
traversal::FieldType::array_of_records(
stringify!(LangSysRecord),
self.lang_sys_records(),
self.offset_data(),
),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for Script<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct LangSysRecord {
/// 4-byte LangSysTag identifier
pub lang_sys_tag: BigEndian<Tag>,
/// Offset to LangSys table, from beginning of Script table
pub lang_sys_offset: BigEndian<Offset16>,
}
impl LangSysRecord {
/// 4-byte LangSysTag identifier
pub fn lang_sys_tag(&self) -> Tag {
self.lang_sys_tag.get()
}
/// Offset to LangSys table, from beginning of Script table
pub fn lang_sys_offset(&self) -> Offset16 {
self.lang_sys_offset.get()
}
/// Offset to LangSys table, from beginning of Script table
///
/// The `data` argument should be retrieved from the parent table
/// By calling its `offset_data` method.
pub fn lang_sys<'a>(&self, data: FontData<'a>) -> Result<LangSys<'a>, ReadError> {
self.lang_sys_offset().resolve(data)
}
}
impl FixedSize for LangSysRecord {
const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeRecord<'a> for LangSysRecord {
fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
RecordResolver {
name: "LangSysRecord",
get_field: Box::new(move |idx, _data| match idx {
0usize => Some(Field::new("lang_sys_tag", self.lang_sys_tag())),
1usize => Some(Field::new(
"lang_sys_offset",
FieldType::offset(self.lang_sys_offset(), self.lang_sys(_data)),
)),
_ => None,
}),
data,
}
}
}
/// [Language System Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#language-system-table)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct LangSysMarker {
feature_indices_byte_len: usize,
}
impl LangSysMarker {
pub fn lookup_order_offset_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn required_feature_index_byte_range(&self) -> Range<usize> {
let start = self.lookup_order_offset_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn feature_index_count_byte_range(&self) -> Range<usize> {
let start = self.required_feature_index_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn feature_indices_byte_range(&self) -> Range<usize> {
let start = self.feature_index_count_byte_range().end;
start..start + self.feature_indices_byte_len
}
}
impl MinByteRange for LangSysMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.feature_indices_byte_range().end
}
}
impl<'a> FontRead<'a> for LangSys<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<u16>();
let feature_index_count: u16 = cursor.read()?;
let feature_indices_byte_len = (feature_index_count as usize)
.checked_mul(u16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(feature_indices_byte_len);
cursor.finish(LangSysMarker {
feature_indices_byte_len,
})
}
}
/// [Language System Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#language-system-table)
pub type LangSys<'a> = TableRef<'a, LangSysMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> LangSys<'a> {
/// Index of a feature required for this language system; if no
/// required features = 0xFFFF
pub fn required_feature_index(&self) -> u16 {
let range = self.shape.required_feature_index_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Number of feature index values for this language system —
/// excludes the required feature
pub fn feature_index_count(&self) -> u16 {
let range = self.shape.feature_index_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of indices into the FeatureList, in arbitrary order
pub fn feature_indices(&self) -> &'a [BigEndian<u16>] {
let range = self.shape.feature_indices_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for LangSys<'a> {
fn type_name(&self) -> &str {
"LangSys"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new(
"required_feature_index",
self.required_feature_index(),
)),
1usize => Some(Field::new(
"feature_index_count",
self.feature_index_count(),
)),
2usize => Some(Field::new("feature_indices", self.feature_indices())),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for LangSys<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// [Feature List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-list-table)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct FeatureListMarker {
feature_records_byte_len: usize,
}
impl FeatureListMarker {
pub fn feature_count_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn feature_records_byte_range(&self) -> Range<usize> {
let start = self.feature_count_byte_range().end;
start..start + self.feature_records_byte_len
}
}
impl MinByteRange for FeatureListMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.feature_records_byte_range().end
}
}
impl<'a> FontRead<'a> for FeatureList<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let feature_count: u16 = cursor.read()?;
let feature_records_byte_len = (feature_count as usize)
.checked_mul(FeatureRecord::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(feature_records_byte_len);
cursor.finish(FeatureListMarker {
feature_records_byte_len,
})
}
}
/// [Feature List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-list-table)
pub type FeatureList<'a> = TableRef<'a, FeatureListMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> FeatureList<'a> {
/// Number of FeatureRecords in this table
pub fn feature_count(&self) -> u16 {
let range = self.shape.feature_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of FeatureRecords — zero-based (first feature has
/// FeatureIndex = 0), listed alphabetically by feature tag
pub fn feature_records(&self) -> &'a [FeatureRecord] {
let range = self.shape.feature_records_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for FeatureList<'a> {
fn type_name(&self) -> &str {
"FeatureList"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("feature_count", self.feature_count())),
1usize => Some(Field::new(
"feature_records",
traversal::FieldType::array_of_records(
stringify!(FeatureRecord),
self.feature_records(),
self.offset_data(),
),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for FeatureList<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// Part of [FeatureList]
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct FeatureRecord {
/// 4-byte feature identification tag
pub feature_tag: BigEndian<Tag>,
/// Offset to Feature table, from beginning of FeatureList
pub feature_offset: BigEndian<Offset16>,
}
impl FeatureRecord {
/// 4-byte feature identification tag
pub fn feature_tag(&self) -> Tag {
self.feature_tag.get()
}
/// Offset to Feature table, from beginning of FeatureList
pub fn feature_offset(&self) -> Offset16 {
self.feature_offset.get()
}
/// Offset to Feature table, from beginning of FeatureList
///
/// The `data` argument should be retrieved from the parent table
/// By calling its `offset_data` method.
pub fn feature<'a>(&self, data: FontData<'a>) -> Result<Feature<'a>, ReadError> {
let args = self.feature_tag();
self.feature_offset().resolve_with_args(data, &args)
}
}
impl FixedSize for FeatureRecord {
const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeRecord<'a> for FeatureRecord {
fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
RecordResolver {
name: "FeatureRecord",
get_field: Box::new(move |idx, _data| match idx {
0usize => Some(Field::new("feature_tag", self.feature_tag())),
1usize => Some(Field::new(
"feature_offset",
FieldType::offset(self.feature_offset(), self.feature(_data)),
)),
_ => None,
}),
data,
}
}
}
/// [Feature Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-table)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct FeatureMarker {
feature_tag: Tag,
lookup_list_indices_byte_len: usize,
}
impl FeatureMarker {
pub fn feature_params_offset_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn lookup_index_count_byte_range(&self) -> Range<usize> {
let start = self.feature_params_offset_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn lookup_list_indices_byte_range(&self) -> Range<usize> {
let start = self.lookup_index_count_byte_range().end;
start..start + self.lookup_list_indices_byte_len
}
}
impl MinByteRange for FeatureMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.lookup_list_indices_byte_range().end
}
}
impl ReadArgs for Feature<'_> {
type Args = Tag;
}
impl<'a> FontReadWithArgs<'a> for Feature<'a> {
fn read_with_args(data: FontData<'a>, args: &Tag) -> Result<Self, ReadError> {
let feature_tag = *args;
let mut cursor = data.cursor();
cursor.advance::<Offset16>();
let lookup_index_count: u16 = cursor.read()?;
let lookup_list_indices_byte_len = (lookup_index_count as usize)
.checked_mul(u16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(lookup_list_indices_byte_len);
cursor.finish(FeatureMarker {
feature_tag,
lookup_list_indices_byte_len,
})
}
}
impl<'a> Feature<'a> {
/// A constructor that requires additional arguments.
///
/// This type requires some external state in order to be
/// parsed.
pub fn read(data: FontData<'a>, feature_tag: Tag) -> Result<Self, ReadError> {
let args = feature_tag;
Self::read_with_args(data, &args)
}
}
/// [Feature Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-table)
pub type Feature<'a> = TableRef<'a, FeatureMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> Feature<'a> {
/// Offset from start of Feature table to FeatureParams table, if defined for the feature and present, else NULL
pub fn feature_params_offset(&self) -> Nullable<Offset16> {
let range = self.shape.feature_params_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Attempt to resolve [`feature_params_offset`][Self::feature_params_offset].
pub fn feature_params(&self) -> Option<Result<FeatureParams<'a>, ReadError>> {
let data = self.data;
let args = self.feature_tag();
self.feature_params_offset().resolve_with_args(data, &args)
}
/// Number of LookupList indices for this feature
pub fn lookup_index_count(&self) -> u16 {
let range = self.shape.lookup_index_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of indices into the LookupList — zero-based (first
/// lookup is LookupListIndex = 0)
pub fn lookup_list_indices(&self) -> &'a [BigEndian<u16>] {
let range = self.shape.lookup_list_indices_byte_range();
self.data.read_array(range).unwrap()
}
pub(crate) fn feature_tag(&self) -> Tag {
self.shape.feature_tag
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Feature<'a> {
fn type_name(&self) -> &str {
"Feature"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new(
"feature_params_offset",
FieldType::offset(self.feature_params_offset(), self.feature_params()),
)),
1usize => Some(Field::new("lookup_index_count", self.lookup_index_count())),
2usize => Some(Field::new(
"lookup_list_indices",
self.lookup_list_indices(),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for Feature<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// [Lookup List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-list-table)
#[derive(Debug)]
#[doc(hidden)]
pub struct LookupListMarker<T = ()> {
lookup_offsets_byte_len: usize,
offset_type: std::marker::PhantomData<*const T>,
}
impl<T> LookupListMarker<T> {
pub fn lookup_count_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn lookup_offsets_byte_range(&self) -> Range<usize> {
let start = self.lookup_count_byte_range().end;
start..start + self.lookup_offsets_byte_len
}
}
impl MinByteRange for LookupListMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.lookup_offsets_byte_range().end
}
}
impl<T> Clone for LookupListMarker<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for LookupListMarker<T> {}
impl<'a, T> FontRead<'a> for LookupList<'a, T> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let lookup_count: u16 = cursor.read()?;
let lookup_offsets_byte_len = (lookup_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(lookup_offsets_byte_len);
cursor.finish(LookupListMarker {
lookup_offsets_byte_len,
offset_type: std::marker::PhantomData,
})
}
}
impl<'a> LookupList<'a, ()> {
#[allow(dead_code)]
pub(crate) fn into_concrete<T>(self) -> LookupList<'a, T> {
let TableRef { data, shape } = self;
TableRef {
shape: LookupListMarker {
lookup_offsets_byte_len: shape.lookup_offsets_byte_len,
offset_type: std::marker::PhantomData,
},
data,
}
}
}
impl<'a, T> LookupList<'a, T> {
#[allow(dead_code)]
/// Replace the specific generic type on this implementation with `()`
pub(crate) fn of_unit_type(&self) -> LookupList<'a, ()> {
let TableRef { data, shape } = self;
TableRef {
shape: LookupListMarker {
lookup_offsets_byte_len: shape.lookup_offsets_byte_len,
offset_type: std::marker::PhantomData,
},
data: *data,
}
}
}
/// [Lookup List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-list-table)
pub type LookupList<'a, T> = TableRef<'a, LookupListMarker<T>>;
#[allow(clippy::needless_lifetimes)]
impl<'a, T> LookupList<'a, T> {
/// Number of lookups in this table
pub fn lookup_count(&self) -> u16 {
let range = self.shape.lookup_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of offsets to Lookup tables, from beginning of LookupList
/// — zero based (first lookup is Lookup index = 0)
pub fn lookup_offsets(&self) -> &'a [BigEndian<Offset16>] {
let range = self.shape.lookup_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`lookup_offsets`][Self::lookup_offsets].
pub fn lookups(&self) -> ArrayOfOffsets<'a, T, Offset16>
where
T: FontRead<'a>,
{
let data = self.data;
let offsets = self.lookup_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> SomeTable<'a> for LookupList<'a, T> {
fn type_name(&self) -> &str {
"LookupList"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("lookup_count", self.lookup_count())),
1usize => Some({
let data = self.data;
Field::new(
"lookup_offsets",
FieldType::array_of_offsets(
better_type_name::<T>(),
self.lookup_offsets(),
move |off| {
let target = off.get().resolve::<T>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> std::fmt::Debug for LookupList<'a, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// [Lookup Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-table)
#[derive(Debug)]
#[doc(hidden)]
pub struct LookupMarker<T = ()> {
subtable_offsets_byte_len: usize,
mark_filtering_set_byte_start: Option<usize>,
offset_type: std::marker::PhantomData<*const T>,
}
impl<T> LookupMarker<T> {
pub fn lookup_type_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn lookup_flag_byte_range(&self) -> Range<usize> {
let start = self.lookup_type_byte_range().end;
start..start + LookupFlag::RAW_BYTE_LEN
}
pub fn sub_table_count_byte_range(&self) -> Range<usize> {
let start = self.lookup_flag_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn subtable_offsets_byte_range(&self) -> Range<usize> {
let start = self.sub_table_count_byte_range().end;
start..start + self.subtable_offsets_byte_len
}
pub fn mark_filtering_set_byte_range(&self) -> Option<Range<usize>> {
let start = self.mark_filtering_set_byte_start?;
Some(start..start + u16::RAW_BYTE_LEN)
}
}
impl MinByteRange for LookupMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.subtable_offsets_byte_range().end
}
}
impl<T> Clone for LookupMarker<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for LookupMarker<T> {}
impl<'a, T> FontRead<'a> for Lookup<'a, T> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
let lookup_flag: LookupFlag = cursor.read()?;
let sub_table_count: u16 = cursor.read()?;
let subtable_offsets_byte_len = (sub_table_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(subtable_offsets_byte_len);
let mark_filtering_set_byte_start = lookup_flag
.contains(LookupFlag::USE_MARK_FILTERING_SET)
.then(|| cursor.position())
.transpose()?;
lookup_flag
.contains(LookupFlag::USE_MARK_FILTERING_SET)
.then(|| cursor.advance::<u16>());
cursor.finish(LookupMarker {
subtable_offsets_byte_len,
mark_filtering_set_byte_start,
offset_type: std::marker::PhantomData,
})
}
}
impl<'a> Lookup<'a, ()> {
#[allow(dead_code)]
pub(crate) fn into_concrete<T>(self) -> Lookup<'a, T> {
let TableRef { data, shape } = self;
TableRef {
shape: LookupMarker {
subtable_offsets_byte_len: shape.subtable_offsets_byte_len,
mark_filtering_set_byte_start: shape.mark_filtering_set_byte_start,
offset_type: std::marker::PhantomData,
},
data,
}
}
}
impl<'a, T> Lookup<'a, T> {
#[allow(dead_code)]
/// Replace the specific generic type on this implementation with `()`
pub(crate) fn of_unit_type(&self) -> Lookup<'a, ()> {
let TableRef { data, shape } = self;
TableRef {
shape: LookupMarker {
subtable_offsets_byte_len: shape.subtable_offsets_byte_len,
mark_filtering_set_byte_start: shape.mark_filtering_set_byte_start,
offset_type: std::marker::PhantomData,
},
data: *data,
}
}
}
/// [Lookup Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-table)
pub type Lookup<'a, T> = TableRef<'a, LookupMarker<T>>;
#[allow(clippy::needless_lifetimes)]
impl<'a, T> Lookup<'a, T> {
/// Different enumerations for GSUB and GPOS
pub fn lookup_type(&self) -> u16 {
let range = self.shape.lookup_type_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Lookup qualifiers
pub fn lookup_flag(&self) -> LookupFlag {
let range = self.shape.lookup_flag_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Number of subtables for this lookup
pub fn sub_table_count(&self) -> u16 {
let range = self.shape.sub_table_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of offsets to lookup subtables, from beginning of Lookup
/// table
pub fn subtable_offsets(&self) -> &'a [BigEndian<Offset16>] {
let range = self.shape.subtable_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`subtable_offsets`][Self::subtable_offsets].
pub fn subtables(&self) -> ArrayOfOffsets<'a, T, Offset16>
where
T: FontRead<'a>,
{
let data = self.data;
let offsets = self.subtable_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
/// Index (base 0) into GDEF mark glyph sets structure. This field
/// is only present if the USE_MARK_FILTERING_SET lookup flag is
/// set.
pub fn mark_filtering_set(&self) -> Option<u16> {
let range = self.shape.mark_filtering_set_byte_range()?;
Some(self.data.read_at(range.start).unwrap())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> SomeTable<'a> for Lookup<'a, T> {
fn type_name(&self) -> &str {
"Lookup"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
let lookup_flag = self.lookup_flag();
match idx {
0usize => Some(Field::new("lookup_type", self.lookup_type())),
1usize => Some(Field::new("lookup_flag", self.traverse_lookup_flag())),
2usize => Some(Field::new("sub_table_count", self.sub_table_count())),
3usize => Some({
let data = self.data;
Field::new(
"subtable_offsets",
FieldType::array_of_offsets(
better_type_name::<T>(),
self.subtable_offsets(),
move |off| {
let target = off.get().resolve::<T>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
4usize if lookup_flag.contains(LookupFlag::USE_MARK_FILTERING_SET) => Some(Field::new(
"mark_filtering_set",
self.mark_filtering_set().unwrap(),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> std::fmt::Debug for Lookup<'a, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for CoverageFormat1Marker {
const FORMAT: u16 = 1;
}
/// [Coverage Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-1)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct CoverageFormat1Marker {
glyph_array_byte_len: usize,
}
impl CoverageFormat1Marker {
pub fn coverage_format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn glyph_count_byte_range(&self) -> Range<usize> {
let start = self.coverage_format_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn glyph_array_byte_range(&self) -> Range<usize> {
let start = self.glyph_count_byte_range().end;
start..start + self.glyph_array_byte_len
}
}
impl MinByteRange for CoverageFormat1Marker {
fn min_byte_range(&self) -> Range<usize> {
0..self.glyph_array_byte_range().end
}
}
impl<'a> FontRead<'a> for CoverageFormat1<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
let glyph_count: u16 = cursor.read()?;
let glyph_array_byte_len = (glyph_count as usize)
.checked_mul(GlyphId16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(glyph_array_byte_len);
cursor.finish(CoverageFormat1Marker {
glyph_array_byte_len,
})
}
}
/// [Coverage Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-1)
pub type CoverageFormat1<'a> = TableRef<'a, CoverageFormat1Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> CoverageFormat1<'a> {
/// Format identifier — format = 1
pub fn coverage_format(&self) -> u16 {
let range = self.shape.coverage_format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Number of glyphs in the glyph array
pub fn glyph_count(&self) -> u16 {
let range = self.shape.glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of glyph IDs — in numerical order
pub fn glyph_array(&self) -> &'a [BigEndian<GlyphId16>] {
let range = self.shape.glyph_array_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for CoverageFormat1<'a> {
fn type_name(&self) -> &str {
"CoverageFormat1"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("coverage_format", self.coverage_format())),
1usize => Some(Field::new("glyph_count", self.glyph_count())),
2usize => Some(Field::new("glyph_array", self.glyph_array())),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for CoverageFormat1<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for CoverageFormat2Marker {
const FORMAT: u16 = 2;
}
/// [Coverage Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-2)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct CoverageFormat2Marker {
range_records_byte_len: usize,
}
impl CoverageFormat2Marker {
pub fn coverage_format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn range_count_byte_range(&self) -> Range<usize> {
let start = self.coverage_format_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn range_records_byte_range(&self) -> Range<usize> {
let start = self.range_count_byte_range().end;
start..start + self.range_records_byte_len
}
}
impl MinByteRange for CoverageFormat2Marker {
fn min_byte_range(&self) -> Range<usize> {
0..self.range_records_byte_range().end
}
}
impl<'a> FontRead<'a> for CoverageFormat2<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
let range_count: u16 = cursor.read()?;
let range_records_byte_len = (range_count as usize)
.checked_mul(RangeRecord::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(range_records_byte_len);
cursor.finish(CoverageFormat2Marker {
range_records_byte_len,
})
}
}
/// [Coverage Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-2)
pub type CoverageFormat2<'a> = TableRef<'a, CoverageFormat2Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> CoverageFormat2<'a> {
/// Format identifier — format = 2
pub fn coverage_format(&self) -> u16 {
let range = self.shape.coverage_format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Number of RangeRecords
pub fn range_count(&self) -> u16 {
let range = self.shape.range_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of glyph ranges — ordered by startGlyphID.
pub fn range_records(&self) -> &'a [RangeRecord] {
let range = self.shape.range_records_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for CoverageFormat2<'a> {
fn type_name(&self) -> &str {
"CoverageFormat2"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("coverage_format", self.coverage_format())),
1usize => Some(Field::new("range_count", self.range_count())),
2usize => Some(Field::new(
"range_records",
traversal::FieldType::array_of_records(
stringify!(RangeRecord),
self.range_records(),
self.offset_data(),
),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for CoverageFormat2<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// Used in [CoverageFormat2]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct RangeRecord {
/// First glyph ID in the range
pub start_glyph_id: BigEndian<GlyphId16>,
/// Last glyph ID in the range
pub end_glyph_id: BigEndian<GlyphId16>,
/// Coverage Index of first glyph ID in range
pub start_coverage_index: BigEndian<u16>,
}
impl RangeRecord {
/// First glyph ID in the range
pub fn start_glyph_id(&self) -> GlyphId16 {
self.start_glyph_id.get()
}
/// Last glyph ID in the range
pub fn end_glyph_id(&self) -> GlyphId16 {
self.end_glyph_id.get()
}
/// Coverage Index of first glyph ID in range
pub fn start_coverage_index(&self) -> u16 {
self.start_coverage_index.get()
}
}
impl FixedSize for RangeRecord {
const RAW_BYTE_LEN: usize =
GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeRecord<'a> for RangeRecord {
fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
RecordResolver {
name: "RangeRecord",
get_field: Box::new(move |idx, _data| match idx {
0usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
1usize => Some(Field::new("end_glyph_id", self.end_glyph_id())),
2usize => Some(Field::new(
"start_coverage_index",
self.start_coverage_index(),
)),
_ => None,
}),
data,
}
}
}
/// [Coverage Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-table)
#[derive(Clone)]
pub enum CoverageTable<'a> {
Format1(CoverageFormat1<'a>),
Format2(CoverageFormat2<'a>),
}
impl<'a> CoverageTable<'a> {
///Return the `FontData` used to resolve offsets for this table.
pub fn offset_data(&self) -> FontData<'a> {
match self {
Self::Format1(item) => item.offset_data(),
Self::Format2(item) => item.offset_data(),
}
}
/// Format identifier — format = 1
pub fn coverage_format(&self) -> u16 {
match self {
Self::Format1(item) => item.coverage_format(),
Self::Format2(item) => item.coverage_format(),
}
}
}
impl<'a> FontRead<'a> for CoverageTable<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let format: u16 = data.read_at(0usize)?;
match format {
CoverageFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
CoverageFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
other => Err(ReadError::InvalidFormat(other.into())),
}
}
}
impl MinByteRange for CoverageTable<'_> {
fn min_byte_range(&self) -> Range<usize> {
match self {
Self::Format1(item) => item.min_byte_range(),
Self::Format2(item) => item.min_byte_range(),
}
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> CoverageTable<'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 CoverageTable<'_> {
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 CoverageTable<'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 ClassDefFormat1Marker {
const FORMAT: u16 = 1;
}
/// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ClassDefFormat1Marker {
class_value_array_byte_len: usize,
}
impl ClassDefFormat1Marker {
pub fn class_format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn start_glyph_id_byte_range(&self) -> Range<usize> {
let start = self.class_format_byte_range().end;
start..start + GlyphId16::RAW_BYTE_LEN
}
pub fn glyph_count_byte_range(&self) -> Range<usize> {
let start = self.start_glyph_id_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn class_value_array_byte_range(&self) -> Range<usize> {
let start = self.glyph_count_byte_range().end;
start..start + self.class_value_array_byte_len
}
}
impl MinByteRange for ClassDefFormat1Marker {
fn min_byte_range(&self) -> Range<usize> {
0..self.class_value_array_byte_range().end
}
}
impl<'a> FontRead<'a> for ClassDefFormat1<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<GlyphId16>();
let glyph_count: u16 = cursor.read()?;
let class_value_array_byte_len = (glyph_count as usize)
.checked_mul(u16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(class_value_array_byte_len);
cursor.finish(ClassDefFormat1Marker {
class_value_array_byte_len,
})
}
}
/// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1)
pub type ClassDefFormat1<'a> = TableRef<'a, ClassDefFormat1Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ClassDefFormat1<'a> {
/// Format identifier — format = 1
pub fn class_format(&self) -> u16 {
let range = self.shape.class_format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// First glyph ID of the classValueArray
pub fn start_glyph_id(&self) -> GlyphId16 {
let range = self.shape.start_glyph_id_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Size of the classValueArray
pub fn glyph_count(&self) -> u16 {
let range = self.shape.glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of Class Values — one per glyph ID
pub fn class_value_array(&self) -> &'a [BigEndian<u16>] {
let range = self.shape.class_value_array_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ClassDefFormat1<'a> {
fn type_name(&self) -> &str {
"ClassDefFormat1"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("class_format", self.class_format())),
1usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
2usize => Some(Field::new("glyph_count", self.glyph_count())),
3usize => Some(Field::new("class_value_array", self.class_value_array())),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ClassDefFormat1<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for ClassDefFormat2Marker {
const FORMAT: u16 = 2;
}
/// [Class Definition Table Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-2)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ClassDefFormat2Marker {
class_range_records_byte_len: usize,
}
impl ClassDefFormat2Marker {
pub fn class_format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn class_range_count_byte_range(&self) -> Range<usize> {
let start = self.class_format_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn class_range_records_byte_range(&self) -> Range<usize> {
let start = self.class_range_count_byte_range().end;
start..start + self.class_range_records_byte_len
}
}
impl MinByteRange for ClassDefFormat2Marker {
fn min_byte_range(&self) -> Range<usize> {
0..self.class_range_records_byte_range().end
}
}
impl<'a> FontRead<'a> for ClassDefFormat2<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
let class_range_count: u16 = cursor.read()?;
let class_range_records_byte_len = (class_range_count as usize)
.checked_mul(ClassRangeRecord::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(class_range_records_byte_len);
cursor.finish(ClassDefFormat2Marker {
class_range_records_byte_len,
})
}
}
/// [Class Definition Table Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-2)
pub type ClassDefFormat2<'a> = TableRef<'a, ClassDefFormat2Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ClassDefFormat2<'a> {
/// Format identifier — format = 2
pub fn class_format(&self) -> u16 {
let range = self.shape.class_format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Number of ClassRangeRecords
pub fn class_range_count(&self) -> u16 {
let range = self.shape.class_range_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of ClassRangeRecords — ordered by startGlyphID
pub fn class_range_records(&self) -> &'a [ClassRangeRecord] {
let range = self.shape.class_range_records_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ClassDefFormat2<'a> {
fn type_name(&self) -> &str {
"ClassDefFormat2"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("class_format", self.class_format())),
1usize => Some(Field::new("class_range_count", self.class_range_count())),
2usize => Some(Field::new(
"class_range_records",
traversal::FieldType::array_of_records(
stringify!(ClassRangeRecord),
self.class_range_records(),
self.offset_data(),
),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ClassDefFormat2<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// Used in [ClassDefFormat2]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct ClassRangeRecord {
/// First glyph ID in the range
pub start_glyph_id: BigEndian<GlyphId16>,
/// Last glyph ID in the range
pub end_glyph_id: BigEndian<GlyphId16>,
/// Applied to all glyphs in the range
pub class: BigEndian<u16>,
}
impl ClassRangeRecord {
/// First glyph ID in the range
pub fn start_glyph_id(&self) -> GlyphId16 {
self.start_glyph_id.get()
}
/// Last glyph ID in the range
pub fn end_glyph_id(&self) -> GlyphId16 {
self.end_glyph_id.get()
}
/// Applied to all glyphs in the range
pub fn class(&self) -> u16 {
self.class.get()
}
}
impl FixedSize for ClassRangeRecord {
const RAW_BYTE_LEN: usize =
GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeRecord<'a> for ClassRangeRecord {
fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
RecordResolver {
name: "ClassRangeRecord",
get_field: Box::new(move |idx, _data| match idx {
0usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
1usize => Some(Field::new("end_glyph_id", self.end_glyph_id())),
2usize => Some(Field::new("class", self.class())),
_ => None,
}),
data,
}
}
}
/// A [Class Definition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table)
#[derive(Clone)]
pub enum ClassDef<'a> {
Format1(ClassDefFormat1<'a>),
Format2(ClassDefFormat2<'a>),
}
impl<'a> ClassDef<'a> {
///Return the `FontData` used to resolve offsets for this table.
pub fn offset_data(&self) -> FontData<'a> {
match self {
Self::Format1(item) => item.offset_data(),
Self::Format2(item) => item.offset_data(),
}
}
/// Format identifier — format = 1
pub fn class_format(&self) -> u16 {
match self {
Self::Format1(item) => item.class_format(),
Self::Format2(item) => item.class_format(),
}
}
}
impl<'a> FontRead<'a> for ClassDef<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let format: u16 = data.read_at(0usize)?;
match format {
ClassDefFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
ClassDefFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
other => Err(ReadError::InvalidFormat(other.into())),
}
}
}
impl MinByteRange for ClassDef<'_> {
fn min_byte_range(&self) -> Range<usize> {
match self {
Self::Format1(item) => item.min_byte_range(),
Self::Format2(item) => item.min_byte_range(),
}
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> ClassDef<'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 ClassDef<'_> {
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 ClassDef<'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)
}
}
/// [Sequence Lookup Record](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-lookup-record)
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct SequenceLookupRecord {
/// Index (zero-based) into the input glyph sequence
pub sequence_index: BigEndian<u16>,
/// Index (zero-based) into the LookupList
pub lookup_list_index: BigEndian<u16>,
}
impl SequenceLookupRecord {
/// Index (zero-based) into the input glyph sequence
pub fn sequence_index(&self) -> u16 {
self.sequence_index.get()
}
/// Index (zero-based) into the LookupList
pub fn lookup_list_index(&self) -> u16 {
self.lookup_list_index.get()
}
}
impl FixedSize for SequenceLookupRecord {
const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeRecord<'a> for SequenceLookupRecord {
fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
RecordResolver {
name: "SequenceLookupRecord",
get_field: Box::new(move |idx, _data| match idx {
0usize => Some(Field::new("sequence_index", self.sequence_index())),
1usize => Some(Field::new("lookup_list_index", self.lookup_list_index())),
_ => None,
}),
data,
}
}
}
impl Format<u16> for SequenceContextFormat1Marker {
const FORMAT: u16 = 1;
}
/// [Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-1-simple-glyph-contexts)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct SequenceContextFormat1Marker {
seq_rule_set_offsets_byte_len: usize,
}
impl SequenceContextFormat1Marker {
pub fn 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.format_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn seq_rule_set_count_byte_range(&self) -> Range<usize> {
let start = self.coverage_offset_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
let start = self.seq_rule_set_count_byte_range().end;
start..start + self.seq_rule_set_offsets_byte_len
}
}
impl MinByteRange for SequenceContextFormat1Marker {
fn min_byte_range(&self) -> Range<usize> {
0..self.seq_rule_set_offsets_byte_range().end
}
}
impl<'a> FontRead<'a> for SequenceContextFormat1<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<Offset16>();
let seq_rule_set_count: u16 = cursor.read()?;
let seq_rule_set_offsets_byte_len = (seq_rule_set_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(seq_rule_set_offsets_byte_len);
cursor.finish(SequenceContextFormat1Marker {
seq_rule_set_offsets_byte_len,
})
}
}
/// [Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-1-simple-glyph-contexts)
pub type SequenceContextFormat1<'a> = TableRef<'a, SequenceContextFormat1Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> SequenceContextFormat1<'a> {
/// Format identifier: format = 1
pub fn format(&self) -> u16 {
let range = self.shape.format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Offset to Coverage table, from beginning of
/// SequenceContextFormat1 table
pub fn coverage_offset(&self) -> Offset16 {
let range = self.shape.coverage_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
let data = self.data;
self.coverage_offset().resolve(data)
}
/// Number of SequenceRuleSet tables
pub fn seq_rule_set_count(&self) -> u16 {
let range = self.shape.seq_rule_set_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of offsets to SequenceRuleSet tables, from beginning of
/// SequenceContextFormat1 table (offsets may be NULL)
pub fn seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
let range = self.shape.seq_rule_set_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`seq_rule_set_offsets`][Self::seq_rule_set_offsets].
pub fn seq_rule_sets(&self) -> ArrayOfNullableOffsets<'a, SequenceRuleSet<'a>, Offset16> {
let data = self.data;
let offsets = self.seq_rule_set_offsets();
ArrayOfNullableOffsets::new(offsets, data, ())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for SequenceContextFormat1<'a> {
fn type_name(&self) -> &str {
"SequenceContextFormat1"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("format", self.format())),
1usize => Some(Field::new(
"coverage_offset",
FieldType::offset(self.coverage_offset(), self.coverage()),
)),
2usize => Some(Field::new("seq_rule_set_count", self.seq_rule_set_count())),
3usize => Some({
let data = self.data;
Field::new(
"seq_rule_set_offsets",
FieldType::array_of_offsets(
better_type_name::<SequenceRuleSet>(),
self.seq_rule_set_offsets(),
move |off| {
let target = off.get().resolve::<SequenceRuleSet>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for SequenceContextFormat1<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// Part of [SequenceContextFormat1]
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct SequenceRuleSetMarker {
seq_rule_offsets_byte_len: usize,
}
impl SequenceRuleSetMarker {
pub fn seq_rule_count_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn seq_rule_offsets_byte_range(&self) -> Range<usize> {
let start = self.seq_rule_count_byte_range().end;
start..start + self.seq_rule_offsets_byte_len
}
}
impl MinByteRange for SequenceRuleSetMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.seq_rule_offsets_byte_range().end
}
}
impl<'a> FontRead<'a> for SequenceRuleSet<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let seq_rule_count: u16 = cursor.read()?;
let seq_rule_offsets_byte_len = (seq_rule_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(seq_rule_offsets_byte_len);
cursor.finish(SequenceRuleSetMarker {
seq_rule_offsets_byte_len,
})
}
}
/// Part of [SequenceContextFormat1]
pub type SequenceRuleSet<'a> = TableRef<'a, SequenceRuleSetMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> SequenceRuleSet<'a> {
/// Number of SequenceRule tables
pub fn seq_rule_count(&self) -> u16 {
let range = self.shape.seq_rule_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of offsets to SequenceRule tables, from beginning of the
/// SequenceRuleSet table
pub fn seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
let range = self.shape.seq_rule_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`seq_rule_offsets`][Self::seq_rule_offsets].
pub fn seq_rules(&self) -> ArrayOfOffsets<'a, SequenceRule<'a>, Offset16> {
let data = self.data;
let offsets = self.seq_rule_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for SequenceRuleSet<'a> {
fn type_name(&self) -> &str {
"SequenceRuleSet"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("seq_rule_count", self.seq_rule_count())),
1usize => Some({
let data = self.data;
Field::new(
"seq_rule_offsets",
FieldType::array_of_offsets(
better_type_name::<SequenceRule>(),
self.seq_rule_offsets(),
move |off| {
let target = off.get().resolve::<SequenceRule>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for SequenceRuleSet<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// Part of [SequenceContextFormat1]
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct SequenceRuleMarker {
input_sequence_byte_len: usize,
seq_lookup_records_byte_len: usize,
}
impl SequenceRuleMarker {
pub fn glyph_count_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
let start = self.glyph_count_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn input_sequence_byte_range(&self) -> Range<usize> {
let start = self.seq_lookup_count_byte_range().end;
start..start + self.input_sequence_byte_len
}
pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
let start = self.input_sequence_byte_range().end;
start..start + self.seq_lookup_records_byte_len
}
}
impl MinByteRange for SequenceRuleMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.seq_lookup_records_byte_range().end
}
}
impl<'a> FontRead<'a> for SequenceRule<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let glyph_count: u16 = cursor.read()?;
let seq_lookup_count: u16 = cursor.read()?;
let input_sequence_byte_len = (transforms::subtract(glyph_count, 1_usize))
.checked_mul(GlyphId16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(input_sequence_byte_len);
let seq_lookup_records_byte_len = (seq_lookup_count as usize)
.checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(seq_lookup_records_byte_len);
cursor.finish(SequenceRuleMarker {
input_sequence_byte_len,
seq_lookup_records_byte_len,
})
}
}
/// Part of [SequenceContextFormat1]
pub type SequenceRule<'a> = TableRef<'a, SequenceRuleMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> SequenceRule<'a> {
/// Number of glyphs in the input glyph sequence
pub fn glyph_count(&self) -> u16 {
let range = self.shape.glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Number of SequenceLookupRecords
pub fn seq_lookup_count(&self) -> u16 {
let range = self.shape.seq_lookup_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of input glyph IDs—starting with the second glyph
pub fn input_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
let range = self.shape.input_sequence_byte_range();
self.data.read_array(range).unwrap()
}
/// Array of Sequence lookup records
pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
let range = self.shape.seq_lookup_records_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for SequenceRule<'a> {
fn type_name(&self) -> &str {
"SequenceRule"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("glyph_count", self.glyph_count())),
1usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
2usize => Some(Field::new("input_sequence", self.input_sequence())),
3usize => Some(Field::new(
"seq_lookup_records",
traversal::FieldType::array_of_records(
stringify!(SequenceLookupRecord),
self.seq_lookup_records(),
self.offset_data(),
),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for SequenceRule<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for SequenceContextFormat2Marker {
const FORMAT: u16 = 2;
}
/// [Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-2-class-based-glyph-contexts)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct SequenceContextFormat2Marker {
class_seq_rule_set_offsets_byte_len: usize,
}
impl SequenceContextFormat2Marker {
pub fn 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.format_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn class_def_offset_byte_range(&self) -> Range<usize> {
let start = self.coverage_offset_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn class_seq_rule_set_count_byte_range(&self) -> Range<usize> {
let start = self.class_def_offset_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn class_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
let start = self.class_seq_rule_set_count_byte_range().end;
start..start + self.class_seq_rule_set_offsets_byte_len
}
}
impl MinByteRange for SequenceContextFormat2Marker {
fn min_byte_range(&self) -> Range<usize> {
0..self.class_seq_rule_set_offsets_byte_range().end
}
}
impl<'a> FontRead<'a> for SequenceContextFormat2<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<Offset16>();
cursor.advance::<Offset16>();
let class_seq_rule_set_count: u16 = cursor.read()?;
let class_seq_rule_set_offsets_byte_len = (class_seq_rule_set_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(class_seq_rule_set_offsets_byte_len);
cursor.finish(SequenceContextFormat2Marker {
class_seq_rule_set_offsets_byte_len,
})
}
}
/// [Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-2-class-based-glyph-contexts)
pub type SequenceContextFormat2<'a> = TableRef<'a, SequenceContextFormat2Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> SequenceContextFormat2<'a> {
/// Format identifier: format = 2
pub fn format(&self) -> u16 {
let range = self.shape.format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Offset to Coverage table, from beginning of
/// SequenceContextFormat2 table
pub fn coverage_offset(&self) -> Offset16 {
let range = self.shape.coverage_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
let data = self.data;
self.coverage_offset().resolve(data)
}
/// Offset to ClassDef table, from beginning of
/// SequenceContextFormat2 table
pub fn class_def_offset(&self) -> Offset16 {
let range = self.shape.class_def_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Attempt to resolve [`class_def_offset`][Self::class_def_offset].
pub fn class_def(&self) -> Result<ClassDef<'a>, ReadError> {
let data = self.data;
self.class_def_offset().resolve(data)
}
/// Number of ClassSequenceRuleSet tables
pub fn class_seq_rule_set_count(&self) -> u16 {
let range = self.shape.class_seq_rule_set_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of offsets to ClassSequenceRuleSet tables, from beginning
/// of SequenceContextFormat2 table (may be NULL)
pub fn class_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
let range = self.shape.class_seq_rule_set_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`class_seq_rule_set_offsets`][Self::class_seq_rule_set_offsets].
pub fn class_seq_rule_sets(
&self,
) -> ArrayOfNullableOffsets<'a, ClassSequenceRuleSet<'a>, Offset16> {
let data = self.data;
let offsets = self.class_seq_rule_set_offsets();
ArrayOfNullableOffsets::new(offsets, data, ())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for SequenceContextFormat2<'a> {
fn type_name(&self) -> &str {
"SequenceContextFormat2"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("format", self.format())),
1usize => Some(Field::new(
"coverage_offset",
FieldType::offset(self.coverage_offset(), self.coverage()),
)),
2usize => Some(Field::new(
"class_def_offset",
FieldType::offset(self.class_def_offset(), self.class_def()),
)),
3usize => Some(Field::new(
"class_seq_rule_set_count",
self.class_seq_rule_set_count(),
)),
4usize => Some({
let data = self.data;
Field::new(
"class_seq_rule_set_offsets",
FieldType::array_of_offsets(
better_type_name::<ClassSequenceRuleSet>(),
self.class_seq_rule_set_offsets(),
move |off| {
let target = off.get().resolve::<ClassSequenceRuleSet>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for SequenceContextFormat2<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// Part of [SequenceContextFormat2]
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ClassSequenceRuleSetMarker {
class_seq_rule_offsets_byte_len: usize,
}
impl ClassSequenceRuleSetMarker {
pub fn class_seq_rule_count_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn class_seq_rule_offsets_byte_range(&self) -> Range<usize> {
let start = self.class_seq_rule_count_byte_range().end;
start..start + self.class_seq_rule_offsets_byte_len
}
}
impl MinByteRange for ClassSequenceRuleSetMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.class_seq_rule_offsets_byte_range().end
}
}
impl<'a> FontRead<'a> for ClassSequenceRuleSet<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let class_seq_rule_count: u16 = cursor.read()?;
let class_seq_rule_offsets_byte_len = (class_seq_rule_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(class_seq_rule_offsets_byte_len);
cursor.finish(ClassSequenceRuleSetMarker {
class_seq_rule_offsets_byte_len,
})
}
}
/// Part of [SequenceContextFormat2]
pub type ClassSequenceRuleSet<'a> = TableRef<'a, ClassSequenceRuleSetMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ClassSequenceRuleSet<'a> {
/// Number of ClassSequenceRule tables
pub fn class_seq_rule_count(&self) -> u16 {
let range = self.shape.class_seq_rule_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of offsets to ClassSequenceRule tables, from beginning of
/// ClassSequenceRuleSet table
pub fn class_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
let range = self.shape.class_seq_rule_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`class_seq_rule_offsets`][Self::class_seq_rule_offsets].
pub fn class_seq_rules(&self) -> ArrayOfOffsets<'a, ClassSequenceRule<'a>, Offset16> {
let data = self.data;
let offsets = self.class_seq_rule_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ClassSequenceRuleSet<'a> {
fn type_name(&self) -> &str {
"ClassSequenceRuleSet"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new(
"class_seq_rule_count",
self.class_seq_rule_count(),
)),
1usize => Some({
let data = self.data;
Field::new(
"class_seq_rule_offsets",
FieldType::array_of_offsets(
better_type_name::<ClassSequenceRule>(),
self.class_seq_rule_offsets(),
move |off| {
let target = off.get().resolve::<ClassSequenceRule>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ClassSequenceRuleSet<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// Part of [SequenceContextFormat2]
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ClassSequenceRuleMarker {
input_sequence_byte_len: usize,
seq_lookup_records_byte_len: usize,
}
impl ClassSequenceRuleMarker {
pub fn glyph_count_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
let start = self.glyph_count_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn input_sequence_byte_range(&self) -> Range<usize> {
let start = self.seq_lookup_count_byte_range().end;
start..start + self.input_sequence_byte_len
}
pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
let start = self.input_sequence_byte_range().end;
start..start + self.seq_lookup_records_byte_len
}
}
impl MinByteRange for ClassSequenceRuleMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.seq_lookup_records_byte_range().end
}
}
impl<'a> FontRead<'a> for ClassSequenceRule<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let glyph_count: u16 = cursor.read()?;
let seq_lookup_count: u16 = cursor.read()?;
let input_sequence_byte_len = (transforms::subtract(glyph_count, 1_usize))
.checked_mul(u16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(input_sequence_byte_len);
let seq_lookup_records_byte_len = (seq_lookup_count as usize)
.checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(seq_lookup_records_byte_len);
cursor.finish(ClassSequenceRuleMarker {
input_sequence_byte_len,
seq_lookup_records_byte_len,
})
}
}
/// Part of [SequenceContextFormat2]
pub type ClassSequenceRule<'a> = TableRef<'a, ClassSequenceRuleMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ClassSequenceRule<'a> {
/// Number of glyphs to be matched
pub fn glyph_count(&self) -> u16 {
let range = self.shape.glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Number of SequenceLookupRecords
pub fn seq_lookup_count(&self) -> u16 {
let range = self.shape.seq_lookup_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Sequence of classes to be matched to the input glyph sequence,
/// beginning with the second glyph position
pub fn input_sequence(&self) -> &'a [BigEndian<u16>] {
let range = self.shape.input_sequence_byte_range();
self.data.read_array(range).unwrap()
}
/// Array of SequenceLookupRecords
pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
let range = self.shape.seq_lookup_records_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ClassSequenceRule<'a> {
fn type_name(&self) -> &str {
"ClassSequenceRule"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("glyph_count", self.glyph_count())),
1usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
2usize => Some(Field::new("input_sequence", self.input_sequence())),
3usize => Some(Field::new(
"seq_lookup_records",
traversal::FieldType::array_of_records(
stringify!(SequenceLookupRecord),
self.seq_lookup_records(),
self.offset_data(),
),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ClassSequenceRule<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for SequenceContextFormat3Marker {
const FORMAT: u16 = 3;
}
/// [Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-3-coverage-based-glyph-contexts)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct SequenceContextFormat3Marker {
coverage_offsets_byte_len: usize,
seq_lookup_records_byte_len: usize,
}
impl SequenceContextFormat3Marker {
pub fn format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn glyph_count_byte_range(&self) -> Range<usize> {
let start = self.format_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
let start = self.glyph_count_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn coverage_offsets_byte_range(&self) -> Range<usize> {
let start = self.seq_lookup_count_byte_range().end;
start..start + self.coverage_offsets_byte_len
}
pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
let start = self.coverage_offsets_byte_range().end;
start..start + self.seq_lookup_records_byte_len
}
}
impl MinByteRange for SequenceContextFormat3Marker {
fn min_byte_range(&self) -> Range<usize> {
0..self.seq_lookup_records_byte_range().end
}
}
impl<'a> FontRead<'a> for SequenceContextFormat3<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
let glyph_count: u16 = cursor.read()?;
let seq_lookup_count: u16 = cursor.read()?;
let coverage_offsets_byte_len = (glyph_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(coverage_offsets_byte_len);
let seq_lookup_records_byte_len = (seq_lookup_count as usize)
.checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(seq_lookup_records_byte_len);
cursor.finish(SequenceContextFormat3Marker {
coverage_offsets_byte_len,
seq_lookup_records_byte_len,
})
}
}
/// [Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-3-coverage-based-glyph-contexts)
pub type SequenceContextFormat3<'a> = TableRef<'a, SequenceContextFormat3Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> SequenceContextFormat3<'a> {
/// Format identifier: format = 3
pub fn format(&self) -> u16 {
let range = self.shape.format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Number of glyphs in the input sequence
pub fn glyph_count(&self) -> u16 {
let range = self.shape.glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Number of SequenceLookupRecords
pub fn seq_lookup_count(&self) -> u16 {
let range = self.shape.seq_lookup_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of offsets to Coverage tables, from beginning of
/// SequenceContextFormat3 subtable
pub fn coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
let range = self.shape.coverage_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`coverage_offsets`][Self::coverage_offsets].
pub fn coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
let data = self.data;
let offsets = self.coverage_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
/// Array of SequenceLookupRecords
pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
let range = self.shape.seq_lookup_records_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for SequenceContextFormat3<'a> {
fn type_name(&self) -> &str {
"SequenceContextFormat3"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("format", self.format())),
1usize => Some(Field::new("glyph_count", self.glyph_count())),
2usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
3usize => Some({
let data = self.data;
Field::new(
"coverage_offsets",
FieldType::array_of_offsets(
better_type_name::<CoverageTable>(),
self.coverage_offsets(),
move |off| {
let target = off.get().resolve::<CoverageTable>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
4usize => Some(Field::new(
"seq_lookup_records",
traversal::FieldType::array_of_records(
stringify!(SequenceLookupRecord),
self.seq_lookup_records(),
self.offset_data(),
),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for SequenceContextFormat3<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
#[derive(Clone)]
pub enum SequenceContext<'a> {
Format1(SequenceContextFormat1<'a>),
Format2(SequenceContextFormat2<'a>),
Format3(SequenceContextFormat3<'a>),
}
impl<'a> SequenceContext<'a> {
///Return the `FontData` used to resolve offsets for this table.
pub fn offset_data(&self) -> FontData<'a> {
match self {
Self::Format1(item) => item.offset_data(),
Self::Format2(item) => item.offset_data(),
Self::Format3(item) => item.offset_data(),
}
}
/// Format identifier: format = 1
pub fn format(&self) -> u16 {
match self {
Self::Format1(item) => item.format(),
Self::Format2(item) => item.format(),
Self::Format3(item) => item.format(),
}
}
}
impl<'a> FontRead<'a> for SequenceContext<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let format: u16 = data.read_at(0usize)?;
match format {
SequenceContextFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
SequenceContextFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
SequenceContextFormat3Marker::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
other => Err(ReadError::InvalidFormat(other.into())),
}
}
}
impl MinByteRange for SequenceContext<'_> {
fn min_byte_range(&self) -> Range<usize> {
match self {
Self::Format1(item) => item.min_byte_range(),
Self::Format2(item) => item.min_byte_range(),
Self::Format3(item) => item.min_byte_range(),
}
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SequenceContext<'a> {
fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
match self {
Self::Format1(table) => table,
Self::Format2(table) => table,
Self::Format3(table) => table,
}
}
}
#[cfg(feature = "experimental_traverse")]
impl std::fmt::Debug for SequenceContext<'_> {
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 SequenceContext<'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 ChainedSequenceContextFormat1Marker {
const FORMAT: u16 = 1;
}
/// [Chained Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-1-simple-glyph-contexts)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ChainedSequenceContextFormat1Marker {
chained_seq_rule_set_offsets_byte_len: usize,
}
impl ChainedSequenceContextFormat1Marker {
pub fn 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.format_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn chained_seq_rule_set_count_byte_range(&self) -> Range<usize> {
let start = self.coverage_offset_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn chained_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
let start = self.chained_seq_rule_set_count_byte_range().end;
start..start + self.chained_seq_rule_set_offsets_byte_len
}
}
impl MinByteRange for ChainedSequenceContextFormat1Marker {
fn min_byte_range(&self) -> Range<usize> {
0..self.chained_seq_rule_set_offsets_byte_range().end
}
}
impl<'a> FontRead<'a> for ChainedSequenceContextFormat1<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<Offset16>();
let chained_seq_rule_set_count: u16 = cursor.read()?;
let chained_seq_rule_set_offsets_byte_len = (chained_seq_rule_set_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(chained_seq_rule_set_offsets_byte_len);
cursor.finish(ChainedSequenceContextFormat1Marker {
chained_seq_rule_set_offsets_byte_len,
})
}
}
/// [Chained Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-1-simple-glyph-contexts)
pub type ChainedSequenceContextFormat1<'a> = TableRef<'a, ChainedSequenceContextFormat1Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ChainedSequenceContextFormat1<'a> {
/// Format identifier: format = 1
pub fn format(&self) -> u16 {
let range = self.shape.format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Offset to Coverage table, from beginning of
/// ChainSequenceContextFormat1 table
pub fn coverage_offset(&self) -> Offset16 {
let range = self.shape.coverage_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
let data = self.data;
self.coverage_offset().resolve(data)
}
/// Number of ChainedSequenceRuleSet tables
pub fn chained_seq_rule_set_count(&self) -> u16 {
let range = self.shape.chained_seq_rule_set_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of offsets to ChainedSeqRuleSet tables, from beginning of
/// ChainedSequenceContextFormat1 table (may be NULL)
pub fn chained_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
let range = self.shape.chained_seq_rule_set_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`chained_seq_rule_set_offsets`][Self::chained_seq_rule_set_offsets].
pub fn chained_seq_rule_sets(
&self,
) -> ArrayOfNullableOffsets<'a, ChainedSequenceRuleSet<'a>, Offset16> {
let data = self.data;
let offsets = self.chained_seq_rule_set_offsets();
ArrayOfNullableOffsets::new(offsets, data, ())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ChainedSequenceContextFormat1<'a> {
fn type_name(&self) -> &str {
"ChainedSequenceContextFormat1"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("format", self.format())),
1usize => Some(Field::new(
"coverage_offset",
FieldType::offset(self.coverage_offset(), self.coverage()),
)),
2usize => Some(Field::new(
"chained_seq_rule_set_count",
self.chained_seq_rule_set_count(),
)),
3usize => Some({
let data = self.data;
Field::new(
"chained_seq_rule_set_offsets",
FieldType::array_of_offsets(
better_type_name::<ChainedSequenceRuleSet>(),
self.chained_seq_rule_set_offsets(),
move |off| {
let target = off.get().resolve::<ChainedSequenceRuleSet>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ChainedSequenceContextFormat1<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// Part of [ChainedSequenceContextFormat1]
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ChainedSequenceRuleSetMarker {
chained_seq_rule_offsets_byte_len: usize,
}
impl ChainedSequenceRuleSetMarker {
pub fn chained_seq_rule_count_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn chained_seq_rule_offsets_byte_range(&self) -> Range<usize> {
let start = self.chained_seq_rule_count_byte_range().end;
start..start + self.chained_seq_rule_offsets_byte_len
}
}
impl MinByteRange for ChainedSequenceRuleSetMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.chained_seq_rule_offsets_byte_range().end
}
}
impl<'a> FontRead<'a> for ChainedSequenceRuleSet<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let chained_seq_rule_count: u16 = cursor.read()?;
let chained_seq_rule_offsets_byte_len = (chained_seq_rule_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(chained_seq_rule_offsets_byte_len);
cursor.finish(ChainedSequenceRuleSetMarker {
chained_seq_rule_offsets_byte_len,
})
}
}
/// Part of [ChainedSequenceContextFormat1]
pub type ChainedSequenceRuleSet<'a> = TableRef<'a, ChainedSequenceRuleSetMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ChainedSequenceRuleSet<'a> {
/// Number of ChainedSequenceRule tables
pub fn chained_seq_rule_count(&self) -> u16 {
let range = self.shape.chained_seq_rule_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of offsets to ChainedSequenceRule tables, from beginning
/// of ChainedSequenceRuleSet table
pub fn chained_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
let range = self.shape.chained_seq_rule_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`chained_seq_rule_offsets`][Self::chained_seq_rule_offsets].
pub fn chained_seq_rules(&self) -> ArrayOfOffsets<'a, ChainedSequenceRule<'a>, Offset16> {
let data = self.data;
let offsets = self.chained_seq_rule_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ChainedSequenceRuleSet<'a> {
fn type_name(&self) -> &str {
"ChainedSequenceRuleSet"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new(
"chained_seq_rule_count",
self.chained_seq_rule_count(),
)),
1usize => Some({
let data = self.data;
Field::new(
"chained_seq_rule_offsets",
FieldType::array_of_offsets(
better_type_name::<ChainedSequenceRule>(),
self.chained_seq_rule_offsets(),
move |off| {
let target = off.get().resolve::<ChainedSequenceRule>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ChainedSequenceRuleSet<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// Part of [ChainedSequenceContextFormat1]
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ChainedSequenceRuleMarker {
backtrack_sequence_byte_len: usize,
input_sequence_byte_len: usize,
lookahead_sequence_byte_len: usize,
seq_lookup_records_byte_len: usize,
}
impl ChainedSequenceRuleMarker {
pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn backtrack_sequence_byte_range(&self) -> Range<usize> {
let start = self.backtrack_glyph_count_byte_range().end;
start..start + self.backtrack_sequence_byte_len
}
pub fn input_glyph_count_byte_range(&self) -> Range<usize> {
let start = self.backtrack_sequence_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn input_sequence_byte_range(&self) -> Range<usize> {
let start = self.input_glyph_count_byte_range().end;
start..start + self.input_sequence_byte_len
}
pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
let start = self.input_sequence_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn lookahead_sequence_byte_range(&self) -> Range<usize> {
let start = self.lookahead_glyph_count_byte_range().end;
start..start + self.lookahead_sequence_byte_len
}
pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
let start = self.lookahead_sequence_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
let start = self.seq_lookup_count_byte_range().end;
start..start + self.seq_lookup_records_byte_len
}
}
impl MinByteRange for ChainedSequenceRuleMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.seq_lookup_records_byte_range().end
}
}
impl<'a> FontRead<'a> for ChainedSequenceRule<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let backtrack_glyph_count: u16 = cursor.read()?;
let backtrack_sequence_byte_len = (backtrack_glyph_count as usize)
.checked_mul(GlyphId16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(backtrack_sequence_byte_len);
let input_glyph_count: u16 = cursor.read()?;
let input_sequence_byte_len = (transforms::subtract(input_glyph_count, 1_usize))
.checked_mul(GlyphId16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(input_sequence_byte_len);
let lookahead_glyph_count: u16 = cursor.read()?;
let lookahead_sequence_byte_len = (lookahead_glyph_count as usize)
.checked_mul(GlyphId16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(lookahead_sequence_byte_len);
let seq_lookup_count: u16 = cursor.read()?;
let seq_lookup_records_byte_len = (seq_lookup_count as usize)
.checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(seq_lookup_records_byte_len);
cursor.finish(ChainedSequenceRuleMarker {
backtrack_sequence_byte_len,
input_sequence_byte_len,
lookahead_sequence_byte_len,
seq_lookup_records_byte_len,
})
}
}
/// Part of [ChainedSequenceContextFormat1]
pub type ChainedSequenceRule<'a> = TableRef<'a, ChainedSequenceRuleMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ChainedSequenceRule<'a> {
/// Number of glyphs in the backtrack sequence
pub fn backtrack_glyph_count(&self) -> u16 {
let range = self.shape.backtrack_glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of backtrack glyph IDs
pub fn backtrack_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
let range = self.shape.backtrack_sequence_byte_range();
self.data.read_array(range).unwrap()
}
/// Number of glyphs in the input sequence
pub fn input_glyph_count(&self) -> u16 {
let range = self.shape.input_glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of input glyph IDs—start with second glyph
pub fn input_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
let range = self.shape.input_sequence_byte_range();
self.data.read_array(range).unwrap()
}
/// Number of glyphs in the lookahead sequence
pub fn lookahead_glyph_count(&self) -> u16 {
let range = self.shape.lookahead_glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of lookahead glyph IDs
pub fn lookahead_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
let range = self.shape.lookahead_sequence_byte_range();
self.data.read_array(range).unwrap()
}
/// Number of SequenceLookupRecords
pub fn seq_lookup_count(&self) -> u16 {
let range = self.shape.seq_lookup_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of SequenceLookupRecords
pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
let range = self.shape.seq_lookup_records_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ChainedSequenceRule<'a> {
fn type_name(&self) -> &str {
"ChainedSequenceRule"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new(
"backtrack_glyph_count",
self.backtrack_glyph_count(),
)),
1usize => Some(Field::new("backtrack_sequence", self.backtrack_sequence())),
2usize => Some(Field::new("input_glyph_count", self.input_glyph_count())),
3usize => Some(Field::new("input_sequence", self.input_sequence())),
4usize => Some(Field::new(
"lookahead_glyph_count",
self.lookahead_glyph_count(),
)),
5usize => Some(Field::new("lookahead_sequence", self.lookahead_sequence())),
6usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
7usize => Some(Field::new(
"seq_lookup_records",
traversal::FieldType::array_of_records(
stringify!(SequenceLookupRecord),
self.seq_lookup_records(),
self.offset_data(),
),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ChainedSequenceRule<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for ChainedSequenceContextFormat2Marker {
const FORMAT: u16 = 2;
}
/// [Chained Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-2-class-based-glyph-contexts)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ChainedSequenceContextFormat2Marker {
chained_class_seq_rule_set_offsets_byte_len: usize,
}
impl ChainedSequenceContextFormat2Marker {
pub fn 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.format_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn backtrack_class_def_offset_byte_range(&self) -> Range<usize> {
let start = self.coverage_offset_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn input_class_def_offset_byte_range(&self) -> Range<usize> {
let start = self.backtrack_class_def_offset_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn lookahead_class_def_offset_byte_range(&self) -> Range<usize> {
let start = self.input_class_def_offset_byte_range().end;
start..start + Offset16::RAW_BYTE_LEN
}
pub fn chained_class_seq_rule_set_count_byte_range(&self) -> Range<usize> {
let start = self.lookahead_class_def_offset_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn chained_class_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
let start = self.chained_class_seq_rule_set_count_byte_range().end;
start..start + self.chained_class_seq_rule_set_offsets_byte_len
}
}
impl MinByteRange for ChainedSequenceContextFormat2Marker {
fn min_byte_range(&self) -> Range<usize> {
0..self.chained_class_seq_rule_set_offsets_byte_range().end
}
}
impl<'a> FontRead<'a> for ChainedSequenceContextFormat2<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<Offset16>();
cursor.advance::<Offset16>();
cursor.advance::<Offset16>();
cursor.advance::<Offset16>();
let chained_class_seq_rule_set_count: u16 = cursor.read()?;
let chained_class_seq_rule_set_offsets_byte_len = (chained_class_seq_rule_set_count
as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(chained_class_seq_rule_set_offsets_byte_len);
cursor.finish(ChainedSequenceContextFormat2Marker {
chained_class_seq_rule_set_offsets_byte_len,
})
}
}
/// [Chained Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-2-class-based-glyph-contexts)
pub type ChainedSequenceContextFormat2<'a> = TableRef<'a, ChainedSequenceContextFormat2Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ChainedSequenceContextFormat2<'a> {
/// Format identifier: format = 2
pub fn format(&self) -> u16 {
let range = self.shape.format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Offset to Coverage table, from beginning of
/// ChainedSequenceContextFormat2 table
pub fn coverage_offset(&self) -> Offset16 {
let range = self.shape.coverage_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
let data = self.data;
self.coverage_offset().resolve(data)
}
/// Offset to ClassDef table containing backtrack sequence context,
/// from beginning of ChainedSequenceContextFormat2 table
pub fn backtrack_class_def_offset(&self) -> Offset16 {
let range = self.shape.backtrack_class_def_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Attempt to resolve [`backtrack_class_def_offset`][Self::backtrack_class_def_offset].
pub fn backtrack_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
let data = self.data;
self.backtrack_class_def_offset().resolve(data)
}
/// Offset to ClassDef table containing input sequence context,
/// from beginning of ChainedSequenceContextFormat2 table
pub fn input_class_def_offset(&self) -> Offset16 {
let range = self.shape.input_class_def_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Attempt to resolve [`input_class_def_offset`][Self::input_class_def_offset].
pub fn input_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
let data = self.data;
self.input_class_def_offset().resolve(data)
}
/// Offset to ClassDef table containing lookahead sequence context,
/// from beginning of ChainedSequenceContextFormat2 table
pub fn lookahead_class_def_offset(&self) -> Offset16 {
let range = self.shape.lookahead_class_def_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Attempt to resolve [`lookahead_class_def_offset`][Self::lookahead_class_def_offset].
pub fn lookahead_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
let data = self.data;
self.lookahead_class_def_offset().resolve(data)
}
/// Number of ChainedClassSequenceRuleSet tables
pub fn chained_class_seq_rule_set_count(&self) -> u16 {
let range = self.shape.chained_class_seq_rule_set_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of offsets to ChainedClassSequenceRuleSet tables, from
/// beginning of ChainedSequenceContextFormat2 table (may be NULL)
pub fn chained_class_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
let range = self.shape.chained_class_seq_rule_set_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`chained_class_seq_rule_set_offsets`][Self::chained_class_seq_rule_set_offsets].
pub fn chained_class_seq_rule_sets(
&self,
) -> ArrayOfNullableOffsets<'a, ChainedClassSequenceRuleSet<'a>, Offset16> {
let data = self.data;
let offsets = self.chained_class_seq_rule_set_offsets();
ArrayOfNullableOffsets::new(offsets, data, ())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ChainedSequenceContextFormat2<'a> {
fn type_name(&self) -> &str {
"ChainedSequenceContextFormat2"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("format", self.format())),
1usize => Some(Field::new(
"coverage_offset",
FieldType::offset(self.coverage_offset(), self.coverage()),
)),
2usize => Some(Field::new(
"backtrack_class_def_offset",
FieldType::offset(
self.backtrack_class_def_offset(),
self.backtrack_class_def(),
),
)),
3usize => Some(Field::new(
"input_class_def_offset",
FieldType::offset(self.input_class_def_offset(), self.input_class_def()),
)),
4usize => Some(Field::new(
"lookahead_class_def_offset",
FieldType::offset(
self.lookahead_class_def_offset(),
self.lookahead_class_def(),
),
)),
5usize => Some(Field::new(
"chained_class_seq_rule_set_count",
self.chained_class_seq_rule_set_count(),
)),
6usize => Some({
let data = self.data;
Field::new(
"chained_class_seq_rule_set_offsets",
FieldType::array_of_offsets(
better_type_name::<ChainedClassSequenceRuleSet>(),
self.chained_class_seq_rule_set_offsets(),
move |off| {
let target = off.get().resolve::<ChainedClassSequenceRuleSet>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ChainedSequenceContextFormat2<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// Part of [ChainedSequenceContextFormat2]
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ChainedClassSequenceRuleSetMarker {
chained_class_seq_rule_offsets_byte_len: usize,
}
impl ChainedClassSequenceRuleSetMarker {
pub fn chained_class_seq_rule_count_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn chained_class_seq_rule_offsets_byte_range(&self) -> Range<usize> {
let start = self.chained_class_seq_rule_count_byte_range().end;
start..start + self.chained_class_seq_rule_offsets_byte_len
}
}
impl MinByteRange for ChainedClassSequenceRuleSetMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.chained_class_seq_rule_offsets_byte_range().end
}
}
impl<'a> FontRead<'a> for ChainedClassSequenceRuleSet<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let chained_class_seq_rule_count: u16 = cursor.read()?;
let chained_class_seq_rule_offsets_byte_len = (chained_class_seq_rule_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(chained_class_seq_rule_offsets_byte_len);
cursor.finish(ChainedClassSequenceRuleSetMarker {
chained_class_seq_rule_offsets_byte_len,
})
}
}
/// Part of [ChainedSequenceContextFormat2]
pub type ChainedClassSequenceRuleSet<'a> = TableRef<'a, ChainedClassSequenceRuleSetMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ChainedClassSequenceRuleSet<'a> {
/// Number of ChainedClassSequenceRule tables
pub fn chained_class_seq_rule_count(&self) -> u16 {
let range = self.shape.chained_class_seq_rule_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of offsets to ChainedClassSequenceRule tables, from
/// beginning of ChainedClassSequenceRuleSet
pub fn chained_class_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
let range = self.shape.chained_class_seq_rule_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`chained_class_seq_rule_offsets`][Self::chained_class_seq_rule_offsets].
pub fn chained_class_seq_rules(
&self,
) -> ArrayOfOffsets<'a, ChainedClassSequenceRule<'a>, Offset16> {
let data = self.data;
let offsets = self.chained_class_seq_rule_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ChainedClassSequenceRuleSet<'a> {
fn type_name(&self) -> &str {
"ChainedClassSequenceRuleSet"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new(
"chained_class_seq_rule_count",
self.chained_class_seq_rule_count(),
)),
1usize => Some({
let data = self.data;
Field::new(
"chained_class_seq_rule_offsets",
FieldType::array_of_offsets(
better_type_name::<ChainedClassSequenceRule>(),
self.chained_class_seq_rule_offsets(),
move |off| {
let target = off.get().resolve::<ChainedClassSequenceRule>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ChainedClassSequenceRuleSet<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// Part of [ChainedSequenceContextFormat2]
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ChainedClassSequenceRuleMarker {
backtrack_sequence_byte_len: usize,
input_sequence_byte_len: usize,
lookahead_sequence_byte_len: usize,
seq_lookup_records_byte_len: usize,
}
impl ChainedClassSequenceRuleMarker {
pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn backtrack_sequence_byte_range(&self) -> Range<usize> {
let start = self.backtrack_glyph_count_byte_range().end;
start..start + self.backtrack_sequence_byte_len
}
pub fn input_glyph_count_byte_range(&self) -> Range<usize> {
let start = self.backtrack_sequence_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn input_sequence_byte_range(&self) -> Range<usize> {
let start = self.input_glyph_count_byte_range().end;
start..start + self.input_sequence_byte_len
}
pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
let start = self.input_sequence_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn lookahead_sequence_byte_range(&self) -> Range<usize> {
let start = self.lookahead_glyph_count_byte_range().end;
start..start + self.lookahead_sequence_byte_len
}
pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
let start = self.lookahead_sequence_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
let start = self.seq_lookup_count_byte_range().end;
start..start + self.seq_lookup_records_byte_len
}
}
impl MinByteRange for ChainedClassSequenceRuleMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.seq_lookup_records_byte_range().end
}
}
impl<'a> FontRead<'a> for ChainedClassSequenceRule<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let backtrack_glyph_count: u16 = cursor.read()?;
let backtrack_sequence_byte_len = (backtrack_glyph_count as usize)
.checked_mul(u16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(backtrack_sequence_byte_len);
let input_glyph_count: u16 = cursor.read()?;
let input_sequence_byte_len = (transforms::subtract(input_glyph_count, 1_usize))
.checked_mul(u16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(input_sequence_byte_len);
let lookahead_glyph_count: u16 = cursor.read()?;
let lookahead_sequence_byte_len = (lookahead_glyph_count as usize)
.checked_mul(u16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(lookahead_sequence_byte_len);
let seq_lookup_count: u16 = cursor.read()?;
let seq_lookup_records_byte_len = (seq_lookup_count as usize)
.checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(seq_lookup_records_byte_len);
cursor.finish(ChainedClassSequenceRuleMarker {
backtrack_sequence_byte_len,
input_sequence_byte_len,
lookahead_sequence_byte_len,
seq_lookup_records_byte_len,
})
}
}
/// Part of [ChainedSequenceContextFormat2]
pub type ChainedClassSequenceRule<'a> = TableRef<'a, ChainedClassSequenceRuleMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ChainedClassSequenceRule<'a> {
/// Number of glyphs in the backtrack sequence
pub fn backtrack_glyph_count(&self) -> u16 {
let range = self.shape.backtrack_glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of backtrack-sequence classes
pub fn backtrack_sequence(&self) -> &'a [BigEndian<u16>] {
let range = self.shape.backtrack_sequence_byte_range();
self.data.read_array(range).unwrap()
}
/// Total number of glyphs in the input sequence
pub fn input_glyph_count(&self) -> u16 {
let range = self.shape.input_glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of input sequence classes, beginning with the second
/// glyph position
pub fn input_sequence(&self) -> &'a [BigEndian<u16>] {
let range = self.shape.input_sequence_byte_range();
self.data.read_array(range).unwrap()
}
/// Number of glyphs in the lookahead sequence
pub fn lookahead_glyph_count(&self) -> u16 {
let range = self.shape.lookahead_glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of lookahead-sequence classes
pub fn lookahead_sequence(&self) -> &'a [BigEndian<u16>] {
let range = self.shape.lookahead_sequence_byte_range();
self.data.read_array(range).unwrap()
}
/// Number of SequenceLookupRecords
pub fn seq_lookup_count(&self) -> u16 {
let range = self.shape.seq_lookup_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of SequenceLookupRecords
pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
let range = self.shape.seq_lookup_records_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ChainedClassSequenceRule<'a> {
fn type_name(&self) -> &str {
"ChainedClassSequenceRule"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new(
"backtrack_glyph_count",
self.backtrack_glyph_count(),
)),
1usize => Some(Field::new("backtrack_sequence", self.backtrack_sequence())),
2usize => Some(Field::new("input_glyph_count", self.input_glyph_count())),
3usize => Some(Field::new("input_sequence", self.input_sequence())),
4usize => Some(Field::new(
"lookahead_glyph_count",
self.lookahead_glyph_count(),
)),
5usize => Some(Field::new("lookahead_sequence", self.lookahead_sequence())),
6usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
7usize => Some(Field::new(
"seq_lookup_records",
traversal::FieldType::array_of_records(
stringify!(SequenceLookupRecord),
self.seq_lookup_records(),
self.offset_data(),
),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ChainedClassSequenceRule<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for ChainedSequenceContextFormat3Marker {
const FORMAT: u16 = 3;
}
/// [Chained Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-3-coverage-based-glyph-contexts)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ChainedSequenceContextFormat3Marker {
backtrack_coverage_offsets_byte_len: usize,
input_coverage_offsets_byte_len: usize,
lookahead_coverage_offsets_byte_len: usize,
seq_lookup_records_byte_len: usize,
}
impl ChainedSequenceContextFormat3Marker {
pub fn format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
let start = self.format_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 input_glyph_count_byte_range(&self) -> Range<usize> {
let start = self.backtrack_coverage_offsets_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn input_coverage_offsets_byte_range(&self) -> Range<usize> {
let start = self.input_glyph_count_byte_range().end;
start..start + self.input_coverage_offsets_byte_len
}
pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
let start = self.input_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 seq_lookup_count_byte_range(&self) -> Range<usize> {
let start = self.lookahead_coverage_offsets_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
let start = self.seq_lookup_count_byte_range().end;
start..start + self.seq_lookup_records_byte_len
}
}
impl MinByteRange for ChainedSequenceContextFormat3Marker {
fn min_byte_range(&self) -> Range<usize> {
0..self.seq_lookup_records_byte_range().end
}
}
impl<'a> FontRead<'a> for ChainedSequenceContextFormat3<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
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 input_glyph_count: u16 = cursor.read()?;
let input_coverage_offsets_byte_len = (input_glyph_count as usize)
.checked_mul(Offset16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(input_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 seq_lookup_count: u16 = cursor.read()?;
let seq_lookup_records_byte_len = (seq_lookup_count as usize)
.checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(seq_lookup_records_byte_len);
cursor.finish(ChainedSequenceContextFormat3Marker {
backtrack_coverage_offsets_byte_len,
input_coverage_offsets_byte_len,
lookahead_coverage_offsets_byte_len,
seq_lookup_records_byte_len,
})
}
}
/// [Chained Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-3-coverage-based-glyph-contexts)
pub type ChainedSequenceContextFormat3<'a> = TableRef<'a, ChainedSequenceContextFormat3Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ChainedSequenceContextFormat3<'a> {
/// Format identifier: format = 3
pub fn format(&self) -> u16 {
let range = self.shape.format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Number of glyphs in the backtrack sequence
pub fn backtrack_glyph_count(&self) -> u16 {
let range = self.shape.backtrack_glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of offsets to coverage tables for the backtrack sequence
pub fn backtrack_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
let range = self.shape.backtrack_coverage_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`backtrack_coverage_offsets`][Self::backtrack_coverage_offsets].
pub fn backtrack_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
let data = self.data;
let offsets = self.backtrack_coverage_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
/// Number of glyphs in the input sequence
pub fn input_glyph_count(&self) -> u16 {
let range = self.shape.input_glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of offsets to coverage tables for the input sequence
pub fn input_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
let range = self.shape.input_coverage_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`input_coverage_offsets`][Self::input_coverage_offsets].
pub fn input_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
let data = self.data;
let offsets = self.input_coverage_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
/// Number of glyphs in the lookahead sequence
pub fn lookahead_glyph_count(&self) -> u16 {
let range = self.shape.lookahead_glyph_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of offsets to coverage tables for the lookahead sequence
pub fn lookahead_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
let range = self.shape.lookahead_coverage_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`lookahead_coverage_offsets`][Self::lookahead_coverage_offsets].
pub fn lookahead_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
let data = self.data;
let offsets = self.lookahead_coverage_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
/// Number of SequenceLookupRecords
pub fn seq_lookup_count(&self) -> u16 {
let range = self.shape.seq_lookup_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of SequenceLookupRecords
pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
let range = self.shape.seq_lookup_records_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ChainedSequenceContextFormat3<'a> {
fn type_name(&self) -> &str {
"ChainedSequenceContextFormat3"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("format", self.format())),
1usize => Some(Field::new(
"backtrack_glyph_count",
self.backtrack_glyph_count(),
)),
2usize => 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)
},
),
)
}),
3usize => Some(Field::new("input_glyph_count", self.input_glyph_count())),
4usize => Some({
let data = self.data;
Field::new(
"input_coverage_offsets",
FieldType::array_of_offsets(
better_type_name::<CoverageTable>(),
self.input_coverage_offsets(),
move |off| {
let target = off.get().resolve::<CoverageTable>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
5usize => Some(Field::new(
"lookahead_glyph_count",
self.lookahead_glyph_count(),
)),
6usize => 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)
},
),
)
}),
7usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
8usize => Some(Field::new(
"seq_lookup_records",
traversal::FieldType::array_of_records(
stringify!(SequenceLookupRecord),
self.seq_lookup_records(),
self.offset_data(),
),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ChainedSequenceContextFormat3<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
#[derive(Clone)]
pub enum ChainedSequenceContext<'a> {
Format1(ChainedSequenceContextFormat1<'a>),
Format2(ChainedSequenceContextFormat2<'a>),
Format3(ChainedSequenceContextFormat3<'a>),
}
impl<'a> ChainedSequenceContext<'a> {
///Return the `FontData` used to resolve offsets for this table.
pub fn offset_data(&self) -> FontData<'a> {
match self {
Self::Format1(item) => item.offset_data(),
Self::Format2(item) => item.offset_data(),
Self::Format3(item) => item.offset_data(),
}
}
/// Format identifier: format = 1
pub fn format(&self) -> u16 {
match self {
Self::Format1(item) => item.format(),
Self::Format2(item) => item.format(),
Self::Format3(item) => item.format(),
}
}
}
impl<'a> FontRead<'a> for ChainedSequenceContext<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let format: u16 = data.read_at(0usize)?;
match format {
ChainedSequenceContextFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
ChainedSequenceContextFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
ChainedSequenceContextFormat3Marker::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
other => Err(ReadError::InvalidFormat(other.into())),
}
}
}
impl MinByteRange for ChainedSequenceContext<'_> {
fn min_byte_range(&self) -> Range<usize> {
match self {
Self::Format1(item) => item.min_byte_range(),
Self::Format2(item) => item.min_byte_range(),
Self::Format3(item) => item.min_byte_range(),
}
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> ChainedSequenceContext<'a> {
fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
match self {
Self::Format1(table) => table,
Self::Format2(table) => table,
Self::Format3(table) => table,
}
}
}
#[cfg(feature = "experimental_traverse")]
impl std::fmt::Debug for ChainedSequenceContext<'_> {
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 ChainedSequenceContext<'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)
}
}
/// [Device](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables)
/// delta formats
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(u16)]
#[allow(clippy::manual_non_exhaustive)]
pub enum DeltaFormat {
/// Signed 2-bit value, 8 values per uint16
#[default]
Local2BitDeltas = 0x0001,
/// Signed 4-bit value, 4 values per uint16
Local4BitDeltas = 0x0002,
/// Signed 8-bit value, 2 values per uint16
Local8BitDeltas = 0x0003,
/// VariationIndex table, contains a delta-set index pair.
VariationIndex = 0x8000,
#[doc(hidden)]
/// If font data is malformed we will map unknown values to this variant
Unknown,
}
impl DeltaFormat {
/// Create from a raw scalar.
///
/// This will never fail; unknown values will be mapped to the `Unknown` variant
pub fn new(raw: u16) -> Self {
match raw {
0x0001 => Self::Local2BitDeltas,
0x0002 => Self::Local4BitDeltas,
0x0003 => Self::Local8BitDeltas,
0x8000 => Self::VariationIndex,
_ => Self::Unknown,
}
}
}
impl font_types::Scalar for DeltaFormat {
type Raw = <u16 as font_types::Scalar>::Raw;
fn to_raw(self) -> Self::Raw {
(self as u16).to_raw()
}
fn from_raw(raw: Self::Raw) -> Self {
let t = <u16>::from_raw(raw);
Self::new(t)
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> From<DeltaFormat> for FieldType<'a> {
fn from(src: DeltaFormat) -> FieldType<'a> {
(src as u16).into()
}
}
/// [Device Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct DeviceMarker {
delta_value_byte_len: usize,
}
impl DeviceMarker {
pub fn start_size_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn end_size_byte_range(&self) -> Range<usize> {
let start = self.start_size_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn delta_format_byte_range(&self) -> Range<usize> {
let start = self.end_size_byte_range().end;
start..start + DeltaFormat::RAW_BYTE_LEN
}
pub fn delta_value_byte_range(&self) -> Range<usize> {
let start = self.delta_format_byte_range().end;
start..start + self.delta_value_byte_len
}
}
impl MinByteRange for DeviceMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.delta_value_byte_range().end
}
}
impl<'a> FontRead<'a> for Device<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let start_size: u16 = cursor.read()?;
let end_size: u16 = cursor.read()?;
let delta_format: DeltaFormat = cursor.read()?;
let delta_value_byte_len = (DeltaFormat::value_count(delta_format, start_size, end_size))
.checked_mul(u16::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(delta_value_byte_len);
cursor.finish(DeviceMarker {
delta_value_byte_len,
})
}
}
/// [Device Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables)
pub type Device<'a> = TableRef<'a, DeviceMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> Device<'a> {
/// Smallest size to correct, in ppem
pub fn start_size(&self) -> u16 {
let range = self.shape.start_size_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Largest size to correct, in ppem
pub fn end_size(&self) -> u16 {
let range = self.shape.end_size_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Format of deltaValue array data: 0x0001, 0x0002, or 0x0003
pub fn delta_format(&self) -> DeltaFormat {
let range = self.shape.delta_format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of compressed data
pub fn delta_value(&self) -> &'a [BigEndian<u16>] {
let range = self.shape.delta_value_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Device<'a> {
fn type_name(&self) -> &str {
"Device"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("start_size", self.start_size())),
1usize => Some(Field::new("end_size", self.end_size())),
2usize => Some(Field::new("delta_format", self.delta_format())),
3usize => Some(Field::new("delta_value", self.delta_value())),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for Device<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// Variation index table
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct VariationIndexMarker {}
impl VariationIndexMarker {
pub fn delta_set_outer_index_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn delta_set_inner_index_byte_range(&self) -> Range<usize> {
let start = self.delta_set_outer_index_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn delta_format_byte_range(&self) -> Range<usize> {
let start = self.delta_set_inner_index_byte_range().end;
start..start + DeltaFormat::RAW_BYTE_LEN
}
}
impl MinByteRange for VariationIndexMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.delta_format_byte_range().end
}
}
impl<'a> FontRead<'a> for VariationIndex<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<u16>();
cursor.advance::<DeltaFormat>();
cursor.finish(VariationIndexMarker {})
}
}
/// Variation index table
pub type VariationIndex<'a> = TableRef<'a, VariationIndexMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> VariationIndex<'a> {
/// A delta-set outer index — used to select an item variation
/// data subtable within the item variation store.
pub fn delta_set_outer_index(&self) -> u16 {
let range = self.shape.delta_set_outer_index_byte_range();
self.data.read_at(range.start).unwrap()
}
/// A delta-set inner index — used to select a delta-set row
/// within an item variation data subtable.
pub fn delta_set_inner_index(&self) -> u16 {
let range = self.shape.delta_set_inner_index_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Format, = 0x8000
pub fn delta_format(&self) -> DeltaFormat {
let range = self.shape.delta_format_byte_range();
self.data.read_at(range.start).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for VariationIndex<'a> {
fn type_name(&self) -> &str {
"VariationIndex"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new(
"delta_set_outer_index",
self.delta_set_outer_index(),
)),
1usize => Some(Field::new(
"delta_set_inner_index",
self.delta_set_inner_index(),
)),
2usize => Some(Field::new("delta_format", self.delta_format())),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for VariationIndex<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// Either a [Device] table (in a non-variable font) or a [VariationIndex] table (in a variable font)
#[derive(Clone)]
pub enum DeviceOrVariationIndex<'a> {
Device(Device<'a>),
VariationIndex(VariationIndex<'a>),
}
impl<'a> DeviceOrVariationIndex<'a> {
///Return the `FontData` used to resolve offsets for this table.
pub fn offset_data(&self) -> FontData<'a> {
match self {
Self::Device(item) => item.offset_data(),
Self::VariationIndex(item) => item.offset_data(),
}
}
}
impl<'a> FontRead<'a> for DeviceOrVariationIndex<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let format: DeltaFormat = data.read_at(4usize)?;
#[allow(clippy::redundant_guards)]
match format {
format if format != DeltaFormat::VariationIndex => {
Ok(Self::Device(FontRead::read(data)?))
}
format if format == DeltaFormat::VariationIndex => {
Ok(Self::VariationIndex(FontRead::read(data)?))
}
other => Err(ReadError::InvalidFormat(other.into())),
}
}
}
impl MinByteRange for DeviceOrVariationIndex<'_> {
fn min_byte_range(&self) -> Range<usize> {
match self {
Self::Device(item) => item.min_byte_range(),
Self::VariationIndex(item) => item.min_byte_range(),
}
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> DeviceOrVariationIndex<'a> {
fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
match self {
Self::Device(table) => table,
Self::VariationIndex(table) => table,
}
}
}
#[cfg(feature = "experimental_traverse")]
impl std::fmt::Debug for DeviceOrVariationIndex<'_> {
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 DeviceOrVariationIndex<'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)
}
}
/// [FeatureVariations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featurevariations-table)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct FeatureVariationsMarker {
feature_variation_records_byte_len: usize,
}
impl FeatureVariationsMarker {
pub fn version_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + MajorMinor::RAW_BYTE_LEN
}
pub fn feature_variation_record_count_byte_range(&self) -> Range<usize> {
let start = self.version_byte_range().end;
start..start + u32::RAW_BYTE_LEN
}
pub fn feature_variation_records_byte_range(&self) -> Range<usize> {
let start = self.feature_variation_record_count_byte_range().end;
start..start + self.feature_variation_records_byte_len
}
}
impl MinByteRange for FeatureVariationsMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.feature_variation_records_byte_range().end
}
}
impl<'a> FontRead<'a> for FeatureVariations<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<MajorMinor>();
let feature_variation_record_count: u32 = cursor.read()?;
let feature_variation_records_byte_len = (feature_variation_record_count as usize)
.checked_mul(FeatureVariationRecord::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(feature_variation_records_byte_len);
cursor.finish(FeatureVariationsMarker {
feature_variation_records_byte_len,
})
}
}
/// [FeatureVariations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featurevariations-table)
pub type FeatureVariations<'a> = TableRef<'a, FeatureVariationsMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> FeatureVariations<'a> {
pub fn version(&self) -> MajorMinor {
let range = self.shape.version_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Number of feature variation records.
pub fn feature_variation_record_count(&self) -> u32 {
let range = self.shape.feature_variation_record_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of feature variation records.
pub fn feature_variation_records(&self) -> &'a [FeatureVariationRecord] {
let range = self.shape.feature_variation_records_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for FeatureVariations<'a> {
fn type_name(&self) -> &str {
"FeatureVariations"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("version", self.version())),
1usize => Some(Field::new(
"feature_variation_record_count",
self.feature_variation_record_count(),
)),
2usize => Some(Field::new(
"feature_variation_records",
traversal::FieldType::array_of_records(
stringify!(FeatureVariationRecord),
self.feature_variation_records(),
self.offset_data(),
),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for FeatureVariations<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// Part of [FeatureVariations]
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct FeatureVariationRecord {
/// Offset to a condition set table, from beginning of
/// FeatureVariations table.
pub condition_set_offset: BigEndian<Nullable<Offset32>>,
/// Offset to a feature table substitution table, from beginning of
/// the FeatureVariations table.
pub feature_table_substitution_offset: BigEndian<Nullable<Offset32>>,
}
impl FeatureVariationRecord {
/// Offset to a condition set table, from beginning of
/// FeatureVariations table.
pub fn condition_set_offset(&self) -> Nullable<Offset32> {
self.condition_set_offset.get()
}
/// Offset to a condition set table, from beginning of
/// FeatureVariations table.
///
/// The `data` argument should be retrieved from the parent table
/// By calling its `offset_data` method.
pub fn condition_set<'a>(
&self,
data: FontData<'a>,
) -> Option<Result<ConditionSet<'a>, ReadError>> {
self.condition_set_offset().resolve(data)
}
/// Offset to a feature table substitution table, from beginning of
/// the FeatureVariations table.
pub fn feature_table_substitution_offset(&self) -> Nullable<Offset32> {
self.feature_table_substitution_offset.get()
}
/// Offset to a feature table substitution table, from beginning of
/// the FeatureVariations table.
///
/// The `data` argument should be retrieved from the parent table
/// By calling its `offset_data` method.
pub fn feature_table_substitution<'a>(
&self,
data: FontData<'a>,
) -> Option<Result<FeatureTableSubstitution<'a>, ReadError>> {
self.feature_table_substitution_offset().resolve(data)
}
}
impl FixedSize for FeatureVariationRecord {
const RAW_BYTE_LEN: usize = Offset32::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeRecord<'a> for FeatureVariationRecord {
fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
RecordResolver {
name: "FeatureVariationRecord",
get_field: Box::new(move |idx, _data| match idx {
0usize => Some(Field::new(
"condition_set_offset",
FieldType::offset(self.condition_set_offset(), self.condition_set(_data)),
)),
1usize => Some(Field::new(
"feature_table_substitution_offset",
FieldType::offset(
self.feature_table_substitution_offset(),
self.feature_table_substitution(_data),
),
)),
_ => None,
}),
data,
}
}
}
/// [ConditionSet Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#conditionset-table)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ConditionSetMarker {
condition_offsets_byte_len: usize,
}
impl ConditionSetMarker {
pub fn condition_count_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn condition_offsets_byte_range(&self) -> Range<usize> {
let start = self.condition_count_byte_range().end;
start..start + self.condition_offsets_byte_len
}
}
impl MinByteRange for ConditionSetMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.condition_offsets_byte_range().end
}
}
impl<'a> FontRead<'a> for ConditionSet<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
let condition_count: u16 = cursor.read()?;
let condition_offsets_byte_len = (condition_count as usize)
.checked_mul(Offset32::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(condition_offsets_byte_len);
cursor.finish(ConditionSetMarker {
condition_offsets_byte_len,
})
}
}
/// [ConditionSet Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#conditionset-table)
pub type ConditionSet<'a> = TableRef<'a, ConditionSetMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ConditionSet<'a> {
/// Number of conditions for this condition set.
pub fn condition_count(&self) -> u16 {
let range = self.shape.condition_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of offsets to condition tables, from beginning of the
/// ConditionSet table.
pub fn condition_offsets(&self) -> &'a [BigEndian<Offset32>] {
let range = self.shape.condition_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets].
pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset32> {
let data = self.data;
let offsets = self.condition_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ConditionSet<'a> {
fn type_name(&self) -> &str {
"ConditionSet"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("condition_count", self.condition_count())),
1usize => Some({
let data = self.data;
Field::new(
"condition_offsets",
FieldType::array_of_offsets(
better_type_name::<Condition>(),
self.condition_offsets(),
move |off| {
let target = off.get().resolve::<Condition>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ConditionSet<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// [Condition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#condition-table)
///
/// Formats 2..5 are implementations of specification changes currently under debate at ISO for an OFF
/// update. For the time being the specification is <https://github.com/harfbuzz/boring-expansion-spec/blob/main/ConditionTree.md>.
#[derive(Clone)]
pub enum Condition<'a> {
Format1AxisRange(ConditionFormat1<'a>),
Format2VariableValue(ConditionFormat2<'a>),
Format3And(ConditionFormat3<'a>),
Format4Or(ConditionFormat4<'a>),
Format5Negate(ConditionFormat5<'a>),
}
impl<'a> Condition<'a> {
///Return the `FontData` used to resolve offsets for this table.
pub fn offset_data(&self) -> FontData<'a> {
match self {
Self::Format1AxisRange(item) => item.offset_data(),
Self::Format2VariableValue(item) => item.offset_data(),
Self::Format3And(item) => item.offset_data(),
Self::Format4Or(item) => item.offset_data(),
Self::Format5Negate(item) => item.offset_data(),
}
}
/// Format, = 1
pub fn format(&self) -> u16 {
match self {
Self::Format1AxisRange(item) => item.format(),
Self::Format2VariableValue(item) => item.format(),
Self::Format3And(item) => item.format(),
Self::Format4Or(item) => item.format(),
Self::Format5Negate(item) => item.format(),
}
}
}
impl<'a> FontRead<'a> for Condition<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let format: u16 = data.read_at(0usize)?;
match format {
ConditionFormat1Marker::FORMAT => Ok(Self::Format1AxisRange(FontRead::read(data)?)),
ConditionFormat2Marker::FORMAT => Ok(Self::Format2VariableValue(FontRead::read(data)?)),
ConditionFormat3Marker::FORMAT => Ok(Self::Format3And(FontRead::read(data)?)),
ConditionFormat4Marker::FORMAT => Ok(Self::Format4Or(FontRead::read(data)?)),
ConditionFormat5Marker::FORMAT => Ok(Self::Format5Negate(FontRead::read(data)?)),
other => Err(ReadError::InvalidFormat(other.into())),
}
}
}
impl MinByteRange for Condition<'_> {
fn min_byte_range(&self) -> Range<usize> {
match self {
Self::Format1AxisRange(item) => item.min_byte_range(),
Self::Format2VariableValue(item) => item.min_byte_range(),
Self::Format3And(item) => item.min_byte_range(),
Self::Format4Or(item) => item.min_byte_range(),
Self::Format5Negate(item) => item.min_byte_range(),
}
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> Condition<'a> {
fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
match self {
Self::Format1AxisRange(table) => table,
Self::Format2VariableValue(table) => table,
Self::Format3And(table) => table,
Self::Format4Or(table) => table,
Self::Format5Negate(table) => table,
}
}
}
#[cfg(feature = "experimental_traverse")]
impl std::fmt::Debug for Condition<'_> {
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 Condition<'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 ConditionFormat1Marker {
const FORMAT: u16 = 1;
}
/// [Condition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#condition-table-format-1-font-variation-axis-range): Font Variation Axis Range
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ConditionFormat1Marker {}
impl ConditionFormat1Marker {
pub fn format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn axis_index_byte_range(&self) -> Range<usize> {
let start = self.format_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn filter_range_min_value_byte_range(&self) -> Range<usize> {
let start = self.axis_index_byte_range().end;
start..start + F2Dot14::RAW_BYTE_LEN
}
pub fn filter_range_max_value_byte_range(&self) -> Range<usize> {
let start = self.filter_range_min_value_byte_range().end;
start..start + F2Dot14::RAW_BYTE_LEN
}
}
impl MinByteRange for ConditionFormat1Marker {
fn min_byte_range(&self) -> Range<usize> {
0..self.filter_range_max_value_byte_range().end
}
}
impl<'a> FontRead<'a> for ConditionFormat1<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<u16>();
cursor.advance::<F2Dot14>();
cursor.advance::<F2Dot14>();
cursor.finish(ConditionFormat1Marker {})
}
}
/// [Condition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#condition-table-format-1-font-variation-axis-range): Font Variation Axis Range
pub type ConditionFormat1<'a> = TableRef<'a, ConditionFormat1Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ConditionFormat1<'a> {
/// Format, = 1
pub fn format(&self) -> u16 {
let range = self.shape.format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Index (zero-based) for the variation axis within the 'fvar'
/// table.
pub fn axis_index(&self) -> u16 {
let range = self.shape.axis_index_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Minimum value of the font variation instances that satisfy this
/// condition.
pub fn filter_range_min_value(&self) -> F2Dot14 {
let range = self.shape.filter_range_min_value_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Maximum value of the font variation instances that satisfy this
/// condition.
pub fn filter_range_max_value(&self) -> F2Dot14 {
let range = self.shape.filter_range_max_value_byte_range();
self.data.read_at(range.start).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ConditionFormat1<'a> {
fn type_name(&self) -> &str {
"ConditionFormat1"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("format", self.format())),
1usize => Some(Field::new("axis_index", self.axis_index())),
2usize => Some(Field::new(
"filter_range_min_value",
self.filter_range_min_value(),
)),
3usize => Some(Field::new(
"filter_range_max_value",
self.filter_range_max_value(),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ConditionFormat1<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for ConditionFormat2Marker {
const FORMAT: u16 = 2;
}
/// [Condition Table Format 2](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3237-L3255): Variation index
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ConditionFormat2Marker {}
impl ConditionFormat2Marker {
pub fn format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn default_value_byte_range(&self) -> Range<usize> {
let start = self.format_byte_range().end;
start..start + i16::RAW_BYTE_LEN
}
pub fn var_index_byte_range(&self) -> Range<usize> {
let start = self.default_value_byte_range().end;
start..start + u32::RAW_BYTE_LEN
}
}
impl MinByteRange for ConditionFormat2Marker {
fn min_byte_range(&self) -> Range<usize> {
0..self.var_index_byte_range().end
}
}
impl<'a> FontRead<'a> for ConditionFormat2<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<i16>();
cursor.advance::<u32>();
cursor.finish(ConditionFormat2Marker {})
}
}
/// [Condition Table Format 2](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3237-L3255): Variation index
pub type ConditionFormat2<'a> = TableRef<'a, ConditionFormat2Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ConditionFormat2<'a> {
/// Format, = 2
pub fn format(&self) -> u16 {
let range = self.shape.format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Value at default instance.
pub fn default_value(&self) -> i16 {
let range = self.shape.default_value_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Variation index to vary the value based on current designspace location.
pub fn var_index(&self) -> u32 {
let range = self.shape.var_index_byte_range();
self.data.read_at(range.start).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ConditionFormat2<'a> {
fn type_name(&self) -> &str {
"ConditionFormat2"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("format", self.format())),
1usize => Some(Field::new("default_value", self.default_value())),
2usize => Some(Field::new("var_index", self.var_index())),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ConditionFormat2<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for ConditionFormat3Marker {
const FORMAT: u16 = 3;
}
/// [Condition Table Format 3](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3257-L3275): AND
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ConditionFormat3Marker {
condition_offsets_byte_len: usize,
}
impl ConditionFormat3Marker {
pub fn format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn condition_count_byte_range(&self) -> Range<usize> {
let start = self.format_byte_range().end;
start..start + u8::RAW_BYTE_LEN
}
pub fn condition_offsets_byte_range(&self) -> Range<usize> {
let start = self.condition_count_byte_range().end;
start..start + self.condition_offsets_byte_len
}
}
impl MinByteRange for ConditionFormat3Marker {
fn min_byte_range(&self) -> Range<usize> {
0..self.condition_offsets_byte_range().end
}
}
impl<'a> FontRead<'a> for ConditionFormat3<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
let condition_count: u8 = cursor.read()?;
let condition_offsets_byte_len = (condition_count as usize)
.checked_mul(Offset24::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(condition_offsets_byte_len);
cursor.finish(ConditionFormat3Marker {
condition_offsets_byte_len,
})
}
}
/// [Condition Table Format 3](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3257-L3275): AND
pub type ConditionFormat3<'a> = TableRef<'a, ConditionFormat3Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ConditionFormat3<'a> {
/// Format, = 3
pub fn format(&self) -> u16 {
let range = self.shape.format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Number of conditions.
pub fn condition_count(&self) -> u8 {
let range = self.shape.condition_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of condition tables for this conjunction (AND) expression.
pub fn condition_offsets(&self) -> &'a [BigEndian<Offset24>] {
let range = self.shape.condition_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets].
pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset24> {
let data = self.data;
let offsets = self.condition_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ConditionFormat3<'a> {
fn type_name(&self) -> &str {
"ConditionFormat3"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("format", self.format())),
1usize => Some(Field::new("condition_count", self.condition_count())),
2usize => Some({
let data = self.data;
Field::new(
"condition_offsets",
FieldType::array_of_offsets(
better_type_name::<Condition>(),
self.condition_offsets(),
move |off| {
let target = off.get().resolve::<Condition>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ConditionFormat3<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for ConditionFormat4Marker {
const FORMAT: u16 = 4;
}
/// [Condition Table Format 4](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3276-L3295): OR
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ConditionFormat4Marker {
condition_offsets_byte_len: usize,
}
impl ConditionFormat4Marker {
pub fn format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn condition_count_byte_range(&self) -> Range<usize> {
let start = self.format_byte_range().end;
start..start + u8::RAW_BYTE_LEN
}
pub fn condition_offsets_byte_range(&self) -> Range<usize> {
let start = self.condition_count_byte_range().end;
start..start + self.condition_offsets_byte_len
}
}
impl MinByteRange for ConditionFormat4Marker {
fn min_byte_range(&self) -> Range<usize> {
0..self.condition_offsets_byte_range().end
}
}
impl<'a> FontRead<'a> for ConditionFormat4<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
let condition_count: u8 = cursor.read()?;
let condition_offsets_byte_len = (condition_count as usize)
.checked_mul(Offset24::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(condition_offsets_byte_len);
cursor.finish(ConditionFormat4Marker {
condition_offsets_byte_len,
})
}
}
/// [Condition Table Format 4](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3276-L3295): OR
pub type ConditionFormat4<'a> = TableRef<'a, ConditionFormat4Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ConditionFormat4<'a> {
/// Format, = 4
pub fn format(&self) -> u16 {
let range = self.shape.format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Number of conditions.
pub fn condition_count(&self) -> u8 {
let range = self.shape.condition_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of condition tables for this disjunction (OR) expression.
pub fn condition_offsets(&self) -> &'a [BigEndian<Offset24>] {
let range = self.shape.condition_offsets_byte_range();
self.data.read_array(range).unwrap()
}
/// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets].
pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset24> {
let data = self.data;
let offsets = self.condition_offsets();
ArrayOfOffsets::new(offsets, data, ())
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ConditionFormat4<'a> {
fn type_name(&self) -> &str {
"ConditionFormat4"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("format", self.format())),
1usize => Some(Field::new("condition_count", self.condition_count())),
2usize => Some({
let data = self.data;
Field::new(
"condition_offsets",
FieldType::array_of_offsets(
better_type_name::<Condition>(),
self.condition_offsets(),
move |off| {
let target = off.get().resolve::<Condition>(data);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ConditionFormat4<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for ConditionFormat5Marker {
const FORMAT: u16 = 5;
}
/// [Condition Table Format 5](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3296-L3308): NOT
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ConditionFormat5Marker {}
impl ConditionFormat5Marker {
pub fn format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn condition_offset_byte_range(&self) -> Range<usize> {
let start = self.format_byte_range().end;
start..start + Offset24::RAW_BYTE_LEN
}
}
impl MinByteRange for ConditionFormat5Marker {
fn min_byte_range(&self) -> Range<usize> {
0..self.condition_offset_byte_range().end
}
}
impl<'a> FontRead<'a> for ConditionFormat5<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<Offset24>();
cursor.finish(ConditionFormat5Marker {})
}
}
/// [Condition Table Format 5](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3296-L3308): NOT
pub type ConditionFormat5<'a> = TableRef<'a, ConditionFormat5Marker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> ConditionFormat5<'a> {
/// Format, = 5
pub fn format(&self) -> u16 {
let range = self.shape.format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Condition to negate.
pub fn condition_offset(&self) -> Offset24 {
let range = self.shape.condition_offset_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Attempt to resolve [`condition_offset`][Self::condition_offset].
pub fn condition(&self) -> Result<Condition<'a>, ReadError> {
let data = self.data;
self.condition_offset().resolve(data)
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ConditionFormat5<'a> {
fn type_name(&self) -> &str {
"ConditionFormat5"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("format", self.format())),
1usize => Some(Field::new(
"condition_offset",
FieldType::offset(self.condition_offset(), self.condition()),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for ConditionFormat5<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// [FeatureTableSubstitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featuretablesubstitution-table)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct FeatureTableSubstitutionMarker {
substitutions_byte_len: usize,
}
impl FeatureTableSubstitutionMarker {
pub fn version_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + MajorMinor::RAW_BYTE_LEN
}
pub fn substitution_count_byte_range(&self) -> Range<usize> {
let start = self.version_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn substitutions_byte_range(&self) -> Range<usize> {
let start = self.substitution_count_byte_range().end;
start..start + self.substitutions_byte_len
}
}
impl MinByteRange for FeatureTableSubstitutionMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.substitutions_byte_range().end
}
}
impl<'a> FontRead<'a> for FeatureTableSubstitution<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<MajorMinor>();
let substitution_count: u16 = cursor.read()?;
let substitutions_byte_len = (substitution_count as usize)
.checked_mul(FeatureTableSubstitutionRecord::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(substitutions_byte_len);
cursor.finish(FeatureTableSubstitutionMarker {
substitutions_byte_len,
})
}
}
/// [FeatureTableSubstitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featuretablesubstitution-table)
pub type FeatureTableSubstitution<'a> = TableRef<'a, FeatureTableSubstitutionMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> FeatureTableSubstitution<'a> {
/// Major & minor version of the table: (1, 0)
pub fn version(&self) -> MajorMinor {
let range = self.shape.version_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Number of feature table substitution records.
pub fn substitution_count(&self) -> u16 {
let range = self.shape.substitution_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Array of feature table substitution records.
pub fn substitutions(&self) -> &'a [FeatureTableSubstitutionRecord] {
let range = self.shape.substitutions_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for FeatureTableSubstitution<'a> {
fn type_name(&self) -> &str {
"FeatureTableSubstitution"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("version", self.version())),
1usize => Some(Field::new("substitution_count", self.substitution_count())),
2usize => Some(Field::new(
"substitutions",
traversal::FieldType::array_of_records(
stringify!(FeatureTableSubstitutionRecord),
self.substitutions(),
self.offset_data(),
),
)),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for FeatureTableSubstitution<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
/// Used in [FeatureTableSubstitution]
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct FeatureTableSubstitutionRecord {
/// The feature table index to match.
pub feature_index: BigEndian<u16>,
/// Offset to an alternate feature table, from start of the
/// FeatureTableSubstitution table.
pub alternate_feature_offset: BigEndian<Offset32>,
}
impl FeatureTableSubstitutionRecord {
/// The feature table index to match.
pub fn feature_index(&self) -> u16 {
self.feature_index.get()
}
/// Offset to an alternate feature table, from start of the
/// FeatureTableSubstitution table.
pub fn alternate_feature_offset(&self) -> Offset32 {
self.alternate_feature_offset.get()
}
}
impl FixedSize for FeatureTableSubstitutionRecord {
const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeRecord<'a> for FeatureTableSubstitutionRecord {
fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
RecordResolver {
name: "FeatureTableSubstitutionRecord",
get_field: Box::new(move |idx, _data| match idx {
0usize => Some(Field::new("feature_index", self.feature_index())),
1usize => Some(Field::new(
"alternate_feature_offset",
FieldType::offset(
self.alternate_feature_offset(),
self.alternate_feature(_data),
),
)),
_ => None,
}),
data,
}
}
}
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct SizeParamsMarker {}
impl SizeParamsMarker {
pub fn design_size_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn identifier_byte_range(&self) -> Range<usize> {
let start = self.design_size_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn name_entry_byte_range(&self) -> Range<usize> {
let start = self.identifier_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn range_start_byte_range(&self) -> Range<usize> {
let start = self.name_entry_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn range_end_byte_range(&self) -> Range<usize> {
let start = self.range_start_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
}
impl MinByteRange for SizeParamsMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.range_end_byte_range().end
}
}
impl<'a> FontRead<'a> for SizeParams<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<u16>();
cursor.advance::<u16>();
cursor.advance::<u16>();
cursor.advance::<u16>();
cursor.finish(SizeParamsMarker {})
}
}
pub type SizeParams<'a> = TableRef<'a, SizeParamsMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> SizeParams<'a> {
/// The first value represents the design size in 720/inch units (decipoints).
///
/// The design size entry must be non-zero. When there is a design size but
/// no recommended size range, the rest of the array will consist of zeros.
pub fn design_size(&self) -> u16 {
let range = self.shape.design_size_byte_range();
self.data.read_at(range.start).unwrap()
}
/// The second value has no independent meaning, but serves as an identifier that associates fonts in a subfamily.
///
/// All fonts which share a Typographic or Font Family name and which differ
/// only by size range shall have the same subfamily value, and no fonts
/// which differ in weight or style shall have the same subfamily value.
/// If this value is zero, the remaining fields in the array will be ignored.
pub fn identifier(&self) -> u16 {
let range = self.shape.identifier_byte_range();
self.data.read_at(range.start).unwrap()
}
/// The third value enables applications to use a single name for the subfamily identified by the second value.
///
/// If the preceding value is non-zero, this value must be set in the range
/// 256 32767 (inclusive). It records the value of a field in the 'name'
/// table, which must contain English-language strings encoded in Windows
/// Unicode and Macintosh Roman, and may contain additional strings localized
/// to other scripts and languages. Each of these strings is the name
/// an application should use, in combination with the family name, to
/// represent the subfamily in a menu. Applications will choose the
/// appropriate version based on their selection criteria.
pub fn name_entry(&self) -> u16 {
let range = self.shape.name_entry_byte_range();
self.data.read_at(range.start).unwrap()
}
/// The fourth and fifth values represent the small end of the recommended
/// usage range (exclusive) and the large end of the recommended usage range
/// (inclusive), stored in 720/inch units (decipoints).
///
/// Ranges must not overlap, and should generally be contiguous.
pub fn range_start(&self) -> u16 {
let range = self.shape.range_start_byte_range();
self.data.read_at(range.start).unwrap()
}
pub fn range_end(&self) -> u16 {
let range = self.shape.range_end_byte_range();
self.data.read_at(range.start).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for SizeParams<'a> {
fn type_name(&self) -> &str {
"SizeParams"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("design_size", self.design_size())),
1usize => Some(Field::new("identifier", self.identifier())),
2usize => Some(Field::new("name_entry", self.name_entry())),
3usize => Some(Field::new("range_start", self.range_start())),
4usize => Some(Field::new("range_end", self.range_end())),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for SizeParams<'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 StylisticSetParamsMarker {}
impl StylisticSetParamsMarker {
pub fn version_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn ui_name_id_byte_range(&self) -> Range<usize> {
let start = self.version_byte_range().end;
start..start + NameId::RAW_BYTE_LEN
}
}
impl MinByteRange for StylisticSetParamsMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.ui_name_id_byte_range().end
}
}
impl<'a> FontRead<'a> for StylisticSetParams<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<NameId>();
cursor.finish(StylisticSetParamsMarker {})
}
}
pub type StylisticSetParams<'a> = TableRef<'a, StylisticSetParamsMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> StylisticSetParams<'a> {
pub fn version(&self) -> u16 {
let range = self.shape.version_byte_range();
self.data.read_at(range.start).unwrap()
}
/// The 'name' table name ID that specifies a string (or strings, for
/// multiple languages) for a user-interface label for this feature.
///
/// The value of uiLabelNameId is expected to be in the font-specific name
/// ID range (256-32767), though that is not a requirement in this Feature
/// Parameters specification. The user-interface label for the feature can
/// be provided in multiple languages. An English string should be included
/// as a fallback. The string should be kept to a minimal length to fit
/// comfortably with different application interfaces.
pub fn ui_name_id(&self) -> NameId {
let range = self.shape.ui_name_id_byte_range();
self.data.read_at(range.start).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for StylisticSetParams<'a> {
fn type_name(&self) -> &str {
"StylisticSetParams"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("version", self.version())),
1usize => Some(Field::new("ui_name_id", self.ui_name_id())),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for StylisticSetParams<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
impl Format<u16> for CharacterVariantParamsMarker {
const FORMAT: u16 = 0;
}
/// featureParams for ['cv01'-'cv99'](https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct CharacterVariantParamsMarker {
character_byte_len: usize,
}
impl CharacterVariantParamsMarker {
pub fn format_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
pub fn feat_ui_label_name_id_byte_range(&self) -> Range<usize> {
let start = self.format_byte_range().end;
start..start + NameId::RAW_BYTE_LEN
}
pub fn feat_ui_tooltip_text_name_id_byte_range(&self) -> Range<usize> {
let start = self.feat_ui_label_name_id_byte_range().end;
start..start + NameId::RAW_BYTE_LEN
}
pub fn sample_text_name_id_byte_range(&self) -> Range<usize> {
let start = self.feat_ui_tooltip_text_name_id_byte_range().end;
start..start + NameId::RAW_BYTE_LEN
}
pub fn num_named_parameters_byte_range(&self) -> Range<usize> {
let start = self.sample_text_name_id_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn first_param_ui_label_name_id_byte_range(&self) -> Range<usize> {
let start = self.num_named_parameters_byte_range().end;
start..start + NameId::RAW_BYTE_LEN
}
pub fn char_count_byte_range(&self) -> Range<usize> {
let start = self.first_param_ui_label_name_id_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
pub fn character_byte_range(&self) -> Range<usize> {
let start = self.char_count_byte_range().end;
start..start + self.character_byte_len
}
}
impl MinByteRange for CharacterVariantParamsMarker {
fn min_byte_range(&self) -> Range<usize> {
0..self.character_byte_range().end
}
}
impl<'a> FontRead<'a> for CharacterVariantParams<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<NameId>();
cursor.advance::<NameId>();
cursor.advance::<NameId>();
cursor.advance::<u16>();
cursor.advance::<NameId>();
let char_count: u16 = cursor.read()?;
let character_byte_len = (char_count as usize)
.checked_mul(Uint24::RAW_BYTE_LEN)
.ok_or(ReadError::OutOfBounds)?;
cursor.advance_by(character_byte_len);
cursor.finish(CharacterVariantParamsMarker { character_byte_len })
}
}
/// featureParams for ['cv01'-'cv99'](https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99)
pub type CharacterVariantParams<'a> = TableRef<'a, CharacterVariantParamsMarker>;
#[allow(clippy::needless_lifetimes)]
impl<'a> CharacterVariantParams<'a> {
/// Format number is set to 0.
pub fn format(&self) -> u16 {
let range = self.shape.format_byte_range();
self.data.read_at(range.start).unwrap()
}
/// The 'name' table name ID that specifies a string (or strings,
/// for multiple languages) for a user-interface label for this
/// feature. (May be NULL.)
pub fn feat_ui_label_name_id(&self) -> NameId {
let range = self.shape.feat_ui_label_name_id_byte_range();
self.data.read_at(range.start).unwrap()
}
/// The 'name' table name ID that specifies a string (or strings,
/// for multiple languages) that an application can use for tooltip
/// text for this feature. (May be NULL.)
pub fn feat_ui_tooltip_text_name_id(&self) -> NameId {
let range = self.shape.feat_ui_tooltip_text_name_id_byte_range();
self.data.read_at(range.start).unwrap()
}
/// The 'name' table name ID that specifies sample text that
/// illustrates the effect of this feature. (May be NULL.)
pub fn sample_text_name_id(&self) -> NameId {
let range = self.shape.sample_text_name_id_byte_range();
self.data.read_at(range.start).unwrap()
}
/// Number of named parameters. (May be zero.)
pub fn num_named_parameters(&self) -> u16 {
let range = self.shape.num_named_parameters_byte_range();
self.data.read_at(range.start).unwrap()
}
/// The first 'name' table name ID used to specify strings for
/// user-interface labels for the feature parameters. (Must be zero
/// if numParameters is zero.)
pub fn first_param_ui_label_name_id(&self) -> NameId {
let range = self.shape.first_param_ui_label_name_id_byte_range();
self.data.read_at(range.start).unwrap()
}
/// The count of characters for which this feature provides glyph
/// variants. (May be zero.)
pub fn char_count(&self) -> u16 {
let range = self.shape.char_count_byte_range();
self.data.read_at(range.start).unwrap()
}
/// The Unicode Scalar Value of the characters for which this
/// feature provides glyph variants.
pub fn character(&self) -> &'a [BigEndian<Uint24>] {
let range = self.shape.character_byte_range();
self.data.read_array(range).unwrap()
}
}
#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for CharacterVariantParams<'a> {
fn type_name(&self) -> &str {
"CharacterVariantParams"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("format", self.format())),
1usize => Some(Field::new(
"feat_ui_label_name_id",
self.feat_ui_label_name_id(),
)),
2usize => Some(Field::new(
"feat_ui_tooltip_text_name_id",
self.feat_ui_tooltip_text_name_id(),
)),
3usize => Some(Field::new(
"sample_text_name_id",
self.sample_text_name_id(),
)),
4usize => Some(Field::new(
"num_named_parameters",
self.num_named_parameters(),
)),
5usize => Some(Field::new(
"first_param_ui_label_name_id",
self.first_param_ui_label_name_id(),
)),
6usize => Some(Field::new("char_count", self.char_count())),
7usize => Some(Field::new("character", self.character())),
_ => None,
}
}
}
#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for CharacterVariantParams<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}