2133 lines
68 KiB
Rust
2133 lines
68 KiB
Rust
// 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::*;
|
||
|
||
/// [cmap](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#overview)
|
||
#[derive(Debug, Clone, Copy)]
|
||
#[doc(hidden)]
|
||
pub struct CmapMarker {
|
||
encoding_records_byte_len: usize,
|
||
}
|
||
|
||
impl CmapMarker {
|
||
pub fn version_byte_range(&self) -> Range<usize> {
|
||
let start = 0;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn num_tables_byte_range(&self) -> Range<usize> {
|
||
let start = self.version_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn encoding_records_byte_range(&self) -> Range<usize> {
|
||
let start = self.num_tables_byte_range().end;
|
||
start..start + self.encoding_records_byte_len
|
||
}
|
||
}
|
||
|
||
impl MinByteRange for CmapMarker {
|
||
fn min_byte_range(&self) -> Range<usize> {
|
||
0..self.encoding_records_byte_range().end
|
||
}
|
||
}
|
||
|
||
impl TopLevelTable for Cmap<'_> {
|
||
/// `cmap`
|
||
const TAG: Tag = Tag::new(b"cmap");
|
||
}
|
||
|
||
impl<'a> FontRead<'a> for Cmap<'a> {
|
||
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
|
||
let mut cursor = data.cursor();
|
||
cursor.advance::<u16>();
|
||
let num_tables: u16 = cursor.read()?;
|
||
let encoding_records_byte_len = (num_tables as usize)
|
||
.checked_mul(EncodingRecord::RAW_BYTE_LEN)
|
||
.ok_or(ReadError::OutOfBounds)?;
|
||
cursor.advance_by(encoding_records_byte_len);
|
||
cursor.finish(CmapMarker {
|
||
encoding_records_byte_len,
|
||
})
|
||
}
|
||
}
|
||
|
||
/// [cmap](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#overview)
|
||
pub type Cmap<'a> = TableRef<'a, CmapMarker>;
|
||
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> Cmap<'a> {
|
||
/// Table version number (0).
|
||
pub fn version(&self) -> u16 {
|
||
let range = self.shape.version_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Number of encoding tables that follow.
|
||
pub fn num_tables(&self) -> u16 {
|
||
let range = self.shape.num_tables_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
pub fn encoding_records(&self) -> &'a [EncodingRecord] {
|
||
let range = self.shape.encoding_records_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeTable<'a> for Cmap<'a> {
|
||
fn type_name(&self) -> &str {
|
||
"Cmap"
|
||
}
|
||
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
|
||
match idx {
|
||
0usize => Some(Field::new("version", self.version())),
|
||
1usize => Some(Field::new("num_tables", self.num_tables())),
|
||
2usize => Some(Field::new(
|
||
"encoding_records",
|
||
traversal::FieldType::array_of_records(
|
||
stringify!(EncodingRecord),
|
||
self.encoding_records(),
|
||
self.offset_data(),
|
||
),
|
||
)),
|
||
_ => None,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> std::fmt::Debug for Cmap<'a> {
|
||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
(self as &dyn SomeTable<'a>).fmt(f)
|
||
}
|
||
}
|
||
|
||
/// [Encoding Record](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#encoding-records-and-encodings)
|
||
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
|
||
#[repr(C)]
|
||
#[repr(packed)]
|
||
pub struct EncodingRecord {
|
||
/// Platform ID.
|
||
pub platform_id: BigEndian<PlatformId>,
|
||
/// Platform-specific encoding ID.
|
||
pub encoding_id: BigEndian<u16>,
|
||
/// Byte offset from beginning of the [`Cmap`] table to the subtable for this
|
||
/// encoding.
|
||
pub subtable_offset: BigEndian<Offset32>,
|
||
}
|
||
|
||
impl EncodingRecord {
|
||
/// Platform ID.
|
||
pub fn platform_id(&self) -> PlatformId {
|
||
self.platform_id.get()
|
||
}
|
||
|
||
/// Platform-specific encoding ID.
|
||
pub fn encoding_id(&self) -> u16 {
|
||
self.encoding_id.get()
|
||
}
|
||
|
||
/// Byte offset from beginning of the [`Cmap`] table to the subtable for this
|
||
/// encoding.
|
||
pub fn subtable_offset(&self) -> Offset32 {
|
||
self.subtable_offset.get()
|
||
}
|
||
|
||
/// Byte offset from beginning of the [`Cmap`] table to the subtable for this
|
||
/// encoding.
|
||
///
|
||
/// The `data` argument should be retrieved from the parent table
|
||
/// By calling its `offset_data` method.
|
||
pub fn subtable<'a>(&self, data: FontData<'a>) -> Result<CmapSubtable<'a>, ReadError> {
|
||
self.subtable_offset().resolve(data)
|
||
}
|
||
}
|
||
|
||
impl FixedSize for EncodingRecord {
|
||
const RAW_BYTE_LEN: usize =
|
||
PlatformId::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeRecord<'a> for EncodingRecord {
|
||
fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
|
||
RecordResolver {
|
||
name: "EncodingRecord",
|
||
get_field: Box::new(move |idx, _data| match idx {
|
||
0usize => Some(Field::new("platform_id", self.platform_id())),
|
||
1usize => Some(Field::new("encoding_id", self.encoding_id())),
|
||
2usize => Some(Field::new(
|
||
"subtable_offset",
|
||
FieldType::offset(self.subtable_offset(), self.subtable(_data)),
|
||
)),
|
||
_ => None,
|
||
}),
|
||
data,
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#platform-ids>
|
||
#[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 PlatformId {
|
||
#[default]
|
||
Unicode = 0,
|
||
Macintosh = 1,
|
||
ISO = 2,
|
||
Windows = 3,
|
||
Custom = 4,
|
||
#[doc(hidden)]
|
||
/// If font data is malformed we will map unknown values to this variant
|
||
Unknown,
|
||
}
|
||
|
||
impl PlatformId {
|
||
/// 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 {
|
||
0 => Self::Unicode,
|
||
1 => Self::Macintosh,
|
||
2 => Self::ISO,
|
||
3 => Self::Windows,
|
||
4 => Self::Custom,
|
||
_ => Self::Unknown,
|
||
}
|
||
}
|
||
}
|
||
|
||
impl font_types::Scalar for PlatformId {
|
||
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<PlatformId> for FieldType<'a> {
|
||
fn from(src: PlatformId) -> FieldType<'a> {
|
||
(src as u16).into()
|
||
}
|
||
}
|
||
|
||
/// The different cmap subtable formats.
|
||
#[derive(Clone)]
|
||
pub enum CmapSubtable<'a> {
|
||
Format0(Cmap0<'a>),
|
||
Format2(Cmap2<'a>),
|
||
Format4(Cmap4<'a>),
|
||
Format6(Cmap6<'a>),
|
||
Format8(Cmap8<'a>),
|
||
Format10(Cmap10<'a>),
|
||
Format12(Cmap12<'a>),
|
||
Format13(Cmap13<'a>),
|
||
Format14(Cmap14<'a>),
|
||
}
|
||
|
||
impl<'a> CmapSubtable<'a> {
|
||
///Return the `FontData` used to resolve offsets for this table.
|
||
pub fn offset_data(&self) -> FontData<'a> {
|
||
match self {
|
||
Self::Format0(item) => item.offset_data(),
|
||
Self::Format2(item) => item.offset_data(),
|
||
Self::Format4(item) => item.offset_data(),
|
||
Self::Format6(item) => item.offset_data(),
|
||
Self::Format8(item) => item.offset_data(),
|
||
Self::Format10(item) => item.offset_data(),
|
||
Self::Format12(item) => item.offset_data(),
|
||
Self::Format13(item) => item.offset_data(),
|
||
Self::Format14(item) => item.offset_data(),
|
||
}
|
||
}
|
||
|
||
/// Format number is set to 0.
|
||
pub fn format(&self) -> u16 {
|
||
match self {
|
||
Self::Format0(item) => item.format(),
|
||
Self::Format2(item) => item.format(),
|
||
Self::Format4(item) => item.format(),
|
||
Self::Format6(item) => item.format(),
|
||
Self::Format8(item) => item.format(),
|
||
Self::Format10(item) => item.format(),
|
||
Self::Format12(item) => item.format(),
|
||
Self::Format13(item) => item.format(),
|
||
Self::Format14(item) => item.format(),
|
||
}
|
||
}
|
||
}
|
||
|
||
impl<'a> FontRead<'a> for CmapSubtable<'a> {
|
||
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
|
||
let format: u16 = data.read_at(0usize)?;
|
||
match format {
|
||
Cmap0Marker::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
|
||
Cmap2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
|
||
Cmap4Marker::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
|
||
Cmap6Marker::FORMAT => Ok(Self::Format6(FontRead::read(data)?)),
|
||
Cmap8Marker::FORMAT => Ok(Self::Format8(FontRead::read(data)?)),
|
||
Cmap10Marker::FORMAT => Ok(Self::Format10(FontRead::read(data)?)),
|
||
Cmap12Marker::FORMAT => Ok(Self::Format12(FontRead::read(data)?)),
|
||
Cmap13Marker::FORMAT => Ok(Self::Format13(FontRead::read(data)?)),
|
||
Cmap14Marker::FORMAT => Ok(Self::Format14(FontRead::read(data)?)),
|
||
other => Err(ReadError::InvalidFormat(other.into())),
|
||
}
|
||
}
|
||
}
|
||
|
||
impl MinByteRange for CmapSubtable<'_> {
|
||
fn min_byte_range(&self) -> Range<usize> {
|
||
match self {
|
||
Self::Format0(item) => item.min_byte_range(),
|
||
Self::Format2(item) => item.min_byte_range(),
|
||
Self::Format4(item) => item.min_byte_range(),
|
||
Self::Format6(item) => item.min_byte_range(),
|
||
Self::Format8(item) => item.min_byte_range(),
|
||
Self::Format10(item) => item.min_byte_range(),
|
||
Self::Format12(item) => item.min_byte_range(),
|
||
Self::Format13(item) => item.min_byte_range(),
|
||
Self::Format14(item) => item.min_byte_range(),
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> CmapSubtable<'a> {
|
||
fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
|
||
match self {
|
||
Self::Format0(table) => table,
|
||
Self::Format2(table) => table,
|
||
Self::Format4(table) => table,
|
||
Self::Format6(table) => table,
|
||
Self::Format8(table) => table,
|
||
Self::Format10(table) => table,
|
||
Self::Format12(table) => table,
|
||
Self::Format13(table) => table,
|
||
Self::Format14(table) => table,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl std::fmt::Debug for CmapSubtable<'_> {
|
||
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 CmapSubtable<'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 Cmap0Marker {
|
||
const FORMAT: u16 = 0;
|
||
}
|
||
|
||
/// [cmap Format 0](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-0-byte-encoding-table): Byte encoding table
|
||
#[derive(Debug, Clone, Copy)]
|
||
#[doc(hidden)]
|
||
pub struct Cmap0Marker {
|
||
glyph_id_array_byte_len: usize,
|
||
}
|
||
|
||
impl Cmap0Marker {
|
||
pub fn format_byte_range(&self) -> Range<usize> {
|
||
let start = 0;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn length_byte_range(&self) -> Range<usize> {
|
||
let start = self.format_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn language_byte_range(&self) -> Range<usize> {
|
||
let start = self.length_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
|
||
let start = self.language_byte_range().end;
|
||
start..start + self.glyph_id_array_byte_len
|
||
}
|
||
}
|
||
|
||
impl MinByteRange for Cmap0Marker {
|
||
fn min_byte_range(&self) -> Range<usize> {
|
||
0..self.glyph_id_array_byte_range().end
|
||
}
|
||
}
|
||
|
||
impl<'a> FontRead<'a> for Cmap0<'a> {
|
||
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
|
||
let mut cursor = data.cursor();
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u16>();
|
||
let glyph_id_array_byte_len = (256_usize)
|
||
.checked_mul(u8::RAW_BYTE_LEN)
|
||
.ok_or(ReadError::OutOfBounds)?;
|
||
cursor.advance_by(glyph_id_array_byte_len);
|
||
cursor.finish(Cmap0Marker {
|
||
glyph_id_array_byte_len,
|
||
})
|
||
}
|
||
}
|
||
|
||
/// [cmap Format 0](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-0-byte-encoding-table): Byte encoding table
|
||
pub type Cmap0<'a> = TableRef<'a, Cmap0Marker>;
|
||
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> Cmap0<'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()
|
||
}
|
||
|
||
/// This is the length in bytes of the subtable.
|
||
pub fn length(&self) -> u16 {
|
||
let range = self.shape.length_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// For requirements on use of the language field, see “Use of
|
||
/// the language field in 'cmap' subtables” in this document.
|
||
pub fn language(&self) -> u16 {
|
||
let range = self.shape.language_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// An array that maps character codes to glyph index values.
|
||
pub fn glyph_id_array(&self) -> &'a [u8] {
|
||
let range = self.shape.glyph_id_array_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeTable<'a> for Cmap0<'a> {
|
||
fn type_name(&self) -> &str {
|
||
"Cmap0"
|
||
}
|
||
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
|
||
match idx {
|
||
0usize => Some(Field::new("format", self.format())),
|
||
1usize => Some(Field::new("length", self.length())),
|
||
2usize => Some(Field::new("language", self.language())),
|
||
3usize => Some(Field::new("glyph_id_array", self.glyph_id_array())),
|
||
_ => None,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> std::fmt::Debug for Cmap0<'a> {
|
||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
(self as &dyn SomeTable<'a>).fmt(f)
|
||
}
|
||
}
|
||
|
||
impl Format<u16> for Cmap2Marker {
|
||
const FORMAT: u16 = 2;
|
||
}
|
||
|
||
/// [cmap Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-2-high-byte-mapping-through-table): High-byte mapping through table
|
||
#[derive(Debug, Clone, Copy)]
|
||
#[doc(hidden)]
|
||
pub struct Cmap2Marker {
|
||
sub_header_keys_byte_len: usize,
|
||
}
|
||
|
||
impl Cmap2Marker {
|
||
pub fn format_byte_range(&self) -> Range<usize> {
|
||
let start = 0;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn length_byte_range(&self) -> Range<usize> {
|
||
let start = self.format_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn language_byte_range(&self) -> Range<usize> {
|
||
let start = self.length_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn sub_header_keys_byte_range(&self) -> Range<usize> {
|
||
let start = self.language_byte_range().end;
|
||
start..start + self.sub_header_keys_byte_len
|
||
}
|
||
}
|
||
|
||
impl MinByteRange for Cmap2Marker {
|
||
fn min_byte_range(&self) -> Range<usize> {
|
||
0..self.sub_header_keys_byte_range().end
|
||
}
|
||
}
|
||
|
||
impl<'a> FontRead<'a> for Cmap2<'a> {
|
||
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
|
||
let mut cursor = data.cursor();
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u16>();
|
||
let sub_header_keys_byte_len = (256_usize)
|
||
.checked_mul(u16::RAW_BYTE_LEN)
|
||
.ok_or(ReadError::OutOfBounds)?;
|
||
cursor.advance_by(sub_header_keys_byte_len);
|
||
cursor.finish(Cmap2Marker {
|
||
sub_header_keys_byte_len,
|
||
})
|
||
}
|
||
}
|
||
|
||
/// [cmap Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-2-high-byte-mapping-through-table): High-byte mapping through table
|
||
pub type Cmap2<'a> = TableRef<'a, Cmap2Marker>;
|
||
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> Cmap2<'a> {
|
||
/// Format number is set to 2.
|
||
pub fn format(&self) -> u16 {
|
||
let range = self.shape.format_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// This is the length in bytes of the subtable.
|
||
pub fn length(&self) -> u16 {
|
||
let range = self.shape.length_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// For requirements on use of the language field, see “Use of
|
||
/// the language field in 'cmap' subtables” in this document.
|
||
pub fn language(&self) -> u16 {
|
||
let range = self.shape.language_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Array that maps high bytes to subHeaders: value is subHeader
|
||
/// index × 8.
|
||
pub fn sub_header_keys(&self) -> &'a [BigEndian<u16>] {
|
||
let range = self.shape.sub_header_keys_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeTable<'a> for Cmap2<'a> {
|
||
fn type_name(&self) -> &str {
|
||
"Cmap2"
|
||
}
|
||
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
|
||
match idx {
|
||
0usize => Some(Field::new("format", self.format())),
|
||
1usize => Some(Field::new("length", self.length())),
|
||
2usize => Some(Field::new("language", self.language())),
|
||
3usize => Some(Field::new("sub_header_keys", self.sub_header_keys())),
|
||
_ => None,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> std::fmt::Debug for Cmap2<'a> {
|
||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
(self as &dyn SomeTable<'a>).fmt(f)
|
||
}
|
||
}
|
||
|
||
/// Part of [Cmap2]
|
||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
|
||
#[repr(C)]
|
||
#[repr(packed)]
|
||
pub struct SubHeader {
|
||
/// First valid low byte for this SubHeader.
|
||
pub first_code: BigEndian<u16>,
|
||
/// Number of valid low bytes for this SubHeader.
|
||
pub entry_count: BigEndian<u16>,
|
||
/// See text below.
|
||
pub id_delta: BigEndian<i16>,
|
||
/// See text below.
|
||
pub id_range_offset: BigEndian<u16>,
|
||
}
|
||
|
||
impl SubHeader {
|
||
/// First valid low byte for this SubHeader.
|
||
pub fn first_code(&self) -> u16 {
|
||
self.first_code.get()
|
||
}
|
||
|
||
/// Number of valid low bytes for this SubHeader.
|
||
pub fn entry_count(&self) -> u16 {
|
||
self.entry_count.get()
|
||
}
|
||
|
||
/// See text below.
|
||
pub fn id_delta(&self) -> i16 {
|
||
self.id_delta.get()
|
||
}
|
||
|
||
/// See text below.
|
||
pub fn id_range_offset(&self) -> u16 {
|
||
self.id_range_offset.get()
|
||
}
|
||
}
|
||
|
||
impl FixedSize for SubHeader {
|
||
const RAW_BYTE_LEN: usize =
|
||
u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeRecord<'a> for SubHeader {
|
||
fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
|
||
RecordResolver {
|
||
name: "SubHeader",
|
||
get_field: Box::new(move |idx, _data| match idx {
|
||
0usize => Some(Field::new("first_code", self.first_code())),
|
||
1usize => Some(Field::new("entry_count", self.entry_count())),
|
||
2usize => Some(Field::new("id_delta", self.id_delta())),
|
||
3usize => Some(Field::new("id_range_offset", self.id_range_offset())),
|
||
_ => None,
|
||
}),
|
||
data,
|
||
}
|
||
}
|
||
}
|
||
|
||
impl Format<u16> for Cmap4Marker {
|
||
const FORMAT: u16 = 4;
|
||
}
|
||
|
||
/// [cmap Format 4](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-4-segment-mapping-to-delta-values): Segment mapping to delta values
|
||
#[derive(Debug, Clone, Copy)]
|
||
#[doc(hidden)]
|
||
pub struct Cmap4Marker {
|
||
end_code_byte_len: usize,
|
||
start_code_byte_len: usize,
|
||
id_delta_byte_len: usize,
|
||
id_range_offsets_byte_len: usize,
|
||
glyph_id_array_byte_len: usize,
|
||
}
|
||
|
||
impl Cmap4Marker {
|
||
pub fn format_byte_range(&self) -> Range<usize> {
|
||
let start = 0;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn length_byte_range(&self) -> Range<usize> {
|
||
let start = self.format_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn language_byte_range(&self) -> Range<usize> {
|
||
let start = self.length_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn seg_count_x2_byte_range(&self) -> Range<usize> {
|
||
let start = self.language_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn search_range_byte_range(&self) -> Range<usize> {
|
||
let start = self.seg_count_x2_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn entry_selector_byte_range(&self) -> Range<usize> {
|
||
let start = self.search_range_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn range_shift_byte_range(&self) -> Range<usize> {
|
||
let start = self.entry_selector_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn end_code_byte_range(&self) -> Range<usize> {
|
||
let start = self.range_shift_byte_range().end;
|
||
start..start + self.end_code_byte_len
|
||
}
|
||
|
||
pub fn reserved_pad_byte_range(&self) -> Range<usize> {
|
||
let start = self.end_code_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn start_code_byte_range(&self) -> Range<usize> {
|
||
let start = self.reserved_pad_byte_range().end;
|
||
start..start + self.start_code_byte_len
|
||
}
|
||
|
||
pub fn id_delta_byte_range(&self) -> Range<usize> {
|
||
let start = self.start_code_byte_range().end;
|
||
start..start + self.id_delta_byte_len
|
||
}
|
||
|
||
pub fn id_range_offsets_byte_range(&self) -> Range<usize> {
|
||
let start = self.id_delta_byte_range().end;
|
||
start..start + self.id_range_offsets_byte_len
|
||
}
|
||
|
||
pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
|
||
let start = self.id_range_offsets_byte_range().end;
|
||
start..start + self.glyph_id_array_byte_len
|
||
}
|
||
}
|
||
|
||
impl MinByteRange for Cmap4Marker {
|
||
fn min_byte_range(&self) -> Range<usize> {
|
||
0..self.glyph_id_array_byte_range().end
|
||
}
|
||
}
|
||
|
||
impl<'a> FontRead<'a> for Cmap4<'a> {
|
||
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
|
||
let mut cursor = data.cursor();
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u16>();
|
||
let seg_count_x2: u16 = cursor.read()?;
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u16>();
|
||
let end_code_byte_len = (transforms::half(seg_count_x2))
|
||
.checked_mul(u16::RAW_BYTE_LEN)
|
||
.ok_or(ReadError::OutOfBounds)?;
|
||
cursor.advance_by(end_code_byte_len);
|
||
cursor.advance::<u16>();
|
||
let start_code_byte_len = (transforms::half(seg_count_x2))
|
||
.checked_mul(u16::RAW_BYTE_LEN)
|
||
.ok_or(ReadError::OutOfBounds)?;
|
||
cursor.advance_by(start_code_byte_len);
|
||
let id_delta_byte_len = (transforms::half(seg_count_x2))
|
||
.checked_mul(i16::RAW_BYTE_LEN)
|
||
.ok_or(ReadError::OutOfBounds)?;
|
||
cursor.advance_by(id_delta_byte_len);
|
||
let id_range_offsets_byte_len = (transforms::half(seg_count_x2))
|
||
.checked_mul(u16::RAW_BYTE_LEN)
|
||
.ok_or(ReadError::OutOfBounds)?;
|
||
cursor.advance_by(id_range_offsets_byte_len);
|
||
let glyph_id_array_byte_len =
|
||
cursor.remaining_bytes() / u16::RAW_BYTE_LEN * u16::RAW_BYTE_LEN;
|
||
cursor.advance_by(glyph_id_array_byte_len);
|
||
cursor.finish(Cmap4Marker {
|
||
end_code_byte_len,
|
||
start_code_byte_len,
|
||
id_delta_byte_len,
|
||
id_range_offsets_byte_len,
|
||
glyph_id_array_byte_len,
|
||
})
|
||
}
|
||
}
|
||
|
||
/// [cmap Format 4](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-4-segment-mapping-to-delta-values): Segment mapping to delta values
|
||
pub type Cmap4<'a> = TableRef<'a, Cmap4Marker>;
|
||
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> Cmap4<'a> {
|
||
/// Format number is set to 4.
|
||
pub fn format(&self) -> u16 {
|
||
let range = self.shape.format_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// This is the length in bytes of the subtable.
|
||
pub fn length(&self) -> u16 {
|
||
let range = self.shape.length_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// For requirements on use of the language field, see “Use of
|
||
/// the language field in 'cmap' subtables” in this document.
|
||
pub fn language(&self) -> u16 {
|
||
let range = self.shape.language_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// 2 × segCount.
|
||
pub fn seg_count_x2(&self) -> u16 {
|
||
let range = self.shape.seg_count_x2_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Maximum power of 2 less than or equal to segCount, times 2
|
||
/// ((2**floor(log2(segCount))) * 2, where “**” is an
|
||
/// exponentiation operator)
|
||
pub fn search_range(&self) -> u16 {
|
||
let range = self.shape.search_range_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Log2 of the maximum power of 2 less than or equal to numTables
|
||
/// (log2(searchRange/2), which is equal to floor(log2(segCount)))
|
||
pub fn entry_selector(&self) -> u16 {
|
||
let range = self.shape.entry_selector_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// segCount times 2, minus searchRange ((segCount * 2) -
|
||
/// searchRange)
|
||
pub fn range_shift(&self) -> u16 {
|
||
let range = self.shape.range_shift_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// End characterCode for each segment, last=0xFFFF.
|
||
pub fn end_code(&self) -> &'a [BigEndian<u16>] {
|
||
let range = self.shape.end_code_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
|
||
/// Start character code for each segment.
|
||
pub fn start_code(&self) -> &'a [BigEndian<u16>] {
|
||
let range = self.shape.start_code_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
|
||
/// Delta for all character codes in segment.
|
||
pub fn id_delta(&self) -> &'a [BigEndian<i16>] {
|
||
let range = self.shape.id_delta_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
|
||
/// Offsets into glyphIdArray or 0
|
||
pub fn id_range_offsets(&self) -> &'a [BigEndian<u16>] {
|
||
let range = self.shape.id_range_offsets_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
|
||
/// Glyph index array (arbitrary length)
|
||
pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] {
|
||
let range = self.shape.glyph_id_array_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeTable<'a> for Cmap4<'a> {
|
||
fn type_name(&self) -> &str {
|
||
"Cmap4"
|
||
}
|
||
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
|
||
match idx {
|
||
0usize => Some(Field::new("format", self.format())),
|
||
1usize => Some(Field::new("length", self.length())),
|
||
2usize => Some(Field::new("language", self.language())),
|
||
3usize => Some(Field::new("seg_count_x2", self.seg_count_x2())),
|
||
4usize => Some(Field::new("search_range", self.search_range())),
|
||
5usize => Some(Field::new("entry_selector", self.entry_selector())),
|
||
6usize => Some(Field::new("range_shift", self.range_shift())),
|
||
7usize => Some(Field::new("end_code", self.end_code())),
|
||
8usize => Some(Field::new("start_code", self.start_code())),
|
||
9usize => Some(Field::new("id_delta", self.id_delta())),
|
||
10usize => Some(Field::new("id_range_offsets", self.id_range_offsets())),
|
||
11usize => Some(Field::new("glyph_id_array", self.glyph_id_array())),
|
||
_ => None,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> std::fmt::Debug for Cmap4<'a> {
|
||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
(self as &dyn SomeTable<'a>).fmt(f)
|
||
}
|
||
}
|
||
|
||
impl Format<u16> for Cmap6Marker {
|
||
const FORMAT: u16 = 6;
|
||
}
|
||
|
||
/// [cmap Format 6](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-6-trimmed-table-mapping): Trimmed table mapping
|
||
#[derive(Debug, Clone, Copy)]
|
||
#[doc(hidden)]
|
||
pub struct Cmap6Marker {
|
||
glyph_id_array_byte_len: usize,
|
||
}
|
||
|
||
impl Cmap6Marker {
|
||
pub fn format_byte_range(&self) -> Range<usize> {
|
||
let start = 0;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn length_byte_range(&self) -> Range<usize> {
|
||
let start = self.format_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn language_byte_range(&self) -> Range<usize> {
|
||
let start = self.length_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn first_code_byte_range(&self) -> Range<usize> {
|
||
let start = self.language_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn entry_count_byte_range(&self) -> Range<usize> {
|
||
let start = self.first_code_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
|
||
let start = self.entry_count_byte_range().end;
|
||
start..start + self.glyph_id_array_byte_len
|
||
}
|
||
}
|
||
|
||
impl MinByteRange for Cmap6Marker {
|
||
fn min_byte_range(&self) -> Range<usize> {
|
||
0..self.glyph_id_array_byte_range().end
|
||
}
|
||
}
|
||
|
||
impl<'a> FontRead<'a> for Cmap6<'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>();
|
||
let entry_count: u16 = cursor.read()?;
|
||
let glyph_id_array_byte_len = (entry_count as usize)
|
||
.checked_mul(u16::RAW_BYTE_LEN)
|
||
.ok_or(ReadError::OutOfBounds)?;
|
||
cursor.advance_by(glyph_id_array_byte_len);
|
||
cursor.finish(Cmap6Marker {
|
||
glyph_id_array_byte_len,
|
||
})
|
||
}
|
||
}
|
||
|
||
/// [cmap Format 6](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-6-trimmed-table-mapping): Trimmed table mapping
|
||
pub type Cmap6<'a> = TableRef<'a, Cmap6Marker>;
|
||
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> Cmap6<'a> {
|
||
/// Format number is set to 6.
|
||
pub fn format(&self) -> u16 {
|
||
let range = self.shape.format_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// This is the length in bytes of the subtable.
|
||
pub fn length(&self) -> u16 {
|
||
let range = self.shape.length_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// For requirements on use of the language field, see “Use of
|
||
/// the language field in 'cmap' subtables” in this document.
|
||
pub fn language(&self) -> u16 {
|
||
let range = self.shape.language_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// First character code of subrange.
|
||
pub fn first_code(&self) -> u16 {
|
||
let range = self.shape.first_code_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Number of character codes in subrange.
|
||
pub fn entry_count(&self) -> u16 {
|
||
let range = self.shape.entry_count_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Array of glyph index values for character codes in the range.
|
||
pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] {
|
||
let range = self.shape.glyph_id_array_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeTable<'a> for Cmap6<'a> {
|
||
fn type_name(&self) -> &str {
|
||
"Cmap6"
|
||
}
|
||
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
|
||
match idx {
|
||
0usize => Some(Field::new("format", self.format())),
|
||
1usize => Some(Field::new("length", self.length())),
|
||
2usize => Some(Field::new("language", self.language())),
|
||
3usize => Some(Field::new("first_code", self.first_code())),
|
||
4usize => Some(Field::new("entry_count", self.entry_count())),
|
||
5usize => Some(Field::new("glyph_id_array", self.glyph_id_array())),
|
||
_ => None,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> std::fmt::Debug for Cmap6<'a> {
|
||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
(self as &dyn SomeTable<'a>).fmt(f)
|
||
}
|
||
}
|
||
|
||
impl Format<u16> for Cmap8Marker {
|
||
const FORMAT: u16 = 8;
|
||
}
|
||
|
||
/// [cmap Format 8](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-8-mixed-16-bit-and-32-bit-coverage): mixed 16-bit and 32-bit coverage
|
||
#[derive(Debug, Clone, Copy)]
|
||
#[doc(hidden)]
|
||
pub struct Cmap8Marker {
|
||
is32_byte_len: usize,
|
||
groups_byte_len: usize,
|
||
}
|
||
|
||
impl Cmap8Marker {
|
||
pub fn format_byte_range(&self) -> Range<usize> {
|
||
let start = 0;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn reserved_byte_range(&self) -> Range<usize> {
|
||
let start = self.format_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn length_byte_range(&self) -> Range<usize> {
|
||
let start = self.reserved_byte_range().end;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn language_byte_range(&self) -> Range<usize> {
|
||
let start = self.length_byte_range().end;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn is32_byte_range(&self) -> Range<usize> {
|
||
let start = self.language_byte_range().end;
|
||
start..start + self.is32_byte_len
|
||
}
|
||
|
||
pub fn num_groups_byte_range(&self) -> Range<usize> {
|
||
let start = self.is32_byte_range().end;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn groups_byte_range(&self) -> Range<usize> {
|
||
let start = self.num_groups_byte_range().end;
|
||
start..start + self.groups_byte_len
|
||
}
|
||
}
|
||
|
||
impl MinByteRange for Cmap8Marker {
|
||
fn min_byte_range(&self) -> Range<usize> {
|
||
0..self.groups_byte_range().end
|
||
}
|
||
}
|
||
|
||
impl<'a> FontRead<'a> for Cmap8<'a> {
|
||
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
|
||
let mut cursor = data.cursor();
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u32>();
|
||
cursor.advance::<u32>();
|
||
let is32_byte_len = (8192_usize)
|
||
.checked_mul(u8::RAW_BYTE_LEN)
|
||
.ok_or(ReadError::OutOfBounds)?;
|
||
cursor.advance_by(is32_byte_len);
|
||
let num_groups: u32 = cursor.read()?;
|
||
let groups_byte_len = (num_groups as usize)
|
||
.checked_mul(SequentialMapGroup::RAW_BYTE_LEN)
|
||
.ok_or(ReadError::OutOfBounds)?;
|
||
cursor.advance_by(groups_byte_len);
|
||
cursor.finish(Cmap8Marker {
|
||
is32_byte_len,
|
||
groups_byte_len,
|
||
})
|
||
}
|
||
}
|
||
|
||
/// [cmap Format 8](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-8-mixed-16-bit-and-32-bit-coverage): mixed 16-bit and 32-bit coverage
|
||
pub type Cmap8<'a> = TableRef<'a, Cmap8Marker>;
|
||
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> Cmap8<'a> {
|
||
/// Subtable format; set to 8.
|
||
pub fn format(&self) -> u16 {
|
||
let range = self.shape.format_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Byte length of this subtable (including the header)
|
||
pub fn length(&self) -> u32 {
|
||
let range = self.shape.length_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// For requirements on use of the language field, see “Use of
|
||
/// the language field in 'cmap' subtables” in this document.
|
||
pub fn language(&self) -> u32 {
|
||
let range = self.shape.language_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Tightly packed array of bits (8K bytes total) indicating
|
||
/// whether the particular 16-bit (index) value is the start of a
|
||
/// 32-bit character code
|
||
pub fn is32(&self) -> &'a [u8] {
|
||
let range = self.shape.is32_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
|
||
/// Number of groupings which follow
|
||
pub fn num_groups(&self) -> u32 {
|
||
let range = self.shape.num_groups_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Array of SequentialMapGroup records.
|
||
pub fn groups(&self) -> &'a [SequentialMapGroup] {
|
||
let range = self.shape.groups_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeTable<'a> for Cmap8<'a> {
|
||
fn type_name(&self) -> &str {
|
||
"Cmap8"
|
||
}
|
||
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
|
||
match idx {
|
||
0usize => Some(Field::new("format", self.format())),
|
||
1usize => Some(Field::new("length", self.length())),
|
||
2usize => Some(Field::new("language", self.language())),
|
||
3usize => Some(Field::new("is32", self.is32())),
|
||
4usize => Some(Field::new("num_groups", self.num_groups())),
|
||
5usize => Some(Field::new(
|
||
"groups",
|
||
traversal::FieldType::array_of_records(
|
||
stringify!(SequentialMapGroup),
|
||
self.groups(),
|
||
self.offset_data(),
|
||
),
|
||
)),
|
||
_ => None,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> std::fmt::Debug for Cmap8<'a> {
|
||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
(self as &dyn SomeTable<'a>).fmt(f)
|
||
}
|
||
}
|
||
|
||
/// Used in [Cmap8] and [Cmap12]
|
||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
|
||
#[repr(C)]
|
||
#[repr(packed)]
|
||
pub struct SequentialMapGroup {
|
||
/// First character code in this group; note that if this group is
|
||
/// for one or more 16-bit character codes (which is determined
|
||
/// from the is32 array), this 32-bit value will have the high
|
||
/// 16-bits set to zero
|
||
pub start_char_code: BigEndian<u32>,
|
||
/// Last character code in this group; same condition as listed
|
||
/// above for the startCharCode
|
||
pub end_char_code: BigEndian<u32>,
|
||
/// Glyph index corresponding to the starting character code
|
||
pub start_glyph_id: BigEndian<u32>,
|
||
}
|
||
|
||
impl SequentialMapGroup {
|
||
/// First character code in this group; note that if this group is
|
||
/// for one or more 16-bit character codes (which is determined
|
||
/// from the is32 array), this 32-bit value will have the high
|
||
/// 16-bits set to zero
|
||
pub fn start_char_code(&self) -> u32 {
|
||
self.start_char_code.get()
|
||
}
|
||
|
||
/// Last character code in this group; same condition as listed
|
||
/// above for the startCharCode
|
||
pub fn end_char_code(&self) -> u32 {
|
||
self.end_char_code.get()
|
||
}
|
||
|
||
/// Glyph index corresponding to the starting character code
|
||
pub fn start_glyph_id(&self) -> u32 {
|
||
self.start_glyph_id.get()
|
||
}
|
||
}
|
||
|
||
impl FixedSize for SequentialMapGroup {
|
||
const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeRecord<'a> for SequentialMapGroup {
|
||
fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
|
||
RecordResolver {
|
||
name: "SequentialMapGroup",
|
||
get_field: Box::new(move |idx, _data| match idx {
|
||
0usize => Some(Field::new("start_char_code", self.start_char_code())),
|
||
1usize => Some(Field::new("end_char_code", self.end_char_code())),
|
||
2usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
|
||
_ => None,
|
||
}),
|
||
data,
|
||
}
|
||
}
|
||
}
|
||
|
||
impl Format<u16> for Cmap10Marker {
|
||
const FORMAT: u16 = 10;
|
||
}
|
||
|
||
/// [cmap Format 10](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-10-trimmed-array): Tr
|
||
#[derive(Debug, Clone, Copy)]
|
||
#[doc(hidden)]
|
||
pub struct Cmap10Marker {
|
||
glyph_id_array_byte_len: usize,
|
||
}
|
||
|
||
impl Cmap10Marker {
|
||
pub fn format_byte_range(&self) -> Range<usize> {
|
||
let start = 0;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn reserved_byte_range(&self) -> Range<usize> {
|
||
let start = self.format_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn length_byte_range(&self) -> Range<usize> {
|
||
let start = self.reserved_byte_range().end;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn language_byte_range(&self) -> Range<usize> {
|
||
let start = self.length_byte_range().end;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn start_char_code_byte_range(&self) -> Range<usize> {
|
||
let start = self.language_byte_range().end;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn num_chars_byte_range(&self) -> Range<usize> {
|
||
let start = self.start_char_code_byte_range().end;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
|
||
let start = self.num_chars_byte_range().end;
|
||
start..start + self.glyph_id_array_byte_len
|
||
}
|
||
}
|
||
|
||
impl MinByteRange for Cmap10Marker {
|
||
fn min_byte_range(&self) -> Range<usize> {
|
||
0..self.glyph_id_array_byte_range().end
|
||
}
|
||
}
|
||
|
||
impl<'a> FontRead<'a> for Cmap10<'a> {
|
||
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
|
||
let mut cursor = data.cursor();
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u32>();
|
||
cursor.advance::<u32>();
|
||
cursor.advance::<u32>();
|
||
cursor.advance::<u32>();
|
||
let glyph_id_array_byte_len =
|
||
cursor.remaining_bytes() / u16::RAW_BYTE_LEN * u16::RAW_BYTE_LEN;
|
||
cursor.advance_by(glyph_id_array_byte_len);
|
||
cursor.finish(Cmap10Marker {
|
||
glyph_id_array_byte_len,
|
||
})
|
||
}
|
||
}
|
||
|
||
/// [cmap Format 10](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-10-trimmed-array): Tr
|
||
pub type Cmap10<'a> = TableRef<'a, Cmap10Marker>;
|
||
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> Cmap10<'a> {
|
||
/// Subtable format; set to 10.
|
||
pub fn format(&self) -> u16 {
|
||
let range = self.shape.format_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Byte length of this subtable (including the header)
|
||
pub fn length(&self) -> u32 {
|
||
let range = self.shape.length_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// For requirements on use of the language field, see “Use of
|
||
/// the language field in 'cmap' subtables” in this document.
|
||
pub fn language(&self) -> u32 {
|
||
let range = self.shape.language_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// First character code covered
|
||
pub fn start_char_code(&self) -> u32 {
|
||
let range = self.shape.start_char_code_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Number of character codes covered
|
||
pub fn num_chars(&self) -> u32 {
|
||
let range = self.shape.num_chars_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Array of glyph indices for the character codes covered
|
||
pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] {
|
||
let range = self.shape.glyph_id_array_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeTable<'a> for Cmap10<'a> {
|
||
fn type_name(&self) -> &str {
|
||
"Cmap10"
|
||
}
|
||
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
|
||
match idx {
|
||
0usize => Some(Field::new("format", self.format())),
|
||
1usize => Some(Field::new("length", self.length())),
|
||
2usize => Some(Field::new("language", self.language())),
|
||
3usize => Some(Field::new("start_char_code", self.start_char_code())),
|
||
4usize => Some(Field::new("num_chars", self.num_chars())),
|
||
5usize => Some(Field::new("glyph_id_array", self.glyph_id_array())),
|
||
_ => None,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> std::fmt::Debug for Cmap10<'a> {
|
||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
(self as &dyn SomeTable<'a>).fmt(f)
|
||
}
|
||
}
|
||
|
||
impl Format<u16> for Cmap12Marker {
|
||
const FORMAT: u16 = 12;
|
||
}
|
||
|
||
/// [cmap Format 12](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-12-segmented-coverage): Segmented coverage
|
||
#[derive(Debug, Clone, Copy)]
|
||
#[doc(hidden)]
|
||
pub struct Cmap12Marker {
|
||
groups_byte_len: usize,
|
||
}
|
||
|
||
impl Cmap12Marker {
|
||
pub fn format_byte_range(&self) -> Range<usize> {
|
||
let start = 0;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn reserved_byte_range(&self) -> Range<usize> {
|
||
let start = self.format_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn length_byte_range(&self) -> Range<usize> {
|
||
let start = self.reserved_byte_range().end;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn language_byte_range(&self) -> Range<usize> {
|
||
let start = self.length_byte_range().end;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn num_groups_byte_range(&self) -> Range<usize> {
|
||
let start = self.language_byte_range().end;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn groups_byte_range(&self) -> Range<usize> {
|
||
let start = self.num_groups_byte_range().end;
|
||
start..start + self.groups_byte_len
|
||
}
|
||
}
|
||
|
||
impl MinByteRange for Cmap12Marker {
|
||
fn min_byte_range(&self) -> Range<usize> {
|
||
0..self.groups_byte_range().end
|
||
}
|
||
}
|
||
|
||
impl<'a> FontRead<'a> for Cmap12<'a> {
|
||
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
|
||
let mut cursor = data.cursor();
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u32>();
|
||
cursor.advance::<u32>();
|
||
let num_groups: u32 = cursor.read()?;
|
||
let groups_byte_len = (num_groups as usize)
|
||
.checked_mul(SequentialMapGroup::RAW_BYTE_LEN)
|
||
.ok_or(ReadError::OutOfBounds)?;
|
||
cursor.advance_by(groups_byte_len);
|
||
cursor.finish(Cmap12Marker { groups_byte_len })
|
||
}
|
||
}
|
||
|
||
/// [cmap Format 12](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-12-segmented-coverage): Segmented coverage
|
||
pub type Cmap12<'a> = TableRef<'a, Cmap12Marker>;
|
||
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> Cmap12<'a> {
|
||
/// Subtable format; set to 12.
|
||
pub fn format(&self) -> u16 {
|
||
let range = self.shape.format_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Byte length of this subtable (including the header)
|
||
pub fn length(&self) -> u32 {
|
||
let range = self.shape.length_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// For requirements on use of the language field, see “Use of
|
||
/// the language field in 'cmap' subtables” in this document.
|
||
pub fn language(&self) -> u32 {
|
||
let range = self.shape.language_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Number of groupings which follow
|
||
pub fn num_groups(&self) -> u32 {
|
||
let range = self.shape.num_groups_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Array of SequentialMapGroup records.
|
||
pub fn groups(&self) -> &'a [SequentialMapGroup] {
|
||
let range = self.shape.groups_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeTable<'a> for Cmap12<'a> {
|
||
fn type_name(&self) -> &str {
|
||
"Cmap12"
|
||
}
|
||
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
|
||
match idx {
|
||
0usize => Some(Field::new("format", self.format())),
|
||
1usize => Some(Field::new("length", self.length())),
|
||
2usize => Some(Field::new("language", self.language())),
|
||
3usize => Some(Field::new("num_groups", self.num_groups())),
|
||
4usize => Some(Field::new(
|
||
"groups",
|
||
traversal::FieldType::array_of_records(
|
||
stringify!(SequentialMapGroup),
|
||
self.groups(),
|
||
self.offset_data(),
|
||
),
|
||
)),
|
||
_ => None,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> std::fmt::Debug for Cmap12<'a> {
|
||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
(self as &dyn SomeTable<'a>).fmt(f)
|
||
}
|
||
}
|
||
|
||
impl Format<u16> for Cmap13Marker {
|
||
const FORMAT: u16 = 13;
|
||
}
|
||
|
||
/// [cmap Format 13](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-13-many-to-one-range-mappings): Many-to-one range mappings
|
||
#[derive(Debug, Clone, Copy)]
|
||
#[doc(hidden)]
|
||
pub struct Cmap13Marker {
|
||
groups_byte_len: usize,
|
||
}
|
||
|
||
impl Cmap13Marker {
|
||
pub fn format_byte_range(&self) -> Range<usize> {
|
||
let start = 0;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn reserved_byte_range(&self) -> Range<usize> {
|
||
let start = self.format_byte_range().end;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn length_byte_range(&self) -> Range<usize> {
|
||
let start = self.reserved_byte_range().end;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn language_byte_range(&self) -> Range<usize> {
|
||
let start = self.length_byte_range().end;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn num_groups_byte_range(&self) -> Range<usize> {
|
||
let start = self.language_byte_range().end;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn groups_byte_range(&self) -> Range<usize> {
|
||
let start = self.num_groups_byte_range().end;
|
||
start..start + self.groups_byte_len
|
||
}
|
||
}
|
||
|
||
impl MinByteRange for Cmap13Marker {
|
||
fn min_byte_range(&self) -> Range<usize> {
|
||
0..self.groups_byte_range().end
|
||
}
|
||
}
|
||
|
||
impl<'a> FontRead<'a> for Cmap13<'a> {
|
||
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
|
||
let mut cursor = data.cursor();
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u32>();
|
||
cursor.advance::<u32>();
|
||
let num_groups: u32 = cursor.read()?;
|
||
let groups_byte_len = (num_groups as usize)
|
||
.checked_mul(ConstantMapGroup::RAW_BYTE_LEN)
|
||
.ok_or(ReadError::OutOfBounds)?;
|
||
cursor.advance_by(groups_byte_len);
|
||
cursor.finish(Cmap13Marker { groups_byte_len })
|
||
}
|
||
}
|
||
|
||
/// [cmap Format 13](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-13-many-to-one-range-mappings): Many-to-one range mappings
|
||
pub type Cmap13<'a> = TableRef<'a, Cmap13Marker>;
|
||
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> Cmap13<'a> {
|
||
/// Subtable format; set to 13.
|
||
pub fn format(&self) -> u16 {
|
||
let range = self.shape.format_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Byte length of this subtable (including the header)
|
||
pub fn length(&self) -> u32 {
|
||
let range = self.shape.length_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// For requirements on use of the language field, see “Use of
|
||
/// the language field in 'cmap' subtables” in this document.
|
||
pub fn language(&self) -> u32 {
|
||
let range = self.shape.language_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Number of groupings which follow
|
||
pub fn num_groups(&self) -> u32 {
|
||
let range = self.shape.num_groups_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Array of ConstantMapGroup records.
|
||
pub fn groups(&self) -> &'a [ConstantMapGroup] {
|
||
let range = self.shape.groups_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeTable<'a> for Cmap13<'a> {
|
||
fn type_name(&self) -> &str {
|
||
"Cmap13"
|
||
}
|
||
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
|
||
match idx {
|
||
0usize => Some(Field::new("format", self.format())),
|
||
1usize => Some(Field::new("length", self.length())),
|
||
2usize => Some(Field::new("language", self.language())),
|
||
3usize => Some(Field::new("num_groups", self.num_groups())),
|
||
4usize => Some(Field::new(
|
||
"groups",
|
||
traversal::FieldType::array_of_records(
|
||
stringify!(ConstantMapGroup),
|
||
self.groups(),
|
||
self.offset_data(),
|
||
),
|
||
)),
|
||
_ => None,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> std::fmt::Debug for Cmap13<'a> {
|
||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
(self as &dyn SomeTable<'a>).fmt(f)
|
||
}
|
||
}
|
||
|
||
/// Part of [Cmap13]
|
||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
|
||
#[repr(C)]
|
||
#[repr(packed)]
|
||
pub struct ConstantMapGroup {
|
||
/// First character code in this group
|
||
pub start_char_code: BigEndian<u32>,
|
||
/// Last character code in this group
|
||
pub end_char_code: BigEndian<u32>,
|
||
/// Glyph index to be used for all the characters in the group’s
|
||
/// range.
|
||
pub glyph_id: BigEndian<u32>,
|
||
}
|
||
|
||
impl ConstantMapGroup {
|
||
/// First character code in this group
|
||
pub fn start_char_code(&self) -> u32 {
|
||
self.start_char_code.get()
|
||
}
|
||
|
||
/// Last character code in this group
|
||
pub fn end_char_code(&self) -> u32 {
|
||
self.end_char_code.get()
|
||
}
|
||
|
||
/// Glyph index to be used for all the characters in the group’s
|
||
/// range.
|
||
pub fn glyph_id(&self) -> u32 {
|
||
self.glyph_id.get()
|
||
}
|
||
}
|
||
|
||
impl FixedSize for ConstantMapGroup {
|
||
const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeRecord<'a> for ConstantMapGroup {
|
||
fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
|
||
RecordResolver {
|
||
name: "ConstantMapGroup",
|
||
get_field: Box::new(move |idx, _data| match idx {
|
||
0usize => Some(Field::new("start_char_code", self.start_char_code())),
|
||
1usize => Some(Field::new("end_char_code", self.end_char_code())),
|
||
2usize => Some(Field::new("glyph_id", self.glyph_id())),
|
||
_ => None,
|
||
}),
|
||
data,
|
||
}
|
||
}
|
||
}
|
||
|
||
impl Format<u16> for Cmap14Marker {
|
||
const FORMAT: u16 = 14;
|
||
}
|
||
|
||
/// [cmap Format 14](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-14-unicode-variation-sequences): Unicode Variation Sequences
|
||
#[derive(Debug, Clone, Copy)]
|
||
#[doc(hidden)]
|
||
pub struct Cmap14Marker {
|
||
var_selector_byte_len: usize,
|
||
}
|
||
|
||
impl Cmap14Marker {
|
||
pub fn format_byte_range(&self) -> Range<usize> {
|
||
let start = 0;
|
||
start..start + u16::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn length_byte_range(&self) -> Range<usize> {
|
||
let start = self.format_byte_range().end;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn num_var_selector_records_byte_range(&self) -> Range<usize> {
|
||
let start = self.length_byte_range().end;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn var_selector_byte_range(&self) -> Range<usize> {
|
||
let start = self.num_var_selector_records_byte_range().end;
|
||
start..start + self.var_selector_byte_len
|
||
}
|
||
}
|
||
|
||
impl MinByteRange for Cmap14Marker {
|
||
fn min_byte_range(&self) -> Range<usize> {
|
||
0..self.var_selector_byte_range().end
|
||
}
|
||
}
|
||
|
||
impl<'a> FontRead<'a> for Cmap14<'a> {
|
||
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
|
||
let mut cursor = data.cursor();
|
||
cursor.advance::<u16>();
|
||
cursor.advance::<u32>();
|
||
let num_var_selector_records: u32 = cursor.read()?;
|
||
let var_selector_byte_len = (num_var_selector_records as usize)
|
||
.checked_mul(VariationSelector::RAW_BYTE_LEN)
|
||
.ok_or(ReadError::OutOfBounds)?;
|
||
cursor.advance_by(var_selector_byte_len);
|
||
cursor.finish(Cmap14Marker {
|
||
var_selector_byte_len,
|
||
})
|
||
}
|
||
}
|
||
|
||
/// [cmap Format 14](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-14-unicode-variation-sequences): Unicode Variation Sequences
|
||
pub type Cmap14<'a> = TableRef<'a, Cmap14Marker>;
|
||
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> Cmap14<'a> {
|
||
/// Subtable format. Set to 14.
|
||
pub fn format(&self) -> u16 {
|
||
let range = self.shape.format_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Byte length of this subtable (including this header)
|
||
pub fn length(&self) -> u32 {
|
||
let range = self.shape.length_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Number of variation Selector Records
|
||
pub fn num_var_selector_records(&self) -> u32 {
|
||
let range = self.shape.num_var_selector_records_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Array of VariationSelector records.
|
||
pub fn var_selector(&self) -> &'a [VariationSelector] {
|
||
let range = self.shape.var_selector_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeTable<'a> for Cmap14<'a> {
|
||
fn type_name(&self) -> &str {
|
||
"Cmap14"
|
||
}
|
||
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
|
||
match idx {
|
||
0usize => Some(Field::new("format", self.format())),
|
||
1usize => Some(Field::new("length", self.length())),
|
||
2usize => Some(Field::new(
|
||
"num_var_selector_records",
|
||
self.num_var_selector_records(),
|
||
)),
|
||
3usize => Some(Field::new(
|
||
"var_selector",
|
||
traversal::FieldType::array_of_records(
|
||
stringify!(VariationSelector),
|
||
self.var_selector(),
|
||
self.offset_data(),
|
||
),
|
||
)),
|
||
_ => None,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> std::fmt::Debug for Cmap14<'a> {
|
||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
(self as &dyn SomeTable<'a>).fmt(f)
|
||
}
|
||
}
|
||
|
||
/// Part of [Cmap14]
|
||
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
|
||
#[repr(C)]
|
||
#[repr(packed)]
|
||
pub struct VariationSelector {
|
||
/// Variation selector
|
||
pub var_selector: BigEndian<Uint24>,
|
||
/// Offset from the start of the [`Cmap14`] subtable to Default UVS
|
||
/// Table. May be NULL.
|
||
pub default_uvs_offset: BigEndian<Nullable<Offset32>>,
|
||
/// Offset from the start of the [`Cmap14`] subtable to Non-Default
|
||
/// UVS Table. May be NULL.
|
||
pub non_default_uvs_offset: BigEndian<Nullable<Offset32>>,
|
||
}
|
||
|
||
impl VariationSelector {
|
||
/// Variation selector
|
||
pub fn var_selector(&self) -> Uint24 {
|
||
self.var_selector.get()
|
||
}
|
||
|
||
/// Offset from the start of the [`Cmap14`] subtable to Default UVS
|
||
/// Table. May be NULL.
|
||
pub fn default_uvs_offset(&self) -> Nullable<Offset32> {
|
||
self.default_uvs_offset.get()
|
||
}
|
||
|
||
/// Offset from the start of the [`Cmap14`] subtable to Default UVS
|
||
/// Table. May be NULL.
|
||
///
|
||
/// The `data` argument should be retrieved from the parent table
|
||
/// By calling its `offset_data` method.
|
||
pub fn default_uvs<'a>(&self, data: FontData<'a>) -> Option<Result<DefaultUvs<'a>, ReadError>> {
|
||
self.default_uvs_offset().resolve(data)
|
||
}
|
||
|
||
/// Offset from the start of the [`Cmap14`] subtable to Non-Default
|
||
/// UVS Table. May be NULL.
|
||
pub fn non_default_uvs_offset(&self) -> Nullable<Offset32> {
|
||
self.non_default_uvs_offset.get()
|
||
}
|
||
|
||
/// Offset from the start of the [`Cmap14`] subtable to Non-Default
|
||
/// UVS Table. May be NULL.
|
||
///
|
||
/// The `data` argument should be retrieved from the parent table
|
||
/// By calling its `offset_data` method.
|
||
pub fn non_default_uvs<'a>(
|
||
&self,
|
||
data: FontData<'a>,
|
||
) -> Option<Result<NonDefaultUvs<'a>, ReadError>> {
|
||
self.non_default_uvs_offset().resolve(data)
|
||
}
|
||
}
|
||
|
||
impl FixedSize for VariationSelector {
|
||
const RAW_BYTE_LEN: usize =
|
||
Uint24::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeRecord<'a> for VariationSelector {
|
||
fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
|
||
RecordResolver {
|
||
name: "VariationSelector",
|
||
get_field: Box::new(move |idx, _data| match idx {
|
||
0usize => Some(Field::new("var_selector", self.var_selector())),
|
||
1usize => Some(Field::new(
|
||
"default_uvs_offset",
|
||
FieldType::offset(self.default_uvs_offset(), self.default_uvs(_data)),
|
||
)),
|
||
2usize => Some(Field::new(
|
||
"non_default_uvs_offset",
|
||
FieldType::offset(self.non_default_uvs_offset(), self.non_default_uvs(_data)),
|
||
)),
|
||
_ => None,
|
||
}),
|
||
data,
|
||
}
|
||
}
|
||
}
|
||
|
||
/// [Default UVS table](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#default-uvs-table)
|
||
#[derive(Debug, Clone, Copy)]
|
||
#[doc(hidden)]
|
||
pub struct DefaultUvsMarker {
|
||
ranges_byte_len: usize,
|
||
}
|
||
|
||
impl DefaultUvsMarker {
|
||
pub fn num_unicode_value_ranges_byte_range(&self) -> Range<usize> {
|
||
let start = 0;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn ranges_byte_range(&self) -> Range<usize> {
|
||
let start = self.num_unicode_value_ranges_byte_range().end;
|
||
start..start + self.ranges_byte_len
|
||
}
|
||
}
|
||
|
||
impl MinByteRange for DefaultUvsMarker {
|
||
fn min_byte_range(&self) -> Range<usize> {
|
||
0..self.ranges_byte_range().end
|
||
}
|
||
}
|
||
|
||
impl<'a> FontRead<'a> for DefaultUvs<'a> {
|
||
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
|
||
let mut cursor = data.cursor();
|
||
let num_unicode_value_ranges: u32 = cursor.read()?;
|
||
let ranges_byte_len = (num_unicode_value_ranges as usize)
|
||
.checked_mul(UnicodeRange::RAW_BYTE_LEN)
|
||
.ok_or(ReadError::OutOfBounds)?;
|
||
cursor.advance_by(ranges_byte_len);
|
||
cursor.finish(DefaultUvsMarker { ranges_byte_len })
|
||
}
|
||
}
|
||
|
||
/// [Default UVS table](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#default-uvs-table)
|
||
pub type DefaultUvs<'a> = TableRef<'a, DefaultUvsMarker>;
|
||
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> DefaultUvs<'a> {
|
||
/// Number of Unicode character ranges.
|
||
pub fn num_unicode_value_ranges(&self) -> u32 {
|
||
let range = self.shape.num_unicode_value_ranges_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
/// Array of UnicodeRange records.
|
||
pub fn ranges(&self) -> &'a [UnicodeRange] {
|
||
let range = self.shape.ranges_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeTable<'a> for DefaultUvs<'a> {
|
||
fn type_name(&self) -> &str {
|
||
"DefaultUvs"
|
||
}
|
||
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
|
||
match idx {
|
||
0usize => Some(Field::new(
|
||
"num_unicode_value_ranges",
|
||
self.num_unicode_value_ranges(),
|
||
)),
|
||
1usize => Some(Field::new(
|
||
"ranges",
|
||
traversal::FieldType::array_of_records(
|
||
stringify!(UnicodeRange),
|
||
self.ranges(),
|
||
self.offset_data(),
|
||
),
|
||
)),
|
||
_ => None,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> std::fmt::Debug for DefaultUvs<'a> {
|
||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
(self as &dyn SomeTable<'a>).fmt(f)
|
||
}
|
||
}
|
||
|
||
/// [Non-Default UVS table](https://learn.microsoft.com/en-us/typography/opentype/spec/cmap#non-default-uvs-table)
|
||
#[derive(Debug, Clone, Copy)]
|
||
#[doc(hidden)]
|
||
pub struct NonDefaultUvsMarker {
|
||
uvs_mapping_byte_len: usize,
|
||
}
|
||
|
||
impl NonDefaultUvsMarker {
|
||
pub fn num_uvs_mappings_byte_range(&self) -> Range<usize> {
|
||
let start = 0;
|
||
start..start + u32::RAW_BYTE_LEN
|
||
}
|
||
|
||
pub fn uvs_mapping_byte_range(&self) -> Range<usize> {
|
||
let start = self.num_uvs_mappings_byte_range().end;
|
||
start..start + self.uvs_mapping_byte_len
|
||
}
|
||
}
|
||
|
||
impl MinByteRange for NonDefaultUvsMarker {
|
||
fn min_byte_range(&self) -> Range<usize> {
|
||
0..self.uvs_mapping_byte_range().end
|
||
}
|
||
}
|
||
|
||
impl<'a> FontRead<'a> for NonDefaultUvs<'a> {
|
||
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
|
||
let mut cursor = data.cursor();
|
||
let num_uvs_mappings: u32 = cursor.read()?;
|
||
let uvs_mapping_byte_len = (num_uvs_mappings as usize)
|
||
.checked_mul(UvsMapping::RAW_BYTE_LEN)
|
||
.ok_or(ReadError::OutOfBounds)?;
|
||
cursor.advance_by(uvs_mapping_byte_len);
|
||
cursor.finish(NonDefaultUvsMarker {
|
||
uvs_mapping_byte_len,
|
||
})
|
||
}
|
||
}
|
||
|
||
/// [Non-Default UVS table](https://learn.microsoft.com/en-us/typography/opentype/spec/cmap#non-default-uvs-table)
|
||
pub type NonDefaultUvs<'a> = TableRef<'a, NonDefaultUvsMarker>;
|
||
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> NonDefaultUvs<'a> {
|
||
pub fn num_uvs_mappings(&self) -> u32 {
|
||
let range = self.shape.num_uvs_mappings_byte_range();
|
||
self.data.read_at(range.start).unwrap()
|
||
}
|
||
|
||
pub fn uvs_mapping(&self) -> &'a [UvsMapping] {
|
||
let range = self.shape.uvs_mapping_byte_range();
|
||
self.data.read_array(range).unwrap()
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeTable<'a> for NonDefaultUvs<'a> {
|
||
fn type_name(&self) -> &str {
|
||
"NonDefaultUvs"
|
||
}
|
||
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
|
||
match idx {
|
||
0usize => Some(Field::new("num_uvs_mappings", self.num_uvs_mappings())),
|
||
1usize => Some(Field::new(
|
||
"uvs_mapping",
|
||
traversal::FieldType::array_of_records(
|
||
stringify!(UvsMapping),
|
||
self.uvs_mapping(),
|
||
self.offset_data(),
|
||
),
|
||
)),
|
||
_ => None,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
#[allow(clippy::needless_lifetimes)]
|
||
impl<'a> std::fmt::Debug for NonDefaultUvs<'a> {
|
||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
(self as &dyn SomeTable<'a>).fmt(f)
|
||
}
|
||
}
|
||
|
||
/// Part of [Cmap14]
|
||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
|
||
#[repr(C)]
|
||
#[repr(packed)]
|
||
pub struct UvsMapping {
|
||
/// Base Unicode value of the UVS
|
||
pub unicode_value: BigEndian<Uint24>,
|
||
/// Glyph ID of the UVS
|
||
pub glyph_id: BigEndian<u16>,
|
||
}
|
||
|
||
impl UvsMapping {
|
||
/// Base Unicode value of the UVS
|
||
pub fn unicode_value(&self) -> Uint24 {
|
||
self.unicode_value.get()
|
||
}
|
||
|
||
/// Glyph ID of the UVS
|
||
pub fn glyph_id(&self) -> u16 {
|
||
self.glyph_id.get()
|
||
}
|
||
}
|
||
|
||
impl FixedSize for UvsMapping {
|
||
const RAW_BYTE_LEN: usize = Uint24::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeRecord<'a> for UvsMapping {
|
||
fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
|
||
RecordResolver {
|
||
name: "UvsMapping",
|
||
get_field: Box::new(move |idx, _data| match idx {
|
||
0usize => Some(Field::new("unicode_value", self.unicode_value())),
|
||
1usize => Some(Field::new("glyph_id", self.glyph_id())),
|
||
_ => None,
|
||
}),
|
||
data,
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Part of [Cmap14]
|
||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
|
||
#[repr(C)]
|
||
#[repr(packed)]
|
||
pub struct UnicodeRange {
|
||
/// First value in this range
|
||
pub start_unicode_value: BigEndian<Uint24>,
|
||
/// Number of additional values in this range
|
||
pub additional_count: u8,
|
||
}
|
||
|
||
impl UnicodeRange {
|
||
/// First value in this range
|
||
pub fn start_unicode_value(&self) -> Uint24 {
|
||
self.start_unicode_value.get()
|
||
}
|
||
|
||
/// Number of additional values in this range
|
||
pub fn additional_count(&self) -> u8 {
|
||
self.additional_count
|
||
}
|
||
}
|
||
|
||
impl FixedSize for UnicodeRange {
|
||
const RAW_BYTE_LEN: usize = Uint24::RAW_BYTE_LEN + u8::RAW_BYTE_LEN;
|
||
}
|
||
|
||
#[cfg(feature = "experimental_traverse")]
|
||
impl<'a> SomeRecord<'a> for UnicodeRange {
|
||
fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
|
||
RecordResolver {
|
||
name: "UnicodeRange",
|
||
get_field: Box::new(move |idx, _data| match idx {
|
||
0usize => Some(Field::new(
|
||
"start_unicode_value",
|
||
self.start_unicode_value(),
|
||
)),
|
||
1usize => Some(Field::new("additional_count", self.additional_count())),
|
||
_ => None,
|
||
}),
|
||
data,
|
||
}
|
||
}
|
||
}
|