Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
135
third-party/vendor/ttf-parser/src/ggg/chained_context.rs
vendored
Normal file
135
third-party/vendor/ttf-parser/src/ggg/chained_context.rs
vendored
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
use super::{ClassDefinition, Coverage, SequenceLookupRecord};
|
||||
use crate::parser::{FromSlice, LazyArray16, LazyOffsetArray16, Stream};
|
||||
|
||||
/// A [Chained Contextual Lookup Subtable](
|
||||
/// https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chseqctxt1).
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum ChainedContextLookup<'a> {
|
||||
/// Simple glyph contexts.
|
||||
Format1 {
|
||||
coverage: Coverage<'a>,
|
||||
sets: ChainedSequenceRuleSets<'a>,
|
||||
},
|
||||
/// Class-based glyph contexts.
|
||||
Format2 {
|
||||
coverage: Coverage<'a>,
|
||||
backtrack_classes: ClassDefinition<'a>,
|
||||
input_classes: ClassDefinition<'a>,
|
||||
lookahead_classes: ClassDefinition<'a>,
|
||||
sets: ChainedSequenceRuleSets<'a>,
|
||||
},
|
||||
/// Coverage-based glyph contexts.
|
||||
Format3 {
|
||||
coverage: Coverage<'a>,
|
||||
backtrack_coverages: LazyOffsetArray16<'a, Coverage<'a>>,
|
||||
input_coverages: LazyOffsetArray16<'a, Coverage<'a>>,
|
||||
lookahead_coverages: LazyOffsetArray16<'a, Coverage<'a>>,
|
||||
lookups: LazyArray16<'a, SequenceLookupRecord>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> ChainedContextLookup<'a> {
|
||||
pub(crate) fn parse(data: &'a [u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
match s.read::<u16>()? {
|
||||
1 => {
|
||||
let coverage = Coverage::parse(s.read_at_offset16(data)?)?;
|
||||
let count = s.read::<u16>()?;
|
||||
let offsets = s.read_array16(count)?;
|
||||
Some(Self::Format1 {
|
||||
coverage,
|
||||
sets: ChainedSequenceRuleSets::new(data, offsets),
|
||||
})
|
||||
}
|
||||
2 => {
|
||||
let coverage = Coverage::parse(s.read_at_offset16(data)?)?;
|
||||
let backtrack_classes = ClassDefinition::parse(s.read_at_offset16(data)?)?;
|
||||
let input_classes = ClassDefinition::parse(s.read_at_offset16(data)?)?;
|
||||
let lookahead_classes = ClassDefinition::parse(s.read_at_offset16(data)?)?;
|
||||
let count = s.read::<u16>()?;
|
||||
let offsets = s.read_array16(count)?;
|
||||
Some(Self::Format2 {
|
||||
coverage,
|
||||
backtrack_classes,
|
||||
input_classes,
|
||||
lookahead_classes,
|
||||
sets: LazyOffsetArray16::new(data, offsets),
|
||||
})
|
||||
}
|
||||
3 => {
|
||||
let backtrack_count = s.read::<u16>()?;
|
||||
let backtrack_coverages = s.read_array16(backtrack_count)?;
|
||||
let input_count = s.read::<u16>()?;
|
||||
let coverage = Coverage::parse(s.read_at_offset16(data)?)?;
|
||||
let input_coverages = s.read_array16(input_count.checked_sub(1)?)?;
|
||||
let lookahead_count = s.read::<u16>()?;
|
||||
let lookahead_coverages = s.read_array16(lookahead_count)?;
|
||||
let lookup_count = s.read::<u16>()?;
|
||||
let lookups = s.read_array16(lookup_count)?;
|
||||
Some(Self::Format3 {
|
||||
coverage,
|
||||
backtrack_coverages: LazyOffsetArray16::new(data, backtrack_coverages),
|
||||
input_coverages: LazyOffsetArray16::new(data, input_coverages),
|
||||
lookahead_coverages: LazyOffsetArray16::new(data, lookahead_coverages),
|
||||
lookups,
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the subtable coverage.
|
||||
#[inline]
|
||||
pub fn coverage(&self) -> Coverage<'a> {
|
||||
match self {
|
||||
Self::Format1 { coverage, .. } => *coverage,
|
||||
Self::Format2 { coverage, .. } => *coverage,
|
||||
Self::Format3 { coverage, .. } => *coverage,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A list of [`ChainedSequenceRule`] sets.
|
||||
pub type ChainedSequenceRuleSets<'a> = LazyOffsetArray16<'a, ChainedSequenceRuleSet<'a>>;
|
||||
|
||||
/// A set of [`ChainedSequenceRule`].
|
||||
pub type ChainedSequenceRuleSet<'a> = LazyOffsetArray16<'a, ChainedSequenceRule<'a>>;
|
||||
|
||||
impl<'a> FromSlice<'a> for ChainedSequenceRuleSet<'a> {
|
||||
fn parse(data: &'a [u8]) -> Option<Self> {
|
||||
Self::parse(data)
|
||||
}
|
||||
}
|
||||
|
||||
/// A [Chained Sequence Rule](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-1-simple-glyph-contexts).
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ChainedSequenceRule<'a> {
|
||||
/// Contains either glyph IDs or glyph Classes.
|
||||
pub backtrack: LazyArray16<'a, u16>,
|
||||
pub input: LazyArray16<'a, u16>,
|
||||
/// Contains either glyph IDs or glyph Classes.
|
||||
pub lookahead: LazyArray16<'a, u16>,
|
||||
pub lookups: LazyArray16<'a, SequenceLookupRecord>,
|
||||
}
|
||||
|
||||
impl<'a> FromSlice<'a> for ChainedSequenceRule<'a> {
|
||||
fn parse(data: &'a [u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
let backtrack_count = s.read::<u16>()?;
|
||||
let backtrack = s.read_array16(backtrack_count)?;
|
||||
let input_count = s.read::<u16>()?;
|
||||
let input = s.read_array16(input_count.checked_sub(1)?)?;
|
||||
let lookahead_count = s.read::<u16>()?;
|
||||
let lookahead = s.read_array16(lookahead_count)?;
|
||||
let lookup_count = s.read::<u16>()?;
|
||||
let lookups = s.read_array16(lookup_count)?;
|
||||
Some(Self {
|
||||
backtrack,
|
||||
input,
|
||||
lookahead,
|
||||
lookups,
|
||||
})
|
||||
}
|
||||
}
|
||||
129
third-party/vendor/ttf-parser/src/ggg/context.rs
vendored
Normal file
129
third-party/vendor/ttf-parser/src/ggg/context.rs
vendored
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
use super::{ClassDefinition, Coverage, LookupIndex};
|
||||
use crate::parser::{FromData, FromSlice, LazyArray16, LazyOffsetArray16, Stream};
|
||||
|
||||
/// A [Contextual Lookup Subtable](
|
||||
/// https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#seqctxt1).
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum ContextLookup<'a> {
|
||||
/// Simple glyph contexts.
|
||||
Format1 {
|
||||
coverage: Coverage<'a>,
|
||||
sets: SequenceRuleSets<'a>,
|
||||
},
|
||||
/// Class-based glyph contexts.
|
||||
Format2 {
|
||||
coverage: Coverage<'a>,
|
||||
classes: ClassDefinition<'a>,
|
||||
sets: SequenceRuleSets<'a>,
|
||||
},
|
||||
/// Coverage-based glyph contexts.
|
||||
Format3 {
|
||||
coverage: Coverage<'a>,
|
||||
coverages: LazyOffsetArray16<'a, Coverage<'a>>,
|
||||
lookups: LazyArray16<'a, SequenceLookupRecord>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> ContextLookup<'a> {
|
||||
pub(crate) fn parse(data: &'a [u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
match s.read::<u16>()? {
|
||||
1 => {
|
||||
let coverage = Coverage::parse(s.read_at_offset16(data)?)?;
|
||||
let count = s.read::<u16>()?;
|
||||
let offsets = s.read_array16(count)?;
|
||||
Some(Self::Format1 {
|
||||
coverage,
|
||||
sets: SequenceRuleSets::new(data, offsets),
|
||||
})
|
||||
}
|
||||
2 => {
|
||||
let coverage = Coverage::parse(s.read_at_offset16(data)?)?;
|
||||
let classes = ClassDefinition::parse(s.read_at_offset16(data)?)?;
|
||||
let count = s.read::<u16>()?;
|
||||
let offsets = s.read_array16(count)?;
|
||||
Some(Self::Format2 {
|
||||
coverage,
|
||||
classes,
|
||||
sets: SequenceRuleSets::new(data, offsets),
|
||||
})
|
||||
}
|
||||
3 => {
|
||||
let input_count = s.read::<u16>()?;
|
||||
let lookup_count = s.read::<u16>()?;
|
||||
let coverage = Coverage::parse(s.read_at_offset16(data)?)?;
|
||||
let coverages = s.read_array16(input_count.checked_sub(1)?)?;
|
||||
let lookups = s.read_array16(lookup_count)?;
|
||||
Some(Self::Format3 {
|
||||
coverage,
|
||||
coverages: LazyOffsetArray16::new(data, coverages),
|
||||
lookups,
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the subtable coverage.
|
||||
#[inline]
|
||||
pub fn coverage(&self) -> Coverage<'a> {
|
||||
match self {
|
||||
Self::Format1 { coverage, .. } => *coverage,
|
||||
Self::Format2 { coverage, .. } => *coverage,
|
||||
Self::Format3 { coverage, .. } => *coverage,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A list of [`SequenceRuleSet`]s.
|
||||
pub type SequenceRuleSets<'a> = LazyOffsetArray16<'a, SequenceRuleSet<'a>>;
|
||||
|
||||
impl<'a> FromSlice<'a> for SequenceRuleSet<'a> {
|
||||
fn parse(data: &'a [u8]) -> Option<Self> {
|
||||
Self::parse(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromSlice<'a> for SequenceRule<'a> {
|
||||
fn parse(data: &'a [u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
let input_count = s.read::<u16>()?;
|
||||
let lookup_count = s.read::<u16>()?;
|
||||
let input = s.read_array16(input_count.checked_sub(1)?)?;
|
||||
let lookups = s.read_array16(lookup_count)?;
|
||||
Some(Self { input, lookups })
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of [`SequenceRule`]s.
|
||||
pub type SequenceRuleSet<'a> = LazyOffsetArray16<'a, SequenceRule<'a>>;
|
||||
|
||||
/// A sequence rule.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct SequenceRule<'a> {
|
||||
pub input: LazyArray16<'a, u16>,
|
||||
pub lookups: LazyArray16<'a, SequenceLookupRecord>,
|
||||
}
|
||||
|
||||
/// A sequence rule record.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct SequenceLookupRecord {
|
||||
pub sequence_index: u16,
|
||||
pub lookup_list_index: LookupIndex,
|
||||
}
|
||||
|
||||
impl FromData for SequenceLookupRecord {
|
||||
const SIZE: usize = 4;
|
||||
|
||||
#[inline]
|
||||
fn parse(data: &[u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
Some(Self {
|
||||
sequence_index: s.read::<u16>()?,
|
||||
lookup_list_index: s.read::<LookupIndex>()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
186
third-party/vendor/ttf-parser/src/ggg/feature_variations.rs
vendored
Normal file
186
third-party/vendor/ttf-parser/src/ggg/feature_variations.rs
vendored
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
use super::{Feature, FeatureIndex, RecordListItem, VariationIndex};
|
||||
use crate::parser::{FromData, LazyArray16, LazyArray32};
|
||||
use crate::parser::{Offset, Offset32, Stream};
|
||||
use crate::{NormalizedCoordinate, Tag};
|
||||
|
||||
/// A [Feature Variations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featurevariations-table).
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct FeatureVariations<'a> {
|
||||
data: &'a [u8],
|
||||
records: LazyArray32<'a, FeatureVariationRecord>,
|
||||
}
|
||||
|
||||
impl<'a> FeatureVariations<'a> {
|
||||
pub(crate) fn parse(data: &'a [u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
let major_version = s.read::<u16>()?;
|
||||
s.skip::<u16>(); // minor version
|
||||
if major_version != 1 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let count = s.read::<u32>()?;
|
||||
let records = s.read_array32(count)?;
|
||||
Some(Self { data, records })
|
||||
}
|
||||
|
||||
/// Returns a [`VariationIndex`] for variation coordinates.
|
||||
pub fn find_index(&self, coords: &[NormalizedCoordinate]) -> Option<VariationIndex> {
|
||||
for i in 0..self.records.len() {
|
||||
let record = self.records.get(i)?;
|
||||
let offset = record.conditions.to_usize();
|
||||
let set = ConditionSet::parse(self.data.get(offset..)?)?;
|
||||
if set.evaluate(coords) {
|
||||
return Some(i);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns a [`Feature`] at specified indices.
|
||||
pub fn find_substitute(
|
||||
&self,
|
||||
feature_index: FeatureIndex,
|
||||
variation_index: VariationIndex,
|
||||
) -> Option<Feature<'a>> {
|
||||
let offset = self.records.get(variation_index)?.substitutions.to_usize();
|
||||
let subst = FeatureTableSubstitution::parse(self.data.get(offset..)?)?;
|
||||
subst.find_substitute(feature_index)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct FeatureVariationRecord {
|
||||
conditions: Offset32,
|
||||
substitutions: Offset32,
|
||||
}
|
||||
|
||||
impl FromData for FeatureVariationRecord {
|
||||
const SIZE: usize = 8;
|
||||
|
||||
#[inline]
|
||||
fn parse(data: &[u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
Some(Self {
|
||||
conditions: s.read::<Offset32>()?,
|
||||
substitutions: s.read::<Offset32>()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct ConditionSet<'a> {
|
||||
data: &'a [u8],
|
||||
conditions: LazyArray16<'a, Offset32>,
|
||||
}
|
||||
|
||||
impl<'a> ConditionSet<'a> {
|
||||
fn parse(data: &'a [u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
let count = s.read::<u16>()?;
|
||||
let conditions = s.read_array16(count)?;
|
||||
Some(Self { data, conditions })
|
||||
}
|
||||
|
||||
fn evaluate(&self, coords: &[NormalizedCoordinate]) -> bool {
|
||||
self.conditions.into_iter().all(|offset| {
|
||||
self.data
|
||||
.get(offset.to_usize()..)
|
||||
.and_then(Condition::parse)
|
||||
.map_or(false, |c| c.evaluate(coords))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum Condition {
|
||||
Format1 {
|
||||
axis_index: u16,
|
||||
filter_range_min: i16,
|
||||
filter_range_max: i16,
|
||||
},
|
||||
}
|
||||
|
||||
impl Condition {
|
||||
fn parse(data: &[u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
let format = s.read::<u16>()?;
|
||||
match format {
|
||||
1 => {
|
||||
let axis_index = s.read::<u16>()?;
|
||||
let filter_range_min = s.read::<i16>()?;
|
||||
let filter_range_max = s.read::<i16>()?;
|
||||
Some(Self::Format1 {
|
||||
axis_index,
|
||||
filter_range_min,
|
||||
filter_range_max,
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate(&self, coords: &[NormalizedCoordinate]) -> bool {
|
||||
let Self::Format1 {
|
||||
axis_index,
|
||||
filter_range_min,
|
||||
filter_range_max,
|
||||
} = *self;
|
||||
let coord = coords
|
||||
.get(usize::from(axis_index))
|
||||
.map(|c| c.get())
|
||||
.unwrap_or(0);
|
||||
filter_range_min <= coord && coord <= filter_range_max
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct FeatureTableSubstitution<'a> {
|
||||
data: &'a [u8],
|
||||
records: LazyArray16<'a, FeatureTableSubstitutionRecord>,
|
||||
}
|
||||
|
||||
impl<'a> FeatureTableSubstitution<'a> {
|
||||
fn parse(data: &'a [u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
let major_version = s.read::<u16>()?;
|
||||
s.skip::<u16>(); // minor version
|
||||
if major_version != 1 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let count = s.read::<u16>()?;
|
||||
let records = s.read_array16(count)?;
|
||||
Some(Self { data, records })
|
||||
}
|
||||
|
||||
fn find_substitute(&self, feature_index: FeatureIndex) -> Option<Feature<'a>> {
|
||||
for record in self.records {
|
||||
if record.feature_index == feature_index {
|
||||
let offset = record.feature.to_usize();
|
||||
// TODO: set tag
|
||||
return Feature::parse(Tag::from_bytes(b"DFLT"), self.data.get(offset..)?);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct FeatureTableSubstitutionRecord {
|
||||
feature_index: FeatureIndex,
|
||||
feature: Offset32,
|
||||
}
|
||||
|
||||
impl FromData for FeatureTableSubstitutionRecord {
|
||||
const SIZE: usize = 6;
|
||||
|
||||
#[inline]
|
||||
fn parse(data: &[u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
Some(Self {
|
||||
feature_index: s.read::<FeatureIndex>()?,
|
||||
feature: s.read::<Offset32>()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
287
third-party/vendor/ttf-parser/src/ggg/layout_table.rs
vendored
Normal file
287
third-party/vendor/ttf-parser/src/ggg/layout_table.rs
vendored
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
// Suppresses `minor_version` variable warning.
|
||||
#![allow(unused_variables)]
|
||||
|
||||
#[cfg(feature = "variable-fonts")]
|
||||
use super::FeatureVariations;
|
||||
use super::LookupList;
|
||||
#[cfg(feature = "variable-fonts")]
|
||||
use crate::parser::Offset32;
|
||||
use crate::parser::{FromData, LazyArray16, Offset, Offset16, Stream};
|
||||
use crate::Tag;
|
||||
|
||||
/// A [Layout Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#table-organization).
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct LayoutTable<'a> {
|
||||
/// A list of all supported scripts.
|
||||
pub scripts: ScriptList<'a>,
|
||||
/// A list of all supported features.
|
||||
pub features: FeatureList<'a>,
|
||||
/// A list of all lookups.
|
||||
pub lookups: LookupList<'a>,
|
||||
/// Used to substitute an alternate set of lookup tables
|
||||
/// to use for any given feature under specified conditions.
|
||||
#[cfg(feature = "variable-fonts")]
|
||||
pub variations: Option<FeatureVariations<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> LayoutTable<'a> {
|
||||
pub(crate) fn parse(data: &'a [u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
|
||||
let major_version = s.read::<u16>()?;
|
||||
let minor_version = s.read::<u16>()?;
|
||||
if major_version != 1 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let scripts = ScriptList::parse(s.read_at_offset16(data)?)?;
|
||||
let features = FeatureList::parse(s.read_at_offset16(data)?)?;
|
||||
let lookups = LookupList::parse(s.read_at_offset16(data)?)?;
|
||||
|
||||
#[cfg(feature = "variable-fonts")]
|
||||
{
|
||||
let mut variations_offset = None;
|
||||
if minor_version >= 1 {
|
||||
variations_offset = s.read::<Option<Offset32>>()?;
|
||||
}
|
||||
|
||||
let variations = match variations_offset {
|
||||
Some(offset) => data
|
||||
.get(offset.to_usize()..)
|
||||
.and_then(FeatureVariations::parse),
|
||||
None => None,
|
||||
};
|
||||
|
||||
Some(Self {
|
||||
scripts,
|
||||
features,
|
||||
lookups,
|
||||
variations,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "variable-fonts"))]
|
||||
{
|
||||
Some(Self {
|
||||
scripts,
|
||||
features,
|
||||
lookups,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An index in [`ScriptList`].
|
||||
pub type ScriptIndex = u16;
|
||||
/// An index in [`LanguageSystemList`].
|
||||
pub type LanguageIndex = u16;
|
||||
/// An index in [`FeatureList`].
|
||||
pub type FeatureIndex = u16;
|
||||
/// An index in [`LookupList`].
|
||||
pub type LookupIndex = u16;
|
||||
/// An index in [`FeatureVariations`].
|
||||
pub type VariationIndex = u32;
|
||||
|
||||
/// A trait to parse item in [`RecordList`].
|
||||
///
|
||||
/// Internal use only.
|
||||
pub trait RecordListItem<'a>: Sized {
|
||||
/// Parses raw data.
|
||||
fn parse(tag: Tag, data: &'a [u8]) -> Option<Self>;
|
||||
}
|
||||
|
||||
/// A data storage used by [`ScriptList`], [`LanguageSystemList`] and [`FeatureList`] data types.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct RecordList<'a, T: RecordListItem<'a>> {
|
||||
data: &'a [u8],
|
||||
records: LazyArray16<'a, TagRecord>,
|
||||
data_type: core::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: RecordListItem<'a>> RecordList<'a, T> {
|
||||
fn parse(data: &'a [u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
let count = s.read::<u16>()?;
|
||||
let records = s.read_array16(count)?;
|
||||
Some(Self {
|
||||
data,
|
||||
records,
|
||||
data_type: core::marker::PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a number of items in the RecordList.
|
||||
pub fn len(&self) -> u16 {
|
||||
self.records.len()
|
||||
}
|
||||
|
||||
/// Checks that RecordList is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.records.is_empty()
|
||||
}
|
||||
|
||||
/// Returns RecordList value by index.
|
||||
pub fn get(&self, index: u16) -> Option<T> {
|
||||
let record = self.records.get(index)?;
|
||||
self.data
|
||||
.get(record.offset.to_usize()..)
|
||||
.and_then(|data| T::parse(record.tag, data))
|
||||
}
|
||||
|
||||
/// Returns RecordList value by [`Tag`].
|
||||
pub fn find(&self, tag: Tag) -> Option<T> {
|
||||
let record = self
|
||||
.records
|
||||
.binary_search_by(|record| record.tag.cmp(&tag))
|
||||
.map(|p| p.1)?;
|
||||
self.data
|
||||
.get(record.offset.to_usize()..)
|
||||
.and_then(|data| T::parse(record.tag, data))
|
||||
}
|
||||
|
||||
/// Returns RecordList value index by [`Tag`].
|
||||
pub fn index(&self, tag: Tag) -> Option<u16> {
|
||||
self.records
|
||||
.binary_search_by(|record| record.tag.cmp(&tag))
|
||||
.map(|p| p.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: RecordListItem<'a>> IntoIterator for RecordList<'a, T> {
|
||||
type Item = T;
|
||||
type IntoIter = RecordListIter<'a, T>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
RecordListIter {
|
||||
list: self,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over [`RecordList`] values.
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct RecordListIter<'a, T: RecordListItem<'a>> {
|
||||
list: RecordList<'a, T>,
|
||||
index: u16,
|
||||
}
|
||||
|
||||
impl<'a, T: RecordListItem<'a>> Iterator for RecordListIter<'a, T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.index < self.list.len() {
|
||||
self.index += 1;
|
||||
self.list.get(self.index - 1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A list of [`Script`] records.
|
||||
pub type ScriptList<'a> = RecordList<'a, Script<'a>>;
|
||||
/// A list of [`LanguageSystem`] records.
|
||||
pub type LanguageSystemList<'a> = RecordList<'a, LanguageSystem<'a>>;
|
||||
/// A list of [`Feature`] records.
|
||||
pub type FeatureList<'a> = RecordList<'a, Feature<'a>>;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct TagRecord {
|
||||
tag: Tag,
|
||||
offset: Offset16,
|
||||
}
|
||||
|
||||
impl FromData for TagRecord {
|
||||
const SIZE: usize = 6;
|
||||
|
||||
#[inline]
|
||||
fn parse(data: &[u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
Some(Self {
|
||||
tag: s.read::<Tag>()?,
|
||||
offset: s.read::<Offset16>()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A [Script Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-table-and-language-system-record).
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Script<'a> {
|
||||
/// Script tag.
|
||||
pub tag: Tag,
|
||||
/// Default language.
|
||||
pub default_language: Option<LanguageSystem<'a>>,
|
||||
/// List of supported languages, excluding the default one. Listed alphabetically.
|
||||
pub languages: LanguageSystemList<'a>,
|
||||
}
|
||||
|
||||
impl<'a> RecordListItem<'a> for Script<'a> {
|
||||
fn parse(tag: Tag, data: &'a [u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
let mut default_language = None;
|
||||
if let Some(offset) = s.read::<Option<Offset16>>()? {
|
||||
default_language =
|
||||
LanguageSystem::parse(Tag::from_bytes(b"dflt"), data.get(offset.to_usize()..)?);
|
||||
}
|
||||
let mut languages = RecordList::parse(s.tail()?)?;
|
||||
// Offsets are relative to this table.
|
||||
languages.data = data;
|
||||
Some(Self {
|
||||
tag,
|
||||
default_language,
|
||||
languages,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A [Language System Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#language-system-table).
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct LanguageSystem<'a> {
|
||||
/// Language tag.
|
||||
pub tag: Tag,
|
||||
/// Index of a feature required for this language system.
|
||||
pub required_feature: Option<FeatureIndex>,
|
||||
/// Array of indices into the FeatureList, in arbitrary order.
|
||||
pub feature_indices: LazyArray16<'a, FeatureIndex>,
|
||||
}
|
||||
|
||||
impl<'a> RecordListItem<'a> for LanguageSystem<'a> {
|
||||
fn parse(tag: Tag, data: &'a [u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
let _lookup_order = s.read::<Offset16>()?; // Unsupported.
|
||||
let required_feature = match s.read::<FeatureIndex>()? {
|
||||
0xFFFF => None,
|
||||
v => Some(v),
|
||||
};
|
||||
let count = s.read::<u16>()?;
|
||||
let feature_indices = s.read_array16(count)?;
|
||||
Some(Self {
|
||||
tag,
|
||||
required_feature,
|
||||
feature_indices,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A [Feature](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-table).
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Feature<'a> {
|
||||
pub tag: Tag,
|
||||
pub lookup_indices: LazyArray16<'a, LookupIndex>,
|
||||
}
|
||||
|
||||
impl<'a> RecordListItem<'a> for Feature<'a> {
|
||||
fn parse(tag: Tag, data: &'a [u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
let _params_offset = s.read::<Offset16>()?; // Unsupported.
|
||||
let count = s.read::<u16>()?;
|
||||
let lookup_indices = s.read_array16(count)?;
|
||||
Some(Self {
|
||||
tag,
|
||||
lookup_indices,
|
||||
})
|
||||
}
|
||||
}
|
||||
165
third-party/vendor/ttf-parser/src/ggg/lookup.rs
vendored
Normal file
165
third-party/vendor/ttf-parser/src/ggg/lookup.rs
vendored
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
use crate::parser::{
|
||||
FromData, FromSlice, LazyArray16, LazyOffsetArray16, Offset, Offset16, Offset32, Stream,
|
||||
};
|
||||
|
||||
/// A list of [`Lookup`] values.
|
||||
pub type LookupList<'a> = LazyOffsetArray16<'a, Lookup<'a>>;
|
||||
|
||||
/// A [Lookup Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-table).
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Lookup<'a> {
|
||||
/// Lookup qualifiers.
|
||||
pub flags: LookupFlags,
|
||||
/// Available subtables.
|
||||
pub subtables: LookupSubtables<'a>,
|
||||
/// Index into GDEF mark glyph sets structure.
|
||||
pub mark_filtering_set: Option<u16>,
|
||||
}
|
||||
|
||||
impl<'a> FromSlice<'a> for Lookup<'a> {
|
||||
fn parse(data: &'a [u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
let kind = s.read::<u16>()?;
|
||||
let flags = s.read::<LookupFlags>()?;
|
||||
let count = s.read::<u16>()?;
|
||||
let offsets = s.read_array16(count)?;
|
||||
|
||||
let mut mark_filtering_set: Option<u16> = None;
|
||||
if flags.use_mark_filtering_set() {
|
||||
mark_filtering_set = Some(s.read::<u16>()?);
|
||||
}
|
||||
|
||||
Some(Self {
|
||||
flags,
|
||||
subtables: LookupSubtables {
|
||||
kind,
|
||||
data,
|
||||
offsets,
|
||||
},
|
||||
mark_filtering_set,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for parsing Lookup subtables.
|
||||
///
|
||||
/// Internal use only.
|
||||
pub trait LookupSubtable<'a>: Sized {
|
||||
/// Parses raw data.
|
||||
fn parse(data: &'a [u8], kind: u16) -> Option<Self>;
|
||||
}
|
||||
|
||||
/// A list of lookup subtables.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct LookupSubtables<'a> {
|
||||
kind: u16,
|
||||
data: &'a [u8],
|
||||
offsets: LazyArray16<'a, Offset16>,
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for LookupSubtables<'_> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
write!(f, "LookupSubtables {{ ... }}")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> LookupSubtables<'a> {
|
||||
/// Returns a number of items in the LookupSubtables.
|
||||
#[inline]
|
||||
pub fn len(&self) -> u16 {
|
||||
self.offsets.len()
|
||||
}
|
||||
|
||||
/// Checks if there are any items.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.offsets.is_empty()
|
||||
}
|
||||
|
||||
/// Parses a subtable at index.
|
||||
///
|
||||
/// Accepts either
|
||||
/// [`PositioningSubtable`](crate::gpos::PositioningSubtable)
|
||||
/// or [`SubstitutionSubtable`](crate::gsub::SubstitutionSubtable).
|
||||
///
|
||||
/// Technically, we can enforce it at compile time, but it makes code too convoluted.
|
||||
pub fn get<T: LookupSubtable<'a>>(&self, index: u16) -> Option<T> {
|
||||
let offset = self.offsets.get(index)?.to_usize();
|
||||
let data = self.data.get(offset..)?;
|
||||
T::parse(data, self.kind)
|
||||
}
|
||||
|
||||
/// Creates an iterator over subtables.
|
||||
///
|
||||
/// We cannot use `IntoIterator` here, because we have to use user-provided base type.
|
||||
#[allow(clippy::should_implement_trait)]
|
||||
pub fn into_iter<T: LookupSubtable<'a>>(self) -> LookupSubtablesIter<'a, T> {
|
||||
LookupSubtablesIter {
|
||||
data: self,
|
||||
index: 0,
|
||||
data_type: core::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over lookup subtables.
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct LookupSubtablesIter<'a, T: LookupSubtable<'a>> {
|
||||
data: LookupSubtables<'a>,
|
||||
index: u16,
|
||||
data_type: core::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: LookupSubtable<'a>> Iterator for LookupSubtablesIter<'a, T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.index < self.data.len() {
|
||||
self.index += 1;
|
||||
self.data.get(self.index - 1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lookup table flags.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct LookupFlags(pub u16);
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[allow(missing_docs)]
|
||||
impl LookupFlags {
|
||||
#[inline] pub fn right_to_left(self) -> bool { self.0 & 0x0001 != 0 }
|
||||
#[inline] pub fn ignore_base_glyphs(self) -> bool { self.0 & 0x0002 != 0 }
|
||||
#[inline] pub fn ignore_ligatures(self) -> bool { self.0 & 0x0004 != 0 }
|
||||
#[inline] pub fn ignore_marks(self) -> bool { self.0 & 0x0008 != 0 }
|
||||
#[inline] pub fn ignore_flags(self) -> bool { self.0 & 0x000E != 0 }
|
||||
#[inline] pub fn use_mark_filtering_set(self) -> bool { self.0 & 0x0010 != 0 }
|
||||
#[inline] pub fn mark_attachment_type(self) -> u8 { (self.0 & 0xFF00) as u8 }
|
||||
}
|
||||
|
||||
impl FromData for LookupFlags {
|
||||
const SIZE: usize = 2;
|
||||
|
||||
#[inline]
|
||||
fn parse(data: &[u8]) -> Option<Self> {
|
||||
u16::parse(data).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parse_extension_lookup<'a, T: 'a>(
|
||||
data: &'a [u8],
|
||||
parse: impl FnOnce(&'a [u8], u16) -> Option<T>,
|
||||
) -> Option<T> {
|
||||
let mut s = Stream::new(data);
|
||||
let format = s.read::<u16>()?;
|
||||
match format {
|
||||
1 => {
|
||||
let kind = s.read::<u16>()?;
|
||||
let offset = s.read::<Offset32>()?.to_usize();
|
||||
parse(data.get(offset..)?, kind)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
168
third-party/vendor/ttf-parser/src/ggg/mod.rs
vendored
Normal file
168
third-party/vendor/ttf-parser/src/ggg/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
//! Common data types used by GDEF/GPOS/GSUB tables.
|
||||
//!
|
||||
//! <https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2>
|
||||
|
||||
// A heavily modified port of https://github.com/RazrFalcon/rustybuzz implementation
|
||||
// originally written by https://github.com/laurmaedje
|
||||
|
||||
use crate::parser::{FromData, FromSlice, LazyArray16, Stream};
|
||||
use crate::GlyphId;
|
||||
|
||||
mod chained_context;
|
||||
mod context;
|
||||
#[cfg(feature = "variable-fonts")]
|
||||
mod feature_variations;
|
||||
mod layout_table;
|
||||
mod lookup;
|
||||
|
||||
pub use chained_context::*;
|
||||
pub use context::*;
|
||||
#[cfg(feature = "variable-fonts")]
|
||||
pub use feature_variations::*;
|
||||
pub use layout_table::*;
|
||||
pub use lookup::*;
|
||||
|
||||
/// A record that describes a range of glyph IDs.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct RangeRecord {
|
||||
/// First glyph ID in the range
|
||||
pub start: GlyphId,
|
||||
/// Last glyph ID in the range
|
||||
pub end: GlyphId,
|
||||
/// Coverage Index of first glyph ID in range.
|
||||
pub value: u16,
|
||||
}
|
||||
|
||||
impl LazyArray16<'_, RangeRecord> {
|
||||
/// Returns a [`RangeRecord`] for a glyph.
|
||||
pub fn range(&self, glyph: GlyphId) -> Option<RangeRecord> {
|
||||
self.binary_search_by(|record| {
|
||||
if glyph < record.start {
|
||||
core::cmp::Ordering::Greater
|
||||
} else if glyph <= record.end {
|
||||
core::cmp::Ordering::Equal
|
||||
} else {
|
||||
core::cmp::Ordering::Less
|
||||
}
|
||||
})
|
||||
.map(|p| p.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromData for RangeRecord {
|
||||
const SIZE: usize = 6;
|
||||
|
||||
#[inline]
|
||||
fn parse(data: &[u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
Some(RangeRecord {
|
||||
start: s.read::<GlyphId>()?,
|
||||
end: s.read::<GlyphId>()?,
|
||||
value: s.read::<u16>()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A [Coverage Table](
|
||||
/// https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-table).
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Coverage<'a> {
|
||||
Format1 {
|
||||
/// Array of glyph IDs. Sorted.
|
||||
glyphs: LazyArray16<'a, GlyphId>,
|
||||
},
|
||||
Format2 {
|
||||
/// Array of glyph ranges. Ordered by `RangeRecord.start`.
|
||||
records: LazyArray16<'a, RangeRecord>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> FromSlice<'a> for Coverage<'a> {
|
||||
fn parse(data: &'a [u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
match s.read::<u16>()? {
|
||||
1 => {
|
||||
let count = s.read::<u16>()?;
|
||||
let glyphs = s.read_array16(count)?;
|
||||
Some(Self::Format1 { glyphs })
|
||||
}
|
||||
2 => {
|
||||
let count = s.read::<u16>()?;
|
||||
let records = s.read_array16(count)?;
|
||||
Some(Self::Format2 { records })
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Coverage<'a> {
|
||||
/// Checks that glyph is present.
|
||||
pub fn contains(&self, glyph: GlyphId) -> bool {
|
||||
self.get(glyph).is_some()
|
||||
}
|
||||
|
||||
/// Returns the coverage index of the glyph or `None` if it is not covered.
|
||||
pub fn get(&self, glyph: GlyphId) -> Option<u16> {
|
||||
match self {
|
||||
Self::Format1 { glyphs } => glyphs.binary_search(&glyph).map(|p| p.0),
|
||||
Self::Format2 { records } => {
|
||||
let record = records.range(glyph)?;
|
||||
let offset = glyph.0 - record.start.0;
|
||||
record.value.checked_add(offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A value of [Class Definition Table](
|
||||
/// https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table).
|
||||
pub type Class = u16;
|
||||
|
||||
/// A [Class Definition Table](
|
||||
/// https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table).
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum ClassDefinition<'a> {
|
||||
Format1 {
|
||||
start: GlyphId,
|
||||
classes: LazyArray16<'a, Class>,
|
||||
},
|
||||
Format2 {
|
||||
records: LazyArray16<'a, RangeRecord>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> ClassDefinition<'a> {
|
||||
#[inline]
|
||||
pub(crate) fn parse(data: &'a [u8]) -> Option<Self> {
|
||||
let mut s = Stream::new(data);
|
||||
match s.read::<u16>()? {
|
||||
1 => {
|
||||
let start = s.read::<GlyphId>()?;
|
||||
let count = s.read::<u16>()?;
|
||||
let classes = s.read_array16(count)?;
|
||||
Some(Self::Format1 { start, classes })
|
||||
}
|
||||
2 => {
|
||||
let count = s.read::<u16>()?;
|
||||
let records = s.read_array16(count)?;
|
||||
Some(Self::Format2 { records })
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the glyph class of the glyph (zero if it is not defined).
|
||||
pub fn get(&self, glyph: GlyphId) -> Class {
|
||||
match self {
|
||||
Self::Format1 { start, classes } => glyph
|
||||
.0
|
||||
.checked_sub(start.0)
|
||||
.and_then(|index| classes.get(index)),
|
||||
Self::Format2 { records } => records.range(glyph).map(|record| record.value),
|
||||
}
|
||||
.unwrap_or(0)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue