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

2133 lines
68 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// THIS FILE IS AUTOGENERATED.
// Any changes to this file will be overwritten.
// For more information about how codegen works, see font-codegen/README.md
#[allow(unused_imports)]
use crate::codegen_prelude::*;
/// [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 groups
/// 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 groups
/// 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,
}
}
}